diff --git a/Cargo.lock b/Cargo.lock index 3aba4e3c04..17d905b754 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,60 +13,24 @@ dependencies = [ ] [[package]] -name = "actix" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de7fa236829ba0841304542f7614c42b80fca007455315c45c785ccfa873a85b" -dependencies = [ - "actix-macros", - "actix-rt", - "actix_derive", - "bitflags 2.5.0", - "bytes", - "crossbeam-channel", - "futures-core", - "futures-sink", - "futures-task", - "futures-util", - "log", - "once_cell", - "parking_lot 0.12.1", - "pin-project-lite", - "smallvec", - "tokio", - "tokio-util 0.7.10", -] - -[[package]] -name = "actix-macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +name = "abstract-domain-derive" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ + "proc-macro2", "quote", - "syn 2.0.60", -] - -[[package]] -name = "actix-rt" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" -dependencies = [ - "actix-macros", - "futures-core", - "tokio", + "syn 1.0.109", ] [[package]] -name = "actix_derive" -version = "0.6.1" +name = "addchain" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c7db3d5a9718568e4cf4a537cfd7070e6e6ff7481510d0237fb529ac850f6d3" +checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", + "num-bigint 0.3.3", + "num-integer", + "num-traits", ] [[package]] @@ -75,7 +39,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ - "gimli 0.28.1", + "gimli", ] [[package]] @@ -84,6 +48,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array 0.14.7", +] + [[package]] name = "aes" version = "0.8.4" @@ -91,10 +65,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if 1.0.0", - "cipher 0.4.4", + "cipher", "cpufeatures", ] +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle 2.5.0", +] + [[package]] name = "ahash" version = "0.7.8" @@ -128,6 +116,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + [[package]] name = "allocator-api2" version = "0.2.16" @@ -387,7 +381,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a43b18702501396fa9bcdeecd533bc85fac75150d308fc0f6800a01e6234a003" dependencies = [ "alloy-rlp-derive", - "arrayvec", + "arrayvec 0.7.4", "bytes", ] @@ -399,7 +393,7 @@ checksum = "d83524c1f6162fcb5b0decf775498a125066c86dda6066ed609531b0e912f85a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -526,7 +520,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -543,7 +537,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", "syn-solidity", "tiny-keccak", ] @@ -561,7 +555,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.60", + "syn 2.0.77", "syn-solidity", ] @@ -637,7 +631,7 @@ dependencies = [ "pin-project", "serde_json", "tokio", - "tokio-util 0.7.10", + "tokio-util", "tracing", ] @@ -679,6 +673,15 @@ dependencies = [ "libc", ] +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "anstream" version = "0.6.13" @@ -734,3306 +737,4030 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] -name = "aptos-verifier" +name = "aptos-aggregator" version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "bcs", - "hex-literal", - "sha3", - "thiserror", - "unionlabs", + "aptos-logger", + "aptos-types", + "bcs 0.1.4", + "claims", + "move-binary-format", + "move-core-types", + "move-vm-types", ] [[package]] -name = "arbitrary" -version = "1.3.2" -source = "git+https://github.com/unionlabs/arbitrary#b5796f1a0066dc5707d7681a80e19b99a910987d" +name = "aptos-api-types" +version = "0.0.1" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "derive_arbitrary", + "anyhow", + "aptos-config", + "aptos-crypto", + "aptos-framework", + "aptos-logger", + "aptos-openapi", + "aptos-types", + "async-trait", + "bcs 0.1.4", + "bytes", + "hex", + "indoc", + "move-binary-format", + "move-core-types", + "once_cell", + "poem", + "poem-openapi", + "poem-openapi-derive", + "serde", + "serde_json", ] [[package]] -name = "arbitrum-light-client" +name = "aptos-bitvec" version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "arbitrum-verifier", - "base64 0.21.7", - "cosmwasm-std 1.5.2", - "ethereum-light-client", - "ethereum-verifier", - "ethers-core", - "hex", - "ics008-wasm-client", - "protos", - "rlp", - "schemars", "serde", - "serde-json-wasm 1.0.1", - "serde_json", - "sha3", - "thiserror", - "tiny-keccak", - "unionlabs", + "serde_bytes", ] [[package]] -name = "arbitrum-verifier" +name = "aptos-config" version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "error_reporter", - "ethereum-verifier", - "ethers-core", - "hex", - "hex-literal", - "rlp", + "anyhow", + "aptos-crypto", + "aptos-global-constants", + "aptos-logger", + "aptos-secure-storage", + "aptos-short-hex-str", + "aptos-temppath", + "aptos-types", + "arr_macro", + "bcs 0.1.4", + "byteorder", + "cfg-if 1.0.0", + "get_if_addrs", + "maplit", + "num_cpus", + "poem-openapi", + "rand 0.7.3", "serde", - "serde-utils", "serde_json", - "sha3", + "serde_merge", + "serde_yaml 0.8.26", "thiserror", - "unionlabs", + "url", ] [[package]] -name = "arith" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556cabf32c649f5d6ccfbcc5bdf9f5a7cc4aa1eb5043cdabedff3fd49dd2cab9" - -[[package]] -name = "ark-bls12-377" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb00293ba84f51ce3bd026bd0de55899c4e68f0a39a5728cebae3a73ffdc0a4f" +name = "aptos-crypto" +version = "0.0.3" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ + "aes-gcm", + "anyhow", + "aptos-crypto-derive", + "ark-bn254", "ark-ec", "ark-ff 0.4.2", + "ark-groth16", "ark-std 0.4.0", + "base64 0.13.1", + "bcs 0.1.4", + "blst", + "bulletproofs", + "bytes", + "curve25519-dalek 3.2.0", + "curve25519-dalek-ng", + "digest 0.9.0", + "ed25519-dalek 1.0.1", + "ff", + "hex", + "hkdf 0.10.0", + "libsecp256k1 0.7.1", + "merlin", + "more-asserts", + "neptune", + "num-bigint 0.3.3", + "num-integer", + "once_cell", + "p256", + "poseidon-ark", + "rand 0.7.3", + "rand_core 0.5.1", + "ring 0.16.20", + "serde", + "serde-name", + "serde_bytes", + "sha2 0.10.8", + "sha2 0.9.9", + "sha3 0.9.1", + "signature 2.2.0", + "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror", + "tiny-keccak", + "typenum", + "x25519-dalek", ] [[package]] -name = "ark-bls12-381" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +name = "aptos-crypto-derive" +version = "0.0.3" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "ark-ec", - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "ark-bn254" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +name = "aptos-dkg" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "ark-ec", - "ark-ff 0.4.2", - "ark-std 0.4.0", + "anyhow", + "aptos-crypto", + "aptos-crypto-derive", + "aptos-runtimes", + "bcs 0.1.4", + "blst", + "blstrs", + "criterion", + "ff", + "group", + "hex", + "merlin", + "more-asserts", + "num-bigint 0.3.3", + "num-integer", + "num-traits", + "once_cell", + "pairing", + "rand 0.7.3", + "rand_core 0.5.1", + "rayon", + "serde", + "serde_bytes", + "sha3 0.9.1", + "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "ark-ec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +name = "aptos-experimental-runtimes" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" +dependencies = [ + "aptos-runtimes", + "core_affinity", + "libc", + "num_cpus", + "once_cell", + "rayon", +] + +[[package]] +name = "aptos-framework" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ + "anyhow", + "aptos-aggregator", + "aptos-crypto", + "aptos-gas-algebra", + "aptos-gas-schedule", + "aptos-move-stdlib", + "aptos-native-interface", + "aptos-sdk-builder", + "aptos-types", + "aptos-vm-types", + "ark-bls12-381", + "ark-bn254", + "ark-ec", "ark-ff 0.4.2", - "ark-poly", "ark-serialize 0.4.2", "ark-std 0.4.0", - "derivative", - "hashbrown 0.13.2", - "itertools 0.10.5", + "bcs 0.1.4", + "better_any", + "blake2-rfc", + "bulletproofs", + "byteorder", + "clap 4.5.4", + "codespan-reporting", + "curve25519-dalek-ng", + "either", + "flate2", + "hex", + "itertools 0.13.0", + "libsecp256k1 0.7.1", + "log", + "lru 0.7.8", + "merlin", + "move-binary-format", + "move-command-line-common", + "move-compiler", + "move-compiler-v2", + "move-core-types", + "move-docgen", + "move-model", + "move-package", + "move-stackless-bytecode", + "move-vm-runtime", + "move-vm-types", "num-traits", - "rayon", - "zeroize", + "once_cell", + "rand 0.7.3", + "rand_core 0.5.1", + "ripemd", + "serde", + "serde_bytes", + "sha2 0.10.8", + "sha2 0.9.9", + "sha3 0.9.1", + "siphasher", + "smallvec", + "tempfile", + "thiserror", + "tiny-keccak", ] [[package]] -name = "ark-ff" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +name = "aptos-gas-algebra" +version = "0.0.1" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" 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 0.4.4", - "num-traits", - "paste", - "rustc_version 0.3.3", - "zeroize", + "either", + "move-core-types", ] [[package]] -name = "ark-ff" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +name = "aptos-gas-schedule" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" 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 0.4.4", - "num-traits", + "aptos-gas-algebra", + "aptos-global-constants", + "move-core-types", + "move-vm-types", "paste", - "rayon", - "rustc_version 0.4.0", - "zeroize", + "rand 0.7.3", ] [[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", -] +name = "aptos-global-constants" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" [[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", -] +name = "aptos-infallible" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" [[package]] -name = "ark-ff-macros" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +name = "aptos-log-derive" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "num-bigint 0.4.4", - "num-traits", + "proc-macro2", "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" +name = "aptos-logger" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "num-bigint 0.4.4", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", + "aptos-infallible", + "aptos-log-derive", + "backtrace", + "chrono", + "erased-serde 0.3.31", + "futures", + "hostname", + "once_cell", + "prometheus", + "serde", + "serde_json", + "strum 0.24.1", + "strum_macros 0.24.3", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", ] [[package]] -name = "ark-poly" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +name = "aptos-move-stdlib" +version = "0.1.1" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "derivative", - "hashbrown 0.13.2", + "aptos-gas-schedule", + "aptos-native-interface", + "move-core-types", + "move-vm-runtime", + "move-vm-types", + "sha2 0.9.9", + "sha3 0.9.1", + "smallvec", ] [[package]] -name = "ark-serialize" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +name = "aptos-native-interface" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "ark-std 0.3.0", - "digest 0.9.0", + "aptos-gas-algebra", + "aptos-gas-schedule", + "aptos-types", + "bcs 0.1.4", + "bytes", + "move-binary-format", + "move-core-types", + "move-vm-runtime", + "move-vm-types", + "smallvec", ] [[package]] -name = "ark-serialize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +name = "aptos-openapi" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "ark-serialize-derive", - "ark-std 0.4.0", - "digest 0.10.7", - "num-bigint 0.4.4", + "percent-encoding", + "poem", + "poem-openapi", + "serde", + "serde_json", ] [[package]] -name = "ark-serialize-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +name = "aptos-rest-client" +version = "0.0.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "anyhow", + "aptos-api-types", + "aptos-crypto", + "aptos-infallible", + "aptos-logger", + "aptos-types", + "bcs 0.1.4", + "bytes", + "hex", + "move-core-types", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror", + "time", + "tokio", + "url", ] [[package]] -name = "ark-std" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +name = "aptos-rpc" +version = "0.1.0" dependencies = [ - "num-traits", - "rand 0.8.5", + "hex", + "macros", + "reqwest 0.11.27", + "serde", + "serde-utils", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", + "unionlabs", ] [[package]] -name = "ark-std" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +name = "aptos-runtimes" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "num-traits", - "rand 0.8.5", "rayon", + "tokio", ] [[package]] -name = "arrayref" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +name = "aptos-sdk-builder" +version = "0.2.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" +dependencies = [ + "anyhow", + "aptos-types", + "bcs 0.1.4", + "clap 4.5.4", + "heck 0.4.1", + "move-core-types", + "once_cell", + "serde-generate", + "serde-reflection", + "serde_yaml 0.8.26", + "textwrap 0.15.2", +] [[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +name = "aptos-secure-storage" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" +dependencies = [ + "aptos-crypto", + "aptos-infallible", + "aptos-logger", + "aptos-temppath", + "aptos-time-service", + "aptos-vault-client", + "base64 0.13.1", + "bcs 0.1.4", + "chrono", + "enum_dispatch", + "rand 0.7.3", + "serde", + "serde_json", + "thiserror", +] [[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +name = "aptos-short-hex-str" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "term", + "mirai-annotations", + "serde", + "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror", ] [[package]] -name = "ascii_utils" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a" +name = "aptos-temppath" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" +dependencies = [ + "hex", + "rand 0.7.3", +] [[package]] -name = "assert_matches" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" +name = "aptos-time-service" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" +dependencies = [ + "aptos-infallible", + "enum_dispatch", + "futures", + "pin-project", + "thiserror", + "tokio", +] [[package]] -name = "async-graphql" -version = "7.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf338d20ba5bab309f55ce8df95d65ee19446f7737f06f4a64593ab2c6b546ad" +name = "aptos-types" +version = "0.0.3" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "async-graphql-derive", - "async-graphql-parser", - "async-graphql-value", - "async-stream", - "async-trait", - "base64 0.22.1", + "anyhow", + "aptos-bitvec", + "aptos-crypto", + "aptos-crypto-derive", + "aptos-dkg", + "aptos-experimental-runtimes", + "aptos-infallible", + "ark-bn254", + "ark-ff 0.4.2", + "ark-groth16", + "ark-serialize 0.4.2", + "arr_macro", + "base64 0.13.1", + "bcs 0.1.4", "bytes", - "fast_chemail", - "fnv", - "futures-util", - "handlebars", - "http 1.1.0", - "indexmap 2.2.6", - "mime", - "multer", + "fixed", + "fxhash", + "hashbrown 0.14.3", + "hex", + "itertools 0.13.0", + "jsonwebtoken 8.3.0", + "move-binary-format", + "move-bytecode-verifier", + "move-core-types", + "move-table-extension", + "move-vm-runtime", + "move-vm-types", + "num-bigint 0.3.3", + "num-derive", "num-traits", "once_cell", - "pin-project-lite", - "regex", + "passkey-types", + "poem-openapi", + "poem-openapi-derive", + "quick_cache", + "rand 0.7.3", + "rayon", + "ring 0.16.20", + "rsa", "serde", + "serde-big-array", + "serde_bytes", "serde_json", - "serde_urlencoded", - "static_assertions_next", - "tempfile", + "serde_with", + "serde_yaml 0.8.26", + "strum 0.24.1", + "strum_macros 0.24.3", "thiserror", ] [[package]] -name = "async-graphql-axum" -version = "7.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28f874ad4bc10519f3fa500e36814452033a5ce9ea681ab0a2e0d3b1f18bae44" +name = "aptos-vault-client" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "async-graphql", - "async-trait", - "axum 0.7.5", - "bytes", - "futures-util", + "aptos-crypto", + "base64 0.13.1", + "chrono", + "native-tls", + "once_cell", + "serde", "serde_json", - "tokio", - "tokio-stream", - "tokio-util 0.7.10", - "tower-service", + "thiserror", + "ureq", ] [[package]] -name = "async-graphql-derive" -version = "7.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc51fd6b7102acda72bc94e8ae1543844d5688ff394a6cf7c21f2a07fe2d64e4" +name = "aptos-verifier" +version = "0.1.0" dependencies = [ - "Inflector", - "async-graphql-parser", - "darling 0.20.8", - "proc-macro-crate 3.1.0", - "proc-macro2", - "quote", - "strum 0.26.2", - "syn 2.0.60", + "bcs 0.1.4", + "hex-literal", + "sha3 0.10.8", "thiserror", + "unionlabs", ] [[package]] -name = "async-graphql-parser" -version = "7.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75361eefd64e39f89bead4cb45fddbaf60ddb0e7b15fb7c852b6088bcd63071f" +name = "aptos-vm-types" +version = "0.0.1" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "async-graphql-value", - "pest", + "anyhow", + "aptos-aggregator", + "aptos-gas-algebra", + "aptos-gas-schedule", + "aptos-types", + "bcs 0.1.4", + "bytes", + "claims", + "either", + "move-binary-format", + "move-core-types", + "move-vm-runtime", + "move-vm-types", + "rand 0.7.3", "serde", - "serde_json", ] [[package]] -name = "async-graphql-value" -version = "7.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f665d2d52b41c4ed1f01c43f3ef27a2fe0af2452ed5c8bc7ac9b1a8719afaa" +name = "arbitrary" +version = "1.3.2" +source = "git+https://github.com/unionlabs/arbitrary#b5796f1a0066dc5707d7681a80e19b99a910987d" dependencies = [ - "bytes", - "indexmap 2.2.6", + "derive_arbitrary", +] + +[[package]] +name = "arbitrum-light-client" +version = "0.1.0" +dependencies = [ + "arbitrum-verifier", + "base64 0.21.7", + "cosmwasm-std 1.5.2", + "ethereum-light-client", + "ethereum-verifier", + "ethers-core", + "hex", + "ics008-wasm-client", + "protos", + "rlp", + "schemars", "serde", + "serde-json-wasm 1.0.1", "serde_json", + "sha3 0.10.8", + "thiserror", + "tiny-keccak", + "unionlabs", ] [[package]] -name = "async-lock" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" +name = "arbitrum-verifier" +version = "0.1.0" dependencies = [ - "event-listener 4.0.3", - "event-listener-strategy", - "pin-project-lite", + "error_reporter", + "ethereum-verifier", + "ethers-core", + "hex", + "hex-literal", + "rlp", + "serde", + "serde-utils", + "serde_json", + "sha3 0.10.8", + "thiserror", + "unionlabs", ] [[package]] -name = "async-sqlite" -version = "0.2.2" +name = "arc-swap" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d493cddf3cbfc2026299a8b1e1970d9ee539fd6bb1af420c5a48b5c9e2d539" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "arith" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556cabf32c649f5d6ccfbcc5bdf9f5a7cc4aa1eb5043cdabedff3fd49dd2cab9" + +[[package]] +name = "ark-bls12-377" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb00293ba84f51ce3bd026bd0de55899c4e68f0a39a5728cebae3a73ffdc0a4f" dependencies = [ - "crossbeam-channel", - "futures-channel", - "futures-util", - "rusqlite", + "ark-ec", + "ark-ff 0.4.2", + "ark-std 0.4.0", ] [[package]] -name = "async-stream" -version = "0.3.5" +name = "ark-bls12-381" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", + "ark-ec", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", ] [[package]] -name = "async-stream-impl" -version = "0.3.5" +name = "ark-bn254" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", + "ark-ec", + "ark-ff 0.4.2", + "ark-std 0.4.0", ] [[package]] -name = "async-trait" -version = "0.1.79" +name = "ark-crypto-primitives" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "1f3a13b34da09176a8baba701233fdffbaa7c1b1192ce031a3da4e55ce1f1a56" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", + "ark-ec", + "ark-ff 0.4.2", + "ark-relations", + "ark-serialize 0.4.2", + "ark-snark", + "ark-std 0.4.0", + "blake2", + "derivative", + "digest 0.10.7", + "rayon", + "sha2 0.10.8", ] [[package]] -name = "async-tungstenite" -version = "0.24.0" +name = "ark-ec" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3609af4bbf701ddaf1f6bb4e6257dff4ff8932327d0e685d3f653724c258b1ac" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" dependencies = [ - "futures-io", - "futures-util", - "log", - "pin-project-lite", - "rustls-native-certs 0.7.0", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.25.0", - "tungstenite 0.21.0", + "ark-ff 0.4.2", + "ark-poly", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "rayon", + "zeroize", ] [[package]] -name = "async_io_stream" -version = "0.3.3" +name = "ark-ff" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" dependencies = [ - "futures", - "pharos", - "rustc_version 0.4.0", + "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 0.4.6", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", ] [[package]] -name = "atoi" -version = "2.0.0" +name = "ark-ff" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +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 0.4.6", "num-traits", + "paste", + "rayon", + "rustc_version 0.4.0", + "zeroize", ] [[package]] -name = "atomic" -version = "0.6.0" +name = "ark-ff-asm" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" dependencies = [ - "bytemuck", + "quote", + "syn 1.0.109", ] [[package]] -name = "atty" -version = "0.2.14" +name = "ark-ff-asm" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", + "quote", + "syn 1.0.109", ] [[package]] -name = "auto_impl" -version = "1.2.0" +name = "ark-ff-macros" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ - "proc-macro2", + "num-bigint 0.4.6", + "num-traits", "quote", - "syn 2.0.60", + "syn 1.0.109", ] [[package]] -name = "autocfg" -version = "1.2.0" +name = "ark-ff-macros" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] -name = "axum" -version = "0.6.20" +name = "ark-groth16" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +checksum = "20ceafa83848c3e390f1cbf124bc3193b3e639b3f02009e0e290809a501b95fc" dependencies = [ - "async-trait", - "axum-core 0.3.4", - "axum-macros", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.28", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "sync_wrapper 0.1.2", - "tokio", - "tower", - "tower-layer", - "tower-service", + "ark-crypto-primitives", + "ark-ec", + "ark-ff 0.4.2", + "ark-poly", + "ark-relations", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "rayon", ] [[package]] -name = "axum" -version = "0.7.5" +name = "ark-poly" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" dependencies = [ - "async-trait", - "axum-core 0.4.3", - "base64 0.21.7", - "bytes", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "hyper 1.3.1", - "hyper-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sha1", - "sync_wrapper 1.0.1", - "tokio", - "tokio-tungstenite 0.21.0", - "tower", - "tower-layer", - "tower-service", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", + "rayon", +] + +[[package]] +name = "ark-relations" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0" +dependencies = [ + "ark-ff 0.4.2", + "ark-std 0.4.0", "tracing", + "tracing-subscriber 0.2.25", ] [[package]] -name = "axum-core" -version = "0.3.4" +name = "ark-serialize" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", + "ark-std 0.3.0", + "digest 0.9.0", ] [[package]] -name = "axum-core" -version = "0.4.3" +name = "ark-serialize" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper 0.1.2", - "tower-layer", - "tower-service", - "tracing", + "ark-serialize-derive", + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint 0.4.6", ] [[package]] -name = "axum-macros" -version = "0.3.8" +name = "ark-serialize-derive" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.60", + "syn 1.0.109", ] [[package]] -name = "backon" -version = "0.4.4" +name = "ark-snark" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d67782c3f868daa71d3533538e98a8e13713231969def7536e8039606fc46bf0" +checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63" dependencies = [ - "fastrand", - "futures-core", - "pin-project", - "tokio", + "ark-ff 0.4.2", + "ark-relations", + "ark-serialize 0.4.2", + "ark-std 0.4.0", ] [[package]] -name = "backtrace" -version = "0.3.71" +name = "ark-std" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ - "addr2line", - "cc", - "cfg-if 1.0.0", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", + "num-traits", + "rand 0.8.5", ] [[package]] -name = "base16ct" -version = "0.2.0" +name = "ark-std" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", + "rayon", +] [[package]] -name = "base58" -version = "0.1.0" +name = "arr_macro" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" +checksum = "c49336e062fa2ae8aca17a2f99c34d9c1a5d30827e8aff1cb4c294f253afe992" +dependencies = [ + "arr_macro_impl", + "proc-macro-hack", + "proc-macro-nested", +] [[package]] -name = "base58" -version = "0.2.0" +name = "arr_macro_impl" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" +checksum = "9c6368f9ae5c6ec403ca910327ae0c9437b0a85255b6950c90d497e6177f6e5e" +dependencies = [ + "proc-macro-hack", + "quote", + "syn 1.0.109", +] [[package]] -name = "base64" -version = "0.13.1" +name = "arrayref" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] -name = "base64" -version = "0.21.7" +name = "arrayvec" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +dependencies = [ + "nodrop", +] [[package]] -name = "base64" -version = "0.22.1" +name = "arrayvec" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] -name = "base64ct" -version = "1.6.0" +name = "ascii-canvas" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bcs" -version = "0.1.4" -source = "git+https://github.com/aptos-labs/bcs.git?rev=d31fab9d81748e2594be5cd5cdf845786a30562d#d31fab9d81748e2594be5cd5cdf845786a30562d" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" dependencies = [ - "serde", - "thiserror", + "term", ] [[package]] -name = "beacon-api" -version = "0.1.0" +name = "ascii_utils" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a" + +[[package]] +name = "async-graphql" +version = "7.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf338d20ba5bab309f55ce8df95d65ee19446f7737f06f4a64593ab2c6b546ad" dependencies = [ - "hex", - "reqwest 0.11.27", + "async-graphql-derive", + "async-graphql-parser", + "async-graphql-value", + "async-stream", + "async-trait", + "base64 0.22.1", + "bytes", + "fast_chemail", + "fnv", + "futures-util", + "handlebars", + "http 1.1.0", + "indexmap 2.2.6", + "mime", + "multer", + "num-traits", + "once_cell", + "pin-project-lite", + "regex", "serde", - "serde-utils", "serde_json", + "serde_urlencoded", + "static_assertions_next", + "tempfile", "thiserror", - "tokio", - "tracing", - "tracing-subscriber", - "unionlabs", ] [[package]] -name = "bech32" -version = "0.9.1" +name = "async-graphql-axum" +version = "7.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +checksum = "28f874ad4bc10519f3fa500e36814452033a5ce9ea681ab0a2e0d3b1f18bae44" +dependencies = [ + "async-graphql", + "async-trait", + "axum 0.7.5", + "bytes", + "futures-util", + "serde_json", + "tokio", + "tokio-stream", + "tokio-util", + "tower-service", +] [[package]] -name = "bech32" -version = "0.11.0" +name = "async-graphql-derive" +version = "7.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" +checksum = "fc51fd6b7102acda72bc94e8ae1543844d5688ff394a6cf7c21f2a07fe2d64e4" +dependencies = [ + "Inflector", + "async-graphql-parser", + "darling 0.20.8", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "strum 0.26.2", + "syn 2.0.77", + "thiserror", +] [[package]] -name = "beef" -version = "0.5.2" +name = "async-graphql-parser" +version = "7.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +checksum = "75361eefd64e39f89bead4cb45fddbaf60ddb0e7b15fb7c852b6088bcd63071f" dependencies = [ + "async-graphql-value", + "pest", "serde", + "serde_json", ] [[package]] -name = "berachain-light-client" -version = "0.1.0" -dependencies = [ - "base64 0.21.7", +name = "async-graphql-value" +version = "7.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1f665d2d52b41c4ed1f01c43f3ef27a2fe0af2452ed5c8bc7ac9b1a8719afaa" +dependencies = [ "bytes", - "cosmwasm-std 1.5.2", - "ethereum-light-client", - "ethereum-verifier", - "hex", - "hex-literal", - "ics008-wasm-client", - "ics23", - "lazy_static", - "prost 0.12.6", - "protos", - "schemars", + "indexmap 2.2.6", "serde", - "serde-json-wasm 1.0.1", - "serde-utils", "serde_json", - "sha2 0.10.8", - "sha3", - "tendermint-light-client", - "tendermint-verifier", - "thiserror", - "unionlabs", ] [[package]] -name = "bigdecimal" -version = "0.3.1" +name = "async-lock" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" +checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ - "num-bigint 0.4.4", - "num-integer", - "num-traits", + "event-listener 4.0.3", + "event-listener-strategy", + "pin-project-lite", ] [[package]] -name = "bimap" -version = "0.6.3" +name = "async-sqlite" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" +checksum = "d3d493cddf3cbfc2026299a8b1e1970d9ee539fd6bb1af420c5a48b5c9e2d539" +dependencies = [ + "crossbeam-channel", + "futures-channel", + "futures-util", + "rusqlite", +] [[package]] -name = "binary-install" -version = "0.2.0" +name = "async-stream" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93bff426ff93f3610dd2b946f3eb8cb2d1285ca8682834d43be531a3f93db2ff" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ - "anyhow", - "dirs-next", - "flate2", - "fs2", - "hex", - "is_executable", - "siphasher", - "tar", - "ureq", - "zip 0.6.6", + "async-stream-impl", + "futures-core", + "pin-project-lite", ] [[package]] -name = "bindgen" -version = "0.65.1" +name = "async-stream-impl" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ - "bitflags 1.3.2", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", - "prettyplease", "proc-macro2", "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] -name = "bip32" -version = "0.5.1" +name = "async-trait" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e141fb0f8be1c7b45887af94c88b182472b57c96b56773250ae00cd6a14a164" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ - "bs58 0.5.1", - "hmac 0.12.1", - "k256", - "rand_core 0.6.4", - "ripemd", - "sha2 0.10.8", - "subtle 2.5.0", - "zeroize", + "proc-macro2", + "quote", + "syn 2.0.77", ] [[package]] -name = "bip39" -version = "2.0.0" +name = "async-tungstenite" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" +checksum = "3609af4bbf701ddaf1f6bb4e6257dff4ff8932327d0e685d3f653724c258b1ac" dependencies = [ - "bitcoin_hashes", - "serde", - "unicode-normalization", + "futures-io", + "futures-util", + "log", + "pin-project-lite", + "rustls-native-certs 0.7.0", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.25.0", + "tungstenite 0.21.0", ] [[package]] -name = "bit-set" -version = "0.5.3" +name = "async_io_stream" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" dependencies = [ - "bit-vec", + "futures", + "pharos", + "rustc_version 0.4.0", ] [[package]] -name = "bit-vec" -version = "0.6.3" +name = "atoi" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] [[package]] -name = "bitcoin_hashes" -version = "0.11.0" +name = "atomic" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" +checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +dependencies = [ + "bytemuck", +] [[package]] -name = "bitflags" -version = "1.3.2" +name = "atomic-waker" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] -name = "bitflags" -version = "2.5.0" +name = "atty" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "serde", + "hermit-abi 0.1.19", + "libc", + "winapi 0.3.9", ] [[package]] -name = "bitvec" -version = "1.0.1" +name = "auto_impl" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ - "funty", - "radium", - "tap", - "wyz", + "proc-macro2", + "quote", + "syn 2.0.77", ] [[package]] -name = "blake2" -version = "0.9.2" +name = "autocfg" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" -dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", - "opaque-debug 0.3.1", -] +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] -name = "blake2" -version = "0.10.6" +name = "axum" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ - "digest 0.10.7", + "async-trait", + "axum-core 0.3.4", + "axum-macros", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.28", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "sync_wrapper 0.1.2", + "tokio", + "tower", + "tower-layer", + "tower-service", ] [[package]] -name = "blake2b_simd" -version = "1.0.2" +name = "axum" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq 0.3.0", + "async-trait", + "axum-core 0.4.3", + "base64 0.21.7", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.3.1", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper 1.0.1", + "tokio", + "tokio-tungstenite 0.21.0", + "tower", + "tower-layer", + "tower-service", + "tracing", ] [[package]] -name = "block-buffer" -version = "0.7.3" +name = "axum-core" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.4", + "async-trait", + "bytes", + "futures-util", + "http 0.2.12", + "http-body 0.4.6", + "mime", + "rustversion", + "tower-layer", + "tower-service", ] [[package]] -name = "block-buffer" -version = "0.9.0" +name = "axum-core" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" dependencies = [ - "generic-array 0.14.7", + "async-trait", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", + "tracing", ] [[package]] -name = "block-buffer" -version = "0.10.4" +name = "axum-macros" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62" dependencies = [ - "generic-array 0.14.7", + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.77", ] [[package]] -name = "block-message" -version = "0.1.0" -dependencies = [ - "arbitrary", - "beacon-api", - "chain-utils", - "contracts", - "dashmap", - "enumorph", - "ethers", - "frame-support-procedural", - "frunk", - "futures", - "hex", - "hex-literal", - "macros", - "num-bigint 0.4.4", - "prost 0.12.6", - "protos", - "queue-msg", - "serde", - "serde-utils", - "serde_json", - "tendermint", - "tendermint-proto", - "tendermint-rpc", - "thiserror", - "tokio", - "tonic 0.10.2", - "tracing", - "typenum", - "unionlabs", -] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" [[package]] -name = "block-padding" -version = "0.1.5" +name = "backon" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +checksum = "d67782c3f868daa71d3533538e98a8e13713231969def7536e8039606fc46bf0" dependencies = [ - "byte-tools", + "fastrand", + "futures-core", + "pin-project", + "tokio", ] [[package]] -name = "blst" -version = "0.3.13" +name = "backtrace" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ + "addr2line", "cc", - "glob", - "threadpool", - "zeroize", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", ] [[package]] -name = "bnum" -version = "0.8.1" +name = "base16ct" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab9008b6bb9fc80b5277f2fe481c09e828743d9151203e804583eb4c9e15b31d" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] -name = "bnum" -version = "0.11.0" +name = "base58" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790" +checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" [[package]] -name = "borsh" -version = "0.9.3" +name = "base58" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" -dependencies = [ - "borsh-derive 0.9.3", - "hashbrown 0.11.2", -] +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" [[package]] -name = "borsh" -version = "1.5.1" +name = "base64" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" -dependencies = [ - "borsh-derive 1.5.1", - "cfg_aliases", -] +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] -name = "borsh-derive" -version = "0.9.3" +name = "base64" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" -dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate 0.1.5", - "proc-macro2", - "syn 1.0.109", -] +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] -name = "borsh-derive" -version = "1.5.1" +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" -dependencies = [ - "once_cell", - "proc-macro-crate 3.1.0", - "proc-macro2", - "quote", - "syn 2.0.60", - "syn_derive", -] +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "borsh-derive-internal" -version = "0.9.3" +name = "base64ct" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] -name = "borsh-schema-derive-internal" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +name = "bcs" +version = "0.1.4" +source = "git+https://github.com/aptos-labs/bcs.git?rev=d31fab9d81748e2594be5cd5cdf845786a30562d#d31fab9d81748e2594be5cd5cdf845786a30562d" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "serde", + "thiserror", ] [[package]] -name = "brownstone" -version = "1.1.0" +name = "bcs" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030ea61398f34f1395ccbeb046fb68c87b631d1f34567fed0f0f11fa35d18d8d" +checksum = "85b6598a2f5d564fb7855dc6b06fd1c38cff5a72bd8b863a4d021938497b440a" dependencies = [ - "arrayvec", + "serde", + "thiserror", ] [[package]] -name = "bs58" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +name = "beacon-api" +version = "0.1.0" dependencies = [ - "sha2 0.10.8", - "tinyvec", + "enumorph", + "hex", + "macros", + "reqwest 0.11.27", + "serde", + "serde-utils", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", + "unionlabs", ] [[package]] -name = "bumpalo" -version = "3.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byte-tools" -version = "0.3.1" +name = "bech32" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" [[package]] -name = "bytemuck" -version = "1.15.0" +name = "bech32" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" [[package]] -name = "byteorder" -version = "1.5.0" +name = "bellpepper" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "9ae286c2cb403324ab644c7cc68dceb25fe52ca9429908a726d7ed272c1edf7b" +dependencies = [ + "bellpepper-core", + "byteorder", + "ff", +] [[package]] -name = "bytes" -version = "1.6.0" +name = "bellpepper-core" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "1d8abb418570756396d722841b19edfec21d4e89e1cf8990610663040ecb1aea" dependencies = [ + "blake2s_simd", + "byteorder", + "ff", "serde", + "thiserror", ] [[package]] -name = "bytesize" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" +name = "berachain-light-client" +version = "0.1.0" dependencies = [ + "base64 0.21.7", + "bytes", + "cosmwasm-std 1.5.2", + "ethereum-light-client", + "ethereum-verifier", + "hex", + "hex-literal", + "ics008-wasm-client", + "ics23", + "lazy_static", + "prost 0.12.6", + "protos", + "schemars", "serde", + "serde-json-wasm 1.0.1", + "serde-utils", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "tendermint-light-client", + "tendermint-verifier", + "thiserror", + "unionlabs", ] [[package]] -name = "bzip2" -version = "0.4.4" +name = "better_any" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +checksum = "b359aebd937c17c725e19efcb661200883f04c49c53e7132224dac26da39d4a0" dependencies = [ - "bzip2-sys", - "libc", + "better_typeid_derive", ] [[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" +name = "better_typeid_derive" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +checksum = "3deeecb812ca5300b7d3f66f730cc2ebd3511c3d36c691dd79c165d5b19a26e3" dependencies = [ - "cc", - "libc", - "pkg-config", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "c-kzg" -version = "1.0.2" +name = "bigdecimal" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf100c4cea8f207e883ff91ca886d621d8a166cb04971dfaa9bb8fd99ed95df" +checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" dependencies = [ - "blst", - "cc", - "glob", - "hex", - "libc", - "serde", + "num-bigint 0.4.6", + "num-integer", + "num-traits", ] [[package]] -name = "c2-chacha" -version = "0.3.3" +name = "bimap" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d27dae93fe7b1e0424dc57179ac396908c26b035a87234809f5c4dfd1b47dc80" -dependencies = [ - "cipher 0.2.5", - "ppv-lite86", -] +checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" [[package]] -name = "camino" -version = "1.1.6" +name = "bincode" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ "serde", ] [[package]] -name = "cargo-near" -version = "0.3.1" +name = "bip32" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f73eb01da3b6737778d2006645533e75563d1080c64bf714bfb88d3fb0ac09b" +checksum = "7e141fb0f8be1c7b45887af94c88b182472b57c96b56773250ae00cd6a14a164" dependencies = [ - "anyhow", - "atty", - "bs58 0.4.0", - "camino", - "cargo_metadata 0.14.2", - "clap 3.2.25", - "colored", - "env_logger", - "libloading 0.7.4", - "log", - "near-abi 0.3.0", - "rustc_version 0.4.0", - "schemars", - "serde_json", + "bs58 0.5.1", + "hmac 0.12.1", + "k256", + "rand_core 0.6.4", + "ripemd", "sha2 0.10.8", - "symbolic-debuginfo", - "zstd 0.11.2+zstd.1.5.2", + "subtle 2.5.0", + "zeroize", ] [[package]] -name = "cargo-platform" -version = "0.1.8" +name = "bip39" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "93f2635620bf0b9d4576eb7bb9a38a55df78bd1205d26fa994b25911a69f212f" dependencies = [ + "bitcoin_hashes", "serde", + "unicode-normalization", ] [[package]] -name = "cargo-util-schemas" -version = "0.1.0" +name = "bit-set" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c0a67d3ce899b0cd4a1dc756ff00da63e6198ffe6009467679bc0ead964ae3" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ - "anyhow", - "semver 1.0.22", - "serde", - "serde-untagged", - "serde-value", - "toml 0.8.12", - "unicode-xid", - "url", + "bit-vec", ] [[package]] -name = "cargo_metadata" -version = "0.14.2" +name = "bit-vec" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver 1.0.22", - "serde", - "serde_json", -] +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] -name = "cargo_metadata" -version = "0.18.1" +name = "bitcoin_hashes" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" -dependencies = [ - "camino", - "cargo-platform", - "semver 1.0.22", - "serde", - "serde_json", - "thiserror", -] +checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" [[package]] -name = "cast" -version = "0.3.0" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "cc" -version = "1.0.90" +name = "bitflags" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" dependencies = [ - "jobserver", - "libc", + "serde", ] [[package]] -name = "cexpr" -version = "0.6.0" +name = "bitmaps" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" dependencies = [ - "nom", + "typenum", ] [[package]] -name = "cfg-expr" -version = "0.15.7" +name = "bitvec" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d" +checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" dependencies = [ - "smallvec", + "funty 1.1.0", + "radium 0.6.2", + "tap", + "wyz 0.2.0", ] [[package]] -name = "cfg-if" -version = "0.1.10" +name = "bitvec" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty 2.0.0", + "radium 0.7.0", + "tap", + "wyz 0.5.1", +] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "blake2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] [[package]] -name = "cfg_aliases" -version = "0.2.1" +name = "blake2-rfc" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chain-utils" -version = "0.1.0" +checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" dependencies = [ - "arbitrary", - "beacon-api", - "bip32", - "chrono", - "cometbft-rpc", - "contracts", - "crossbeam-queue", - "dashmap", - "enumorph", - "ethers", - "frame-support-procedural", - "futures", - "hex", - "hex-literal", - "ics23", - "num-rational 0.4.2", - "num_enum", - "prost 0.12.6", - "protos", - "rand 0.8.5", - "reqwest 0.11.27", - "scroll-api", - "scroll-rpc", - "serde", - "serde-utils", - "serde_json", - "sha2 0.10.8", - "tendermint-rpc", - "thiserror", - "tokio", - "tonic 0.10.2", - "tracing", - "tracing-subscriber", - "typenum", - "unionlabs", + "arrayvec 0.4.12", + "constant_time_eq 0.1.5", ] [[package]] -name = "chrono" -version = "0.4.38" +name = "blake2b_simd" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-targets 0.52.4", + "arrayref", + "arrayvec 0.7.4", + "constant_time_eq 0.3.0", ] [[package]] -name = "cipher" -version = "0.2.5" +name = "blake2s_simd" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" dependencies = [ - "generic-array 0.14.7", + "arrayref", + "arrayvec 0.7.4", + "constant_time_eq 0.3.0", ] [[package]] -name = "cipher" -version = "0.4.4" +name = "block-buffer" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "crypto-common", - "inout", + "block-padding 0.1.5", + "byte-tools", + "byteorder", + "generic-array 0.12.4", ] [[package]] -name = "clang-sys" -version = "1.8.1" +name = "block-buffer" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "glob", - "libc", - "libloading 0.8.3", + "block-padding 0.2.1", + "generic-array 0.14.7", ] [[package]] -name = "clap" -version = "2.34.0" +name = "block-buffer" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "bitflags 1.3.2", - "textwrap 0.11.0", - "unicode-width", + "generic-array 0.14.7", ] [[package]] -name = "clap" -version = "3.2.25" +name = "block-padding" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_derive 3.2.25", - "clap_lex 0.2.4", - "indexmap 1.9.3", - "once_cell", - "strsim 0.10.0", - "termcolor", - "textwrap 0.16.1", + "byte-tools", ] [[package]] -name = "clap" -version = "4.5.4" +name = "block-padding" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" -dependencies = [ - "clap_builder", - "clap_derive 4.5.4", -] +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] -name = "clap_builder" -version = "4.5.2" +name = "blst" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" dependencies = [ - "anstream", - "anstyle", - "clap_lex 0.7.0", - "strsim 0.11.0", + "cc", + "glob", + "threadpool", + "zeroize", ] [[package]] -name = "clap_derive" -version = "3.2.25" +name = "blstrs" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +checksum = "7a8a8ed6fefbeef4a8c7b460e4110e12c5e22a5b7cf32621aae6ad650c4dcf29" dependencies = [ - "heck 0.4.1", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", + "blst", + "byte-slice-cast", + "ff", + "group", + "pairing", + "rand_core 0.6.4", + "serde", + "subtle 2.5.0", ] [[package]] -name = "clap_derive" -version = "4.5.4" +name = "bnum" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.60", -] +checksum = "ab9008b6bb9fc80b5277f2fe481c09e828743d9151203e804583eb4c9e15b31d" [[package]] -name = "clap_lex" -version = "0.2.4" +name = "bnum" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] +checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790" [[package]] -name = "clap_lex" -version = "0.7.0" +name = "borsh" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +dependencies = [ + "borsh-derive", + "cfg_aliases 0.2.1", +] [[package]] -name = "cliclack" -version = "0.2.5" +name = "borsh-derive" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4febf49beeedc40528e4956995631f1bbdb4d8804ef940b44351f393a996c739" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" dependencies = [ - "console", - "indicatif", "once_cell", - "textwrap 0.16.1", - "zeroize", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.77", + "syn_derive", ] [[package]] -name = "coins-bip32" -version = "0.8.7" +name = "bs58" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" -dependencies = [ - "bs58 0.5.1", - "coins-core", - "digest 0.10.7", - "hmac 0.12.1", - "k256", - "serde", - "sha2 0.10.8", - "thiserror", -] +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] -name = "coins-bip39" -version = "0.8.7" +name = "bs58" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ - "bitvec", - "coins-bip32", - "hmac 0.12.1", - "once_cell", - "pbkdf2 0.12.2", - "rand 0.8.5", "sha2 0.10.8", - "thiserror", + "tinyvec", ] [[package]] -name = "coins-core" -version = "0.8.7" +name = "bulletproofs" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +checksum = "40e698f1df446cc6246afd823afbe2d121134d089c9102c1dd26d1264991ba32" dependencies = [ - "base64 0.21.7", - "bech32 0.9.1", - "bs58 0.5.1", - "digest 0.10.7", - "generic-array 0.14.7", - "hex", - "ripemd", + "byteorder", + "clear_on_drop", + "curve25519-dalek-ng", + "digest 0.9.0", + "merlin", + "rand 0.8.5", + "rand_core 0.6.4", "serde", "serde_derive", - "sha2 0.10.8", - "sha3", + "sha3 0.9.1", + "subtle-ng", "thiserror", ] [[package]] -name = "color-eyre" -version = "0.6.3" +name = "bumpalo" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] -name = "color-spantrace" -version = "0.2.1" +name = "byte-slice-cast" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] -name = "colorchoice" -version = "1.0.0" +name = "byte-tools" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] -name = "colored" -version = "2.1.0" +name = "bytemuck" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" -dependencies = [ - "lazy_static", - "windows-sys 0.48.0", -] - -[[package]] -name = "cometbft-rpc" -version = "0.1.0" -dependencies = [ - "hex", - "jsonrpsee", - "macros", - "protos", - "serde", - "serde-utils", - "serde_json", - "thiserror", - "tokio", - "tracing", - "tracing-subscriber", - "unionlabs", -] +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" [[package]] -name = "cometbls-groth16-verifier" -version = "0.1.0" -dependencies = [ - "ark-ff 0.4.2", - "byteorder", - "ethabi", - "gnark-key-parser", - "hex-literal", - "sha2 0.10.8", - "sha3", - "substrate-bn", - "unionlabs", -] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "cometbls-light-client" -version = "0.1.0" +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" dependencies = [ - "base64 0.21.7", - "bytes", - "cometbls-groth16-verifier", - "cosmwasm-std 1.5.2", - "dlmalloc", - "hex", - "ics008-wasm-client", - "ics23", - "lazy_static", - "prost 0.12.6", - "protos", - "ripemd", - "schemars", "serde", - "serde-json-wasm 1.0.1", - "serde-utils", - "serde_json", - "sha2 0.10.8", - "sha3", - "thiserror", - "unionlabs", ] [[package]] -name = "concurrent-queue" -version = "2.4.0" +name = "bzip2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" dependencies = [ - "crossbeam-utils", + "bzip2-sys", + "libc", ] [[package]] -name = "console" -version = "0.15.8" +name = "bzip2-sys" +version = "0.1.11+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" dependencies = [ - "encode_unicode", - "lazy_static", + "cc", "libc", - "unicode-width", - "windows-sys 0.52.0", + "pkg-config", ] [[package]] -name = "const-hex" -version = "1.12.0" +name = "c-kzg" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +checksum = "cdf100c4cea8f207e883ff91ca886d621d8a166cb04971dfaa9bb8fd99ed95df" dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", + "blst", + "cc", + "glob", "hex", - "proptest", + "libc", "serde", ] [[package]] -name = "const-oid" -version = "0.9.6" +name = "c_linked_list" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +checksum = "4964518bd3b4a8190e832886cdc0da9794f12e8e6c1613a9e90ff331c4c8724b" [[package]] -name = "const-random" -version = "0.1.18" +name = "camino" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" dependencies = [ - "const-random-macro", + "serde", ] [[package]] -name = "const-random-macro" -version = "0.1.16" +name = "cargo-platform" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ - "getrandom 0.2.12", - "once_cell", - "tiny-keccak", + "serde", ] [[package]] -name = "constant_time_eq" -version = "0.1.5" +name = "cargo-util-schemas" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "56c0a67d3ce899b0cd4a1dc756ff00da63e6198ffe6009467679bc0ead964ae3" +dependencies = [ + "anyhow", + "semver 1.0.22", + "serde", + "serde-untagged", + "serde-value", + "toml 0.8.12", + "unicode-xid", + "url", +] [[package]] -name = "constant_time_eq" -version = "0.3.0" +name = "cargo_metadata" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" - -[[package]] -name = "contracts" -version = "0.0.0" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ - "arbitrary", - "ethers", + "camino", + "cargo-platform", + "semver 1.0.22", "serde", + "serde_json", + "thiserror", ] [[package]] -name = "convert_case" -version = "0.4.0" +name = "cast" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] -name = "core-foundation" -version = "0.9.4" +name = "cc" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" dependencies = [ - "core-foundation-sys", + "jobserver", "libc", ] [[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cosmwasm-core" -version = "2.1.0" +name = "cesu8" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d075f6bb1483a6ce83b5cbc73a3a1207e0316ac1e34ed1f2a4d9fc3a0f07bf6" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] -name = "cosmwasm-crypto" -version = "1.5.2" +name = "cfg-expr" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6aa9f904de106fa16443ad14ec2abe75e94ba003bb61c681c0e43d4c58d2a" +checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d" dependencies = [ - "digest 0.10.7", - "ecdsa", - "ed25519-zebra 3.1.0", - "k256", - "rand_core 0.6.4", - "thiserror", + "smallvec", ] [[package]] -name = "cosmwasm-crypto" -version = "2.1.0" +name = "cfg-if" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ced5a6dd2801a383d3e14e5ae5caa7fdfeff1bd9f22b30e810e0aded8a5869" -dependencies = [ - "ark-bls12-381", - "ark-ec", - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "cosmwasm-core", - "digest 0.10.7", - "ecdsa", - "ed25519-zebra 4.0.3", - "k256", - "num-traits", - "p256", - "rand_core 0.6.4", - "rayon", - "sha2 0.10.8", - "thiserror", -] +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] -name = "cosmwasm-derive" -version = "1.5.3" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5e72e330bd3bdab11c52b5ecbdeb6a8697a004c57964caeb5d876f0b088b3c" -dependencies = [ - "syn 1.0.109", -] +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cosmwasm-derive" -version = "2.1.0" +name = "cfg_aliases" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd1873f84d9b17edf8a90ffe10a89a649b82feacc00e36788b81d2c3cbf03c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] -name = "cosmwasm-schema" -version = "1.5.3" +name = "cfg_aliases" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3e3a2136e2a60e8b6582f5dffca5d1a683ed77bf38537d330bc1dfccd69010" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chain-utils" +version = "0.1.0" dependencies = [ - "cosmwasm-schema-derive 1.5.3", - "schemars", + "beacon-api", + "bip32", + "chrono", + "cometbft-rpc", + "contracts", + "crossbeam-queue", + "dashmap", + "enumorph", + "ethers", + "frame-support-procedural", + "futures", + "hex", + "hex-literal", + "ics23", + "num-rational 0.4.2", + "num_enum", + "prost 0.12.6", + "protos", + "rand 0.8.5", + "reqwest 0.11.27", + "scroll-api", + "scroll-rpc", "serde", + "serde-utils", "serde_json", + "sha2 0.10.8", + "tendermint-rpc", "thiserror", + "tokio", + "tonic", + "tracing", + "tracing-subscriber 0.3.18", + "typenum", + "unionlabs", ] [[package]] -name = "cosmwasm-schema" -version = "2.1.0" +name = "chrono" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27984b137eb2ac561f97f6bdb02004a98eb6f2ba263062c140b8e231ee1826b7" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ - "cosmwasm-schema-derive 2.1.0", - "schemars", + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", "serde", - "serde_json", - "thiserror", + "wasm-bindgen", + "windows-targets 0.52.4", ] [[package]] -name = "cosmwasm-schema-derive" -version = "1.5.3" +name = "chunked_transfer" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d803bea6bd9ed61bd1ee0b4a2eb09ee20dbb539cc6e0b8795614d20952ebb1" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" [[package]] -name = "cosmwasm-schema-derive" -version = "2.1.0" +name = "ciborium" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ef0d201f611bdb6c9124207032423eb956f1fc8ab3e3ee7253a9c08a5f5809" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", + "ciborium-io", + "ciborium-ll", + "serde", ] [[package]] -name = "cosmwasm-std" -version = "1.5.2" +name = "ciborium-io" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad011ae7447188e26e4a7dbca2fcd0fc186aa21ae5c86df0503ea44c78f9e469" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ - "base64 0.21.7", - "bech32 0.9.1", - "bnum 0.8.1", - "cosmwasm-crypto 1.5.2", - "cosmwasm-derive 1.5.3", - "derivative", - "forward_ref", - "hex", - "schemars", - "serde", - "serde-json-wasm 0.5.2", - "sha2 0.10.8", - "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror", + "ciborium-io", + "half 2.4.1", ] [[package]] -name = "cosmwasm-std" -version = "2.1.0" +name = "cipher" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2522fb5c9a0409712bb1d036128bccf3564e6b2ac82f942ae4cf3c8df3e26fa8" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "base64 0.22.1", - "bech32 0.11.0", - "bnum 0.11.0", - "cosmwasm-core", - "cosmwasm-crypto 2.1.0", - "cosmwasm-derive 2.1.0", - "derive_more 1.0.0-beta.6", - "hex", - "rand_core 0.6.4", - "schemars", - "serde", - "serde-json-wasm 1.0.1", - "sha2 0.10.8", - "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror", + "crypto-common", + "inout", ] [[package]] -name = "cpufeatures" -version = "0.2.12" +name = "claims" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "b6995bbe186456c36307f8ea36be3eefe42f49d106896414e18efc4fb2f846b5" dependencies = [ - "libc", + "autocfg", ] [[package]] -name = "crc" -version = "3.0.1" +name = "clap" +version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ - "crc-catalog", + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim 0.8.0", + "textwrap 0.11.0", + "unicode-width", + "vec_map", ] [[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crc32fast" -version = "1.4.0" +name = "clap" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ - "cfg-if 1.0.0", + "clap_builder", + "clap_derive", ] [[package]] -name = "criterion" -version = "0.3.6" +name = "clap_builder" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ - "atty", - "cast", - "clap 2.34.0", - "criterion-plot", - "csv", - "itertools 0.10.5", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_cbor", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.0", + "terminal_size", ] [[package]] -name = "criterion-plot" -version = "0.4.5" +name = "clap_derive" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ - "cast", - "itertools 0.10.5", + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.77", ] [[package]] -name = "crossbeam" -version = "0.8.4" +name = "clap_lex" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] -name = "crossbeam-channel" -version = "0.5.13" +name = "clear_on_drop" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "38508a63f4979f0048febc9966fadbd48e5dab31fd0ec6a3f151bbf4a74f7423" dependencies = [ - "crossbeam-utils", + "cc", ] [[package]] -name = "crossbeam-deque" -version = "0.8.5" +name = "cliclack" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "4febf49beeedc40528e4956995631f1bbdb4d8804ef940b44351f393a996c739" dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", + "console", + "indicatif", + "once_cell", + "textwrap 0.16.1", + "zeroize", ] [[package]] -name = "crossbeam-epoch" -version = "0.9.18" +name = "codespan" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "3362992a0d9f1dd7c3d0e89e0ab2bb540b7a95fea8cd798090e758fda2899b5e" dependencies = [ - "crossbeam-utils", + "codespan-reporting", + "serde", ] [[package]] -name = "crossbeam-queue" -version = "0.3.11" +name = "codespan-reporting" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" dependencies = [ - "crossbeam-utils", + "serde", + "termcolor", + "unicode-width", ] [[package]] -name = "crossbeam-utils" -version = "0.8.19" +name = "coins-bip32" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" +dependencies = [ + "bs58 0.5.1", + "coins-core", + "digest 0.10.7", + "hmac 0.12.1", + "k256", + "serde", + "sha2 0.10.8", + "thiserror", +] [[package]] -name = "crunchy" -version = "0.2.2" +name = "coins-bip39" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +dependencies = [ + "bitvec 1.0.1", + "coins-bip32", + "hmac 0.12.1", + "once_cell", + "pbkdf2 0.12.2", + "rand 0.8.5", + "sha2 0.10.8", + "thiserror", +] [[package]] -name = "crypto-bigint" -version = "0.5.5" +name = "coins-core" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" dependencies = [ + "base64 0.21.7", + "bech32 0.9.1", + "bs58 0.5.1", + "digest 0.10.7", "generic-array 0.14.7", - "rand_core 0.6.4", - "subtle 2.5.0", - "zeroize", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2 0.10.8", + "sha3 0.10.8", + "thiserror", ] [[package]] -name = "crypto-common" -version = "0.1.6" +name = "color-eyre" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" dependencies = [ - "generic-array 0.14.7", - "typenum", + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", ] [[package]] -name = "crypto-mac" -version = "0.7.0" +name = "color-spantrace" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" dependencies = [ - "generic-array 0.12.4", - "subtle 1.0.0", + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", ] [[package]] -name = "crypto-mac" -version = "0.8.0" +name = "colorchoice" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array 0.14.7", - "subtle 2.5.0", -] +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] -name = "csv" -version = "1.3.0" +name = "colored" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ - "csv-core", - "itoa", - "ryu", - "serde", + "lazy_static", + "windows-sys 0.48.0", ] [[package]] -name = "csv-core" -version = "0.1.11" +name = "combine" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ + "bytes", "memchr", ] [[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +name = "cometbft-rpc" +version = "0.1.0" dependencies = [ - "cipher 0.4.4", + "base64 0.21.7", + "hex", + "hex-literal", + "jsonrpsee", + "macros", + "protos", + "reconnecting-jsonrpc-ws-client", + "serde", + "serde-utils", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", + "unionlabs", ] [[package]] -name = "curve25519-dalek" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +name = "cometbls-groth16-verifier" +version = "0.1.0" dependencies = [ + "ark-ff 0.4.2", "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle 2.5.0", - "zeroize", + "ethabi", + "gnark-key-parser", + "hex-literal", + "sha2 0.10.8", + "sha3 0.10.8", + "substrate-bn", + "unionlabs", ] [[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +name = "cometbls-light-client" +version = "0.1.0" dependencies = [ - "cfg-if 1.0.0", - "cpufeatures", - "curve25519-dalek-derive", - "digest 0.10.7", - "fiat-crypto", - "rand_core 0.6.4", - "rustc_version 0.4.0", - "subtle 2.5.0", - "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.60", + "base64 0.21.7", + "bytes", + "cometbls-groth16-verifier", + "cosmwasm-std 1.5.2", + "dlmalloc", + "hex", + "ics008-wasm-client", + "ics23", + "lazy_static", + "prost 0.12.6", + "protos", + "ripemd", + "schemars", + "serde", + "serde-json-wasm 1.0.1", + "serde-utils", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "thiserror", + "unionlabs", ] [[package]] -name = "curve25519-dalek-ng" -version = "4.1.1" +name = "concurrent-queue" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.6.4", - "subtle-ng", - "zeroize", + "crossbeam-utils", ] [[package]] -name = "cw-address-like" -version = "1.0.4" +name = "console" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451a4691083a88a3c0630a8a88799e9d4cd6679b7ce8ff22b8da2873ff31d380" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ - "cosmwasm-std 1.5.2", + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", ] [[package]] -name = "cw-cii" -version = "0.1.0" -source = "git+https://github.com/hussein-aitlahcen/cw-ics721?rev=dd5b7add6fdc81e633084031f8512e5e909dd42a#dd5b7add6fdc81e633084031f8512e5e909dd42a" +name = "const-hex" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" dependencies = [ - "cosmwasm-schema 1.5.3", - "cosmwasm-std 1.5.2", + "cfg-if 1.0.0", + "cpufeatures", + "hex", + "proptest", + "serde", ] [[package]] -name = "cw-controllers" -version = "2.0.0" +name = "const-oid" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c1804013d21060b994dea28a080f9eab78a3bcb6b617f05e7634b0600bf7b1" -dependencies = [ - "cosmwasm-schema 2.1.0", - "cosmwasm-std 2.1.0", - "cw-storage-plus 2.0.0", - "cw-utils 2.0.0", - "schemars", - "serde", - "thiserror", -] +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] -name = "cw-multi-test" -version = "2.1.0-rc.1" -source = "git+https://github.com/CosmWasm/cw-multi-test.git?rev=e1a2f587c7f9d723444ec93ad8fa48f1d88b65bc#e1a2f587c7f9d723444ec93ad8fa48f1d88b65bc" +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" dependencies = [ - "anyhow", - "bech32 0.11.0", - "cosmwasm-schema 2.1.0", - "cosmwasm-std 2.1.0", - "cw-storage-plus 2.0.0", - "cw-utils 2.0.0", - "cw20-ics20", - "derivative", - "hex", - "itertools 0.13.0", - "log", - "prost 0.12.6", - "schemars", - "serde", - "serde_json", - "sha2 0.10.8", - "thiserror", + "const-random-macro", ] [[package]] -name = "cw-ownable" -version = "0.5.1" +name = "const-random-macro" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093dfb4520c48b5848274dd88ea99e280a04bc08729603341c7fb0d758c74321" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "cosmwasm-schema 1.5.3", - "cosmwasm-std 1.5.2", - "cw-address-like", - "cw-ownable-derive", - "cw-storage-plus 1.2.0", - "cw-utils 1.0.3", - "thiserror", + "getrandom 0.2.12", + "once_cell", + "tiny-keccak", ] [[package]] -name = "cw-ownable-derive" -version = "0.5.1" +name = "constant_time_eq" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d3bf2e0f341bb6cc100d7d441d31cf713fbd3ce0c511f91e79f14b40a889af" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] -name = "cw-paginate-storage" -version = "2.4.2" -source = "git+https://github.com/DA0-DA0/dao-contracts.git#3ab701747d6d5571cfee7f5a78d8fe39ffa3a8f7" -dependencies = [ - "cosmwasm-std 1.5.2", - "cw-storage-plus 1.2.0", - "serde", -] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] -name = "cw-pause-once" -version = "0.1.0" -source = "git+https://github.com/hussein-aitlahcen/cw-ics721?rev=dd5b7add6fdc81e633084031f8512e5e909dd42a#dd5b7add6fdc81e633084031f8512e5e909dd42a" +name = "contracts" +version = "0.0.0" dependencies = [ - "cosmwasm-schema 1.5.3", - "cosmwasm-std 1.5.2", - "cw-storage-plus 1.2.0", - "cw-utils 1.0.3", - "thiserror", + "ethers", + "serde", ] [[package]] -name = "cw-storage-plus" -version = "0.16.0" +name = "convert_case" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b6f91c0b94481a3e9ef1ceb183c37d00764f8751e39b45fc09f4d9b970d469" -dependencies = [ - "cosmwasm-std 1.5.2", - "schemars", - "serde", -] +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] -name = "cw-storage-plus" -version = "1.2.0" +name = "cookie" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5ff29294ee99373e2cd5fd21786a3c0ced99a52fec2ca347d565489c61b723c" +checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24" dependencies = [ - "cosmwasm-std 1.5.2", - "schemars", - "serde", + "percent-encoding", + "time", + "version_check", ] [[package]] -name = "cw-storage-plus" -version = "2.0.0" +name = "cookie" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f13360e9007f51998d42b1bc6b7fa0141f74feae61ed5fd1e5b0a89eec7b5de1" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" dependencies = [ - "cosmwasm-std 2.1.0", - "schemars", - "serde", + "aes-gcm", + "base64 0.22.1", + "hkdf 0.12.4", + "hmac 0.12.1", + "percent-encoding", + "rand 0.8.5", + "sha2 0.10.8", + "subtle 2.5.0", + "time", + "version_check", ] [[package]] -name = "cw-utils" -version = "0.16.0" +name = "cookie_store" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6a84c6c1c0acc3616398eba50783934bd6c964bad6974241eaee3460c8f5b26" +checksum = "387461abbc748185c3a6e1673d826918b450b87ff22639429c694619a83b6cf6" dependencies = [ - "cosmwasm-schema 1.5.3", - "cosmwasm-std 1.5.2", - "cw2 0.16.0", - "schemars", - "semver 1.0.22", + "cookie 0.17.0", + "idna 0.3.0", + "log", + "publicsuffix", "serde", - "thiserror", + "serde_derive", + "serde_json", + "time", + "url", ] [[package]] -name = "cw-utils" -version = "1.0.3" +name = "core-foundation" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c4a657e5caacc3a0d00ee96ca8618745d050b8f757c709babafb81208d4239c" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ - "cosmwasm-schema 1.5.3", - "cosmwasm-std 1.5.2", - "cw2 1.1.2", - "schemars", - "semver 1.0.22", - "serde", - "thiserror", + "core-foundation-sys", + "libc", ] [[package]] -name = "cw-utils" -version = "2.0.0" +name = "core-foundation-sys" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07dfee7f12f802431a856984a32bce1cb7da1e6c006b5409e3981035ce562dec" -dependencies = [ - "cosmwasm-schema 2.1.0", - "cosmwasm-std 2.1.0", - "schemars", - "serde", - "thiserror", -] +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] -name = "cw2" -version = "0.16.0" +name = "core_affinity" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91398113b806f4d2a8d5f8d05684704a20ffd5968bf87e3473e1973710b884ad" +checksum = "622892f5635ce1fc38c8f16dfc938553ed64af482edb5e150bf4caedbfcb2304" dependencies = [ - "cosmwasm-schema 1.5.3", - "cosmwasm-std 1.5.2", - "cw-storage-plus 0.16.0", - "schemars", - "serde", + "libc", + "num_cpus", + "winapi 0.3.9", ] [[package]] -name = "cw2" -version = "1.1.2" +name = "coset" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c120b24fbbf5c3bedebb97f2cc85fbfa1c3287e09223428e7e597b5293c1fa" +checksum = "f4c8cc80f631f8307b887faca24dcc3abc427cd0367f6eb6188f6e8f5b7ad8fb" dependencies = [ - "cosmwasm-schema 1.5.3", - "cosmwasm-std 1.5.2", - "cw-storage-plus 1.2.0", - "schemars", - "semver 1.0.22", - "serde", - "thiserror", + "ciborium", + "ciborium-io", ] [[package]] -name = "cw2" -version = "2.0.0" +name = "cosmwasm-core" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b04852cd38f044c0751259d5f78255d07590d136b8a86d4e09efdd7666bd6d27" -dependencies = [ - "cosmwasm-schema 2.1.0", - "cosmwasm-std 2.1.0", - "cw-storage-plus 2.0.0", - "schemars", - "semver 1.0.22", - "serde", - "thiserror", -] +checksum = "8d075f6bb1483a6ce83b5cbc73a3a1207e0316ac1e34ed1f2a4d9fc3a0f07bf6" [[package]] -name = "cw20" -version = "2.0.0" +name = "cosmwasm-crypto" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a42212b6bf29bbdda693743697c621894723f35d3db0d5df930be22903d0e27c" +checksum = "8ed6aa9f904de106fa16443ad14ec2abe75e94ba003bb61c681c0e43d4c58d2a" dependencies = [ - "cosmwasm-schema 2.1.0", - "cosmwasm-std 2.1.0", - "cw-utils 2.0.0", - "schemars", - "serde", + "digest 0.10.7", + "ecdsa", + "ed25519-zebra 3.1.0", + "k256", + "rand_core 0.6.4", + "thiserror", ] [[package]] -name = "cw20-ics20" -version = "2.0.0" +name = "cosmwasm-crypto" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80a9e377dbbd1ffb3b6a8a2dbf9128609a6458a3292f88f99e0b6840a7e9762e" +checksum = "88ced5a6dd2801a383d3e14e5ae5caa7fdfeff1bd9f22b30e810e0aded8a5869" dependencies = [ - "cosmwasm-schema 2.1.0", - "cosmwasm-std 2.1.0", - "cw-controllers", - "cw-storage-plus 2.0.0", - "cw-utils 2.0.0", - "cw2 2.0.0", - "cw20", - "schemars", - "semver 1.0.22", - "serde", + "ark-bls12-381", + "ark-ec", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "cosmwasm-core", + "digest 0.10.7", + "ecdsa", + "ed25519-zebra 4.0.3", + "k256", + "num-traits", + "p256", + "rand_core 0.6.4", + "rayon", + "sha2 0.10.8", "thiserror", ] [[package]] -name = "cw721" -version = "0.16.0" +name = "cosmwasm-derive" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94a1ea6e6277bdd6dfc043a9b1380697fe29d6e24b072597439523658d21d791" +checksum = "bc5e72e330bd3bdab11c52b5ecbdeb6a8697a004c57964caeb5d876f0b088b3c" dependencies = [ - "cosmwasm-schema 1.5.3", - "cosmwasm-std 1.5.2", - "cw-utils 0.16.0", - "schemars", - "serde", + "syn 1.0.109", ] [[package]] -name = "cw721" -version = "0.18.0" -source = "git+https://github.com/CosmWasm/cw-nfts?branch=main#e63a7bbb620e6ea39224bb5580967477066cb7ae" +name = "cosmwasm-derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd1873f84d9b17edf8a90ffe10a89a649b82feacc00e36788b81d2c3cbf03c" dependencies = [ - "cosmwasm-schema 1.5.3", - "cosmwasm-std 1.5.2", - "cw-utils 1.0.3", - "schemars", - "serde", + "proc-macro2", + "quote", + "syn 2.0.77", ] [[package]] -name = "cw721-base" -version = "0.16.0" +name = "cosmwasm-schema" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77518e27431d43214cff4cdfbd788a7508f68d9b1f32389e6fce513e7eaccbef" +checksum = "ac3e3a2136e2a60e8b6582f5dffca5d1a683ed77bf38537d330bc1dfccd69010" dependencies = [ - "cosmwasm-schema 1.5.3", - "cosmwasm-std 1.5.2", - "cw-storage-plus 0.16.0", - "cw-utils 0.16.0", - "cw2 0.16.0", - "cw721 0.16.0", + "cosmwasm-schema-derive 1.5.3", "schemars", "serde", + "serde_json", "thiserror", ] [[package]] -name = "cw721-base" -version = "0.18.0" -source = "git+https://github.com/CosmWasm/cw-nfts?branch=main#e63a7bbb620e6ea39224bb5580967477066cb7ae" +name = "cosmwasm-schema" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27984b137eb2ac561f97f6bdb02004a98eb6f2ba263062c140b8e231ee1826b7" dependencies = [ - "cosmwasm-schema 1.5.3", - "cosmwasm-std 1.5.2", - "cw-ownable", - "cw-storage-plus 1.2.0", - "cw-utils 1.0.3", - "cw2 1.1.2", - "cw721 0.18.0", - "cw721-base 0.16.0", + "cosmwasm-schema-derive 2.1.0", "schemars", "serde", + "serde_json", "thiserror", ] [[package]] -name = "darling" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" -dependencies = [ - "darling_core 0.13.4", - "darling_macro 0.13.4", -] - -[[package]] -name = "darling" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" -dependencies = [ - "darling_core 0.20.8", - "darling_macro 0.20.8", -] - -[[package]] -name = "darling_core" -version = "0.13.4" +name = "cosmwasm-schema-derive" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +checksum = "f5d803bea6bd9ed61bd1ee0b4a2eb09ee20dbb539cc6e0b8795614d20952ebb1" dependencies = [ - "fnv", - "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", "syn 1.0.109", ] [[package]] -name = "darling_core" -version = "0.20.8" +name = "cosmwasm-schema-derive" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +checksum = "f4ef0d201f611bdb6c9124207032423eb956f1fc8ab3e3ee7253a9c08a5f5809" dependencies = [ - "fnv", - "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] -name = "darling_macro" -version = "0.13.4" +name = "cosmwasm-std" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +checksum = "ad011ae7447188e26e4a7dbca2fcd0fc186aa21ae5c86df0503ea44c78f9e469" dependencies = [ - "darling_core 0.13.4", - "quote", - "syn 1.0.109", + "base64 0.21.7", + "bech32 0.9.1", + "bnum 0.8.1", + "cosmwasm-crypto 1.5.2", + "cosmwasm-derive 1.5.3", + "derivative", + "forward_ref", + "hex", + "schemars", + "serde", + "serde-json-wasm 0.5.2", + "sha2 0.10.8", + "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror", ] [[package]] -name = "darling_macro" -version = "0.20.8" +name = "cosmwasm-std" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +checksum = "2522fb5c9a0409712bb1d036128bccf3564e6b2ac82f942ae4cf3c8df3e26fa8" dependencies = [ - "darling_core 0.20.8", - "quote", - "syn 2.0.60", + "base64 0.22.1", + "bech32 0.11.0", + "bnum 0.11.0", + "cosmwasm-core", + "cosmwasm-crypto 2.1.0", + "cosmwasm-derive 2.1.0", + "derive_more 1.0.0-beta.6", + "hex", + "rand_core 0.6.4", + "schemars", + "serde", + "serde-json-wasm 1.0.1", + "sha2 0.10.8", + "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror", ] [[package]] -name = "dashmap" -version = "5.5.3" +name = "cpufeatures" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ - "cfg-if 1.0.0", - "hashbrown 0.14.3", - "lock_api", - "once_cell", - "parking_lot_core 0.9.9", + "libc", ] [[package]] -name = "data-encoding" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" - -[[package]] -name = "debugid" -version = "0.7.3" +name = "crc" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ee87af31d84ef885378aebca32be3d682b0e0dc119d5b4860a2c5bb5046730" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" dependencies = [ - "uuid 0.8.2", + "crc-catalog", ] [[package]] -name = "der" -version = "0.7.9" +name = "crc-catalog" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] -name = "deranged" -version = "0.3.11" +name = "crc32fast" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ - "powerfmt", - "serde", + "cfg-if 1.0.0", ] [[package]] -name = "derivative" -version = "2.2.0" +name = "criterion" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "derive-syn-parse" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "atty", + "cast", + "clap 2.34.0", + "criterion-plot", + "csv", + "itertools 0.10.5", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", ] [[package]] -name = "derive-where" -version = "1.2.7" +name = "criterion-plot" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", + "cast", + "itertools 0.10.5", ] [[package]] -name = "derive_arbitrary" -version = "1.3.2" -source = "git+https://github.com/unionlabs/arbitrary#b5796f1a0066dc5707d7681a80e19b99a910987d" +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", + "crossbeam-utils", ] [[package]] -name = "derive_more" -version = "0.99.17" +name = "crossbeam-deque" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version 0.4.0", - "syn 1.0.109", + "crossbeam-epoch", + "crossbeam-utils", ] [[package]] -name = "derive_more" -version = "1.0.0-beta.6" +name = "crossbeam-epoch" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7abbfc297053be59290e3152f8cbcd52c8642e0728b69ee187d991d4c1af08d" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "derive_more-impl", + "crossbeam-utils", ] [[package]] -name = "derive_more-impl" -version = "1.0.0-beta.6" +name = "crossbeam-queue" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bba3e9872d7c58ce7ef0fcf1844fcc3e23ef2a58377b50df35dd98e42a5726e" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", - "unicode-xid", + "crossbeam-utils", ] [[package]] -name = "devnet-compose" -version = "0.1.0" +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[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 = [ - "cliclack", - "console", - "itertools 0.12.1", - "serde", - "serde_json", - "serde_with", - "strum 0.26.2", + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle 2.5.0", + "zeroize", ] [[package]] -name = "devnet-utils" -version = "0.1.0" +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "base64 0.21.7", - "bip39", - "clap 4.5.4", - "cosmwasm-std 2.1.0", - "ed25519-compact", - "hex", - "strum 0.26.2", - "tiny-hderive", - "unionlabs", + "generic-array 0.14.7", + "rand_core 0.6.4", + "typenum", ] [[package]] -name = "digest" -version = "0.8.1" +name = "crypto-mac" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" dependencies = [ "generic-array 0.12.4", + "subtle 1.0.0", ] [[package]] -name = "digest" -version = "0.9.0" +name = "crypto-mac" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ "generic-array 0.14.7", + "subtle 2.5.0", ] [[package]] -name = "digest" -version = "0.10.7" +name = "crypto-mac" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" dependencies = [ - "block-buffer 0.10.4", - "const-oid", - "crypto-common", + "generic-array 0.14.7", "subtle 2.5.0", ] [[package]] -name = "dirs" -version = "5.0.1" +name = "csv" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" dependencies = [ - "dirs-sys", + "csv-core", + "itoa", + "ryu", + "serde", ] [[package]] -name = "dirs-next" -version = "2.0.0" +name = "csv-core" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" dependencies = [ - "cfg-if 1.0.0", - "dirs-sys-next", + "memchr", ] [[package]] -name = "dirs-sys" -version = "0.4.1" +name = "ctr" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", + "cipher", ] [[package]] -name = "dirs-sys-next" -version = "0.1.2" +name = "curve25519-dalek" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" dependencies = [ - "libc", - "redox_users", - "winapi", + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle 2.5.0", + "zeroize", ] [[package]] -name = "dissimilar" -version = "1.0.7" +name = "curve25519-dalek" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rustc_version 0.4.0", + "subtle 2.5.0", + "zeroize", +] [[package]] -name = "dlmalloc" -version = "0.2.4" +name = "curve25519-dalek-derive" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "203540e710bfadb90e5e29930baf5d10270cec1f43ab34f46f78b147b2de715a" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "libc", + "proc-macro2", + "quote", + "syn 2.0.77", ] [[package]] -name = "dmsort" -version = "1.0.2" +name = "curve25519-dalek-ng" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0bc8fbe9441c17c9f46f75dfe27fa1ddb6c68a461ccaed0481419219d4f10d3" +checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.6.4", + "serde", + "subtle-ng", + "zeroize", +] [[package]] -name = "doctest-file" -version = "1.0.0" +name = "cw-address-like" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" +checksum = "451a4691083a88a3c0630a8a88799e9d4cd6679b7ce8ff22b8da2873ff31d380" +dependencies = [ + "cosmwasm-std 1.5.2", +] [[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +name = "cw-cii" +version = "0.1.0" +source = "git+https://github.com/hussein-aitlahcen/cw-ics721?rev=dd5b7add6fdc81e633084031f8512e5e909dd42a#dd5b7add6fdc81e633084031f8512e5e909dd42a" +dependencies = [ + "cosmwasm-schema 1.5.3", + "cosmwasm-std 1.5.2", +] [[package]] -name = "drip" -version = "0.1.0" +name = "cw-controllers" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c1804013d21060b994dea28a080f9eab78a3bcb6b617f05e7634b0600bf7b1" dependencies = [ - "async-graphql", - "async-graphql-axum", - "async-sqlite", - "axum 0.7.5", - "chain-utils", - "chrono", - "clap 4.5.4", - "dashmap", - "prost 0.12.6", - "protos", - "recaptcha-verify", + "cosmwasm-schema 2.1.0", + "cosmwasm-std 2.1.0", + "cw-storage-plus 2.0.0", + "cw-utils 2.0.0", + "schemars", "serde", - "serde_json", - "subtle-encoding", - "tendermint-rpc", - "tokio", - "tonic 0.10.2", - "tracing", - "tracing-subscriber", - "unionlabs", + "thiserror", ] [[package]] -name = "dummy-ibc-app" -version = "0.1.0" +name = "cw-multi-test" +version = "2.1.0-rc.1" +source = "git+https://github.com/CosmWasm/cw-multi-test.git?rev=e1a2f587c7f9d723444ec93ad8fa48f1d88b65bc#e1a2f587c7f9d723444ec93ad8fa48f1d88b65bc" dependencies = [ - "borsh 1.5.1", - "ibc-vm-rs", - "near-contract-standards", - "near-sdk", - "near-sdk-contract-tools", + "anyhow", + "bech32 0.11.0", + "cosmwasm-schema 2.1.0", + "cosmwasm-std 2.1.0", + "cw-storage-plus 2.0.0", + "cw-utils 2.0.0", + "cw20-ics20", + "derivative", + "hex", + "itertools 0.13.0", + "log", + "prost 0.12.6", + "schemars", "serde", "serde_json", - "unionlabs", + "sha2 0.10.8", + "thiserror", ] [[package]] -name = "dunce" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - -[[package]] -name = "dyn-clone" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" - -[[package]] -name = "easy-ext" -version = "0.2.9" +name = "cw-ownable" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53aff6fdc1b181225acdcb5b14c47106726fd8e486707315b1b138baed68ee31" +checksum = "093dfb4520c48b5848274dd88ea99e280a04bc08729603341c7fb0d758c74321" +dependencies = [ + "cosmwasm-schema 1.5.3", + "cosmwasm-std 1.5.2", + "cw-address-like", + "cw-ownable-derive", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "thiserror", +] [[package]] -name = "ecdsa" -version = "0.16.9" +name = "cw-ownable-derive" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +checksum = "a1d3bf2e0f341bb6cc100d7d441d31cf713fbd3ce0c511f91e79f14b40a889af" dependencies = [ - "der", - "digest 0.10.7", - "elliptic-curve", - "rfc6979", - "signature", - "spki", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +name = "cw-paginate-storage" +version = "2.4.2" +source = "git+https://github.com/DA0-DA0/dao-contracts.git#3ab701747d6d5571cfee7f5a78d8fe39ffa3a8f7" dependencies = [ - "pkcs8", - "signature", + "cosmwasm-std 1.5.2", + "cw-storage-plus 1.2.0", + "serde", ] [[package]] -name = "ed25519-compact" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9b3460f44bea8cd47f45a0c70892f1eff856d97cd55358b2f73f663789f6190" +name = "cw-pause-once" +version = "0.1.0" +source = "git+https://github.com/hussein-aitlahcen/cw-ics721?rev=dd5b7add6fdc81e633084031f8512e5e909dd42a#dd5b7add6fdc81e633084031f8512e5e909dd42a" dependencies = [ - "ed25519", + "cosmwasm-schema 1.5.3", + "cosmwasm-std 1.5.2", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "thiserror", ] [[package]] -name = "ed25519-consensus" -version = "2.1.0" +name = "cw-storage-plus" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" +checksum = "d9b6f91c0b94481a3e9ef1ceb183c37d00764f8751e39b45fc09f4d9b970d469" dependencies = [ - "curve25519-dalek-ng", - "hex", - "rand_core 0.6.4", - "sha2 0.9.9", - "zeroize", + "cosmwasm-std 1.5.2", + "schemars", + "serde", ] [[package]] -name = "ed25519-dalek" -version = "2.1.1" +name = "cw-storage-plus" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +checksum = "d5ff29294ee99373e2cd5fd21786a3c0ced99a52fec2ca347d565489c61b723c" dependencies = [ - "curve25519-dalek 4.1.3", - "ed25519", - "merlin", - "rand_core 0.6.4", + "cosmwasm-std 1.5.2", + "schemars", "serde", - "sha2 0.10.8", - "subtle 2.5.0", - "zeroize", ] [[package]] -name = "ed25519-zebra" -version = "3.1.0" +name = "cw-storage-plus" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +checksum = "f13360e9007f51998d42b1bc6b7fa0141f74feae61ed5fd1e5b0a89eec7b5de1" dependencies = [ - "curve25519-dalek 3.2.0", - "hashbrown 0.12.3", - "hex", - "rand_core 0.6.4", + "cosmwasm-std 2.1.0", + "schemars", "serde", - "sha2 0.9.9", - "zeroize", ] [[package]] -name = "ed25519-zebra" -version = "4.0.3" +name = "cw-utils" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" +checksum = "d6a84c6c1c0acc3616398eba50783934bd6c964bad6974241eaee3460c8f5b26" dependencies = [ - "curve25519-dalek 4.1.3", - "ed25519", - "hashbrown 0.14.3", - "hex", - "rand_core 0.6.4", - "sha2 0.10.8", - "zeroize", + "cosmwasm-schema 1.5.3", + "cosmwasm-std 1.5.2", + "cw2 0.16.0", + "schemars", + "semver 1.0.22", + "serde", + "thiserror", ] [[package]] -name = "either" -version = "1.10.0" +name = "cw-utils" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "1c4a657e5caacc3a0d00ee96ca8618745d050b8f757c709babafb81208d4239c" dependencies = [ + "cosmwasm-schema 1.5.3", + "cosmwasm-std 1.5.2", + "cw2 1.1.2", + "schemars", + "semver 1.0.22", "serde", + "thiserror", ] [[package]] -name = "elementtree" -version = "0.7.0" +name = "cw-utils" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6319c9433cf1e95c60c8533978bccf0614f27f03bb4e514253468eeeaa7fe3" +checksum = "07dfee7f12f802431a856984a32bce1cb7da1e6c006b5409e3981035ce562dec" dependencies = [ - "string_cache", - "xml-rs", + "cosmwasm-schema 2.1.0", + "cosmwasm-std 2.1.0", + "schemars", + "serde", + "thiserror", ] [[package]] -name = "elliptic-curve" -version = "0.13.8" +name = "cw2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +checksum = "91398113b806f4d2a8d5f8d05684704a20ffd5968bf87e3473e1973710b884ad" dependencies = [ - "base16ct", - "crypto-bigint", - "digest 0.10.7", - "ff", - "generic-array 0.14.7", - "group", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "subtle 2.5.0", - "zeroize", + "cosmwasm-schema 1.5.3", + "cosmwasm-std 1.5.2", + "cw-storage-plus 0.16.0", + "schemars", + "serde", ] [[package]] -name = "ena" -version = "0.14.2" +name = "cw2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +checksum = "c6c120b24fbbf5c3bedebb97f2cc85fbfa1c3287e09223428e7e597b5293c1fa" dependencies = [ - "log", + "cosmwasm-schema 1.5.3", + "cosmwasm-std 1.5.2", + "cw-storage-plus 1.2.0", + "schemars", + "semver 1.0.22", + "serde", + "thiserror", ] [[package]] -name = "encode_unicode" -version = "0.3.6" +name = "cw2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "b04852cd38f044c0751259d5f78255d07590d136b8a86d4e09efdd7666bd6d27" +dependencies = [ + "cosmwasm-schema 2.1.0", + "cosmwasm-std 2.1.0", + "cw-storage-plus 2.0.0", + "schemars", + "semver 1.0.22", + "serde", + "thiserror", +] [[package]] -name = "encoding_rs" -version = "0.8.33" +name = "cw20" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "a42212b6bf29bbdda693743697c621894723f35d3db0d5df930be22903d0e27c" dependencies = [ - "cfg-if 1.0.0", + "cosmwasm-schema 2.1.0", + "cosmwasm-std 2.1.0", + "cw-utils 2.0.0", + "schemars", + "serde", ] [[package]] -name = "enr" -version = "0.9.1" +name = "cw20-ics20" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe81b5c06ecfdbc71dd845216f225f53b62a10cb8a16c946836a3467f701d05b" +checksum = "80a9e377dbbd1ffb3b6a8a2dbf9128609a6458a3292f88f99e0b6840a7e9762e" dependencies = [ - "base64 0.21.7", - "bytes", - "hex", - "k256", - "log", - "rand 0.8.5", - "rlp", + "cosmwasm-schema 2.1.0", + "cosmwasm-std 2.1.0", + "cw-controllers", + "cw-storage-plus 2.0.0", + "cw-utils 2.0.0", + "cw2 2.0.0", + "cw20", + "schemars", + "semver 1.0.22", "serde", - "sha3", - "zeroize", + "thiserror", ] [[package]] -name = "ensure-blocks" -version = "0.0.0" +name = "cw721" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94a1ea6e6277bdd6dfc043a9b1380697fe29d6e24b072597439523658d21d791" dependencies = [ - "clap 4.5.4", - "ethers", - "reqwest 0.11.27", - "tendermint-rpc", - "tokio", - "tracing", - "tracing-subscriber", + "cosmwasm-schema 1.5.3", + "cosmwasm-std 1.5.2", + "cw-utils 0.16.0", + "schemars", + "serde", ] [[package]] -name = "enum-map" -version = "2.7.3" +name = "cw721" +version = "0.18.0" +source = "git+https://github.com/CosmWasm/cw-nfts?branch=main#e63a7bbb620e6ea39224bb5580967477066cb7ae" +dependencies = [ + "cosmwasm-schema 1.5.3", + "cosmwasm-std 1.5.2", + "cw-utils 1.0.3", + "schemars", + "serde", +] + +[[package]] +name = "cw721-base" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +checksum = "77518e27431d43214cff4cdfbd788a7508f68d9b1f32389e6fce513e7eaccbef" dependencies = [ - "enum-map-derive", + "cosmwasm-schema 1.5.3", + "cosmwasm-std 1.5.2", + "cw-storage-plus 0.16.0", + "cw-utils 0.16.0", + "cw2 0.16.0", + "cw721 0.16.0", + "schemars", + "serde", + "thiserror", ] [[package]] -name = "enum-map-derive" -version = "0.17.0" +name = "cw721-base" +version = "0.18.0" +source = "git+https://github.com/CosmWasm/cw-nfts?branch=main#e63a7bbb620e6ea39224bb5580967477066cb7ae" +dependencies = [ + "cosmwasm-schema 1.5.3", + "cosmwasm-std 1.5.2", + "cw-ownable", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw2 1.1.2", + "cw721 0.18.0", + "cw721-base 0.16.0", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "darling" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", + "darling_core 0.13.4", + "darling_macro 0.13.4", ] [[package]] -name = "enumorph" -version = "0.1.2" +name = "darling" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d3e2610493c0a1fc3bf33fb420650c6ebf7990c55e3d5e71a57bee374486824" +checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +dependencies = [ + "darling_core 0.20.8", + "darling_macro 0.20.8", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ + "fnv", + "ident_case", "proc-macro2", "quote", - "syn 2.0.60", + "strsim 0.10.0", + "syn 1.0.109", ] [[package]] -name = "env_logger" -version = "0.9.3" +name = "darling_core" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 2.0.77", ] [[package]] -name = "equivalent" -version = "1.0.1" +name = "darling_macro" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote", + "syn 1.0.109", +] [[package]] -name = "erased-serde" -version = "0.4.4" +name = "darling_macro" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b73807008a3c7f171cc40312f37d95ef0396e048b5848d775f54b1a4dd4a0d3" +checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ - "serde", + "darling_core 0.20.8", + "quote", + "syn 2.0.77", ] [[package]] -name = "errno" -version = "0.3.8" +name = "dashmap" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ - "libc", - "windows-sys 0.52.0", + "cfg-if 1.0.0", + "hashbrown 0.14.3", + "lock_api", + "once_cell", + "parking_lot_core", ] [[package]] -name = "error_reporter" -version = "1.0.0" +name = "data-encoding" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31ae425815400e5ed474178a7a22e275a9687086a12ca63ec793ff292d8fdae8" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] -name = "etcetera" -version = "0.8.0" +name = "der" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ - "cfg-if 1.0.0", - "home", - "windows-sys 0.48.0", + "const-oid", + "pem-rfc7468", + "zeroize", ] [[package]] -name = "eth-keystore" -version = "0.5.0" +name = "deranged" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ - "aes", - "ctr", - "digest 0.10.7", - "hex", - "hmac 0.12.1", - "pbkdf2 0.11.0", - "rand 0.8.5", - "scrypt", + "powerfmt", "serde", - "serde_json", - "sha2 0.10.8", - "sha3", - "thiserror", - "uuid 0.8.2", ] [[package]] -name = "ethabi" -version = "18.0.0" +name = "derivative" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "ethbloom" -version = "0.13.0" +name = "derive-syn-parse" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" dependencies = [ - "crunchy", - "fixed-hash 0.8.0", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "tiny-keccak", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "ethereum-light-client" -version = "0.1.0" +name = "derive_arbitrary" +version = "1.3.2" +source = "git+https://github.com/unionlabs/arbitrary#b5796f1a0066dc5707d7681a80e19b99a910987d" dependencies = [ - "base64 0.21.7", - "bytes", - "cosmwasm-std 1.5.2", - "ethereum-verifier", - "ethers-contract-derive", - "ethers-core", - "hex", - "hex-literal", - "ics008-wasm-client", - "lazy_static", - "prost 0.12.6", - "protos", - "rlp", - "schemars", - "serde", - "serde-json-wasm 1.0.1", - "serde-utils", - "serde_json", - "sha3", - "thiserror", - "tiny-keccak", - "unionlabs", + "proc-macro2", + "quote", + "syn 2.0.77", ] [[package]] -name = "ethereum-types" -version = "0.14.1" +name = "derive_more" +version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "ethbloom", + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "1.0.0-beta.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7abbfc297053be59290e3152f8cbcd52c8642e0728b69ee187d991d4c1af08d" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0-beta.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bba3e9872d7c58ce7ef0fcf1844fcc3e23ef2a58377b50df35dd98e42a5726e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", + "unicode-xid", +] + +[[package]] +name = "devnet-compose" +version = "0.1.0" +dependencies = [ + "cliclack", + "console", + "itertools 0.12.1", + "serde", + "serde_json", + "serde_with", + "strum 0.26.2", +] + +[[package]] +name = "devnet-utils" +version = "0.1.0" +dependencies = [ + "base64 0.21.7", + "bip39", + "clap 4.5.4", + "cosmwasm-std 2.1.0", + "ed25519-compact", + "hex", + "strum 0.26.2", + "tiny-hderive", + "unionlabs", +] + +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.7", +] + +[[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 2.5.0", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi 0.3.9", +] + +[[package]] +name = "dissimilar" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" + +[[package]] +name = "dlmalloc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "203540e710bfadb90e5e29930baf5d10270cec1f43ab34f46f78b147b2de715a" +dependencies = [ + "libc", +] + +[[package]] +name = "doctest-file" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "drip" +version = "0.1.0" +dependencies = [ + "async-graphql", + "async-graphql-axum", + "async-sqlite", + "axum 0.7.5", + "chain-utils", + "chrono", + "clap 4.5.4", + "dashmap", + "prost 0.12.6", + "protos", + "recaptcha-verify", + "serde", + "serde_json", + "subtle-encoding", + "tendermint-rpc", + "tokio", + "tonic", + "tracing", + "tracing-subscriber 0.3.18", + "unionlabs", +] + +[[package]] +name = "dummy-ibc-app" +version = "0.1.0" +dependencies = [ + "borsh", + "ibc-vm-rs", + "near-contract-standards", + "near-sdk", + "near-sdk-contract-tools", + "serde", + "serde_json", + "unionlabs", +] + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[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 2.2.0", + "spki", +] + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "serde", + "signature 1.6.4", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature 2.2.0", +] + +[[package]] +name = "ed25519-compact" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9b3460f44bea8cd47f45a0c70892f1eff856d97cd55358b2f73f663789f6190" +dependencies = [ + "ed25519 2.2.3", +] + +[[package]] +name = "ed25519-consensus" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" +dependencies = [ + "curve25519-dalek-ng", + "hex", + "rand_core 0.6.4", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.2.0", + "ed25519 1.5.3", + "rand 0.7.3", + "serde", + "serde_bytes", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", + "merlin", + "rand_core 0.6.4", + "serde", + "sha2 0.10.8", + "subtle 2.5.0", + "zeroize", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek 3.2.0", + "hashbrown 0.12.3", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-zebra" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" +dependencies = [ + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", + "hashbrown 0.14.3", + "hex", + "rand_core 0.6.4", + "sha2 0.10.8", + "zeroize", +] + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +dependencies = [ + "serde", +] + +[[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 0.14.7", + "group", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle 2.5.0", + "zeroize", +] + +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "enr" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe81b5c06ecfdbc71dd845216f225f53b62a10cb8a16c946836a3467f701d05b" +dependencies = [ + "base64 0.21.7", + "bytes", + "hex", + "k256", + "log", + "rand 0.8.5", + "rlp", + "serde", + "sha3 0.10.8", + "zeroize", +] + +[[package]] +name = "ensure-blocks" +version = "0.0.0" +dependencies = [ + "clap 4.5.4", + "ethers", + "reqwest 0.11.27", + "tendermint-rpc", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", +] + +[[package]] +name = "enum-map" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +dependencies = [ + "enum-map-derive", +] + +[[package]] +name = "enum-map-derive" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "enum_dispatch" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "enumorph" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d3e2610493c0a1fc3bf33fb420650c6ebf7990c55e3d5e71a57bee374486824" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "erased-serde" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" +dependencies = [ + "serde", +] + +[[package]] +name = "erased-serde" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b73807008a3c7f171cc40312f37d95ef0396e048b5848d775f54b1a4dd4a0d3" +dependencies = [ + "serde", +] + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "error_reporter" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31ae425815400e5ed474178a7a22e275a9687086a12ca63ec793ff292d8fdae8" + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if 1.0.0", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "thiserror", + "uuid 0.8.2", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3 0.10.8", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash 0.8.0", + "impl-codec 0.6.0", + "impl-rlp", + "impl-serde 0.4.0", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-light-client" +version = "0.1.0" +dependencies = [ + "base64 0.21.7", + "bytes", + "cosmwasm-std 1.5.2", + "ethereum-verifier", + "ethers-contract-derive", + "ethers-core", + "hex", + "hex-literal", + "ics008-wasm-client", + "lazy_static", + "prost 0.12.6", + "protos", + "rlp", + "schemars", + "serde", + "serde-json-wasm 1.0.1", + "serde-utils", + "serde_json", + "sha3 0.10.8", + "thiserror", + "tiny-keccak", + "unionlabs", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", "fixed-hash 0.8.0", - "impl-codec", + "impl-codec 0.6.0", "impl-rlp", - "impl-serde", + "impl-serde 0.4.0", "primitive-types 0.12.2", "scale-info", "uint", @@ -4057,7 +4784,7 @@ dependencies = [ "serde-utils", "serde_json", "sha2 0.10.8", - "sha3", + "sha3 0.10.8", "ssz", "thiserror", "trie-db", @@ -4127,7 +4854,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "syn 2.0.60", + "syn 2.0.77", "toml 0.8.12", "walkdir", ] @@ -4144,7 +4871,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -4152,9 +4879,9 @@ name = "ethers-core" version = "2.0.10" source = "git+https://github.com/unionlabs/ethers-rs?branch=ethers-core-wasm#fd10abba9a9d5347b71bd4cde6418a6f6f2f1279" dependencies = [ - "arrayvec", + "arrayvec 0.7.4", "bytes", - "cargo_metadata 0.18.1", + "cargo_metadata", "chrono", "const-hex", "elliptic-curve", @@ -4170,7 +4897,7 @@ dependencies = [ "serde", "serde_json", "strum 0.25.0", - "syn 2.0.60", + "syn 2.0.77", "tempfile", "thiserror", "tiny-keccak", @@ -4303,6 +5030,12 @@ dependencies = [ "yansi", ] +[[package]] +name = "ethnum" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" + [[package]] name = "event-listener" version = "2.5.3" @@ -4320,6 +5053,17 @@ dependencies = [ "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.4.0" @@ -4349,12 +5093,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00e83c02035136f1592a47964ea60c05a50e4ed8b5892cfac197063850898d4d" dependencies = [ - "blake2 0.10.6", + "blake2", "fs-err", "prettier-please", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -4367,6 +5111,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fail" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5e43d0f78a42ad591453aedb1d7ae631ce7ee445c7643691055a9ed8d3b01c" +dependencies = [ + "log", + "once_cell", + "rand 0.8.5", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -4412,7 +5167,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" dependencies = [ - "arrayvec", + "arrayvec 0.7.4", "auto_impl", "bytes", ] @@ -4423,6 +5178,9 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ + "bitvec 1.0.1", + "byteorder", + "ff_derive", "rand_core 0.6.4", "subtle 2.5.0", ] @@ -4440,13 +5198,29 @@ dependencies = [ "serde", ] +[[package]] +name = "ff_derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f54704be45ed286151c5e11531316eaef5b8f5af7d597b806fdb8af108d84a" +dependencies = [ + "addchain", + "cfg-if 1.0.0", + "num-bigint 0.3.3", + "num-integer", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ff_derive_ce" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b96fbccd88dbb1fac4ee4a07c2fcc4ca719a74ffbd9d2b9d41d8c8eb073d8b20" dependencies = [ - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-integer", "num-traits", "proc-macro2", @@ -4475,30 +5249,33 @@ dependencies = [ "version_check", ] -[[package]] -name = "filetime" -version = "0.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", -] - [[package]] name = "finl_unicode" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" +[[package]] +name = "fixed" +version = "1.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c6e0b89bf864acd20590dbdbad56f69aeb898abfc9443008fd7bd48b2cc85a" +dependencies = [ + "az", + "bytemuck", + "half 2.4.1", + "typenum", +] + [[package]] name = "fixed-hash" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4508,13 +5285,18 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ - "arbitrary", "byteorder", "rand 0.8.5", "rustc-hex", "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fixedbitset" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" + [[package]] name = "fixedbitset" version = "0.4.2" @@ -4541,6 +5323,22 @@ dependencies = [ "paste", ] +[[package]] +name = "flexi_logger" +version = "0.27.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469e584c031833564840fb0cdbce99bdfe946fd45480a188545e73a76f45461c" +dependencies = [ + "chrono", + "glob", + "is-terminal", + "lazy_static", + "log", + "nu-ansi-term 0.49.0", + "regex", + "thiserror", +] + [[package]] name = "flume" version = "0.11.0" @@ -4605,7 +5403,7 @@ dependencies = [ "proc-macro2", "quote", "sp-core-hashing", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -4618,7 +5416,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -4629,7 +5427,7 @@ checksum = "d9c078db2242ea7265faa486004e7fd8daaf1a577cfcac0070ce55d926922883" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -4656,7 +5454,7 @@ checksum = "b0fa992f1656e1707946bbba340ad244f0814009ef8c0118eb7b658395f19a2e" dependencies = [ "frunk_proc_macro_helpers", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -4668,7 +5466,7 @@ dependencies = [ "frunk_core", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -4687,7 +5485,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" dependencies = [ "libc", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -4702,6 +5500,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + [[package]] name = "funty" version = "2.0.0" @@ -4758,7 +5562,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.12.1", + "parking_lot", ] [[package]] @@ -4785,7 +5589,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -4843,6 +5647,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + [[package]] name = "generate-rust-sol-bindings" version = "0.1.0" @@ -4871,6 +5681,28 @@ dependencies = [ "zeroize", ] +[[package]] +name = "get_if_addrs" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abddb55a898d32925f3148bd281174a68eeb68bbfd9a5938a57b18f506ee4ef7" +dependencies = [ + "c_linked_list", + "get_if_addrs-sys", + "libc", + "winapi 0.2.8", +] + +[[package]] +name = "get_if_addrs-sys" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d04f9fb746cf36b191c00f3ede8bde9c8e64f9f4b05ae2694a9ccf5e3f5ab48" +dependencies = [ + "gcc", + "libc", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -4895,28 +5727,49 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug 0.3.1", + "polyval", +] + [[package]] name = "gimli" -version = "0.26.2" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gloo-net" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580" dependencies = [ - "fallible-iterator 0.2.0", - "stable_deref_trait", + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "http 1.1.0", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", ] -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "gloo-timers" version = "0.2.6" @@ -4929,6 +5782,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gnark-key-parser" version = "0.1.0" @@ -4948,11 +5814,11 @@ dependencies = [ "ark-bls12-377", "ark-bn254", "ark-ff 0.4.2", - "num-bigint 0.4.4", + "num-bigint 0.4.6", "serde", "serde-utils", "serde_json", - "sha3", + "sha3 0.10.8", "thiserror", "tiny-keccak", "unionlabs", @@ -4964,17 +5830,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "558b88954871f5e5b2af0e62e2e176c8bde7a6c2c4ed41b13d138d96da2e2cbd" -[[package]] -name = "goblin" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143" -dependencies = [ - "log", - "plain", - "scroll 0.11.0", -] - [[package]] name = "group" version = "0.13.0" @@ -4982,7 +5837,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", + "rand 0.8.5", "rand_core 0.6.4", + "rand_xorshift", "subtle 2.5.0", ] @@ -5001,7 +5858,26 @@ dependencies = [ "indexmap 2.2.6", "slab", "tokio", - "tokio-util 0.7.10", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", + "indexmap 2.2.6", + "slab", + "tokio", + "tokio-util", "tracing", ] @@ -5011,6 +5887,16 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if 1.0.0", + "crunchy", +] + [[package]] name = "handlebars" version = "5.1.2" @@ -5040,15 +5926,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash 0.7.8", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -5095,6 +5972,30 @@ dependencies = [ "hashbrown 0.14.3", ] +[[package]] +name = "headers" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" +dependencies = [ + "base64 0.21.7", + "bytes", + "headers-core", + "http 1.1.0", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http 1.1.0", +] + [[package]] name = "heck" version = "0.3.3" @@ -5134,6 +6035,12 @@ 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" @@ -5149,6 +6056,22 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hifijson" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9958ab3ce3170c061a27679916bd9b969eceeb5e8b120438e6751d0987655c42" + +[[package]] +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest 0.9.0", + "hmac 0.10.1", +] + [[package]] name = "hkdf" version = "0.12.4" @@ -5168,6 +6091,26 @@ dependencies = [ "digest 0.8.1", ] +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac 0.10.0", + "digest 0.9.0", +] + [[package]] name = "hmac" version = "0.12.1" @@ -5188,6 +6131,17 @@ dependencies = [ "hmac 0.7.1", ] +[[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 0.14.7", + "hmac 0.8.1", +] + [[package]] name = "home" version = "0.5.9" @@ -5197,6 +6151,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi 0.3.9", +] + [[package]] name = "http" version = "0.2.12" @@ -5301,20 +6266,14 @@ dependencies = [ "tikv-jemallocator", "time", "tokio", - "tonic 0.10.2", + "tonic", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.18", "unionlabs", "url", "valuable", ] -[[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.28" @@ -5325,7 +6284,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.25", "http 0.2.12", "http-body 0.4.6", "httparse", @@ -5348,6 +6307,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.0", "httparse", @@ -5383,6 +6343,7 @@ dependencies = [ "http 1.1.0", "hyper 1.3.1", "hyper-util", + "log", "rustls 0.23.7", "rustls-pki-types", "tokio", @@ -5511,7 +6472,7 @@ name = "ics08-movement" version = "0.1.0" dependencies = [ "aptos-verifier", - "bcs", + "bcs 0.1.4", "cosmwasm-std 1.5.2", "ethereum-verifier", "hex", @@ -5522,7 +6483,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.8", - "sha3", + "sha3 0.10.8", "thiserror", "unionlabs", ] @@ -5598,6 +6559,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.5.0" @@ -5608,13 +6579,36 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "im" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" +dependencies = [ + "bitmaps", + "rand_core 0.6.4", + "rand_xoshiro", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] +name = "impl-codec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" +dependencies = [ + "parity-scale-codec 2.3.1", +] + [[package]] name = "impl-codec" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.9", ] [[package]] @@ -5626,6 +6620,15 @@ dependencies = [ "rlp", ] +[[package]] +name = "impl-serde" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +dependencies = [ + "serde", +] + [[package]] name = "impl-serde" version = "0.4.0" @@ -5647,10 +6650,28 @@ dependencies = [ ] [[package]] -name = "indent_write" -version = "2.2.0" +name = "include_dir" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b56e147e6187d61e9d0f039f10e070d0c0a887e24fe0bb9ca3f29bfde62cab" +dependencies = [ + "glob", + "include_dir_impl", + "proc-macro-hack", +] + +[[package]] +name = "include_dir_impl" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cfe9645a18782869361d9c8732246be7b410ad4e919d3609ebabdac00ba12c3" +checksum = "0a0c890c85da4bab7bce4204c707396bbd3c6c8a681716a51c8814cfc2b682df" +dependencies = [ + "anyhow", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] name = "indenter" @@ -5693,6 +6714,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "indoc" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" + [[package]] name = "inout" version = "0.1.3" @@ -5711,6 +6738,19 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "internment" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab388864246d58a276e60e7569a833d9cc4cd75c66e5ca77c177dad38e59996" +dependencies = [ + "ahash 0.7.8", + "dashmap", + "hashbrown 0.12.3", + "once_cell", + "parking_lot", +] + [[package]] name = "interprocess" version = "2.2.1" @@ -5722,7 +6762,7 @@ dependencies = [ "libc", "recvmsg", "tokio", - "widestring", + "widestring 1.1.0", "windows-sys 0.52.0", ] @@ -5733,12 +6773,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] -name = "is_executable" -version = "0.1.2" +name = "is-terminal" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d553b8abc8187beb7d663e34c065ac4570b273bc9511a50e940e99409c577" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "winapi", + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", ] [[package]] @@ -5784,122 +6826,258 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] -name = "jobserver" -version = "0.1.28" +name = "jaq-core" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +checksum = "d6fda09ee08c84c81293fdf811d9ebaa87b327557b5391f290c926d728c2ddd4" dependencies = [ - "libc", + "aho-corasick", + "base64 0.22.1", + "chrono", + "hifijson", + "jaq-interpret", + "libm", + "log", + "regex", + "urlencoding", ] [[package]] -name = "joinery" -version = "2.1.0" +name = "jaq-interpret" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72167d68f5fce3b8655487b8038691a3c9984ee769590f93f2a631f4ad64e4f5" +checksum = "2fe95ec3c24af3fd9f3dd1091593f5e49b003a66c496a8aa39d764d0a06ae17b" +dependencies = [ + "ahash 0.8.11", + "dyn-clone", + "hifijson", + "indexmap 2.2.6", + "jaq-syn", + "once_cell", + "serde_json", +] [[package]] -name = "js-sys" -version = "0.3.69" +name = "jaq-std" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "bfbaa55578fd3b70433b594a370741e0c364e4afff92cc0099623fce87311bc1" dependencies = [ - "wasm-bindgen", + "jaq-syn", ] [[package]] -name = "json-patch" -version = "1.4.0" +name = "jaq-syn" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec9ad60d674508f3ca8f380a928cfe7b096bc729c4e2dbfe3852bc45da3ab30b" +checksum = "1ba44fe4428c71304604261ecbae047ee9cfb60c4f1a6bd222ebbb31726d3948" dependencies = [ "serde", - "serde_json", +] + +[[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 = "json_comments" -version = "0.2.2" +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dbbfed4e59ba9750e15ba154fdfd9329cee16ff3df539c2666b70f58cc32105" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] [[package]] name = "jsonrpsee" -version = "0.22.3" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cdbb7cb6f3ba28f5b212dd250ab4483105efc3e381f5c8bb90340f14f0a2cc3" +checksum = "5ec465b607a36dc5dd45d48b7689bc83f679f66a3ac6b6b21cc787a11e0f8685" dependencies = [ + "jsonrpsee-client-transport", "jsonrpsee-core", + "jsonrpsee-http-client", + "jsonrpsee-proc-macros", + "jsonrpsee-server", "jsonrpsee-types", + "jsonrpsee-wasm-client", "jsonrpsee-ws-client", + "tokio", "tracing", ] [[package]] name = "jsonrpsee-client-transport" -version = "0.22.3" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ab2e14e727d2faf388c99d9ca5210566ed3b044f07d92c29c3611718d178380" +checksum = "90f0977f9c15694371b8024c35ab58ca043dbbf4b51ccb03db8858a021241df1" dependencies = [ + "base64 0.22.1", + "futures-channel", "futures-util", - "http 0.2.12", + "gloo-net", + "http 1.1.0", "jsonrpsee-core", "pin-project", - "rustls-native-certs 0.7.0", + "rustls 0.23.7", "rustls-pki-types", + "rustls-platform-verifier", "soketto", "thiserror", "tokio", - "tokio-rustls 0.25.0", - "tokio-util 0.7.10", + "tokio-rustls 0.26.0", + "tokio-util", "tracing", "url", ] [[package]] name = "jsonrpsee-core" -version = "0.22.3" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71962a1c49af43adf81d337e4ebc93f3c915faf6eccaa14d74e255107dfd7723" +checksum = "e942c55635fbf5dc421938b8558a8141c7e773720640f4f1dbe1f4164ca4e221" dependencies = [ - "anyhow", - "async-lock", "async-trait", - "beef", + "bytes", "futures-timer", "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "jsonrpsee-types", + "parking_lot", + "pin-project", + "rand 0.8.5", + "rustc-hash 2.0.0", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "wasm-bindgen-futures", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33774602df12b68a2310b38a535733c477ca4a498751739f89fe8dbbb62ec4c" +dependencies = [ + "async-trait", + "base64 0.22.1", + "http-body 1.0.0", + "hyper 1.3.1", + "hyper-rustls 0.27.2", + "hyper-util", + "jsonrpsee-core", + "jsonrpsee-types", + "rustls 0.23.7", + "rustls-platform-verifier", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-proc-macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b07a2daf52077ab1b197aea69a5c990c060143835bf04c77070e98903791715" +dependencies = [ + "heck 0.5.0", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "jsonrpsee-server" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038fb697a709bec7134e9ccbdbecfea0e2d15183f7140254afef7c5610a3f488" +dependencies = [ + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.3.1", + "hyper-util", + "jsonrpsee-core", "jsonrpsee-types", "pin-project", - "rustc-hash", + "route-recognizer", "serde", "serde_json", + "soketto", "thiserror", "tokio", "tokio-stream", + "tokio-util", + "tower", "tracing", ] [[package]] name = "jsonrpsee-types" -version = "0.22.3" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e53c72de6cd2ad6ac1aa6e848206ef8b736f92ed02354959130373dfa5b3cbd" +checksum = "23b67d6e008164f027afbc2e7bb79662650158d26df200040282d2aa1cbb093b" dependencies = [ - "anyhow", - "beef", + "http 1.1.0", "serde", "serde_json", "thiserror", ] +[[package]] +name = "jsonrpsee-wasm-client" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0470d0ae043ffcb0cd323797a631e637fb4b55fe3eaa6002934819458bba62a7" +dependencies = [ + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", +] + [[package]] name = "jsonrpsee-ws-client" -version = "0.22.3" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8a07ab8da9a283b906f6735ddd17d3680158bb72259e853441d1dd0167079ec" +checksum = "992bf67d1132f88edf4a4f8cff474cf01abb2be203004a2b8e11c2b20795b99e" dependencies = [ - "http 0.2.12", + "http 1.1.0", "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", @@ -5946,7 +7124,7 @@ dependencies = [ "elliptic-curve", "once_cell", "sha2 0.10.8", - "signature", + "signature 2.2.0", ] [[package]] @@ -5979,7 +7157,7 @@ dependencies = [ "ena", "itertools 0.11.0", "lalrpop-util", - "petgraph", + "petgraph 0.6.4", "regex", "regex-syntax 0.8.3", "string_cache", @@ -6007,38 +7185,12 @@ dependencies = [ "spin 0.5.2", ] -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if 1.0.0", - "winapi", -] - -[[package]] -name = "libloading" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" -dependencies = [ - "cfg-if 1.0.0", - "windows-targets 0.52.4", -] - [[package]] name = "libm" version = "0.2.8" @@ -6055,23 +7207,6 @@ dependencies = [ "libc", ] -[[package]] -name = "librocksdb-sys" -version = "0.11.0+8.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3386f101bcb4bd252d8e9d2fb41ec3b0862a15a62b478c355b2982efa469e3e" -dependencies = [ - "bindgen", - "bzip2-sys", - "cc", - "glob", - "libc", - "libz-sys", - "lz4-sys", - "tikv-jemalloc-sys", - "zstd-sys", -] - [[package]] name = "libsecp256k1" version = "0.3.5" @@ -6081,7 +7216,7 @@ dependencies = [ "arrayref", "crunchy", "digest 0.8.1", - "hmac-drbg", + "hmac-drbg 0.2.0", "rand 0.7.3", "sha2 0.8.2", "subtle 2.5.0", @@ -6089,21 +7224,58 @@ dependencies = [ ] [[package]] -name = "libsqlite3-sys" -version = "0.27.0" +name = "libsecp256k1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ - "cc", - "pkg-config", - "vcpkg", + "arrayref", + "base64 0.13.1", + "digest 0.9.0", + "hmac-drbg 0.3.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "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 2.5.0", +] + +[[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 = "libz-sys" -version = "1.1.16" +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 = "libsqlite3-sys" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" dependencies = [ "cc", "pkg-config", @@ -6130,7 +7302,7 @@ dependencies = [ "serde", "serde-json-wasm 1.0.1", "serde_json", - "sha3", + "sha3 0.10.8", "thiserror", "tiny-keccak", "unionlabs", @@ -6151,7 +7323,7 @@ dependencies = [ "serde", "serde-utils", "serde_json", - "sha3", + "sha3 0.10.8", "thiserror", "unionlabs", ] @@ -6170,6 +7342,12 @@ dependencies = [ "unionlabs", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -6191,6 +7369,9 @@ name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +dependencies = [ + "serde", +] [[package]] name = "lru" @@ -6210,16 +7391,6 @@ dependencies = [ "hashbrown 0.14.3", ] -[[package]] -name = "lz4-sys" -version = "1.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9764018d143cc854c9f17f0b907de70f14393b1f502da6375dce70f00514eb3" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "macro_magic" version = "0.5.0" @@ -6229,7 +7400,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -6243,7 +7414,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -6254,7 +7425,7 @@ checksum = "9ea73aa640dc01d62a590d48c0c3521ed739d53b27f919b25c3551e233481654" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -6265,7 +7436,7 @@ checksum = "ef9d79ae96aaba821963320eb2b6e34d17df1e5a83d8a1985c29cc5be59577b3" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -6274,9 +7445,21 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matchers" version = "0.1.0" @@ -6308,24 +7491,6 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" -[[package]] -name = "memmap2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" -dependencies = [ - "libc", -] - -[[package]] -name = "memoffset" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" -dependencies = [ - "autocfg", -] - [[package]] name = "memory-db" version = "0.32.0" @@ -6350,8 +7515,7 @@ checksum = "93c0d11ac30a033511ae414355d80f70d9f29a44a49140face477117a1ee90db" [[package]] name = "merlin" version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +source = "git+https://github.com/aptos-labs/merlin#3454ccc85e37355c729ba40e6dac6e867ddf59f5" dependencies = [ "byteorder", "keccak", @@ -6375,6 +7539,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -6392,683 +7566,660 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - -[[package]] -name = "multer" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http 1.1.0", - "httparse", - "memchr", - "mime", - "spin 0.9.8", - "version_check", -] - -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "native-tls" -version = "0.2.12" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi 0.3.9", "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", ] [[package]] -name = "near-abi" -version = "0.3.0" +name = "mirai-annotations" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" + +[[package]] +name = "moka" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "885db39b08518fa700b73fa2214e8adbbfba316ba82dd510f50519173eadaf73" +checksum = "32cf62eb4dd975d2dde76432fb1075c49e3ee2331cf36f1f8fd4b66550d32b6f" dependencies = [ - "borsh 0.9.3", - "schemars", - "semver 1.0.22", - "serde", + "async-lock", + "async-trait", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "event-listener 5.3.1", + "futures-util", + "once_cell", + "parking_lot", + "quanta", + "rustc_version 0.4.0", + "smallvec", + "tagptr", + "thiserror", + "triomphe", + "uuid 1.10.0", ] [[package]] -name = "near-abi" -version = "0.4.3" +name = "more-asserts" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c49593c9e94454a2368a4c0a511bf4bf1413aff4d23f16e1d8f4e64b5215351" +checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" + +[[package]] +name = "move-abigen" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "borsh 1.5.1", - "schemars", - "semver 1.0.22", + "anyhow", + "bcs 0.1.4", + "heck 0.4.1", + "log", + "move-binary-format", + "move-bytecode-verifier", + "move-command-line-common", + "move-core-types", + "move-model", "serde", ] [[package]] -name = "near-account-id" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35cbb989542587b47205e608324ddd391f0cee1c22b4b64ae49f458334b95907" +name = "move-binary-format" +version = "0.0.3" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "borsh 1.5.1", - "schemars", + "anyhow", + "backtrace", + "indexmap 1.9.3", + "move-bytecode-spec", + "move-core-types", + "ref-cast", "serde", + "variant_count", ] [[package]] -name = "near-async" +name = "move-bindgen" version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" dependencies = [ - "actix", - "derive_more 0.99.17", + "aptos-crypto", + "aptos-rest-client", + "aptos-types", "futures", - "near-async-derive", - "near-o11y 0.0.0", - "near-performance-metrics", - "near-time", - "once_cell", - "serde", - "serde_json", - "time", + "move-bindgen-derive", + "move-core-types", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.77", "tokio", - "tracing", ] [[package]] -name = "near-async-derive" +name = "move-bindgen-derive" version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] -name = "near-chain-configs" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" -dependencies = [ - "anyhow", - "bytesize", - "chrono", - "derive_more 0.99.17", - "near-async", - "near-config-utils 0.0.0", - "near-crypto 0.0.0", - "near-o11y 0.0.0", - "near-parameters 0.0.0", - "near-primitives 0.0.0", - "num-rational 0.3.2", - "once_cell", - "serde", - "serde_json", - "sha2 0.10.8", - "smart-default", - "time", - "tracing", -] +name = "move-borrow-graph" +version = "0.0.1" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" [[package]] -name = "near-chain-configs" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e5a8ace81c09d7eb165dffc1742358a021b2fa761f2160943305f83216003" +name = "move-bytecode-source-map" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ "anyhow", - "bytesize", - "chrono", - "derive_more 0.99.17", - "near-config-utils 0.20.1", - "near-crypto 0.20.1", - "near-parameters 0.20.1", - "near-primitives 0.20.1", - "num-rational 0.3.2", - "once_cell", + "bcs 0.1.4", + "move-binary-format", + "move-command-line-common", + "move-core-types", + "move-ir-types", + "move-symbol-pool", "serde", - "serde_json", - "sha2 0.10.8", - "smart-default", - "tracing", ] [[package]] -name = "near-config-utils" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" +name = "move-bytecode-spec" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "anyhow", - "json_comments", - "thiserror", - "tracing", + "once_cell", + "quote", + "syn 1.0.109", ] [[package]] -name = "near-config-utils" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ae1eaab1d545a9be7a55b6ef09f365c2017f93a03063547591d12c0c6d27e58" +name = "move-bytecode-utils" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ "anyhow", - "json_comments", - "thiserror", - "tracing", + "move-binary-format", + "move-core-types", + "petgraph 0.5.1", + "serde-reflection", ] [[package]] -name = "near-contract-standards" -version = "5.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e78fe14d389ae76f792735a2108a6b8332a2bed61197310bf5ad718fb1e424" +name = "move-bytecode-verifier" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "near-sdk", + "fail", + "move-binary-format", + "move-borrow-graph", + "move-core-types", + "petgraph 0.5.1", + "serde", + "typed-arena", ] [[package]] -name = "near-crypto" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" +name = "move-command-line-common" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "blake2 0.10.6", - "borsh 1.5.1", - "bs58 0.4.0", - "curve25519-dalek 4.1.3", - "derive_more 0.99.17", - "ed25519-dalek", + "anyhow", + "difference", + "dirs-next", "hex", - "near-account-id", - "near-config-utils 0.0.0", - "near-stdx 0.0.0", + "move-core-types", + "num-bigint 0.3.3", "once_cell", - "primitive-types 0.10.1", - "secp256k1", "serde", - "serde_json", - "subtle 2.5.0", - "thiserror", + "sha2 0.9.9", + "walkdir", ] [[package]] -name = "near-crypto" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2991d2912218a80ec0733ac87f84fa803accea105611eea209d4419271957667" +name = "move-compiler" +version = "0.0.1" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "blake2 0.9.2", - "borsh 1.5.1", - "bs58 0.4.0", - "c2-chacha", - "curve25519-dalek 4.1.3", - "derive_more 0.99.17", - "ed25519-dalek", + "anyhow", + "bcs 0.1.4", + "clap 4.5.4", + "codespan-reporting", "hex", - "near-account-id", - "near-config-utils 0.20.1", - "near-stdx 0.20.1", + "move-binary-format", + "move-borrow-graph", + "move-bytecode-source-map", + "move-bytecode-verifier", + "move-command-line-common", + "move-core-types", + "move-ir-to-bytecode", + "move-ir-types", + "move-symbol-pool", "once_cell", - "primitive-types 0.10.1", - "rand 0.7.3", - "secp256k1", - "serde", - "serde_json", - "subtle 2.5.0", - "thiserror", + "petgraph 0.5.1", + "regex", + "sha3 0.9.1", + "tempfile", ] [[package]] -name = "near-fmt" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" +name = "move-compiler-v2" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "near-primitives-core 0.0.0", + "abstract-domain-derive", + "anyhow", + "bcs 0.1.4", + "clap 4.5.4", + "codespan-reporting", + "ethnum", + "flexi_logger", + "im", + "itertools 0.13.0", + "log", + "move-binary-format", + "move-borrow-graph", + "move-bytecode-source-map", + "move-bytecode-verifier", + "move-command-line-common", + "move-compiler", + "move-core-types", + "move-disassembler", + "move-ir-types", + "move-model", + "move-stackless-bytecode", + "move-symbol-pool", + "num", + "once_cell", + "petgraph 0.5.1", + "strum 0.24.1", + "strum_macros 0.24.3", ] [[package]] -name = "near-fmt" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7d998dfc1e04001608899b2498ad5a782c7d036b73769d510de21964db99286" +name = "move-core-types" +version = "0.0.4" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "near-primitives-core 0.20.1", + "anyhow", + "bcs 0.1.4", + "bytes", + "ethnum", + "hashbrown 0.14.3", + "hex", + "num", + "once_cell", + "primitive-types 0.10.1", + "rand 0.8.5", + "ref-cast", + "serde", + "serde_bytes", + "thiserror", + "uint", ] [[package]] -name = "near-gas" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14e75c875026229902d065e4435804497337b631ec69ba746b102954273e9ad1" +name = "move-coverage" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "borsh 1.5.1", - "schemars", + "anyhow", + "bcs 0.1.4", + "clap 4.5.4", + "codespan", + "colored", + "move-binary-format", + "move-bytecode-source-map", + "move-command-line-common", + "move-core-types", + "move-ir-types", + "petgraph 0.5.1", "serde", ] [[package]] -name = "near-ibc" +name = "move-disassembler" version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "borsh 1.5.1", - "ibc-vm-rs", - "near-contract-standards", - "near-sdk", - "near-sdk-contract-tools", - "schemars", - "serde", - "serde_json", - "thiserror", - "unionlabs", + "anyhow", + "clap 4.5.4", + "colored", + "move-binary-format", + "move-bytecode-source-map", + "move-command-line-common", + "move-compiler", + "move-core-types", + "move-coverage", + "move-ir-types", ] [[package]] -name = "near-ibc-tests" +name = "move-docgen" version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ "anyhow", - "base64 0.21.7", - "borsh 1.5.1", - "env_logger", - "hex", - "ibc-vm-rs", - "near-contract-standards", - "near-crypto 0.20.1", - "near-jsonrpc-client", - "near-jsonrpc-primitives", - "near-primitives 0.20.1", - "near-primitives-core 0.21.2", - "near-sdk", - "near-sdk-contract-tools", - "near-store", - "near-units", - "near-workspaces", + "clap 4.5.4", + "codespan", + "codespan-reporting", + "itertools 0.13.0", + "log", + "move-compiler", + "move-core-types", + "move-model", + "once_cell", + "regex", "serde", - "serde_json", - "sha2 0.10.8", - "time", - "tokio", - "unionlabs", ] [[package]] -name = "near-jsonrpc-client" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18ad81e015f7aced8925d5b9ba3f369b36da9575c15812cfd0786bc1213284ca" +name = "move-ir-to-bytecode" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "borsh 1.5.1", - "lazy_static", + "anyhow", + "codespan-reporting", "log", - "near-chain-configs 0.20.1", - "near-crypto 0.20.1", - "near-jsonrpc-primitives", - "near-primitives 0.20.1", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror", + "move-binary-format", + "move-bytecode-source-map", + "move-command-line-common", + "move-core-types", + "move-ir-to-bytecode-syntax", + "move-ir-types", + "move-symbol-pool", + "ouroboros", ] [[package]] -name = "near-jsonrpc-primitives" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0ce745e954ae776eef05957602e638ee9581106a3675946fb43c2fe7e38ef03" +name = "move-ir-to-bytecode-syntax" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "arbitrary", - "near-chain-configs 0.20.1", - "near-crypto 0.20.1", - "near-primitives 0.20.1", - "near-rpc-error-macro 0.20.1", - "serde", - "serde_json", - "thiserror", + "anyhow", + "hex", + "move-command-line-common", + "move-core-types", + "move-ir-types", + "move-symbol-pool", ] [[package]] -name = "near-light-client" +name = "move-ir-types" version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "anyhow", - "borsh 1.5.1", - "ibc-vm-rs", - "near-contract-standards", - "near-primitives-core 0.21.2", - "near-sdk", - "near-sdk-contract-tools", - "near-units", + "hex", + "move-command-line-common", + "move-core-types", + "move-symbol-pool", + "once_cell", "serde", - "serde_json", - "tokio", - "unionlabs", ] [[package]] -name = "near-o11y" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" +name = "move-model" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "actix", - "base64 0.21.7", - "clap 4.5.4", - "near-crypto 0.0.0", - "near-primitives-core 0.0.0", + "anyhow", + "codespan", + "codespan-reporting", + "internment", + "itertools 0.13.0", + "log", + "move-binary-format", + "move-bytecode-source-map", + "move-command-line-common", + "move-compiler", + "move-core-types", + "move-disassembler", + "move-ir-types", + "move-symbol-pool", + "num", + "num-traits", "once_cell", - "opentelemetry 0.22.0", - "opentelemetry-otlp 0.15.0", - "opentelemetry-semantic-conventions 0.14.0", - "opentelemetry_sdk", - "prometheus", + "regex", "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", - "tracing-appender", - "tracing-opentelemetry 0.23.0", - "tracing-subscriber", ] [[package]] -name = "near-o11y" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d20762631bc8253030013bbae9b5f0542691edc1aa6722f1e8141cc9b928ae5b" +name = "move-package" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "actix", - "base64 0.21.7", + "anyhow", "clap 4.5.4", - "near-crypto 0.20.1", - "near-fmt 0.20.1", - "near-primitives-core 0.20.1", + "colored", + "itertools 0.13.0", + "move-abigen", + "move-binary-format", + "move-bytecode-source-map", + "move-bytecode-utils", + "move-command-line-common", + "move-compiler", + "move-compiler-v2", + "move-core-types", + "move-docgen", + "move-model", + "move-symbol-pool", + "named-lock", "once_cell", - "opentelemetry 0.17.0", - "opentelemetry-otlp 0.10.0", - "opentelemetry-semantic-conventions 0.9.0", - "prometheus", + "petgraph 0.5.1", + "regex", "serde", - "serde_json", - "strum 0.24.1", - "thiserror", - "tokio", - "tracing", - "tracing-appender", - "tracing-opentelemetry 0.17.4", - "tracing-subscriber", + "serde_yaml 0.8.26", + "sha2 0.9.9", + "tempfile", + "termcolor", + "toml 0.7.8", + "walkdir", + "whoami", +] + +[[package]] +name = "move-stackless-bytecode" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" +dependencies = [ + "abstract-domain-derive", + "codespan-reporting", + "ethnum", + "im", + "itertools 0.13.0", + "log", + "move-binary-format", + "move-core-types", + "move-model", + "num", + "paste", + "petgraph 0.5.1", ] [[package]] -name = "near-parameters" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" +name = "move-symbol-pool" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "borsh 1.5.1", - "enum-map", - "near-account-id", - "near-primitives-core 0.0.0", - "num-rational 0.3.2", + "once_cell", "serde", - "serde_repr", - "serde_yaml", - "strum 0.24.1", - "thiserror", ] [[package]] -name = "near-parameters" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f16a59b6c3e69b0585be951af6fe42a0ba86c0e207cb8c63badd19efd16680" +name = "move-table-extension" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "assert_matches", - "borsh 1.5.1", - "enum-map", - "near-account-id", - "near-primitives-core 0.20.1", - "num-rational 0.3.2", - "serde", - "serde_repr", - "serde_yaml", - "strum 0.24.1", - "thiserror", + "better_any", + "bytes", + "move-binary-format", + "move-core-types", + "move-vm-runtime", + "move-vm-types", + "sha3 0.9.1", + "smallvec", ] [[package]] -name = "near-performance-metrics" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" +name = "move-vm-runtime" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "actix", - "bitflags 1.3.2", + "better_any", "bytes", - "futures", - "libc", + "fail", + "hashbrown 0.14.3", + "lazy_static", + "lru 0.7.8", + "move-binary-format", + "move-bytecode-verifier", + "move-core-types", + "move-vm-types", "once_cell", - "tokio", - "tokio-util 0.7.10", + "parking_lot", + "serde", + "sha3 0.9.1", "tracing", + "triomphe", + "typed-arena", ] [[package]] -name = "near-primitives" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" +name = "move-vm-types" +version = "0.1.0" +source = "git+https://github.com/unionlabs/aptos-core#119e510cb6be4b380bc82b46551abaf04c640f1d" dependencies = [ - "arbitrary", - "base64 0.21.7", - "borsh 1.5.1", + "bcs 0.1.4", "bytes", - "bytesize", - "cfg-if 1.0.0", - "chrono", - "derive_more 0.99.17", - "easy-ext", - "enum-map", - "hex", - "itertools 0.10.5", - "near-crypto 0.0.0", - "near-fmt 0.0.0", - "near-parameters 0.0.0", - "near-primitives-core 0.0.0", - "near-rpc-error-macro 0.0.0", - "near-stdx 0.0.0", - "near-time", - "num-rational 0.3.2", - "once_cell", - "primitive-types 0.10.1", - "rand 0.8.5", - "rand_chacha 0.3.1", - "reed-solomon-erasure 6.0.0", + "derivative", + "itertools 0.13.0", + "move-binary-format", + "move-core-types", "serde", - "serde_json", - "serde_with", - "sha3", - "smart-default", - "strum 0.24.1", - "thiserror", - "tracing", - "zstd 0.13.1", + "smallbitvec", + "smallvec", + "triomphe", ] [[package]] -name = "near-primitives" -version = "0.20.1" +name = "multer" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0462b067732132babcc89d5577db3bfcb0a1bcfbaaed3f2db4c11cd033666314" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" dependencies = [ - "arbitrary", - "base64 0.21.7", - "borsh 1.5.1", - "bytesize", - "cfg-if 1.0.0", - "chrono", - "derive_more 0.99.17", - "easy-ext", - "enum-map", - "hex", - "near-crypto 0.20.1", - "near-fmt 0.20.1", - "near-o11y 0.20.1", - "near-parameters 0.20.1", - "near-primitives-core 0.20.1", - "near-rpc-error-macro 0.20.1", - "near-stdx 0.20.1", - "near-vm-runner 0.20.1", - "num-rational 0.3.2", - "once_cell", - "primitive-types 0.10.1", - "rand 0.8.5", - "rand_chacha 0.3.1", - "reed-solomon-erasure 4.0.2", - "serde", - "serde_json", - "serde_with", - "serde_yaml", - "sha3", - "smart-default", - "strum 0.24.1", - "thiserror", - "time", - "tracing", + "bytes", + "encoding_rs", + "futures-util", + "http 1.1.0", + "httparse", + "memchr", + "mime", + "spin 0.9.8", + "tokio", + "version_check", ] [[package]] -name = "near-primitives-core" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "named-lock" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40a3eb6b7c682b65d1f631ec3176829d72ab450b3aacdd3f719bf220822e59ac" dependencies = [ - "arbitrary", - "base64 0.21.7", - "borsh 1.5.1", - "bs58 0.4.0", - "derive_more 0.99.17", - "enum-map", - "near-account-id", - "num-rational 0.3.2", - "serde", - "serde_repr", - "sha2 0.10.8", + "libc", + "once_cell", + "parking_lot", "thiserror", + "widestring 0.5.1", + "winapi 0.3.9", ] [[package]] -name = "near-primitives-core" -version = "0.20.1" +name = "native-tls" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8443eb718606f572c438be6321a097a8ebd69f8e48d953885b4f16601af88225" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "arbitrary", - "base64 0.21.7", - "borsh 1.5.1", - "bs58 0.4.0", - "derive_more 0.99.17", - "enum-map", - "near-account-id", - "num-rational 0.3.2", - "serde", - "serde_repr", - "serde_with", - "sha2 0.10.8", - "strum 0.24.1", - "thiserror", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", ] [[package]] -name = "near-primitives-core" -version = "0.21.2" +name = "near-abi" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "082b1d3f6c7e273ec5cd9588e00bdbfc51be6cc9a3a7ec31fc899b4b7d2d3f9d" +checksum = "7c49593c9e94454a2368a4c0a511bf4bf1413aff4d23f16e1d8f4e64b5215351" dependencies = [ - "arbitrary", - "base64 0.21.7", - "borsh 1.5.1", - "bs58 0.4.0", - "derive_more 0.99.17", - "enum-map", - "near-account-id", - "num-rational 0.3.2", + "borsh", + "schemars", + "semver 1.0.22", "serde", - "serde_repr", - "serde_with", - "sha2 0.10.8", - "strum 0.24.1", - "thiserror", ] [[package]] -name = "near-rpc-error-core" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" +name = "near-account-id" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35cbb989542587b47205e608324ddd391f0cee1c22b4b64ae49f458334b95907" dependencies = [ - "quote", + "borsh", + "schemars", "serde", - "syn 2.0.60", ] [[package]] -name = "near-rpc-error-core" -version = "0.20.1" +name = "near-contract-standards" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80fca203c51edd9595ec14db1d13359fb9ede32314990bf296b6c5c4502f6ab7" +checksum = "a0e78fe14d389ae76f792735a2108a6b8332a2bed61197310bf5ad718fb1e424" dependencies = [ - "quote", - "serde", - "syn 2.0.60", + "near-sdk", ] [[package]] -name = "near-rpc-error-macro" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" +name = "near-gas" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e75c875026229902d065e4435804497337b631ec69ba746b102954273e9ad1" dependencies = [ - "near-rpc-error-core 0.0.0", + "borsh", + "schemars", "serde", - "syn 2.0.60", ] [[package]] -name = "near-rpc-error-macro" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897a445de2102f6732c8a185d922f5e3bf7fd0a41243ce40854df2197237f799" +name = "near-ibc" +version = "0.1.0" dependencies = [ - "fs2", - "near-rpc-error-core 0.20.1", + "borsh", + "ibc-vm-rs", + "near-contract-standards", + "near-sdk", + "near-sdk-contract-tools", + "schemars", "serde", - "syn 2.0.60", + "serde_json", + "thiserror", + "unionlabs", ] [[package]] -name = "near-sandbox-utils" -version = "0.7.1" -source = "git+https://github.com/unionlabs/near-sandbox-union?branch=near-ibc#cb6d805a82e52dbc3badc34b55c6bb70b6ca45bf" +name = "near-light-client" +version = "0.1.0" dependencies = [ "anyhow", - "binary-install", - "chrono", - "fs2", - "home", + "borsh", + "ibc-vm-rs", + "near-contract-standards", + "near-primitives-core", + "near-sdk", + "near-sdk-contract-tools", + "near-units", + "serde", + "serde_json", "tokio", + "unionlabs", +] + +[[package]] +name = "near-primitives-core" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "082b1d3f6c7e273ec5cd9588e00bdbfc51be6cc9a3a7ec31fc899b4b7d2d3f9d" +dependencies = [ + "arbitrary", + "base64 0.21.7", + "borsh", + "bs58 0.4.0", + "derive_more 0.99.17", + "enum-map", + "near-account-id", + "num-rational 0.3.2", + "serde", + "serde_repr", + "serde_with", + "sha2 0.10.8", + "strum 0.24.1", + "thiserror", ] [[package]] @@ -7078,9 +8229,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520234cfdf04a805ac2f04715889d096eb83fdd5b99ca7d0f8027ae473f891a8" dependencies = [ "base64 0.21.7", - "borsh 1.5.1", + "borsh", "bs58 0.5.1", - "near-abi 0.4.3", + "near-abi", "near-account-id", "near-gas", "near-sdk-macros", @@ -7116,7 +8267,7 @@ dependencies = [ "quote", "strum 0.26.2", "strum_macros 0.26.2", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -7133,62 +8284,7 @@ dependencies = [ "serde_json", "strum 0.26.2", "strum_macros 0.26.2", - "syn 2.0.60", -] - -[[package]] -name = "near-stdx" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" - -[[package]] -name = "near-stdx" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "855fd5540e3b4ff6fedf12aba2db1ee4b371b36f465da1363a6d022b27cb43b8" - -[[package]] -name = "near-store" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" -dependencies = [ - "actix", - "actix-rt", - "anyhow", - "borsh 1.5.1", - "bytesize", - "crossbeam", - "derive-where", - "derive_more 0.99.17", - "enum-map", - "hex", - "itertools 0.10.5", - "itoa", - "lru 0.12.3", - "near-async", - "near-chain-configs 0.0.0", - "near-crypto 0.0.0", - "near-fmt 0.0.0", - "near-o11y 0.0.0", - "near-parameters 0.0.0", - "near-primitives 0.0.0", - "near-stdx 0.0.0", - "near-vm-runner 0.0.0", - "num_cpus", - "once_cell", - "rand 0.8.5", - "rayon", - "reed-solomon-erasure 6.0.0", - "rlimit", - "rocksdb", - "serde", - "serde_json", - "smallvec", - "strum 0.24.1", - "tempfile", - "thiserror", - "tokio", - "tracing", + "syn 2.0.77", ] [[package]] @@ -7197,24 +8293,13 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "397688591acf8d3ebf2c2485ba32d4b24fc10aad5334e3ad8ec0b7179bfdf06b" -[[package]] -name = "near-time" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" -dependencies = [ - "once_cell", - "serde", - "time", - "tokio", -] - [[package]] name = "near-token" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b68f3f8a2409f72b43efdbeff8e820b81e70824c49fee8572979d789d1683fb" dependencies = [ - "borsh 1.5.1", + "borsh", "schemars", "serde", ] @@ -7252,103 +8337,47 @@ dependencies = [ ] [[package]] -name = "near-vm-runner" -version = "0.0.0" -source = "git+https://github.com/near/nearcore#5251bd9d830f2ff7ffceeca149f1950399300776" +name = "neptune" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06626c9ac04c894e9a23d061ba1309f28506cdc5fe64156d28a15fb57fc8e438" dependencies = [ - "borsh 1.5.1", - "bytesize", - "ed25519-dalek", - "enum-map", - "lru 0.12.3", - "near-crypto 0.0.0", - "near-parameters 0.0.0", - "near-primitives-core 0.0.0", - "near-stdx 0.0.0", - "num-rational 0.3.2", - "once_cell", - "ripemd", - "rustix", + "bellpepper", + "bellpepper-core", + "blake2s_simd", + "blstrs", + "byteorder", + "ff", + "generic-array 0.14.7", + "log", + "pasta_curves", "serde", - "serde_repr", - "sha2 0.10.8", - "sha3", - "strum 0.24.1", - "tempfile", - "thiserror", - "tracing", - "zeropool-bn", + "trait-set", ] [[package]] -name = "near-vm-runner" -version = "0.20.1" +name = "new_debug_unreachable" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56c80bdb1954808f59bd36a9112377197b38d424991383bf05f52d0fe2e0da5" -dependencies = [ - "base64 0.21.7", - "borsh 1.5.1", - "ed25519-dalek", - "enum-map", - "memoffset", - "near-crypto 0.20.1", - "near-parameters 0.20.1", - "near-primitives-core 0.20.1", - "near-stdx 0.20.1", - "num-rational 0.3.2", - "once_cell", - "prefix-sum-vec", - "ripemd", - "serde", - "serde_repr", - "serde_with", - "sha2 0.10.8", - "sha3", - "strum 0.24.1", - "thiserror", - "tracing", - "zeropool-bn", -] +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] -name = "near-workspaces" -version = "0.10.0" -source = "git+https://github.com/unionlabs/near-workspaces-rs-union?branch=near-ibc#d9ec09801eb8c1f745080d267daa46f4b71062f4" +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "async-trait", - "base64 0.21.7", - "bs58 0.5.1", - "cargo-near", - "chrono", - "fs2", - "json-patch", + "bitflags 2.5.0", + "cfg-if 1.0.0", + "cfg_aliases 0.1.1", "libc", - "near-account-id", - "near-crypto 0.20.1", - "near-gas", - "near-jsonrpc-client", - "near-jsonrpc-primitives", - "near-primitives 0.20.1", - "near-sandbox-utils", - "near-token", - "rand 0.8.5", - "reqwest 0.11.27", - "serde", - "serde_json", - "sha2 0.10.8", - "tempfile", - "thiserror", - "tokio", - "tokio-retry", - "tracing", - "url", ] [[package]] -name = "new_debug_unreachable" -version = "1.0.6" +name = "nodrop" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" [[package]] name = "nom" @@ -7361,26 +8390,36 @@ dependencies = [ ] [[package]] -name = "nom-supreme" -version = "0.6.0" +name = "nu-ansi-term" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aadc66631948f6b65da03be4c4cd8bd104d481697ecbb9bbd65719b1ec60bc9f" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ - "brownstone", - "indent_write", - "joinery", - "memchr", - "nom", + "overload", + "winapi 0.3.9", ] [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68" dependencies = [ - "overload", - "winapi", + "windows-sys 0.48.0", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint 0.4.6", + "num-complex", + "num-integer", + "num-iter", + "num-rational 0.4.2", + "num-traits", ] [[package]] @@ -7392,15 +8431,15 @@ dependencies = [ "autocfg", "num-integer", "num-traits", + "rand 0.7.3", ] [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -7422,19 +8461,39 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "num-format" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ - "arrayvec", + "arrayvec 0.7.4", "itoa", ] @@ -7449,9 +8508,9 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -7477,7 +8536,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-integer", "num-traits", ] @@ -7520,7 +8579,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -7568,7 +8627,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" dependencies = [ - "arrayvec", + "arrayvec 0.7.4", "auto_impl", "bytes", "ethereum-types", @@ -7610,7 +8669,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -7631,128 +8690,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "opentelemetry" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8" -dependencies = [ - "async-trait", - "crossbeam-channel", - "futures-channel", - "futures-executor", - "futures-util", - "js-sys", - "lazy_static", - "percent-encoding", - "pin-project", - "rand 0.8.5", - "thiserror", - "tokio", - "tokio-stream", -] - -[[package]] -name = "opentelemetry" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900d57987be3f2aeb70d385fff9b27fb74c5723cc9a52d904d4f9c807a0667bf" -dependencies = [ - "futures-core", - "futures-sink", - "js-sys", - "once_cell", - "pin-project-lite", - "thiserror", - "urlencoding", -] - -[[package]] -name = "opentelemetry-otlp" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1a6ca9de4c8b00aa7f1a153bd76cb263287155cec642680d79d98706f3d28a" -dependencies = [ - "async-trait", - "futures", - "futures-util", - "http 0.2.12", - "opentelemetry 0.17.0", - "prost 0.9.0", - "thiserror", - "tokio", - "tonic 0.6.2", - "tonic-build", -] - -[[package]] -name = "opentelemetry-otlp" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a016b8d9495c639af2145ac22387dcb88e44118e45320d9238fbf4e7889abcb" -dependencies = [ - "async-trait", - "futures-core", - "http 0.2.12", - "opentelemetry 0.22.0", - "opentelemetry-proto", - "opentelemetry-semantic-conventions 0.14.0", - "opentelemetry_sdk", - "prost 0.12.6", - "thiserror", - "tokio", - "tonic 0.11.0", -] - -[[package]] -name = "opentelemetry-proto" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8fddc9b68f5b80dae9d6f510b88e02396f006ad48cac349411fbecc80caae4" -dependencies = [ - "opentelemetry 0.22.0", - "opentelemetry_sdk", - "prost 0.12.6", - "tonic 0.11.0", -] - -[[package]] -name = "opentelemetry-semantic-conventions" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "985cc35d832d412224b2cffe2f9194b1b89b6aa5d0bef76d080dce09d90e62bd" -dependencies = [ - "opentelemetry 0.17.0", -] - -[[package]] -name = "opentelemetry-semantic-conventions" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9ab5bd6c42fb9349dcf28af2ba9a0667f697f9bdcca045d39f2cec5543e2910" - -[[package]] -name = "opentelemetry_sdk" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e90c7113be649e31e9a0f8b5ee24ed7a16923b322c3c5ab6367469c049d6b7e" -dependencies = [ - "async-trait", - "crossbeam-channel", - "futures-channel", - "futures-executor", - "futures-util", - "glob", - "once_cell", - "opentelemetry 0.22.0", - "ordered-float 4.2.0", - "percent-encoding", - "rand 0.8.5", - "thiserror", - "tokio", - "tokio-stream", -] - [[package]] name = "option-ext" version = "0.2.0" @@ -7769,19 +8706,27 @@ dependencies = [ ] [[package]] -name = "ordered-float" -version = "4.2.0" +name = "ouroboros" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76df7075c7d4d01fdcb46c912dd17fba5b60c78ea480b475f2b6ab6f666584e" +checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" dependencies = [ - "num-traits", + "aliasable", + "ouroboros_macro", ] [[package]] -name = "os_str_bytes" -version = "6.6.1" +name = "ouroboros_macro" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" +dependencies = [ + "Inflector", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] name = "overload" @@ -7807,20 +8752,55 @@ dependencies = [ "sha2 0.10.8", ] +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + +[[package]] +name = "parity-scale-codec" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" +dependencies = [ + "arrayvec 0.7.4", + "bitvec 0.20.4", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive 2.3.1", + "serde", +] + [[package]] name = "parity-scale-codec" version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" dependencies = [ - "arrayvec", - "bitvec", + "arrayvec 0.7.4", + "bitvec 1.0.1", "byte-slice-cast", "impl-trait-for-tuples", - "parity-scale-codec-derive", + "parity-scale-codec-derive 3.6.9", "serde", ] +[[package]] +name = "parity-scale-codec-derive" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "parity-scale-codec-derive" version = "3.6.9" @@ -7841,37 +8821,12 @@ checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core 0.9.9", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "lock_api", + "parking_lot_core", ] [[package]] @@ -7882,7 +8837,7 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", "windows-targets 0.48.5", ] @@ -7895,6 +8850,25 @@ dependencies = [ "unionlabs", ] +[[package]] +name = "passkey-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "499cff8432e71c5f8784d9645aac0f9fca604d67f59b68a606170b5e229c6538" +dependencies = [ + "bitflags 2.5.0", + "ciborium", + "coset", + "data-encoding", + "indexmap 2.2.6", + "rand 0.8.5", + "serde", + "serde_json", + "sha2 0.10.8", + "strum 0.25.0", + "typeshare", +] + [[package]] name = "password-hash" version = "0.4.2" @@ -7906,6 +8880,23 @@ dependencies = [ "subtle 2.5.0", ] +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "hex", + "lazy_static", + "rand 0.8.5", + "serde", + "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.5.0", +] + [[package]] name = "paste" version = "1.0.14" @@ -7935,7 +8926,7 @@ dependencies = [ "heck 0.4.1", "itertools 0.11.0", "prost 0.12.6", - "prost-types 0.12.3", + "prost-types", ] [[package]] @@ -7948,7 +8939,7 @@ dependencies = [ "pbjson", "pbjson-build", "prost 0.12.6", - "prost-build 0.12.3", + "prost-build", "serde", ] @@ -7974,23 +8965,6 @@ dependencies = [ "hmac 0.12.1", ] -[[package]] -name = "pdb" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f4d162ecaaa1467de5afbe62d597757b674b51da8bb4e587430c5fdb2af7aa" -dependencies = [ - "fallible-iterator 0.2.0", - "scroll 0.10.2", - "uuid 0.8.2", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "peg" version = "0.8.4" @@ -8083,7 +9057,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -8097,13 +9071,23 @@ dependencies = [ "sha2 0.10.8", ] +[[package]] +name = "petgraph" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset 0.2.0", + "indexmap 1.9.3", +] + [[package]] name = "petgraph" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ - "fixedbitset", + "fixedbitset 0.4.2", "indexmap 2.2.6", ] @@ -8162,7 +9146,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -8200,7 +9184,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -8242,12 +9226,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "plotters" version = "0.3.5" @@ -8276,12 +9254,130 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "poem" +version = "3.0.1" +source = "git+https://github.com/poem-web/poem.git?rev=809b2816d3504beeba140fef3fdfe9432d654c5b#809b2816d3504beeba140fef3fdfe9432d654c5b" +dependencies = [ + "anyhow", + "bytes", + "chrono", + "cookie 0.18.1", + "futures-util", + "headers", + "http 1.1.0", + "http-body-util", + "hyper 1.3.1", + "hyper-util", + "mime", + "multer", + "nix", + "parking_lot", + "percent-encoding", + "pin-project-lite", + "poem-derive", + "quick-xml", + "regex", + "rfc7239", + "rustls-pemfile 2.1.1", + "serde", + "serde_json", + "serde_urlencoded", + "serde_yaml 0.9.34+deprecated", + "smallvec", + "sync_wrapper 1.0.1", + "tempfile", + "thiserror", + "time", + "tokio", + "tokio-rustls 0.25.0", + "tokio-stream", + "tokio-util", + "tracing", + "wildmatch", +] + +[[package]] +name = "poem-derive" +version = "3.0.0" +source = "git+https://github.com/poem-web/poem.git?rev=809b2816d3504beeba140fef3fdfe9432d654c5b#809b2816d3504beeba140fef3fdfe9432d654c5b" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "poem-openapi" +version = "5.0.2" +source = "git+https://github.com/poem-web/poem.git?rev=809b2816d3504beeba140fef3fdfe9432d654c5b#809b2816d3504beeba140fef3fdfe9432d654c5b" +dependencies = [ + "base64 0.22.1", + "bytes", + "derive_more 0.99.17", + "futures-util", + "indexmap 2.2.6", + "mime", + "num-traits", + "poem", + "poem-openapi-derive", + "quick-xml", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "serde_yaml 0.9.34+deprecated", + "thiserror", + "tokio", + "url", +] + +[[package]] +name = "poem-openapi-derive" +version = "5.0.2" +source = "git+https://github.com/poem-web/poem.git?rev=809b2816d3504beeba140fef3fdfe9432d654c5b#809b2816d3504beeba140fef3fdfe9432d654c5b" +dependencies = [ + "darling 0.20.8", + "http 1.1.0", + "indexmap 2.2.6", + "mime", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "regex", + "syn 2.0.77", + "thiserror", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "opaque-debug 0.3.1", + "universal-hash", +] + [[package]] name = "portable-atomic" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +[[package]] +name = "poseidon-ark" +version = "0.0.1" +source = "git+https://github.com/arnaucube/poseidon-ark.git?rev=6d2487aa1308d9d3860a2b724c485d73095c1c68#6d2487aa1308d9d3860a2b724c485d73095c1c68" +dependencies = [ + "ark-bn254", + "ark-ff 0.4.2", + "ark-std 0.4.0", +] + [[package]] name = "poseidon-rs" version = "0.0.10" @@ -8344,12 +9440,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -[[package]] -name = "prefix-sum-vec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa06bd51638b6e76ac9ba9b6afb4164fa647bd2916d722f2623fbb6d1ed8bdba" - [[package]] name = "prettier-please" version = "0.2.0" @@ -8357,17 +9447,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22020dfcf177fcc7bf5deaf7440af371400c67c0de14c399938d8ed4fb4645d3" dependencies = [ "proc-macro2", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] name = "prettyplease" -version = "0.2.19" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac2cf0f2e4f42b49f5ffd07dae8d746508ef7526c13940e5f524012ae6c6550" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -8386,6 +9476,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" dependencies = [ "fixed-hash 0.7.0", + "impl-codec 0.5.1", + "impl-serde 0.3.2", "uint", ] @@ -8396,22 +9488,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash 0.8.0", - "impl-codec", + "impl-codec 0.6.0", "impl-rlp", - "impl-serde", + "impl-serde 0.4.0", "scale-info", "uint", ] -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml 0.5.11", -] - [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -8464,6 +9547,18 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" + [[package]] name = "proc-macro-warning" version = "1.0.2" @@ -8472,14 +9567,14 @@ checksum = "834da187cfe638ae8abb0203f0b33e5ccdb02a28e7199f2f47b3e2754f50edca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -8518,7 +9613,7 @@ dependencies = [ "lazy_static", "libc", "memchr", - "parking_lot 0.12.1", + "parking_lot", "procfs", "protobuf", "thiserror", @@ -8544,16 +9639,6 @@ dependencies = [ "unarray", ] -[[package]] -name = "prost" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" -dependencies = [ - "bytes", - "prost-derive 0.9.0", -] - [[package]] name = "prost" version = "0.12.6" @@ -8574,26 +9659,6 @@ dependencies = [ "prost-derive 0.13.2", ] -[[package]] -name = "prost-build" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" -dependencies = [ - "bytes", - "heck 0.3.3", - "itertools 0.10.5", - "lazy_static", - "log", - "multimap", - "petgraph", - "prost 0.9.0", - "prost-types 0.9.0", - "regex", - "tempfile", - "which", -] - [[package]] name = "prost-build" version = "0.12.3" @@ -8602,33 +9667,20 @@ checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" dependencies = [ "bytes", "heck 0.4.1", - "itertools 0.10.5", + "itertools 0.11.0", "log", "multimap", "once_cell", - "petgraph", + "petgraph 0.6.4", "prettyplease", "prost 0.12.6", - "prost-types 0.12.3", + "prost-types", "regex", - "syn 2.0.60", + "syn 2.0.77", "tempfile", "which", ] -[[package]] -name = "prost-derive" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "prost-derive" version = "0.12.6" @@ -8639,7 +9691,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -8649,20 +9701,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.60", -] - -[[package]] -name = "prost-types" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" -dependencies = [ - "bytes", - "prost 0.9.0", + "syn 2.0.77", ] [[package]] @@ -8691,14 +9733,53 @@ dependencies = [ "schemars", "serde", "serde-utils", - "tonic 0.10.2", + "tonic", +] + +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + +[[package]] +name = "publicsuffix" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" +dependencies = [ + "idna 0.3.0", + "psl-types", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "quanta" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi 0.11.0+wasi-snapshot-preview1", + "web-sys", + "winapi 0.3.9", ] [[package]] name = "queue-msg" version = "0.1.0" dependencies = [ - "arbitrary", "either", "enumorph", "frame-support-procedural", @@ -8712,7 +9793,7 @@ dependencies = [ "static_assertions 1.1.0 (git+https://github.com/nvzqz/static-assertions)", "tokio", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.18", "unionlabs", ] @@ -8726,15 +9807,37 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.60", + "syn 2.0.77", "trybuild", ] [[package]] -name = "quick-error" -version = "1.2.3" +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-xml" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quick_cache" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +checksum = "eb55a1aa7668676bb93926cd4e9cdfe60f03bb866553bcca9112554911b6d3dc" +dependencies = [ + "ahash 0.8.11", + "equivalent", + "hashbrown 0.14.3", + "parking_lot", +] [[package]] name = "quinn" @@ -8746,7 +9849,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 1.1.0", "rustls 0.23.7", "thiserror", "tokio", @@ -8762,7 +9865,7 @@ dependencies = [ "bytes", "rand 0.8.5", "ring 0.17.8", - "rustc-hash", + "rustc-hash 1.1.0", "rustls 0.23.7", "slab", "thiserror", @@ -8792,6 +9895,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" + [[package]] name = "radium" version = "0.7.0" @@ -8808,7 +9917,7 @@ dependencies = [ "libc", "rand_core 0.3.1", "rdrand", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -8906,6 +10015,24 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "raw-cpuid" +version = "11.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb9ee317cfe3fbd54b36a511efc1edd42e216903c9cd575e686dd68a2ba90d8d" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "rayon" version = "1.10.0" @@ -8946,21 +10073,26 @@ dependencies = [ "serde_json", ] +[[package]] +name = "reconnecting-jsonrpc-ws-client" +version = "0.1.0" +dependencies = [ + "arc-swap", + "futures", + "jsonrpsee", + "thiserror", + "tokio", + "tokio-util", + "tracing", + "tracing-subscriber 0.3.18", +] + [[package]] name = "recvmsg" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -8982,32 +10114,30 @@ dependencies = [ ] [[package]] -name = "reed-solomon-erasure" -version = "4.0.2" +name = "ref-cast" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a415a013dd7c5d4221382329a5a3482566da675737494935cbbbcdec04662f9d" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" dependencies = [ - "smallvec", + "ref-cast-impl", ] [[package]] -name = "reed-solomon-erasure" -version = "6.0.0" +name = "ref-cast-impl" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7263373d500d4d4f505d43a2a662d475a894aa94503a1ee28e9188b5f3960d4f" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ - "libm", - "lru 0.7.8", - "parking_lot 0.11.2", - "smallvec", - "spin 0.9.8", + "proc-macro2", + "quote", + "syn 2.0.77", ] [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -9047,47 +10177,6 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" -[[package]] -name = "relay-message" -version = "0.1.0" -dependencies = [ - "arbitrary", - "arbitrum-verifier", - "beacon-api", - "chain-utils", - "contracts", - "dashmap", - "enumorph", - "ethereum-verifier", - "ethers", - "frame-support-procedural", - "frunk", - "futures", - "hex", - "hex-literal", - "macros", - "num-bigint 0.4.4", - "prost 0.12.6", - "protos", - "queue-msg", - "scroll-codec", - "scroll-rpc", - "scroll-verifier", - "serde", - "serde-utils", - "serde_json", - "static_assertions 1.1.0 (git+https://github.com/nvzqz/static-assertions)", - "tendermint", - "tendermint-proto", - "tendermint-rpc", - "thiserror", - "tokio", - "tonic 0.10.2", - "tracing", - "typenum", - "unionlabs", -] - [[package]] name = "reqwest" version = "0.11.27" @@ -9096,10 +10185,12 @@ checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64 0.21.7", "bytes", + "cookie 0.17.0", + "cookie_store", "encoding_rs", "futures-core", "futures-util", - "h2", + "h2 0.3.25", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.28", @@ -9109,6 +10200,7 @@ dependencies = [ "js-sys", "log", "mime", + "mime_guess", "native-tls", "once_cell", "percent-encoding", @@ -9124,10 +10216,12 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls 0.24.1", + "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", "webpki-roots 0.25.4", "winreg 0.50.0", @@ -9178,6 +10272,27 @@ dependencies = [ "winreg 0.52.0", ] +[[package]] +name = "reth-ipc" +version = "1.0.6" +source = "git+https://github.com/paradigmxyz/reth#fcab695a93526c704ef898a3a8d2b6afb183f579" +dependencies = [ + "async-trait", + "bytes", + "futures", + "futures-util", + "interprocess", + "jsonrpsee", + "pin-project", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tracing", +] + [[package]] name = "rfc6979" version = "0.4.0" @@ -9188,6 +10303,15 @@ dependencies = [ "subtle 2.5.0", ] +[[package]] +name = "rfc7239" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b106a85eeb5b0336d16d6a20eab857f92861d4fbb1eb9a239866fb98fb6a1063" +dependencies = [ + "uncased", +] + [[package]] name = "ring" version = "0.16.20" @@ -9200,7 +10324,7 @@ dependencies = [ "spin 0.5.2", "untrusted 0.7.1", "web-sys", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -9227,15 +10351,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "rlimit" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "347703a5ae47adf1e693144157be231dde38c72bd485925cae7407ad3e52480b" -dependencies = [ - "libc", -] - [[package]] name = "rlp" version = "0.5.2" @@ -9259,14 +10374,10 @@ dependencies = [ ] [[package]] -name = "rocksdb" -version = "0.21.0" +name = "route-recognizer" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6f170a4041d50a0ce04b0d2e14916d6ca863ea2e422689a5b694395d299ffe" -dependencies = [ - "libc", - "librocksdb-sys", -] +checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" [[package]] name = "rs_merkle" @@ -9291,7 +10402,7 @@ dependencies = [ "pkcs1", "pkcs8", "rand_core 0.6.4", - "signature", + "signature 2.2.0", "spki", "subtle 2.5.0", "zeroize", @@ -9308,9 +10419,9 @@ dependencies = [ "ark-ff 0.4.2", "bytes", "fastrlp", - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", - "parity-scale-codec", + "parity-scale-codec 3.6.9", "primitive-types 0.12.2", "proptest", "rand 0.8.5", @@ -9353,6 +10464,12 @@ 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" @@ -9422,6 +10539,7 @@ version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebbbdb961df0ad3f2652da8f3fdc4b36122f568f968f45ad3316f26c025c677b" dependencies = [ + "log", "once_cell", "ring 0.17.8", "rustls-pki-types", @@ -9480,6 +10598,33 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" +[[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.7", + "rustls-native-certs 0.7.0", + "rustls-platform-verifier-android", + "rustls-webpki 0.102.2", + "security-framework", + "security-framework-sys", + "webpki-roots 0.26.3", + "winapi 0.3.9", +] + +[[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" @@ -9531,7 +10676,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" dependencies = [ - "cipher 0.4.4", + "cipher", ] [[package]] @@ -9551,7 +10696,7 @@ checksum = "788745a868b0e751750388f4e6546eb921ef714a4317fa6954f7cde114eb2eb7" dependencies = [ "cfg-if 1.0.0", "derive_more 0.99.17", - "parity-scale-codec", + "parity-scale-codec 3.6.9", "scale-info-derive", ] @@ -9597,7 +10742,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -9606,21 +10751,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "scroll" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" - -[[package]] -name = "scroll" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" -dependencies = [ - "scroll_derive", -] - [[package]] name = "scroll-api" version = "0.1.0" @@ -9642,7 +10772,7 @@ dependencies = [ "serde", "serde-utils", "serde_json", - "sha3", + "sha3 0.10.8", "thiserror", "unionlabs", ] @@ -9666,7 +10796,7 @@ dependencies = [ "serde", "serde-json-wasm 1.0.1", "serde_json", - "sha3", + "sha3 0.10.8", "thiserror", "tiny-keccak", "unionlabs", @@ -9682,7 +10812,7 @@ dependencies = [ "serde-utils", "serde_json", "tokio", - "tracing-subscriber", + "tracing-subscriber 0.3.18", "unionlabs", ] @@ -9699,23 +10829,12 @@ dependencies = [ "serde", "serde-utils", "serde_json", - "sha3", + "sha3 0.10.8", "thiserror", "unionlabs", "zktrie", ] -[[package]] -name = "scroll_derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.60", -] - [[package]] name = "scrypt" version = "0.10.0" @@ -9752,25 +10871,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "secp256k1" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" -dependencies = [ - "rand 0.8.5", - "secp256k1-sys", -] - -[[package]] -name = "secp256k1-sys" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" -dependencies = [ - "cc", -] - [[package]] name = "security-framework" version = "2.10.0" @@ -9781,6 +10881,7 @@ dependencies = [ "core-foundation", "core-foundation-sys", "libc", + "num-bigint 0.4.6", "security-framework-sys", ] @@ -9853,6 +10954,33 @@ dependencies = [ "serde_json", ] +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + +[[package]] +name = "serde-generate" +version = "0.20.6" +source = "git+https://github.com/aptos-labs/serde-reflection?rev=73b6bbf748334b71ff6d7d09d06a29e3062ca075#73b6bbf748334b71ff6d7d09d06a29e3062ca075" +dependencies = [ + "bcs 0.1.6", + "bincode", + "heck 0.3.3", + "include_dir", + "maplit", + "serde", + "serde-reflection", + "serde_bytes", + "serde_yaml 0.8.26", + "structopt", + "textwrap 0.13.4", +] + [[package]] name = "serde-json-wasm" version = "0.5.2" @@ -9871,13 +10999,33 @@ dependencies = [ "serde", ] +[[package]] +name = "serde-name" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12c47087018ec281d1cdab673d36aea22d816b54d498264029c05d5fa1910da6" +dependencies = [ + "serde", + "thiserror", +] + +[[package]] +name = "serde-reflection" +version = "0.3.5" +source = "git+https://github.com/aptos-labs/serde-reflection?rev=73b6bbf748334b71ff6d7d09d06a29e3062ca075#73b6bbf748334b71ff6d7d09d06a29e3062ca075" +dependencies = [ + "once_cell", + "serde", + "thiserror", +] + [[package]] name = "serde-untagged" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a160535368dfc353348e7eaa299156bd508c60c45a9249725f5f6d370d82a66" dependencies = [ - "erased-serde", + "erased-serde 0.4.4", "serde", ] @@ -9886,7 +11034,7 @@ name = "serde-utils" version = "0.1.0" dependencies = [ "base64 0.21.7", - "bitvec", + "bitvec 1.0.1", "chrono", "hex", "primitive-types 0.12.2", @@ -9899,7 +11047,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" dependencies = [ - "ordered-float 2.10.1", + "ordered-float", "serde", ] @@ -9918,7 +11066,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ - "half", + "half 1.8.3", "serde", ] @@ -9930,7 +11078,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -9941,7 +11089,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -9950,11 +11098,23 @@ version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ + "indexmap 2.2.6", "itoa", "ryu", "serde", ] +[[package]] +name = "serde_merge" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "606e91878516232ac3b16c12e063d4468d762f16d77e7aef14a1f2326c5f409b" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "serde_path_to_error" version = "0.1.16" @@ -9973,7 +11133,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -9999,11 +11159,11 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.7.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", @@ -10017,40 +11177,39 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.7.0" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ "darling 0.20.8", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] name = "serde_yaml" -version = "0.9.34+deprecated" +version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" dependencies = [ - "indexmap 2.2.6", - "itoa", + "indexmap 1.9.3", "ryu", "serde", - "unsafe-libyaml", + "yaml-rust", ] [[package]] -name = "sha-1" -version = "0.9.8" +name = "serde_yaml" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "block-buffer 0.9.0", - "cfg-if 1.0.0", - "cpufeatures", - "digest 0.9.0", - "opaque-debug 0.3.1", + "indexmap 2.2.6", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", ] [[package]] @@ -10100,6 +11259,18 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug 0.3.1", +] + [[package]] name = "sha3" version = "0.10.8" @@ -10129,12 +11300,6 @@ dependencies = [ "lazy_static", ] -[[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.1" @@ -10144,6 +11309,12 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + [[package]] name = "signature" version = "2.2.0" @@ -10160,7 +11331,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" dependencies = [ - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "thiserror", "time", @@ -10172,6 +11343,16 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + [[package]] name = "slab" version = "0.4.9" @@ -10182,21 +11363,16 @@ dependencies = [ ] [[package]] -name = "smallvec" -version = "1.13.2" +name = "smallbitvec" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "fcc3fc564a4b53fd1e8589628efafe57602d91bde78be18186b5f61e8faea470" [[package]] -name = "smart-default" -version = "0.6.0" +name = "smallvec" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smawk" @@ -10222,17 +11398,18 @@ dependencies = [ [[package]] name = "soketto" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" +checksum = "37468c595637c10857701c990f93a40ce0e357cedb0953d1c26c8d8027f9bb53" dependencies = [ - "base64 0.13.1", + "base64 0.22.1", "bytes", "futures", + "http 1.1.0", "httparse", "log", "rand 0.8.5", - "sha-1", + "sha1", ] [[package]] @@ -10259,7 +11436,7 @@ dependencies = [ "byteorder", "digest 0.10.7", "sha2 0.10.8", - "sha3", + "sha3 0.10.8", "twox-hash", ] @@ -10417,7 +11594,7 @@ dependencies = [ "futures-util", "generic-array 0.14.7", "hex", - "hkdf", + "hkdf 0.12.4", "hmac 0.12.1", "itoa", "log", @@ -10458,14 +11635,14 @@ dependencies = [ "futures-io", "futures-util", "hex", - "hkdf", + "hkdf 0.12.4", "hmac 0.12.1", "home", "itoa", "log", "md-5", "memchr", - "num-bigint 0.4.4", + "num-bigint 0.4.6", "once_cell", "rand 0.8.5", "serde", @@ -10508,7 +11685,6 @@ dependencies = [ name = "ssz" version = "0.5.3" dependencies = [ - "arbitrary", "derivative", "hex-literal", "itertools 0.10.5", @@ -10516,7 +11692,7 @@ dependencies = [ "serde", "serde-utils", "serde_json", - "serde_yaml", + "serde_yaml 0.9.34+deprecated", "sha2 0.10.8", "smallvec", "snap", @@ -10544,7 +11720,7 @@ dependencies = [ "serde", "serde-utils", "serde_json", - "serde_yaml", + "serde_yaml 0.9.34+deprecated", "snap", "ssz", "typenum", @@ -10582,10 +11758,9 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", - "parking_lot 0.12.1", + "parking_lot", "phf_shared 0.10.0", "precomputed-hash", - "serde", ] [[package]] @@ -10599,6 +11774,12 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "strsim" version = "0.10.0" @@ -10611,6 +11792,30 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +[[package]] +name = "structopt" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +dependencies = [ + "clap 2.34.0", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck 0.3.3", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "strum" version = "0.24.1" @@ -10661,7 +11866,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -10674,7 +11879,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -10734,49 +11939,7 @@ dependencies = [ "sha2 0.10.8", "thiserror", "url", - "zip 0.6.6", -] - -[[package]] -name = "symbolic-common" -version = "8.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f551f902d5642e58039aee6a9021a61037926af96e071816361644983966f540" -dependencies = [ - "debugid", - "memmap2", - "stable_deref_trait", - "uuid 0.8.2", -] - -[[package]] -name = "symbolic-debuginfo" -version = "8.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165dabf9fc1d6bb6819c2c0e27c8dd0e3068d2c53cf186d319788e96517f0d6" -dependencies = [ - "bitvec", - "dmsort", - "elementtree", - "fallible-iterator 0.2.0", - "flate2", - "gimli 0.26.2", - "goblin", - "lazy_static", - "lazycell", - "nom", - "nom-supreme", - "parking_lot 0.12.1", - "pdb", - "regex", - "scroll 0.11.0", - "serde", - "serde_json", - "smallvec", - "symbolic-common", - "thiserror", - "wasmparser 0.83.0", - "zip 0.5.13", + "zip", ] [[package]] @@ -10792,9 +11955,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -10810,7 +11973,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -10822,7 +11985,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -10836,6 +11999,9 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "system-configuration" @@ -10859,21 +12025,16 @@ dependencies = [ ] [[package]] -name = "tap" -version = "1.0.1" +name = "tagptr" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" [[package]] -name = "tar" -version = "0.4.41" +name = "tap" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" -dependencies = [ - "filetime", - "libc", - "xattr", -] +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" @@ -10892,10 +12053,9 @@ name = "tendermint" version = "0.39.1" source = "git+https://github.com/unionlabs/tendermint-rs?branch=v0.39.1-bn254#e891d238e263935b7cae17068d726154f4a95a6b" dependencies = [ - "arbitrary", "bytes", "digest 0.10.7", - "ed25519", + "ed25519 2.2.3", "ed25519-consensus", "flex-error", "futures", @@ -10907,7 +12067,7 @@ dependencies = [ "serde_json", "serde_repr", "sha2 0.10.8", - "signature", + "signature 2.2.0", "subtle 2.5.0", "subtle-encoding", "tendermint-proto", @@ -10947,7 +12107,7 @@ dependencies = [ "serde-utils", "serde_json", "sha2 0.10.8", - "sha3", + "sha3 0.10.8", "tendermint-verifier", "thiserror", "unionlabs", @@ -11004,7 +12164,7 @@ dependencies = [ name = "tendermint-verifier" version = "0.1.0" dependencies = [ - "ed25519-dalek", + "ed25519-dalek 2.1.1", "hex-literal", "prost 0.12.6", "protos", @@ -11023,7 +12183,7 @@ checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" dependencies = [ "dirs-next", "rustversion", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -11035,6 +12195,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -11044,6 +12214,27 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd05616119e612a8041ef58f2b578906cc2531a6069047ae092cfb86a325d835" +dependencies = [ + "smawk", + "unicode-width", +] + +[[package]] +name = "textwrap" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + [[package]] name = "textwrap" version = "0.16.1" @@ -11072,7 +12263,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -11099,11 +12290,11 @@ name = "tidy" version = "0.1.0" dependencies = [ "cargo-util-schemas", - "cargo_metadata 0.18.1", + "cargo_metadata", "clap 4.5.4", "toml 0.8.12", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.18", ] [[package]] @@ -11165,7 +12356,7 @@ checksum = "01b874a4992538d4b2f4fbbac11b9419d685f4b39bdc3fed95b04e07bfd76040" dependencies = [ "base58 0.1.0", "hmac 0.7.1", - "libsecp256k1", + "libsecp256k1 0.3.5", "memzero", "sha2 0.8.2", ] @@ -11214,21 +12405,20 @@ dependencies = [ [[package]] name = "tokio" -version = "1.37.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -11243,13 +12433,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -11275,7 +12465,7 @@ dependencies = [ "futures-channel", "futures-util", "log", - "parking_lot 0.12.1", + "parking_lot", "percent-encoding", "phf", "pin-project-lite", @@ -11284,21 +12474,10 @@ dependencies = [ "rand 0.8.5", "socket2", "tokio", - "tokio-util 0.7.10", + "tokio-util", "whoami", ] -[[package]] -name = "tokio-retry" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f57eb36ecbe0fc510036adff84824dd3c24bb781e21bfa67b69d556aa85214f" -dependencies = [ - "pin-project", - "rand 0.8.5", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.24.1" @@ -11340,7 +12519,7 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", - "tokio-util 0.7.10", + "tokio-util", ] [[package]] @@ -11388,23 +12567,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.10" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -11412,16 +12577,18 @@ dependencies = [ "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] name = "toml" -version = "0.5.11" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", ] [[package]] @@ -11452,6 +12619,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.2.6", + "serde", + "serde_spanned", "toml_datetime", "winnow 0.5.40", ] @@ -11491,37 +12660,6 @@ dependencies = [ "winnow 0.6.5", ] -[[package]] -name = "tonic" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff08f4649d10a70ffa3522ca559031285d8e421d727ac85c60825761818f5d0a" -dependencies = [ - "async-stream", - "async-trait", - "base64 0.13.1", - "bytes", - "futures-core", - "futures-util", - "h2", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.28", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost 0.9.0", - "prost-derive 0.9.0", - "tokio", - "tokio-stream", - "tokio-util 0.6.10", - "tower", - "tower-layer", - "tower-service", - "tracing", - "tracing-futures", -] - [[package]] name = "tonic" version = "0.10.2" @@ -11534,7 +12672,7 @@ dependencies = [ "base64 0.21.7", "bytes", "flate2", - "h2", + "h2 0.3.25", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.28", @@ -11555,45 +12693,6 @@ dependencies = [ "webpki-roots 0.25.4", ] -[[package]] -name = "tonic" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" -dependencies = [ - "async-stream", - "async-trait", - "axum 0.6.20", - "base64 0.21.7", - "bytes", - "h2", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.28", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost 0.12.6", - "tokio", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-build" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9403f1bafde247186684b230dc6f38b5cd514584e8bec1dd32514be4745fa757" -dependencies = [ - "proc-macro2", - "prost-build 0.9.0", - "quote", - "syn 1.0.109", -] - [[package]] name = "tower" version = "0.4.13" @@ -11608,7 +12707,7 @@ dependencies = [ "rand 0.8.5", "slab", "tokio", - "tokio-util 0.7.10", + "tokio-util", "tower-layer", "tower-service", "tracing", @@ -11638,18 +12737,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-appender" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" -dependencies = [ - "crossbeam-channel", - "thiserror", - "time", - "tracing-subscriber", -] - [[package]] name = "tracing-attributes" version = "0.1.27" @@ -11658,7 +12745,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -11678,7 +12765,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" dependencies = [ "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.18", ] [[package]] @@ -11687,62 +12774,21 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ - "pin-project", - "tracing", -] - -[[package]] -name = "tracing-log" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-opentelemetry" -version = "0.17.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbbe89715c1dbbb790059e2565353978564924ee85017b5fff365c872ff6721f" -dependencies = [ - "once_cell", - "opentelemetry 0.17.0", + "futures", + "futures-task", + "pin-project", "tracing", - "tracing-core", - "tracing-log 0.1.4", - "tracing-subscriber", ] [[package]] -name = "tracing-opentelemetry" -version = "0.23.0" +name = "tracing-log" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9be14ba1bbe4ab79e9229f7f89fab8d120b865859f10527f31c033e599d2284" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "js-sys", + "log", "once_cell", - "opentelemetry 0.22.0", - "opentelemetry_sdk", - "smallvec", - "tracing", "tracing-core", - "tracing-log 0.2.0", - "tracing-subscriber", - "web-time", ] [[package]] @@ -11755,6 +12801,15 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.18" @@ -11762,7 +12817,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", - "nu-ansi-term", + "nu-ansi-term 0.46.0", "once_cell", "regex", "serde", @@ -11772,7 +12827,7 @@ dependencies = [ "thread_local", "tracing", "tracing-core", - "tracing-log 0.2.0", + "tracing-log", "tracing-serde", ] @@ -11784,7 +12839,7 @@ checksum = "3a2c0ff408fe918a94c428a3f2ad04e4afd5c95bbc08fcf868eff750c15728a4" dependencies = [ "lazy_static", "tracing-core", - "tracing-subscriber", + "tracing-subscriber 0.3.18", "tracing-test-macro", ] @@ -11799,6 +12854,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "trait-set" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79e2e9c9ab44c6d7c20d5976961b47e8f49ac199154daa514b77cd1ab536625" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "trie-db" version = "0.28.0" @@ -11811,6 +12877,16 @@ dependencies = [ "smallvec", ] +[[package]] +name = "triomphe" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" +dependencies = [ + "serde", + "stable_deref_trait", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -11900,18 +12976,46 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "digest 0.10.7", - "rand 0.4.6", + "rand 0.8.5", "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "typeshare" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f17399b76c2e743d58eac0635d7686e9c00f48cd4776f00695d9882a7d3187" +dependencies = [ + "chrono", + "serde", + "serde_json", + "typeshare-annotation", +] + +[[package]] +name = "typeshare-annotation" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a615d6c2764852a2e88a4f16e9ce1ea49bb776b5872956309e170d63a042a34f" +dependencies = [ + "quote", + "syn 2.0.77", +] + [[package]] name = "ucd-trie" version = "0.1.6" @@ -11978,7 +13082,7 @@ dependencies = [ "thiserror", "token-factory-api", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.18", "ucs01-relay-api", "unionlabs", ] @@ -12025,7 +13129,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ - "arbitrary", "byteorder", "crunchy", "hex", @@ -12047,6 +13150,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -12069,294 +13181,671 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" name = "unicode-normalization" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "unionlabs" +version = "0.1.0" +dependencies = [ + "bcs 0.1.4", + "bip32", + "bitvec 1.0.1", + "borsh", + "bs58 0.4.0", + "chrono", + "clap 4.5.4", + "contracts", + "cosmwasm-std 1.5.2", + "derive_more 0.99.17", + "either", + "enumorph", + "ethers", + "ethers-contract-derive", + "ethers-core", + "frame-support-procedural", + "generic-array 0.14.7", + "hex", + "hex-literal", + "k256", + "macros", + "milagro_bls", + "near-primitives-core", + "near-sdk", + "paste", + "primitive-types 0.12.2", + "prost 0.12.6", + "protos", + "rand 0.8.5", + "ripemd", + "rlp", + "rs_merkle", + "schemars", + "serde", + "serde-utils", + "serde_bytes", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "ssz", + "static_assertions 1.1.0 (git+https://github.com/nvzqz/static-assertions)", + "subtle-encoding", + "thiserror", + "tracing", + "typenum", + "uint", + "wasmparser", +] + +[[package]] +name = "unionvisor" +version = "0.1.0" +dependencies = [ + "clap 4.5.4", + "color-eyre", + "figment", + "fs_extra", + "reqwest 0.11.27", + "serde", + "serde_json", + "tempfile", + "thiserror", + "toml 0.8.12", + "tracing", + "tracing-subscriber 0.3.18", + "tracing-test", +] + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle 2.5.0", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8b063c2d59218ae09f22b53c42eaad0d53516457905f5235ca4bc9e99daa71" +dependencies = [ + "base64 0.13.1", + "chunked_transfer", + "log", + "native-tls", + "once_cell", + "qstring", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna 0.5.0", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.12", + "serde", +] + +[[package]] +name = "uuid" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +dependencies = [ + "getrandom 0.2.12", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +dependencies = [ + "valuable-derive", +] + +[[package]] +name = "valuable-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d44690c645190cfce32f91a1582281654b2338c6073fa250b0949fd25c55b32" dependencies = [ - "tinyvec", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "unicode-segmentation" -version = "1.11.0" +name = "variant_count" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "aae2faf80ac463422992abf4de234731279c058aaf33171ca70277c98406b124" +dependencies = [ + "quote", + "syn 1.0.109", +] [[package]] -name = "unicode-width" -version = "0.1.11" +name = "vcpkg" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] -name = "unicode-xid" -version = "0.2.4" +name = "vec_map" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] -name = "unicode_categories" -version = "0.1.1" +name = "version_check" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] -name = "unionlabs" +name = "voyager" version = "0.1.0" dependencies = [ - "arbitrary", - "bcs", + "axum 0.6.20", + "beacon-api", + "bech32 0.9.1", "bip32", - "bitvec", - "borsh 1.5.1", - "bs58 0.4.0", - "chrono", + "bitvec 1.0.1", + "chain-utils", "clap 4.5.4", "contracts", - "cosmwasm-std 1.5.2", + "crossbeam-queue", "derive_more 0.99.17", "either", "enumorph", "ethers", - "ethers-contract-derive", - "ethers-core", "frame-support-procedural", - "generic-array 0.14.7", + "frunk", + "futures", "hex", "hex-literal", - "k256", - "macros", - "milagro_bls", - "near-primitives-core 0.21.2", - "near-sdk", - "paste", - "primitive-types 0.12.2", + "itertools 0.13.0", + "jsonrpsee", + "num-bigint 0.4.6", + "pg-queue", + "pin-utils", + "prometheus", "prost 0.12.6", "protos", - "rand 0.8.5", + "queue-msg", + "reqwest 0.11.27", "ripemd", - "rlp", - "rs_merkle", - "schemars", "serde", "serde-utils", - "serde_bytes", "serde_json", "sha2 0.10.8", - "sha3", - "ssz", - "static_assertions 1.1.0 (git+https://github.com/nvzqz/static-assertions)", + "soketto", + "sqlx", "subtle-encoding", + "tendermint", + "tendermint-proto", + "tendermint-rpc", "thiserror", + "tikv-jemallocator", + "tokio", + "tokio-stream", + "tokio-util", + "tonic", "tracing", + "tracing-futures", + "tracing-subscriber 0.3.18", "typenum", - "uint", - "wasmparser 0.113.3", + "unionlabs", + "voyager-message", ] [[package]] -name = "unionvisor" +name = "voyager-chain-module-cosmos-sdk" version = "0.1.0" dependencies = [ "clap 4.5.4", - "color-eyre", - "figment", - "fs_extra", - "reqwest 0.11.27", + "cometbft-rpc", + "dashmap", + "enumorph", + "frunk", + "futures", + "jsonrpsee", + "macros", + "prost 0.12.6", + "protos", + "queue-msg", "serde", + "serde-utils", "serde_json", - "tempfile", "thiserror", - "toml 0.8.12", + "tokio", "tracing", - "tracing-subscriber", - "tracing-test", + "tracing-subscriber 0.3.18", + "unionlabs", + "voyager-message", ] [[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "ureq" -version = "2.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" +name = "voyager-chain-module-ethereum" +version = "0.1.0" dependencies = [ - "base64 0.21.7", - "flate2", - "log", - "once_cell", - "rustls 0.22.3", - "rustls-pki-types", - "rustls-webpki 0.102.2", - "url", - "webpki-roots 0.26.3", + "beacon-api", + "chain-utils", + "contracts", + "enumorph", + "ethers", + "frunk", + "futures", + "jsonrpsee", + "macros", + "queue-msg", + "serde", + "serde-utils", + "serde_json", + "static_assertions 1.1.0 (git+https://github.com/nvzqz/static-assertions)", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", + "unionlabs", + "voyager-message", ] [[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +name = "voyager-chain-module-movement" +version = "0.1.0" dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", + "aptos-crypto", + "aptos-rest-client", + "aptos-types", + "bcs 0.1.6", + "clap 4.5.4", + "enumorph", + "frunk", + "futures", + "hex", + "hex-literal", + "jsonrpsee", + "macros", + "move-bindgen", + "move-core-types", + "prost 0.12.6", + "protos", + "queue-msg", "serde", + "serde-utils", + "serde_json", + "sha3 0.10.8", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", + "unionlabs", + "voyager-message", ] [[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +name = "voyager-client-module-cometbls" +version = "0.1.0" +dependencies = [ + "clap 4.5.4", + "cometbft-rpc", + "dashmap", + "enumorph", + "frunk", + "futures", + "jsonrpsee", + "macros", + "prost 0.12.6", + "protos", + "queue-msg", + "serde", + "serde-utils", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", + "unionlabs", + "voyager-message", +] [[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +name = "voyager-client-module-ethereum" +version = "0.1.0" +dependencies = [ + "chain-utils", + "enumorph", + "frunk", + "futures", + "jsonrpsee", + "macros", + "prost 0.12.6", + "protos", + "queue-msg", + "serde", + "serde-utils", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", + "unionlabs", + "voyager-message", +] [[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +name = "voyager-consensus-module-cometbls" +version = "0.1.0" +dependencies = [ + "cometbft-rpc", + "dashmap", + "enumorph", + "frunk", + "futures", + "jsonrpsee", + "macros", + "num-bigint 0.4.6", + "prost 0.12.6", + "protos", + "queue-msg", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", + "unionlabs", + "voyager-message", +] [[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +name = "voyager-consensus-module-ethereum" +version = "0.1.0" dependencies = [ - "getrandom 0.2.12", + "beacon-api", + "bitvec 1.0.1", + "chain-utils", + "enumorph", + "ethereum-verifier", + "ethers", + "frunk", + "futures", + "jsonrpsee", + "macros", + "num-bigint 0.4.6", + "prost 0.12.6", + "protos", + "queue-msg", "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", + "unionlabs", + "voyager-message", ] [[package]] -name = "uuid" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" - -[[package]] -name = "valuable" +name = "voyager-message" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" dependencies = [ - "valuable-derive", + "beacon-api", + "chain-utils", + "clap 4.5.4", + "contracts", + "dashmap", + "enumorph", + "ethers", + "frame-support-procedural", + "frunk", + "futures", + "hex", + "hex-literal", + "jaq-core", + "jaq-interpret", + "jaq-std", + "jaq-syn", + "jsonrpsee", + "macros", + "moka", + "num-bigint 0.4.6", + "prost 0.12.6", + "protos", + "queue-msg", + "reconnecting-jsonrpc-ws-client", + "reth-ipc", + "serde", + "serde-utils", + "serde_json", + "soketto", + "tendermint", + "tendermint-proto", + "tendermint-rpc", + "thiserror", + "tokio", + "tokio-util", + "tonic", + "tracing", + "tracing-subscriber 0.3.18", + "typenum", + "unionlabs", ] [[package]] -name = "valuable-derive" +name = "voyager-plugin-packet-filter" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d44690c645190cfce32f91a1582281654b2338c6073fa250b0949fd25c55b32" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "enumorph", + "frunk", + "futures", + "jsonrpsee", + "macros", + "queue-msg", + "regex", + "serde", + "serde_json", + "serde_with", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", + "unionlabs", + "voyager-message", ] [[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +name = "voyager-plugin-transaction-batch" +version = "0.1.0" +dependencies = [ + "cometbft-rpc", + "dashmap", + "either", + "enumorph", + "frunk", + "futures", + "itertools 0.13.0", + "jsonrpsee", + "macros", + "prost 0.12.6", + "protos", + "queue-msg", + "reconnecting-jsonrpc-ws-client", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", + "unionlabs", + "voyager-message", +] [[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +name = "voyager-transaction-module-aptos" +version = "0.1.0" +dependencies = [ + "aptos-crypto", + "aptos-rest-client", + "aptos-types", + "bip32", + "chain-utils", + "enumorph", + "frunk", + "futures", + "jsonrpsee", + "macros", + "move-core-types", + "queue-msg", + "serde", + "serde-utils", + "serde_json", + "sha3 0.10.8", + "thiserror", + "tokio", + "tracing", + "tracing-subscriber 0.3.18", + "unionlabs", + "voyager-message", +] [[package]] -name = "voyager" +name = "voyager-transaction-module-cosmos-sdk" version = "0.1.0" dependencies = [ - "arbitrary", - "axum 0.6.20", - "beacon-api", - "bech32 0.9.1", "bip32", - "bitvec", - "block-message", "chain-utils", - "clap 4.5.4", - "contracts", - "crossbeam-queue", - "derive_more 0.99.17", - "either", + "cometbft-rpc", + "dashmap", "enumorph", - "ethers", - "frame-support-procedural", "frunk", "futures", "hex", - "hex-literal", - "itertools 0.13.0", - "num-bigint 0.4.4", - "pg-queue", - "pin-utils", - "prometheus", + "jsonrpsee", + "macros", "prost 0.12.6", "protos", "queue-msg", - "relay-message", - "reqwest 0.11.27", - "ripemd", "serde", "serde-utils", "serde_json", "sha2 0.10.8", - "sqlx", - "subtle-encoding", - "tendermint", - "tendermint-proto", - "tendermint-rpc", "thiserror", - "tikv-jemallocator", "tokio", - "tokio-stream", - "tokio-util 0.7.10", - "tonic 0.10.2", + "tonic", "tracing", - "tracing-subscriber", - "typenum", + "tracing-subscriber 0.3.18", "unionlabs", "voyager-message", ] [[package]] -name = "voyager-message" +name = "voyager-transaction-module-ethereum" version = "0.1.0" dependencies = [ - "arbitrary", - "block-message", + "beacon-api", + "bip32", "chain-utils", + "contracts", + "enumorph", + "ethers", + "frunk", "futures", - "hex-literal", + "jsonrpsee", "macros", "queue-msg", - "relay-message", "serde", + "serde-utils", "serde_json", + "thiserror", + "tokio", "tracing", + "tracing-subscriber 0.3.18", "unionlabs", + "voyager-message", ] [[package]] @@ -12426,7 +13915,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", "wasm-bindgen-shared", ] @@ -12460,7 +13949,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -12472,10 +13961,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] -name = "wasmparser" -version = "0.83.0" +name = "wasm-streams" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] [[package]] name = "wasmparser" @@ -12497,16 +13993,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "webpki-roots" version = "0.25.4" @@ -12531,7 +14017,7 @@ dependencies = [ "cfg-if 0.1.10", "libc", "memory_units", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -12552,17 +14038,35 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall", "wasite", "web-sys", ] +[[package]] +name = "widestring" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" + [[package]] name = "widestring" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" +[[package]] +name = "wildmatch" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3928939971918220fed093266b809d1ee4ec6c1a2d72692ff6876898f3b16c19" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.9" @@ -12585,7 +14089,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -12792,6 +14296,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" + [[package]] name = "wyz" version = "0.5.1" @@ -12802,21 +14312,23 @@ dependencies = [ ] [[package]] -name = "xattr" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +name = "x25519-dalek" +version = "1.2.0" +source = "git+https://github.com/aptos-labs/x25519-dalek?branch=zeroize_v1#762a9501668d213daa4a1864fa1f9db22716b661" dependencies = [ - "libc", - "linux-raw-sys", - "rustix", + "curve25519-dalek 3.2.0", + "rand_core 0.5.1", + "zeroize", ] [[package]] -name = "xml-rs" -version = "0.8.20" +name = "yaml-rust" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] [[package]] name = "yansi" @@ -12841,7 +14353,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.77", ] [[package]] @@ -12861,32 +14373,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", -] - -[[package]] -name = "zeropool-bn" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e61de68ede9ffdd69c01664f65a178c5188b73f78faa21f0936016a888ff7c" -dependencies = [ - "byteorder", - "crunchy", - "lazy_static", - "rand 0.8.5", - "rustc-hex", -] - -[[package]] -name = "zip" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" -dependencies = [ - "byteorder", - "crc32fast", - "flate2", - "thiserror", + "syn 2.0.77", ] [[package]] @@ -12906,7 +14393,7 @@ dependencies = [ "pbkdf2 0.11.0", "sha1", "time", - "zstd 0.11.2+zstd.1.5.2", + "zstd", ] [[package]] @@ -12931,16 +14418,7 @@ version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ - "zstd-safe 5.0.2+zstd.1.5.2", -] - -[[package]] -name = "zstd" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" -dependencies = [ - "zstd-safe 7.1.0", + "zstd-safe", ] [[package]] @@ -12953,15 +14431,6 @@ dependencies = [ "zstd-sys", ] -[[package]] -name = "zstd-safe" -version = "7.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" -dependencies = [ - "zstd-sys", -] - [[package]] name = "zstd-sys" version = "2.0.10+zstd.1.5.6" diff --git a/Cargo.toml b/Cargo.toml index 43479b8d4e..39a6d47ed5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,10 +16,11 @@ members = [ "hubble", + "lib/aptos-rpc", "lib/beacon-api", - "lib/block-message", - "lib/chain-utils", "lib/cometbft-rpc", + + "lib/chain-utils", "lib/gnark-key-parser", "lib/gnark-mimc", "lib/ibc-vm-rs", @@ -32,7 +33,6 @@ members = [ "lib/poseidon-rs", "lib/queue-msg", "lib/queue-msg-macro", - "lib/relay-message", "lib/scroll-api", "lib/scroll-codec", "lib/scroll-rpc", @@ -41,13 +41,12 @@ members = [ "lib/ssz/tests-generator", "lib/ssz-derive", "lib/unionlabs", - "lib/voyager-message", "lib/zktrie-rs", "lib/near/near-ibc", "lib/near/near-light-client", "lib/near/dummy-ibc-app", - "lib/near/near-ibc-tests", + # "lib/near/near-ibc-tests", "lib/arbitrum-verifier", "lib/cometbls-groth16-verifier", @@ -68,14 +67,35 @@ members = [ "tools/devnet-utils", "tools/parse-wasm-client-type", "tools/tidy", + "tools/move-bindgen", + "lib/move-bindgen-derive", "ucli", "unionvisor", + "voyager", + "voyager/modules/chain/cosmos-sdk", + "voyager/modules/chain/ethereum", + "voyager/modules/chain/movement", + + "voyager/modules/client/cometbls", + "voyager/modules/client/ethereum", + + "voyager/modules/consensus/cometbls", + "voyager/modules/consensus/ethereum", + + "voyager/modules/transaction/cosmos-sdk", + "voyager/modules/transaction/ethereum", + "voyager/modules/transaction/aptos", + + "voyager/plugins/packet-filter", + "voyager/plugins/transaction-batch", "drip", "light-clients/movement/ics08-movement", "lib/aptos-verifier", + + "lib/reconnecting-jsonrpc-ws-client", ] [workspace.package] @@ -91,45 +111,45 @@ lto = "thin" opt-level = 3 [workspace.dependencies] -aptos-verifier = { path = "lib/aptos-verifier", default-features = false } -arbitrum-verifier = { path = "lib/arbitrum-verifier", default-features = false } -beacon-api = { path = "lib/beacon-api", default-features = false } -block-message = { path = "lib/block-message", default-features = false } -chain-utils = { path = "lib/chain-utils", default-features = false } -cometbft-rpc = { path = "lib/cometbft-rpc", default-features = false } -cometbls-groth16-verifier = { path = "lib/cometbls-groth16-verifier", default-features = false } -contracts = { path = "generated/rust/contracts", default-features = false } -ethereum-light-client = { path = "light-clients/ethereum-light-client", default-features = false } -ethereum-verifier = { path = "lib/ethereum-verifier", default-features = false } -evm-in-cosmos-light-client = { path = "light-clients/evm-in-cosmos-light-client", default-features = false } -gnark-key-parser = { path = "lib/gnark-key-parser", default-features = false } -gnark-mimc = { path = "lib/gnark-mimc", default-features = false } -ibc-vm-rs = { path = "lib/ibc-vm-rs", default-features = false } -ics008-wasm-client = { path = "lib/ics-008-wasm-client", default-features = false } -ics23 = { path = "lib/ics23", default-features = false } -linea-verifier = { path = "lib/linea-verifier", default-features = false } -linea-zktrie = { path = "lib/linea-zktrie", default-features = false } -macros = { path = "lib/macros", default-features = false } -pg-queue = { path = "lib/pg-queue", default-features = false } -poseidon-rs = { path = "lib/poseidon-rs", default-features = false } -protos = { path = "generated/rust/protos", default-features = false } -queue-msg = { path = "lib/queue-msg", default-features = false } -queue-msg-macro = { path = "lib/queue-msg-macro", default-features = false } -relay-message = { path = "lib/relay-message", default-features = false } -scroll-api = { path = "lib/scroll-api", default-features = false } -scroll-codec = { path = "lib/scroll-codec", default-features = false } -scroll-rpc = { path = "lib/scroll-rpc", default-features = false } -scroll-verifier = { path = "lib/scroll-verifier", default-features = false } -serde-utils = { path = "lib/serde-utils", default-features = false } -ssz = { path = "lib/ssz", default-features = false } -ssz-derive = { path = "lib/ssz-derive", default-features = false } -tendermint-light-client = { path = "light-clients/tendermint-light-client", default-features = false } -tendermint-verifier = { path = "lib/tendermint-verifier", default-features = false } -token-factory-api = { path = "cosmwasm/token-factory-api", default-features = false } -ucs01-relay-api = { path = "cosmwasm/ucs01-relay-api", default-features = false } -unionlabs = { path = "lib/unionlabs", default-features = false } -voyager-message = { path = "lib/voyager-message", default-features = false } -zktrie = { path = "lib/zktrie-rs", default-features = false } +aptos-verifier = { path = "lib/aptos-verifier", default-features = false } +arbitrum-verifier = { path = "lib/arbitrum-verifier", default-features = false } +beacon-api = { path = "lib/beacon-api", default-features = false } +chain-utils = { path = "lib/chain-utils", default-features = false } +cometbft-rpc = { path = "lib/cometbft-rpc", default-features = false } +cometbls-groth16-verifier = { path = "lib/cometbls-groth16-verifier", default-features = false } +contracts = { path = "generated/rust/contracts", default-features = false } +ethereum-light-client = { path = "light-clients/ethereum-light-client", default-features = false } +ethereum-verifier = { path = "lib/ethereum-verifier", default-features = false } +gnark-key-parser = { path = "lib/gnark-key-parser", default-features = false } +gnark-mimc = { path = "lib/gnark-mimc", default-features = false } +ibc-vm-rs = { path = "lib/ibc-vm-rs", default-features = false } +ics008-wasm-client = { path = "lib/ics-008-wasm-client", default-features = false } +ics23 = { path = "lib/ics23", default-features = false } +linea-verifier = { path = "lib/linea-verifier", default-features = false } +linea-zktrie = { path = "lib/linea-zktrie", default-features = false } +macros = { path = "lib/macros", default-features = false } +move-bindgen = { path = "tools/move-bindgen", default-features = false } +move-bindgen-derive = { path = "lib/move-bindgen-derive", default-features = false } +pg-queue = { path = "lib/pg-queue", default-features = false } +poseidon-rs = { path = "lib/poseidon-rs", default-features = false } +protos = { path = "generated/rust/protos", default-features = false } +queue-msg = { path = "lib/queue-msg", default-features = false } +queue-msg-macro = { path = "lib/queue-msg-macro", default-features = false } +reconnecting-jsonrpc-ws-client = { path = "lib/reconnecting-jsonrpc-ws-client", default-features = false } +scroll-api = { path = "lib/scroll-api", default-features = false } +scroll-codec = { path = "lib/scroll-codec", default-features = false } +scroll-rpc = { path = "lib/scroll-rpc", default-features = false } +scroll-verifier = { path = "lib/scroll-verifier", default-features = false } +serde-utils = { path = "lib/serde-utils", default-features = false } +ssz = { path = "lib/ssz", default-features = false } +ssz-derive = { path = "lib/ssz-derive", default-features = false } +tendermint-light-client = { path = "light-clients/tendermint-light-client", default-features = false } +tendermint-verifier = { path = "lib/tendermint-verifier", default-features = false } +token-factory-api = { path = "cosmwasm/token-factory-api", default-features = false } +ucs01-relay-api = { path = "cosmwasm/ucs01-relay-api", default-features = false } +unionlabs = { path = "lib/unionlabs", default-features = false } +voyager-message = { path = "lib/voyager-message", default-features = false } +zktrie = { path = "lib/zktrie-rs", default-features = false } # external dependencies milagro_bls = { git = "https://github.com/Snowfork/milagro_bls", rev = "bc2b5b5e8d48b7e2e1bfaa56dc2d93e13cb32095", default-features = false } @@ -143,9 +163,10 @@ ethers-contract-abigen = { git = "https://github.com/unionlabs/ethers-rs", branc ethers-contract-derive = { git = "https://github.com/unionlabs/ethers-rs", branch = "ethers-core-wasm", default-features = false } ethers-core = { git = "https://github.com/unionlabs/ethers-rs", branch = "ethers-core-wasm", default-features = false } -near-workspaces = { git = "https://github.com/unionlabs/near-workspaces-rs-union", branch = "near-ibc", default-features = false } - -arbitrary = { version = "1.3.0", default-features = false } +# https://github.com/aptos-labs/aptos-core/pull/12636 +aptos-crypto = { git = "https://github.com/unionlabs/aptos-core" } +aptos-rest-client = { git = "https://github.com/unionlabs/aptos-core" } +aptos-types = { git = "https://github.com/unionlabs/aptos-core" } axum = { version = "0.6.20", default-features = false } base64 = { version = "0.21", default-features = false } bip32 = { version = "0.5.0", default-features = false } @@ -171,7 +192,9 @@ futures = { version = "0.3.28", default-features = false } go-parse-duration = { version = "0.1.1", default-features = false } hex = { version = "0.4.3", default-features = false } hex-literal = { version = "0.4.1", default-features = false } +jsonrpsee = { version = "0.24.2", default-features = false } lazy_static = { version = "1.4.0", default-features = false } +move-core-types = { git = "https://github.com/unionlabs/aptos-core" } near-contract-standards = { version = "5.1.0", default-features = false } near-sdk = { version = "5.1.0", default-features = false } near-sdk-contract-tools = { version = "3.0.2", default-features = false } @@ -205,3 +228,7 @@ typenum = { version = "1.17.0", default-features = false } [patch."crates-io"] arbitrary = { git = "https://github.com/unionlabs/arbitrary" } # parity-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" } + +# https://aptos.dev/en/build/sdks/rust-sdk +merlin = { git = "https://github.com/aptos-labs/merlin" } +x25519-dalek = { git = "https://github.com/aptos-labs/x25519-dalek", branch = "zeroize_v1" } diff --git a/cosmwasm/ucs01-relay-api/src/middleware.rs b/cosmwasm/ucs01-relay-api/src/middleware.rs index 24a56b4ab4..21ba8240e3 100644 --- a/cosmwasm/ucs01-relay-api/src/middleware.rs +++ b/cosmwasm/ucs01-relay-api/src/middleware.rs @@ -169,10 +169,20 @@ mod tests { #[test] fn serde_parses_memo() { // let memo = "\"balls\": \"string\""; - let memo = "{\"forward\": {\"receiver\": \"[eth_addr]\",\"port\": \"[union-eth port]\",\"channel\": \"[union-eth channel]\",\"timeout\": \"1000000\",\"retries\": 0}}"; + let memo = r#"{"forward": {"receiver": "[eth_addr]","port": "[union-eth port]","channel": "[union-eth channel]","timeout": "1000000","retries": 0}}"#; let parsed = serde_json_wasm::from_str::(memo).expect("works"); dbg!(parsed); } + + #[test] + fn serde_parses_memo_without_port_as_none() { + // let memo = "\"balls\": \"string\""; + let memo = r#"{"forward":{"channel":"channel-201","receiver":"2C96e52fCE14BAa13868CA8182f8A7903e4e76E0"}}"#; + + let parsed = serde_json_wasm::from_str::(memo).expect("works"); + + assert_eq!(parsed, Memo::None {}) + } } diff --git a/cosmwasm/ucs01-relay/Cargo.toml b/cosmwasm/ucs01-relay/Cargo.toml index 4c1a863dea..c2a77cd961 100644 --- a/cosmwasm/ucs01-relay/Cargo.toml +++ b/cosmwasm/ucs01-relay/Cargo.toml @@ -38,7 +38,7 @@ sha2 = { workspace = true } thiserror = { workspace = true } token-factory-api = { workspace = true } tracing = { workspace = true } -tracing-subscriber = { workspace = true, default-features = false, features = ["fmt", "ansi"] } +tracing-subscriber = { workspace = true } ucs01-relay-api = { workspace = true } unionlabs = { workspace = true } diff --git a/cosmwasm/ucs01-relay/src/ibc.rs b/cosmwasm/ucs01-relay/src/ibc.rs index 17ef031d6a..2d5271f832 100644 --- a/cosmwasm/ucs01-relay/src/ibc.rs +++ b/cosmwasm/ucs01-relay/src/ibc.rs @@ -21,6 +21,9 @@ use crate::{ state::{ChannelInfo, PfmRefundPacketKey, CHANNEL_INFO, IN_FLIGHT_PFM_PACKETS}, }; +#[cfg(test)] +mod tests; + fn to_response( IbcReceiveResponse { acknowledgement, @@ -309,6 +312,3 @@ pub fn ibc_packet_timeout( }), } } - -#[cfg(test)] -mod tests; diff --git a/cosmwasm/ucs01-relay/src/protocol.rs b/cosmwasm/ucs01-relay/src/protocol.rs index 1c2aaa2acc..6539dc7b6d 100644 --- a/cosmwasm/ucs01-relay/src/protocol.rs +++ b/cosmwasm/ucs01-relay/src/protocol.rs @@ -1127,6 +1127,7 @@ impl<'a> TransferProtocol for Ucs01Protocol<'a> { } #[cfg(test)] +#[allow(deprecated)] // TODO: Remove usage of mock_info mod tests { use cosmwasm_std::{ testing::{message_info, mock_dependencies, mock_env}, diff --git a/devnet-compose/Cargo.toml b/devnet-compose/Cargo.toml index 349fc880b1..17df2151a2 100644 --- a/devnet-compose/Cargo.toml +++ b/devnet-compose/Cargo.toml @@ -1,9 +1,9 @@ [package] -edition.workspace = true -license-file.workspace = true -name = "devnet-compose" -repository.workspace = true -version = "0.1.0" +edition = { workspace = true } +license-file = { workspace = true } +name = "devnet-compose" +repository = { workspace = true } +version = "0.1.0" [dependencies] cliclack = "0.2.5" diff --git a/dictionary.txt b/dictionary.txt index fb0e6764f0..0a34f30b98 100644 --- a/dictionary.txt +++ b/dictionary.txt @@ -266,6 +266,7 @@ anypb anys appchain appchains +appetito appmodule appparams aptos @@ -306,6 +307,7 @@ bankkeeper banktypes bartio baseapp +batchable beacond beacondata beatae @@ -353,6 +355,7 @@ brainer builtins bumpp bunx +buon byteorder bytevec cachix @@ -794,6 +797,7 @@ misbehaviour misbehiavor mktemp mmxyqu +moka mollitia monitonically monniker @@ -853,6 +857,7 @@ nums numtide observablehq oceanlewis +octas ofetch offchain omit @@ -925,6 +930,7 @@ preimages preprocessors prerender prerendered +prettyplease prevote prevotes println @@ -984,6 +990,7 @@ redelegating redelegation redelegations reencode +reencoded reentrancy reexcute reexecute @@ -1069,6 +1076,7 @@ slurpfile smallvec snapshotter snapshottypes +soketto solomachine sonner spearbit @@ -1228,6 +1236,7 @@ unbonded unbonding uncompr uncons +unconstructable undelegate undelegations unergonomic @@ -1259,6 +1268,7 @@ unloadable unmarshal unmarshalling unopinionated +unparse unplugin unprefixed unsetting @@ -1345,13 +1355,16 @@ xprv xqxp xsmfxu yamlfmt +yoinked ypyp yqyp yzmmzyfhxg zellij zerion +zeroize zerolog zetachain +zkevm zkgm zkps zktrie diff --git a/docs/src/content/docs/integrations/cometbft/opening-connection.mdx b/docs/src/content/docs/integrations/cometbft/opening-connection.mdx index 7fc5bae36f..4ead866b79 100644 --- a/docs/src/content/docs/integrations/cometbft/opening-connection.mdx +++ b/docs/src/content/docs/integrations/cometbft/opening-connection.mdx @@ -98,7 +98,7 @@ We recommend running Voyager on a machine co-located with your chain's RPC nodes }, "voyager": { "num_workers": 4, - "laddr": "0.0.0.0:65534", + "laddr": "0.0.0.0:7717", "queue": { "type": "pg-queue", "database_url": "postgres://user:password@127.0.0.1:5432/default", diff --git a/evm/contracts/core/03-connection/IBCConnection.sol b/evm/contracts/core/03-connection/IBCConnection.sol index 4d0c9a7e8d..7f1788929f 100644 --- a/evm/contracts/core/03-connection/IBCConnection.sol +++ b/evm/contracts/core/03-connection/IBCConnection.sol @@ -37,7 +37,8 @@ library IBCConnectionLib { error ErrNoCounterpartyVersion(); error ErrUnsupportedVersion(); error ErrVersionMustBeUnset(); - error ErrInvalidProof(); + error ErrInvalidConnectionProof(); + error ErrInvalidClientStateProof(); error ErrInvalidConnectionState(); // yes, these are all defined as strings in the ibc spec @@ -443,7 +444,7 @@ contract IBCConnection is IBCStore, IIBCConnectionHandshake { expectedConnection ) ) { - revert IBCConnectionLib.ErrInvalidProof(); + revert IBCConnectionLib.ErrInvalidConnectionProof(); } if ( !verifyClientState( @@ -454,7 +455,7 @@ contract IBCConnection is IBCStore, IIBCConnectionHandshake { msg_.clientStateBytes ) ) { - revert IBCConnectionLib.ErrInvalidProof(); + revert IBCConnectionLib.ErrInvalidClientStateProof(); } updateConnectionCommitment(connectionId); @@ -521,7 +522,7 @@ contract IBCConnection is IBCStore, IIBCConnectionHandshake { expectedConnection ) ) { - revert IBCConnectionLib.ErrInvalidProof(); + revert IBCConnectionLib.ErrInvalidConnectionProof(); } if ( !verifyClientState( @@ -532,7 +533,7 @@ contract IBCConnection is IBCStore, IIBCConnectionHandshake { msg_.clientStateBytes ) ) { - revert IBCConnectionLib.ErrInvalidProof(); + revert IBCConnectionLib.ErrInvalidClientStateProof(); } connection.state = IbcCoreConnectionV1GlobalEnums.State.STATE_OPEN; @@ -593,7 +594,7 @@ contract IBCConnection is IBCStore, IIBCConnectionHandshake { expectedConnection ) ) { - revert IBCConnectionLib.ErrInvalidProof(); + revert IBCConnectionLib.ErrInvalidClientStateProof(); } connection.state = IbcCoreConnectionV1GlobalEnums.State.STATE_OPEN; diff --git a/evm/tests/src/25-handler/IBCConnectionHandler.t.sol b/evm/tests/src/25-handler/IBCConnectionHandler.t.sol index 8b7c3c5194..96a0b8cd21 100644 --- a/evm/tests/src/25-handler/IBCConnectionHandler.t.sol +++ b/evm/tests/src/25-handler/IBCConnectionHandler.t.sol @@ -226,13 +226,13 @@ contract IBCConnectionHandlerTests is TestPlus { function preAckInvalidConnectionStateProof() public { client.reset(); - vm.expectRevert(IBCConnectionLib.ErrInvalidProof.selector); + vm.expectRevert(IBCConnectionLib.ErrInvalidConnectionProof.selector); } function preAckInvalidClientStateProof() public { client.reset(); client.pushValidMembership(0); - vm.expectRevert(IBCConnectionLib.ErrInvalidProof.selector); + vm.expectRevert(IBCConnectionLib.ErrInvalidClientStateProof.selector); } function preTryValidProofs() public { @@ -243,13 +243,13 @@ contract IBCConnectionHandlerTests is TestPlus { function preTryInvalidConnectionStateProof() public { client.reset(); - vm.expectRevert(IBCConnectionLib.ErrInvalidProof.selector); + vm.expectRevert(IBCConnectionLib.ErrInvalidConnectionProof.selector); } function preTryInvalidClientStateProof() public { client.reset(); client.pushValidMembership(0); - vm.expectRevert(IBCConnectionLib.ErrInvalidProof.selector); + vm.expectRevert(IBCConnectionLib.ErrInvalidClientStateProof.selector); } function preConfirmValidProofs() public { @@ -258,7 +258,11 @@ contract IBCConnectionHandlerTests is TestPlus { } function preConfirmInvalidConnectionState() public { - vm.expectRevert(IBCConnectionLib.ErrInvalidProof.selector); + vm.expectRevert(IBCConnectionLib.ErrInvalidConnectionProof.selector); + } + + function preConfirmInvalidClientState() public { + vm.expectRevert(IBCConnectionLib.ErrInvalidClientStateProof.selector); } function test_handshake_init_ack_ok(uint64 proofHeight) public { @@ -597,7 +601,7 @@ contract IBCConnectionHandlerTests is TestPlus { IBCMsgs.MsgConnectionOpenConfirm memory msg_confirm = MsgMocks.connectionOpenConfirm(clientId, connId, proofHeight); - preConfirmInvalidConnectionState(); + preConfirmInvalidClientState(); handler.connectionOpenConfirm(msg_confirm); } diff --git a/generated/rust/contracts/Cargo.toml b/generated/rust/contracts/Cargo.toml index 9f6b34a174..8e6dabf625 100644 --- a/generated/rust/contracts/Cargo.toml +++ b/generated/rust/contracts/Cargo.toml @@ -6,9 +6,7 @@ version = "0.0.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -arbitrary = { workspace = true, optional = true, features = ["derive"] } -ethers = { workspace = true, features = ["abigen"] } -serde = { workspace = true, features = ["derive"] } +ethers = { workspace = true, features = ["abigen"] } +serde = { workspace = true, features = ["derive"] } [features] -arbitrary = ["dep:arbitrary"] providers = ["ethers/providers"] diff --git a/generated/rust/contracts/src/cometbls_client.rs b/generated/rust/contracts/src/cometbls_client.rs index 931568012c..7edd3560bc 100644 --- a/generated/rust/contracts/src/cometbls_client.rs +++ b/generated/rust/contracts/src/cometbls_client.rs @@ -954,7 +954,7 @@ pub mod cometbls_client { fallback: false, } } - ///The parsed JSON ABI of the contract. + /// The parsed JSON ABI of the contract. #[cfg(feature = "providers")] pub static COMETBLSCLIENT_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); @@ -1054,7 +1054,7 @@ pub mod cometbls_client { let deployer = ::ethers::contract::ContractDeployer::new(deployer); Ok(deployer) } - ///Calls the contract's `UPGRADE_INTERFACE_VERSION` (0xad3cb1cc) function + /// Calls the contract's `UPGRADE_INTERFACE_VERSION` (0xad3cb1cc) function pub fn upgrade_interface_version( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1062,7 +1062,7 @@ pub mod cometbls_client { .method_hash([173, 60, 177, 204], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `createClient` (0x2629636b) function + /// Calls the contract's `createClient` (0x2629636b) function pub fn create_client( &self, client_id: ::std::string::String, @@ -1077,7 +1077,7 @@ pub mod cometbls_client { ) .expect("method not found (this should never happen)") } - ///Calls the contract's `getClientState` (0x76c81c42) function + /// Calls the contract's `getClientState` (0x76c81c42) function pub fn get_client_state( &self, client_id: ::std::string::String, @@ -1086,7 +1086,7 @@ pub mod cometbls_client { .method_hash([118, 200, 28, 66], client_id) .expect("method not found (this should never happen)") } - ///Calls the contract's `getConsensusState` (0x6cf44bf4) function + /// Calls the contract's `getConsensusState` (0x6cf44bf4) function pub fn get_consensus_state( &self, client_id: ::std::string::String, @@ -1096,7 +1096,7 @@ pub mod cometbls_client { .method_hash([108, 244, 75, 244], (client_id, height)) .expect("method not found (this should never happen)") } - ///Calls the contract's `getLatestHeight` (0x329681d0) function + /// Calls the contract's `getLatestHeight` (0x329681d0) function pub fn get_latest_height( &self, client_id: ::std::string::String, @@ -1105,7 +1105,7 @@ pub mod cometbls_client { .method_hash([50, 150, 129, 208], client_id) .expect("method not found (this should never happen)") } - ///Calls the contract's `getTimestampAtHeight` (0x4b0bbdc4) function + /// Calls the contract's `getTimestampAtHeight` (0x4b0bbdc4) function pub fn get_timestamp_at_height( &self, client_id: ::std::string::String, @@ -1115,7 +1115,7 @@ pub mod cometbls_client { .method_hash([75, 11, 189, 196], (client_id, height)) .expect("method not found (this should never happen)") } - ///Calls the contract's `initialize` (0x485cc955) function + /// Calls the contract's `initialize` (0x485cc955) function pub fn initialize( &self, ibc_handler: ::ethers::core::types::Address, @@ -1125,7 +1125,7 @@ pub mod cometbls_client { .method_hash([72, 92, 201, 85], (ibc_handler, admin)) .expect("method not found (this should never happen)") } - ///Calls the contract's `misbehavior` (0x21c90b05) function + /// Calls the contract's `misbehavior` (0x21c90b05) function pub fn misbehavior( &self, client_id: ::std::string::String, @@ -1136,7 +1136,7 @@ pub mod cometbls_client { .method_hash([33, 201, 11, 5], (client_id, header_a, header_b)) .expect("method not found (this should never happen)") } - ///Calls the contract's `owner` (0x8da5cb5b) function + /// Calls the contract's `owner` (0x8da5cb5b) function pub fn owner( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1144,25 +1144,25 @@ pub mod cometbls_client { .method_hash([141, 165, 203, 91], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `paused` (0x5c975abb) function + /// Calls the contract's `paused` (0x5c975abb) function pub fn paused(&self) -> ::ethers::contract::builders::ContractCall { self.0 .method_hash([92, 151, 90, 187], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `proxiableUUID` (0x52d1902d) function + /// Calls the contract's `proxiableUUID` (0x52d1902d) function pub fn proxiable_uuid(&self) -> ::ethers::contract::builders::ContractCall { self.0 .method_hash([82, 209, 144, 45], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `renounceOwnership` (0x715018a6) function + /// Calls the contract's `renounceOwnership` (0x715018a6) function pub fn renounce_ownership(&self) -> ::ethers::contract::builders::ContractCall { self.0 .method_hash([113, 80, 24, 166], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `transferOwnership` (0xf2fde38b) function + /// Calls the contract's `transferOwnership` (0xf2fde38b) function pub fn transfer_ownership( &self, new_owner: ::ethers::core::types::Address, @@ -1171,7 +1171,7 @@ pub mod cometbls_client { .method_hash([242, 253, 227, 139], new_owner) .expect("method not found (this should never happen)") } - ///Calls the contract's `updateClient` (0x6fbf8079) function + /// Calls the contract's `updateClient` (0x6fbf8079) function pub fn update_client( &self, client_id: ::std::string::String, @@ -1184,7 +1184,7 @@ pub mod cometbls_client { .method_hash([111, 191, 128, 121], (client_id, client_message_bytes)) .expect("method not found (this should never happen)") } - ///Calls the contract's `upgradeToAndCall` (0x4f1ef286) function + /// Calls the contract's `upgradeToAndCall` (0x4f1ef286) function pub fn upgrade_to_and_call( &self, new_implementation: ::ethers::core::types::Address, @@ -1194,7 +1194,7 @@ pub mod cometbls_client { .method_hash([79, 30, 242, 134], (new_implementation, data)) .expect("method not found (this should never happen)") } - ///Calls the contract's `verifyMembership` (0xf9bb5a51) function + /// Calls the contract's `verifyMembership` (0xf9bb5a51) function pub fn verify_membership( &self, client_id: ::std::string::String, @@ -1222,7 +1222,7 @@ pub mod cometbls_client { ) .expect("method not found (this should never happen)") } - ///Calls the contract's `verifyNonMembership` (0x999fbbb3) function + /// Calls the contract's `verifyNonMembership` (0x999fbbb3) function pub fn verify_non_membership( &self, client_id: ::std::string::String, @@ -1248,7 +1248,7 @@ pub mod cometbls_client { ) .expect("method not found (this should never happen)") } - ///Calls the contract's `verifyZKP` (0x61ce4b12) function + /// Calls the contract's `verifyZKP` (0x61ce4b12) function pub fn verify_zkp( &self, zkp_bytes: ::ethers::core::types::Bytes, @@ -1263,33 +1263,33 @@ pub mod cometbls_client { ) .expect("method not found (this should never happen)") } - ///Gets the contract's `Initialized` event + /// Gets the contract's `Initialized` event pub fn initialized_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, InitializedFilter> { self.0.event() } - ///Gets the contract's `OwnershipTransferred` event + /// Gets the contract's `OwnershipTransferred` event pub fn ownership_transferred_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, OwnershipTransferredFilter> { self.0.event() } - ///Gets the contract's `Paused` event + /// Gets the contract's `Paused` event pub fn paused_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, PausedFilter> { self.0.event() } - ///Gets the contract's `Unpaused` event + /// Gets the contract's `Unpaused` event pub fn unpaused_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, UnpausedFilter> { self.0.event() } - ///Gets the contract's `Upgraded` event + /// Gets the contract's `Upgraded` event pub fn upgraded_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, UpgradedFilter> { @@ -1312,7 +1312,7 @@ pub mod cometbls_client { Self::new(contract.address(), contract.client()) } } - ///Custom Error type `AddressEmptyCode` with signature `AddressEmptyCode(address)` and selector `0x9996b315` + /// Custom Error type `AddressEmptyCode` with signature `AddressEmptyCode(address)` and selector `0x9996b315` #[derive( Clone, ::ethers::contract::EthError, @@ -1327,7 +1327,7 @@ pub mod cometbls_client { pub struct AddressEmptyCode { pub target: ::ethers::core::types::Address, } - ///Custom Error type `ERC1967InvalidImplementation` with signature `ERC1967InvalidImplementation(address)` and selector `0x4c9c8ce3` + /// Custom Error type `ERC1967InvalidImplementation` with signature `ERC1967InvalidImplementation(address)` and selector `0x4c9c8ce3` #[derive( Clone, ::ethers::contract::EthError, @@ -1345,7 +1345,7 @@ pub mod cometbls_client { pub struct ERC1967InvalidImplementation { pub implementation: ::ethers::core::types::Address, } - ///Custom Error type `ERC1967NonPayable` with signature `ERC1967NonPayable()` and selector `0xb398979f` + /// Custom Error type `ERC1967NonPayable` with signature `ERC1967NonPayable()` and selector `0xb398979f` #[derive( Clone, ::ethers::contract::EthError, @@ -1358,7 +1358,7 @@ pub mod cometbls_client { )] #[etherror(name = "ERC1967NonPayable", abi = "ERC1967NonPayable()")] pub struct ERC1967NonPayable; - ///Custom Error type `EnforcedPause` with signature `EnforcedPause()` and selector `0xd93c0665` + /// Custom Error type `EnforcedPause` with signature `EnforcedPause()` and selector `0xd93c0665` #[derive( Clone, ::ethers::contract::EthError, @@ -1371,7 +1371,7 @@ pub mod cometbls_client { )] #[etherror(name = "EnforcedPause", abi = "EnforcedPause()")] pub struct EnforcedPause; - ///Custom Error type `ErrClientFrozen` with signature `ErrClientFrozen()` and selector `0xb3e34670` + /// Custom Error type `ErrClientFrozen` with signature `ErrClientFrozen()` and selector `0xb3e34670` #[derive( Clone, ::ethers::contract::EthError, @@ -1384,7 +1384,7 @@ pub mod cometbls_client { )] #[etherror(name = "ErrClientFrozen", abi = "ErrClientFrozen()")] pub struct ErrClientFrozen; - ///Custom Error type `ErrDelayPeriodNotExpired` with signature `ErrDelayPeriodNotExpired()` and selector `0x54e4c159` + /// Custom Error type `ErrDelayPeriodNotExpired` with signature `ErrDelayPeriodNotExpired()` and selector `0x54e4c159` #[derive( Clone, ::ethers::contract::EthError, @@ -1397,7 +1397,7 @@ pub mod cometbls_client { )] #[etherror(name = "ErrDelayPeriodNotExpired", abi = "ErrDelayPeriodNotExpired()")] pub struct ErrDelayPeriodNotExpired; - ///Custom Error type `ErrHeaderExpired` with signature `ErrHeaderExpired()` and selector `0x6c4c87b6` + /// Custom Error type `ErrHeaderExpired` with signature `ErrHeaderExpired()` and selector `0x6c4c87b6` #[derive( Clone, ::ethers::contract::EthError, @@ -1410,7 +1410,7 @@ pub mod cometbls_client { )] #[etherror(name = "ErrHeaderExpired", abi = "ErrHeaderExpired()")] pub struct ErrHeaderExpired; - ///Custom Error type `ErrInvalidMisbehavior` with signature `ErrInvalidMisbehavior()` and selector `0x5882336d` + /// Custom Error type `ErrInvalidMisbehavior` with signature `ErrInvalidMisbehavior()` and selector `0x5882336d` #[derive( Clone, ::ethers::contract::EthError, @@ -1423,7 +1423,7 @@ pub mod cometbls_client { )] #[etherror(name = "ErrInvalidMisbehavior", abi = "ErrInvalidMisbehavior()")] pub struct ErrInvalidMisbehavior; - ///Custom Error type `ErrInvalidMisbehaviorHeadersSequence` with signature `ErrInvalidMisbehaviorHeadersSequence()` and selector `0xce011f04` + /// Custom Error type `ErrInvalidMisbehaviorHeadersSequence` with signature `ErrInvalidMisbehaviorHeadersSequence()` and selector `0xce011f04` #[derive( Clone, ::ethers::contract::EthError, @@ -1439,7 +1439,7 @@ pub mod cometbls_client { abi = "ErrInvalidMisbehaviorHeadersSequence()" )] pub struct ErrInvalidMisbehaviorHeadersSequence; - ///Custom Error type `ErrInvalidUntrustedValidatorsHash` with signature `ErrInvalidUntrustedValidatorsHash()` and selector `0x895cf0ce` + /// Custom Error type `ErrInvalidUntrustedValidatorsHash` with signature `ErrInvalidUntrustedValidatorsHash()` and selector `0x895cf0ce` #[derive( Clone, ::ethers::contract::EthError, @@ -1455,7 +1455,7 @@ pub mod cometbls_client { abi = "ErrInvalidUntrustedValidatorsHash()" )] pub struct ErrInvalidUntrustedValidatorsHash; - ///Custom Error type `ErrInvalidZKP` with signature `ErrInvalidZKP()` and selector `0x396df4ec` + /// Custom Error type `ErrInvalidZKP` with signature `ErrInvalidZKP()` and selector `0x396df4ec` #[derive( Clone, ::ethers::contract::EthError, @@ -1468,7 +1468,7 @@ pub mod cometbls_client { )] #[etherror(name = "ErrInvalidZKP", abi = "ErrInvalidZKP()")] pub struct ErrInvalidZKP; - ///Custom Error type `ErrMaxClockDriftExceeded` with signature `ErrMaxClockDriftExceeded()` and selector `0x4ccc303c` + /// Custom Error type `ErrMaxClockDriftExceeded` with signature `ErrMaxClockDriftExceeded()` and selector `0x4ccc303c` #[derive( Clone, ::ethers::contract::EthError, @@ -1481,7 +1481,7 @@ pub mod cometbls_client { )] #[etherror(name = "ErrMaxClockDriftExceeded", abi = "ErrMaxClockDriftExceeded()")] pub struct ErrMaxClockDriftExceeded; - ///Custom Error type `ErrNotIBC` with signature `ErrNotIBC()` and selector `0xe54f8f9d` + /// Custom Error type `ErrNotIBC` with signature `ErrNotIBC()` and selector `0xe54f8f9d` #[derive( Clone, ::ethers::contract::EthError, @@ -1494,7 +1494,7 @@ pub mod cometbls_client { )] #[etherror(name = "ErrNotIBC", abi = "ErrNotIBC()")] pub struct ErrNotIBC; - ///Custom Error type `ErrTrustedConsensusStateNotFound` with signature `ErrTrustedConsensusStateNotFound()` and selector `0x09128dc8` + /// Custom Error type `ErrTrustedConsensusStateNotFound` with signature `ErrTrustedConsensusStateNotFound()` and selector `0x09128dc8` #[derive( Clone, ::ethers::contract::EthError, @@ -1510,7 +1510,7 @@ pub mod cometbls_client { abi = "ErrTrustedConsensusStateNotFound()" )] pub struct ErrTrustedConsensusStateNotFound; - ///Custom Error type `ErrUntrustedHeightLTETrustedHeight` with signature `ErrUntrustedHeightLTETrustedHeight()` and selector `0xf97b0922` + /// Custom Error type `ErrUntrustedHeightLTETrustedHeight` with signature `ErrUntrustedHeightLTETrustedHeight()` and selector `0xf97b0922` #[derive( Clone, ::ethers::contract::EthError, @@ -1526,7 +1526,7 @@ pub mod cometbls_client { abi = "ErrUntrustedHeightLTETrustedHeight()" )] pub struct ErrUntrustedHeightLTETrustedHeight; - ///Custom Error type `ErrUntrustedTimestampLTETrustedTimestamp` with signature `ErrUntrustedTimestampLTETrustedTimestamp()` and selector `0x14a286e4` + /// Custom Error type `ErrUntrustedTimestampLTETrustedTimestamp` with signature `ErrUntrustedTimestampLTETrustedTimestamp()` and selector `0x14a286e4` #[derive( Clone, ::ethers::contract::EthError, @@ -1542,7 +1542,7 @@ pub mod cometbls_client { abi = "ErrUntrustedTimestampLTETrustedTimestamp()" )] pub struct ErrUntrustedTimestampLTETrustedTimestamp; - ///Custom Error type `ExpectedPause` with signature `ExpectedPause()` and selector `0x8dfc202b` + /// Custom Error type `ExpectedPause` with signature `ExpectedPause()` and selector `0x8dfc202b` #[derive( Clone, ::ethers::contract::EthError, @@ -1555,7 +1555,7 @@ pub mod cometbls_client { )] #[etherror(name = "ExpectedPause", abi = "ExpectedPause()")] pub struct ExpectedPause; - ///Custom Error type `FailedInnerCall` with signature `FailedInnerCall()` and selector `0x1425ea42` + /// Custom Error type `FailedInnerCall` with signature `FailedInnerCall()` and selector `0x1425ea42` #[derive( Clone, ::ethers::contract::EthError, @@ -1568,7 +1568,7 @@ pub mod cometbls_client { )] #[etherror(name = "FailedInnerCall", abi = "FailedInnerCall()")] pub struct FailedInnerCall; - ///Custom Error type `InvalidInitialization` with signature `InvalidInitialization()` and selector `0xf92ee8a9` + /// Custom Error type `InvalidInitialization` with signature `InvalidInitialization()` and selector `0xf92ee8a9` #[derive( Clone, ::ethers::contract::EthError, @@ -1581,7 +1581,7 @@ pub mod cometbls_client { )] #[etherror(name = "InvalidInitialization", abi = "InvalidInitialization()")] pub struct InvalidInitialization; - ///Custom Error type `NotInitializing` with signature `NotInitializing()` and selector `0xd7e6bcf8` + /// Custom Error type `NotInitializing` with signature `NotInitializing()` and selector `0xd7e6bcf8` #[derive( Clone, ::ethers::contract::EthError, @@ -1594,7 +1594,7 @@ pub mod cometbls_client { )] #[etherror(name = "NotInitializing", abi = "NotInitializing()")] pub struct NotInitializing; - ///Custom Error type `OwnableInvalidOwner` with signature `OwnableInvalidOwner(address)` and selector `0x1e4fbdf7` + /// Custom Error type `OwnableInvalidOwner` with signature `OwnableInvalidOwner(address)` and selector `0x1e4fbdf7` #[derive( Clone, ::ethers::contract::EthError, @@ -1609,7 +1609,7 @@ pub mod cometbls_client { pub struct OwnableInvalidOwner { pub owner: ::ethers::core::types::Address, } - ///Custom Error type `OwnableUnauthorizedAccount` with signature `OwnableUnauthorizedAccount(address)` and selector `0x118cdaa7` + /// Custom Error type `OwnableUnauthorizedAccount` with signature `OwnableUnauthorizedAccount(address)` and selector `0x118cdaa7` #[derive( Clone, ::ethers::contract::EthError, @@ -1627,7 +1627,7 @@ pub mod cometbls_client { pub struct OwnableUnauthorizedAccount { pub account: ::ethers::core::types::Address, } - ///Custom Error type `UUPSUnauthorizedCallContext` with signature `UUPSUnauthorizedCallContext()` and selector `0xe07c8dba` + /// Custom Error type `UUPSUnauthorizedCallContext` with signature `UUPSUnauthorizedCallContext()` and selector `0xe07c8dba` #[derive( Clone, ::ethers::contract::EthError, @@ -1643,7 +1643,7 @@ pub mod cometbls_client { abi = "UUPSUnauthorizedCallContext()" )] pub struct UUPSUnauthorizedCallContext; - ///Custom Error type `UUPSUnsupportedProxiableUUID` with signature `UUPSUnsupportedProxiableUUID(bytes32)` and selector `0xaa1d49a4` + /// Custom Error type `UUPSUnsupportedProxiableUUID` with signature `UUPSUnsupportedProxiableUUID(bytes32)` and selector `0xaa1d49a4` #[derive( Clone, ::ethers::contract::EthError, @@ -1661,7 +1661,7 @@ pub mod cometbls_client { pub struct UUPSUnsupportedProxiableUUID { pub slot: [u8; 32], } - ///Container type for all of the contract's custom errors + /// Container type for all of the contract's custom errors #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum CometblsClientErrors { AddressEmptyCode(AddressEmptyCode), @@ -2220,7 +2220,7 @@ pub mod cometbls_client { #[ethevent(indexed)] pub implementation: ::ethers::core::types::Address, } - ///Container type for all of the contract's events + /// Container type for all of the contract's events #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum CometblsClientEvents { InitializedFilter(InitializedFilter), @@ -2287,7 +2287,7 @@ pub mod cometbls_client { Self::UpgradedFilter(value) } } - ///Container type for all input parameters for the `UPGRADE_INTERFACE_VERSION` function with signature `UPGRADE_INTERFACE_VERSION()` and selector `0xad3cb1cc` + /// Container type for all input parameters for the `UPGRADE_INTERFACE_VERSION` function with signature `UPGRADE_INTERFACE_VERSION()` and selector `0xad3cb1cc` #[derive( Clone, ::ethers::contract::EthCall, @@ -2303,7 +2303,7 @@ pub mod cometbls_client { abi = "UPGRADE_INTERFACE_VERSION()" )] pub struct UpgradeInterfaceVersionCall; - ///Container type for all input parameters for the `createClient` function with signature `createClient(string,bytes,bytes)` and selector `0x2629636b` + /// Container type for all input parameters for the `createClient` function with signature `createClient(string,bytes,bytes)` and selector `0x2629636b` #[derive( Clone, ::ethers::contract::EthCall, @@ -2320,7 +2320,7 @@ pub mod cometbls_client { pub client_state_bytes: ::ethers::core::types::Bytes, pub consensus_state_bytes: ::ethers::core::types::Bytes, } - ///Container type for all input parameters for the `getClientState` function with signature `getClientState(string)` and selector `0x76c81c42` + /// Container type for all input parameters for the `getClientState` function with signature `getClientState(string)` and selector `0x76c81c42` #[derive( Clone, ::ethers::contract::EthCall, @@ -2335,7 +2335,7 @@ pub mod cometbls_client { pub struct GetClientStateCall { pub client_id: ::std::string::String, } - ///Container type for all input parameters for the `getConsensusState` function with signature `getConsensusState(string,(uint64,uint64))` and selector `0x6cf44bf4` + /// Container type for all input parameters for the `getConsensusState` function with signature `getConsensusState(string,(uint64,uint64))` and selector `0x6cf44bf4` #[derive( Clone, ::ethers::contract::EthCall, @@ -2354,7 +2354,7 @@ pub mod cometbls_client { pub client_id: ::std::string::String, pub height: IbcCoreClientV1HeightData, } - ///Container type for all input parameters for the `getLatestHeight` function with signature `getLatestHeight(string)` and selector `0x329681d0` + /// Container type for all input parameters for the `getLatestHeight` function with signature `getLatestHeight(string)` and selector `0x329681d0` #[derive( Clone, ::ethers::contract::EthCall, @@ -2369,7 +2369,7 @@ pub mod cometbls_client { pub struct GetLatestHeightCall { pub client_id: ::std::string::String, } - ///Container type for all input parameters for the `getTimestampAtHeight` function with signature `getTimestampAtHeight(string,(uint64,uint64))` and selector `0x4b0bbdc4` + /// Container type for all input parameters for the `getTimestampAtHeight` function with signature `getTimestampAtHeight(string,(uint64,uint64))` and selector `0x4b0bbdc4` #[derive( Clone, ::ethers::contract::EthCall, @@ -2388,7 +2388,7 @@ pub mod cometbls_client { pub client_id: ::std::string::String, pub height: IbcCoreClientV1HeightData, } - ///Container type for all input parameters for the `initialize` function with signature `initialize(address,address)` and selector `0x485cc955` + /// Container type for all input parameters for the `initialize` function with signature `initialize(address,address)` and selector `0x485cc955` #[derive( Clone, ::ethers::contract::EthCall, @@ -2404,7 +2404,7 @@ pub mod cometbls_client { pub ibc_handler: ::ethers::core::types::Address, pub admin: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `misbehavior` function with signature `misbehavior(string,((int64,(int64,int64),bytes,bytes,bytes),(uint64,uint64),bytes),((int64,(int64,int64),bytes,bytes,bytes),(uint64,uint64),bytes))` and selector `0x21c90b05` + /// Container type for all input parameters for the `misbehavior` function with signature `misbehavior(string,((int64,(int64,int64),bytes,bytes,bytes),(uint64,uint64),bytes),((int64,(int64,int64),bytes,bytes,bytes),(uint64,uint64),bytes))` and selector `0x21c90b05` #[derive( Clone, ::ethers::contract::EthCall, @@ -2424,7 +2424,7 @@ pub mod cometbls_client { pub header_a: UnionIbcLightclientsCometblsV1HeaderData, pub header_b: UnionIbcLightclientsCometblsV1HeaderData, } - ///Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` + /// Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` #[derive( Clone, ::ethers::contract::EthCall, @@ -2437,7 +2437,7 @@ pub mod cometbls_client { )] #[ethcall(name = "owner", abi = "owner()")] pub struct OwnerCall; - ///Container type for all input parameters for the `paused` function with signature `paused()` and selector `0x5c975abb` + /// Container type for all input parameters for the `paused` function with signature `paused()` and selector `0x5c975abb` #[derive( Clone, ::ethers::contract::EthCall, @@ -2450,7 +2450,7 @@ pub mod cometbls_client { )] #[ethcall(name = "paused", abi = "paused()")] pub struct PausedCall; - ///Container type for all input parameters for the `proxiableUUID` function with signature `proxiableUUID()` and selector `0x52d1902d` + /// Container type for all input parameters for the `proxiableUUID` function with signature `proxiableUUID()` and selector `0x52d1902d` #[derive( Clone, ::ethers::contract::EthCall, @@ -2463,7 +2463,7 @@ pub mod cometbls_client { )] #[ethcall(name = "proxiableUUID", abi = "proxiableUUID()")] pub struct ProxiableUUIDCall; - ///Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` + /// Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` #[derive( Clone, ::ethers::contract::EthCall, @@ -2476,7 +2476,7 @@ pub mod cometbls_client { )] #[ethcall(name = "renounceOwnership", abi = "renounceOwnership()")] pub struct RenounceOwnershipCall; - ///Container type for all input parameters for the `transferOwnership` function with signature `transferOwnership(address)` and selector `0xf2fde38b` + /// Container type for all input parameters for the `transferOwnership` function with signature `transferOwnership(address)` and selector `0xf2fde38b` #[derive( Clone, ::ethers::contract::EthCall, @@ -2491,7 +2491,7 @@ pub mod cometbls_client { pub struct TransferOwnershipCall { pub new_owner: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `updateClient` function with signature `updateClient(string,bytes)` and selector `0x6fbf8079` + /// Container type for all input parameters for the `updateClient` function with signature `updateClient(string,bytes)` and selector `0x6fbf8079` #[derive( Clone, ::ethers::contract::EthCall, @@ -2507,7 +2507,7 @@ pub mod cometbls_client { pub client_id: ::std::string::String, pub client_message_bytes: ::ethers::core::types::Bytes, } - ///Container type for all input parameters for the `upgradeToAndCall` function with signature `upgradeToAndCall(address,bytes)` and selector `0x4f1ef286` + /// Container type for all input parameters for the `upgradeToAndCall` function with signature `upgradeToAndCall(address,bytes)` and selector `0x4f1ef286` #[derive( Clone, ::ethers::contract::EthCall, @@ -2523,7 +2523,7 @@ pub mod cometbls_client { pub new_implementation: ::ethers::core::types::Address, pub data: ::ethers::core::types::Bytes, } - ///Container type for all input parameters for the `verifyMembership` function with signature `verifyMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes,bytes)` and selector `0xf9bb5a51` + /// Container type for all input parameters for the `verifyMembership` function with signature `verifyMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes,bytes)` and selector `0xf9bb5a51` #[derive( Clone, ::ethers::contract::EthCall, @@ -2548,7 +2548,7 @@ pub mod cometbls_client { pub path: ::ethers::core::types::Bytes, pub value: ::ethers::core::types::Bytes, } - ///Container type for all input parameters for the `verifyNonMembership` function with signature `verifyNonMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes)` and selector `0x999fbbb3` + /// Container type for all input parameters for the `verifyNonMembership` function with signature `verifyNonMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes)` and selector `0x999fbbb3` #[derive( Clone, ::ethers::contract::EthCall, @@ -2572,7 +2572,7 @@ pub mod cometbls_client { pub prefix: ::ethers::core::types::Bytes, pub path: ::ethers::core::types::Bytes, } - ///Container type for all input parameters for the `verifyZKP` function with signature `verifyZKP(bytes,string,bytes32,(int64,(int64,int64),bytes,bytes,bytes))` and selector `0x61ce4b12` + /// Container type for all input parameters for the `verifyZKP` function with signature `verifyZKP(bytes,string,bytes32,(int64,(int64,int64),bytes,bytes,bytes))` and selector `0x61ce4b12` #[derive( Clone, ::ethers::contract::EthCall, @@ -2593,7 +2593,7 @@ pub mod cometbls_client { pub trusted_validators_hash: [u8; 32], pub header: UnionIbcLightclientsCometblsV1LightHeaderData, } - ///Container type for all of the contract's call + /// Container type for all of the contract's call #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum CometblsClientCalls { UpgradeInterfaceVersion(UpgradeInterfaceVersionCall), @@ -2844,7 +2844,7 @@ pub mod cometbls_client { Self::VerifyZKP(value) } } - ///Container type for all return fields from the `UPGRADE_INTERFACE_VERSION` function with signature `UPGRADE_INTERFACE_VERSION()` and selector `0xad3cb1cc` + /// Container type for all return fields from the `UPGRADE_INTERFACE_VERSION` function with signature `UPGRADE_INTERFACE_VERSION()` and selector `0xad3cb1cc` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2856,7 +2856,7 @@ pub mod cometbls_client { Hash, )] pub struct UpgradeInterfaceVersionReturn(pub ::std::string::String); - ///Container type for all return fields from the `createClient` function with signature `createClient(string,bytes,bytes)` and selector `0x2629636b` + /// Container type for all return fields from the `createClient` function with signature `createClient(string,bytes,bytes)` and selector `0x2629636b` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2872,7 +2872,7 @@ pub mod cometbls_client { pub update: ConsensusStateUpdate, pub ok: bool, } - ///Container type for all return fields from the `getClientState` function with signature `getClientState(string)` and selector `0x76c81c42` + /// Container type for all return fields from the `getClientState` function with signature `getClientState(string)` and selector `0x76c81c42` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2884,7 +2884,7 @@ pub mod cometbls_client { Hash, )] pub struct GetClientStateReturn(pub ::ethers::core::types::Bytes); - ///Container type for all return fields from the `getConsensusState` function with signature `getConsensusState(string,(uint64,uint64))` and selector `0x6cf44bf4` + /// Container type for all return fields from the `getConsensusState` function with signature `getConsensusState(string,(uint64,uint64))` and selector `0x6cf44bf4` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2896,7 +2896,7 @@ pub mod cometbls_client { Hash, )] pub struct GetConsensusStateReturn(pub ::ethers::core::types::Bytes); - ///Container type for all return fields from the `getLatestHeight` function with signature `getLatestHeight(string)` and selector `0x329681d0` + /// Container type for all return fields from the `getLatestHeight` function with signature `getLatestHeight(string)` and selector `0x329681d0` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2908,7 +2908,7 @@ pub mod cometbls_client { Hash, )] pub struct GetLatestHeightReturn(pub IbcCoreClientV1HeightData); - ///Container type for all return fields from the `getTimestampAtHeight` function with signature `getTimestampAtHeight(string,(uint64,uint64))` and selector `0x4b0bbdc4` + /// Container type for all return fields from the `getTimestampAtHeight` function with signature `getTimestampAtHeight(string,(uint64,uint64))` and selector `0x4b0bbdc4` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2920,7 +2920,7 @@ pub mod cometbls_client { Hash, )] pub struct GetTimestampAtHeightReturn(pub u64); - ///Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` + /// Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2932,7 +2932,7 @@ pub mod cometbls_client { Hash, )] pub struct OwnerReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `paused` function with signature `paused()` and selector `0x5c975abb` + /// Container type for all return fields from the `paused` function with signature `paused()` and selector `0x5c975abb` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2944,7 +2944,7 @@ pub mod cometbls_client { Hash, )] pub struct PausedReturn(pub bool); - ///Container type for all return fields from the `proxiableUUID` function with signature `proxiableUUID()` and selector `0x52d1902d` + /// Container type for all return fields from the `proxiableUUID` function with signature `proxiableUUID()` and selector `0x52d1902d` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2956,7 +2956,7 @@ pub mod cometbls_client { Hash, )] pub struct ProxiableUUIDReturn(pub [u8; 32]); - ///Container type for all return fields from the `updateClient` function with signature `updateClient(string,bytes)` and selector `0x6fbf8079` + /// Container type for all return fields from the `updateClient` function with signature `updateClient(string,bytes)` and selector `0x6fbf8079` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2968,7 +2968,7 @@ pub mod cometbls_client { Hash, )] pub struct UpdateClientReturn(pub [u8; 32], pub ::std::vec::Vec); - ///Container type for all return fields from the `verifyMembership` function with signature `verifyMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes,bytes)` and selector `0xf9bb5a51` + /// Container type for all return fields from the `verifyMembership` function with signature `verifyMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes,bytes)` and selector `0xf9bb5a51` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2980,7 +2980,7 @@ pub mod cometbls_client { Hash, )] pub struct VerifyMembershipReturn(pub bool); - ///Container type for all return fields from the `verifyNonMembership` function with signature `verifyNonMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes)` and selector `0x999fbbb3` + /// Container type for all return fields from the `verifyNonMembership` function with signature `verifyNonMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes)` and selector `0x999fbbb3` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2992,7 +2992,7 @@ pub mod cometbls_client { Hash, )] pub struct VerifyNonMembershipReturn(pub bool); - ///Container type for all return fields from the `verifyZKP` function with signature `verifyZKP(bytes,string,bytes32,(int64,(int64,int64),bytes,bytes,bytes))` and selector `0x61ce4b12` + /// Container type for all return fields from the `verifyZKP` function with signature `verifyZKP(bytes,string,bytes32,(int64,(int64,int64),bytes,bytes,bytes))` and selector `0x61ce4b12` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/generated/rust/contracts/src/erc20.rs b/generated/rust/contracts/src/erc20.rs index 7a86a04cd0..7eeafb3996 100644 --- a/generated/rust/contracts/src/erc20.rs +++ b/generated/rust/contracts/src/erc20.rs @@ -401,7 +401,7 @@ pub mod erc20 { fallback: false, } } - ///The parsed JSON ABI of the contract. + /// The parsed JSON ABI of the contract. #[cfg(feature = "providers")] pub static ERC20_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); @@ -448,7 +448,7 @@ pub mod erc20 { client, )) } - ///Calls the contract's `allowance` (0xdd62ed3e) function + /// Calls the contract's `allowance` (0xdd62ed3e) function pub fn allowance( &self, owner: ::ethers::core::types::Address, @@ -458,7 +458,7 @@ pub mod erc20 { .method_hash([221, 98, 237, 62], (owner, spender)) .expect("method not found (this should never happen)") } - ///Calls the contract's `approve` (0x095ea7b3) function + /// Calls the contract's `approve` (0x095ea7b3) function pub fn approve( &self, spender: ::ethers::core::types::Address, @@ -468,7 +468,7 @@ pub mod erc20 { .method_hash([9, 94, 167, 179], (spender, value)) .expect("method not found (this should never happen)") } - ///Calls the contract's `balanceOf` (0x70a08231) function + /// Calls the contract's `balanceOf` (0x70a08231) function pub fn balance_of( &self, account: ::ethers::core::types::Address, @@ -477,19 +477,19 @@ pub mod erc20 { .method_hash([112, 160, 130, 49], account) .expect("method not found (this should never happen)") } - ///Calls the contract's `decimals` (0x313ce567) function + /// Calls the contract's `decimals` (0x313ce567) function pub fn decimals(&self) -> ::ethers::contract::builders::ContractCall { self.0 .method_hash([49, 60, 229, 103], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `name` (0x06fdde03) function + /// Calls the contract's `name` (0x06fdde03) function pub fn name(&self) -> ::ethers::contract::builders::ContractCall { self.0 .method_hash([6, 253, 222, 3], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `symbol` (0x95d89b41) function + /// Calls the contract's `symbol` (0x95d89b41) function pub fn symbol( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -497,7 +497,7 @@ pub mod erc20 { .method_hash([149, 216, 155, 65], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `totalSupply` (0x18160ddd) function + /// Calls the contract's `totalSupply` (0x18160ddd) function pub fn total_supply( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -505,7 +505,7 @@ pub mod erc20 { .method_hash([24, 22, 13, 221], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `transfer` (0xa9059cbb) function + /// Calls the contract's `transfer` (0xa9059cbb) function pub fn transfer( &self, to: ::ethers::core::types::Address, @@ -515,7 +515,7 @@ pub mod erc20 { .method_hash([169, 5, 156, 187], (to, value)) .expect("method not found (this should never happen)") } - ///Calls the contract's `transferFrom` (0x23b872dd) function + /// Calls the contract's `transferFrom` (0x23b872dd) function pub fn transfer_from( &self, from: ::ethers::core::types::Address, @@ -526,13 +526,13 @@ pub mod erc20 { .method_hash([35, 184, 114, 221], (from, to, value)) .expect("method not found (this should never happen)") } - ///Gets the contract's `Approval` event + /// Gets the contract's `Approval` event pub fn approval_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ApprovalFilter> { self.0.event() } - ///Gets the contract's `Transfer` event + /// Gets the contract's `Transfer` event pub fn transfer_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, TransferFilter> { @@ -552,7 +552,7 @@ pub mod erc20 { Self::new(contract.address(), contract.client()) } } - ///Custom Error type `ERC20InsufficientAllowance` with signature `ERC20InsufficientAllowance(address,uint256,uint256)` and selector `0xfb8f41b2` + /// Custom Error type `ERC20InsufficientAllowance` with signature `ERC20InsufficientAllowance(address,uint256,uint256)` and selector `0xfb8f41b2` #[derive( Clone, ::ethers::contract::EthError, @@ -572,7 +572,7 @@ pub mod erc20 { pub allowance: ::ethers::core::types::U256, pub needed: ::ethers::core::types::U256, } - ///Custom Error type `ERC20InsufficientBalance` with signature `ERC20InsufficientBalance(address,uint256,uint256)` and selector `0xe450d38c` + /// Custom Error type `ERC20InsufficientBalance` with signature `ERC20InsufficientBalance(address,uint256,uint256)` and selector `0xe450d38c` #[derive( Clone, ::ethers::contract::EthError, @@ -592,7 +592,7 @@ pub mod erc20 { pub balance: ::ethers::core::types::U256, pub needed: ::ethers::core::types::U256, } - ///Custom Error type `ERC20InvalidApprover` with signature `ERC20InvalidApprover(address)` and selector `0xe602df05` + /// Custom Error type `ERC20InvalidApprover` with signature `ERC20InvalidApprover(address)` and selector `0xe602df05` #[derive( Clone, ::ethers::contract::EthError, @@ -607,7 +607,7 @@ pub mod erc20 { pub struct ERC20InvalidApprover { pub approver: ::ethers::core::types::Address, } - ///Custom Error type `ERC20InvalidReceiver` with signature `ERC20InvalidReceiver(address)` and selector `0xec442f05` + /// Custom Error type `ERC20InvalidReceiver` with signature `ERC20InvalidReceiver(address)` and selector `0xec442f05` #[derive( Clone, ::ethers::contract::EthError, @@ -622,7 +622,7 @@ pub mod erc20 { pub struct ERC20InvalidReceiver { pub receiver: ::ethers::core::types::Address, } - ///Custom Error type `ERC20InvalidSender` with signature `ERC20InvalidSender(address)` and selector `0x96c6fd1e` + /// Custom Error type `ERC20InvalidSender` with signature `ERC20InvalidSender(address)` and selector `0x96c6fd1e` #[derive( Clone, ::ethers::contract::EthError, @@ -637,7 +637,7 @@ pub mod erc20 { pub struct ERC20InvalidSender { pub sender: ::ethers::core::types::Address, } - ///Custom Error type `ERC20InvalidSpender` with signature `ERC20InvalidSpender(address)` and selector `0x94280d62` + /// Custom Error type `ERC20InvalidSpender` with signature `ERC20InvalidSpender(address)` and selector `0x94280d62` #[derive( Clone, ::ethers::contract::EthError, @@ -652,7 +652,7 @@ pub mod erc20 { pub struct ERC20InvalidSpender { pub spender: ::ethers::core::types::Address, } - ///Container type for all of the contract's custom errors + /// Container type for all of the contract's custom errors #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum ERC20Errors { ERC20InsufficientAllowance(ERC20InsufficientAllowance), @@ -855,7 +855,7 @@ pub mod erc20 { pub to: ::ethers::core::types::Address, pub value: ::ethers::core::types::U256, } - ///Container type for all of the contract's events + /// Container type for all of the contract's events #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum ERC20Events { ApprovalFilter(ApprovalFilter), @@ -892,7 +892,7 @@ pub mod erc20 { Self::TransferFilter(value) } } - ///Container type for all input parameters for the `allowance` function with signature `allowance(address,address)` and selector `0xdd62ed3e` + /// Container type for all input parameters for the `allowance` function with signature `allowance(address,address)` and selector `0xdd62ed3e` #[derive( Clone, ::ethers::contract::EthCall, @@ -908,7 +908,7 @@ pub mod erc20 { pub owner: ::ethers::core::types::Address, pub spender: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `approve` function with signature `approve(address,uint256)` and selector `0x095ea7b3` + /// Container type for all input parameters for the `approve` function with signature `approve(address,uint256)` and selector `0x095ea7b3` #[derive( Clone, ::ethers::contract::EthCall, @@ -924,7 +924,7 @@ pub mod erc20 { pub spender: ::ethers::core::types::Address, pub value: ::ethers::core::types::U256, } - ///Container type for all input parameters for the `balanceOf` function with signature `balanceOf(address)` and selector `0x70a08231` + /// Container type for all input parameters for the `balanceOf` function with signature `balanceOf(address)` and selector `0x70a08231` #[derive( Clone, ::ethers::contract::EthCall, @@ -939,7 +939,7 @@ pub mod erc20 { pub struct BalanceOfCall { pub account: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `decimals` function with signature `decimals()` and selector `0x313ce567` + /// Container type for all input parameters for the `decimals` function with signature `decimals()` and selector `0x313ce567` #[derive( Clone, ::ethers::contract::EthCall, @@ -952,7 +952,7 @@ pub mod erc20 { )] #[ethcall(name = "decimals", abi = "decimals()")] pub struct DecimalsCall; - ///Container type for all input parameters for the `name` function with signature `name()` and selector `0x06fdde03` + /// Container type for all input parameters for the `name` function with signature `name()` and selector `0x06fdde03` #[derive( Clone, ::ethers::contract::EthCall, @@ -965,7 +965,7 @@ pub mod erc20 { )] #[ethcall(name = "name", abi = "name()")] pub struct NameCall; - ///Container type for all input parameters for the `symbol` function with signature `symbol()` and selector `0x95d89b41` + /// Container type for all input parameters for the `symbol` function with signature `symbol()` and selector `0x95d89b41` #[derive( Clone, ::ethers::contract::EthCall, @@ -978,7 +978,7 @@ pub mod erc20 { )] #[ethcall(name = "symbol", abi = "symbol()")] pub struct SymbolCall; - ///Container type for all input parameters for the `totalSupply` function with signature `totalSupply()` and selector `0x18160ddd` + /// Container type for all input parameters for the `totalSupply` function with signature `totalSupply()` and selector `0x18160ddd` #[derive( Clone, ::ethers::contract::EthCall, @@ -991,7 +991,7 @@ pub mod erc20 { )] #[ethcall(name = "totalSupply", abi = "totalSupply()")] pub struct TotalSupplyCall; - ///Container type for all input parameters for the `transfer` function with signature `transfer(address,uint256)` and selector `0xa9059cbb` + /// Container type for all input parameters for the `transfer` function with signature `transfer(address,uint256)` and selector `0xa9059cbb` #[derive( Clone, ::ethers::contract::EthCall, @@ -1007,7 +1007,7 @@ pub mod erc20 { pub to: ::ethers::core::types::Address, pub value: ::ethers::core::types::U256, } - ///Container type for all input parameters for the `transferFrom` function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd` + /// Container type for all input parameters for the `transferFrom` function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd` #[derive( Clone, ::ethers::contract::EthCall, @@ -1024,7 +1024,7 @@ pub mod erc20 { pub to: ::ethers::core::types::Address, pub value: ::ethers::core::types::U256, } - ///Container type for all of the contract's call + /// Container type for all of the contract's call #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum ERC20Calls { Allowance(AllowanceCall), @@ -1148,7 +1148,7 @@ pub mod erc20 { Self::TransferFrom(value) } } - ///Container type for all return fields from the `allowance` function with signature `allowance(address,address)` and selector `0xdd62ed3e` + /// Container type for all return fields from the `allowance` function with signature `allowance(address,address)` and selector `0xdd62ed3e` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1160,7 +1160,7 @@ pub mod erc20 { Hash, )] pub struct AllowanceReturn(pub ::ethers::core::types::U256); - ///Container type for all return fields from the `approve` function with signature `approve(address,uint256)` and selector `0x095ea7b3` + /// Container type for all return fields from the `approve` function with signature `approve(address,uint256)` and selector `0x095ea7b3` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1172,7 +1172,7 @@ pub mod erc20 { Hash, )] pub struct ApproveReturn(pub bool); - ///Container type for all return fields from the `balanceOf` function with signature `balanceOf(address)` and selector `0x70a08231` + /// Container type for all return fields from the `balanceOf` function with signature `balanceOf(address)` and selector `0x70a08231` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1184,7 +1184,7 @@ pub mod erc20 { Hash, )] pub struct BalanceOfReturn(pub ::ethers::core::types::U256); - ///Container type for all return fields from the `decimals` function with signature `decimals()` and selector `0x313ce567` + /// Container type for all return fields from the `decimals` function with signature `decimals()` and selector `0x313ce567` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1196,7 +1196,7 @@ pub mod erc20 { Hash, )] pub struct DecimalsReturn(pub u8); - ///Container type for all return fields from the `name` function with signature `name()` and selector `0x06fdde03` + /// Container type for all return fields from the `name` function with signature `name()` and selector `0x06fdde03` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1208,7 +1208,7 @@ pub mod erc20 { Hash, )] pub struct NameReturn(pub ::std::string::String); - ///Container type for all return fields from the `symbol` function with signature `symbol()` and selector `0x95d89b41` + /// Container type for all return fields from the `symbol` function with signature `symbol()` and selector `0x95d89b41` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1220,7 +1220,7 @@ pub mod erc20 { Hash, )] pub struct SymbolReturn(pub ::std::string::String); - ///Container type for all return fields from the `totalSupply` function with signature `totalSupply()` and selector `0x18160ddd` + /// Container type for all return fields from the `totalSupply` function with signature `totalSupply()` and selector `0x18160ddd` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1232,7 +1232,7 @@ pub mod erc20 { Hash, )] pub struct TotalSupplyReturn(pub ::ethers::core::types::U256); - ///Container type for all return fields from the `transfer` function with signature `transfer(address,uint256)` and selector `0xa9059cbb` + /// Container type for all return fields from the `transfer` function with signature `transfer(address,uint256)` and selector `0xa9059cbb` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1244,7 +1244,7 @@ pub mod erc20 { Hash, )] pub struct TransferReturn(pub bool); - ///Container type for all return fields from the `transferFrom` function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd` + /// Container type for all return fields from the `transferFrom` function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/generated/rust/contracts/src/glue.rs b/generated/rust/contracts/src/glue.rs index 63bf52e823..f807ce8e3d 100644 --- a/generated/rust/contracts/src/glue.rs +++ b/generated/rust/contracts/src/glue.rs @@ -875,7 +875,7 @@ pub mod glue { fallback: false, } } - ///The parsed JSON ABI of the contract. + /// The parsed JSON ABI of the contract. #[cfg(feature = "providers")] pub static GLUE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); @@ -975,7 +975,7 @@ pub mod glue { let deployer = ::ethers::contract::ContractDeployer::new(deployer); Ok(deployer) } - ///Calls the contract's `typesTelescope` (0x4652dc1f) function + /// Calls the contract's `typesTelescope` (0x4652dc1f) function pub fn types_telescope( &self, p0: IbcCoreConnectionV1ConnectionEndData, @@ -1007,7 +1007,7 @@ pub mod glue { Self::new(contract.address(), contract.client()) } } - ///Container type for all input parameters for the `typesTelescope` function with signature `typesTelescope((string,uint64,uint64,uint64,(uint64,uint64),(uint64,uint64)),(uint64,(bytes),bytes),((int64,(int64,int64),bytes,bytes,bytes),(uint64,uint64),bytes),((uint64,uint64),string,int64,(int64,int64),(bytes,(uint32,bytes)),bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes),(int64,int32,(bytes,(uint32,bytes)),(uint8,bytes,(int64,int64),bytes)[]),(uint64,uint64),(uint64,bytes32,bytes32),(uint256,uint256),(uint8,int64,int64,(bytes,(uint32,bytes)),string),(string,(uint64,uint64),(int64,int32),(int64,int32),(int64,int32),(uint64,uint64),(uint64,uint64),((uint8,uint8,uint8,uint8,bytes),(int32[],int32,int32,int32,bytes,uint8),int32,int32)[],string[],bool,bool),((int64,int64),(bytes),bytes),((((uint64,uint64),string,int64,(int64,int64),(bytes,(uint32,bytes)),bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes),(int64,int32,(bytes,(uint32,bytes)),(uint8,bytes,(int64,int64),bytes)[])),((bytes,(bytes,bytes,bytes),int64,int64)[],(bytes,(bytes,bytes,bytes),int64,int64),int64),(uint64,uint64),((bytes,(bytes,bytes,bytes),int64,int64)[],(bytes,(bytes,bytes,bytes),int64,int64),int64)),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])))[]),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[])))[],(uint8,bytes,bytes)[]))[]),(string,(string,string[])[],uint8,(string,string,(bytes)),uint64))` and selector `0x4652dc1f` + /// Container type for all input parameters for the `typesTelescope` function with signature `typesTelescope((string,uint64,uint64,uint64,(uint64,uint64),(uint64,uint64)),(uint64,(bytes),bytes),((int64,(int64,int64),bytes,bytes,bytes),(uint64,uint64),bytes),((uint64,uint64),string,int64,(int64,int64),(bytes,(uint32,bytes)),bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes),(int64,int32,(bytes,(uint32,bytes)),(uint8,bytes,(int64,int64),bytes)[]),(uint64,uint64),(uint64,bytes32,bytes32),(uint256,uint256),(uint8,int64,int64,(bytes,(uint32,bytes)),string),(string,(uint64,uint64),(int64,int32),(int64,int32),(int64,int32),(uint64,uint64),(uint64,uint64),((uint8,uint8,uint8,uint8,bytes),(int32[],int32,int32,int32,bytes,uint8),int32,int32)[],string[],bool,bool),((int64,int64),(bytes),bytes),((((uint64,uint64),string,int64,(int64,int64),(bytes,(uint32,bytes)),bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes),(int64,int32,(bytes,(uint32,bytes)),(uint8,bytes,(int64,int64),bytes)[])),((bytes,(bytes,bytes,bytes),int64,int64)[],(bytes,(bytes,bytes,bytes),int64,int64),int64),(uint64,uint64),((bytes,(bytes,bytes,bytes),int64,int64)[],(bytes,(bytes,bytes,bytes),int64,int64),int64)),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])))[]),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[])))[],(uint8,bytes,bytes)[]))[]),(string,(string,string[])[],uint8,(string,string,(bytes)),uint64))` and selector `0x4652dc1f` #[derive(Clone, ::ethers::contract::EthCall, ::ethers::contract::EthDisplay)] #[ethcall( name = "typesTelescope", @@ -1029,7 +1029,7 @@ pub mod glue { pub IbcCoreConnectionV1ConnectionEndData, pub IbcCoreConnectionV1ConnectionEndData, ); - ///`CosmosIcs23V1BatchEntryData((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])))` + /// `CosmosIcs23V1BatchEntryData((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])))` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1044,7 +1044,7 @@ pub mod glue { pub exist: CosmosIcs23V1ExistenceProofData, pub nonexist: CosmosIcs23V1NonExistenceProofData, } - ///`CosmosIcs23V1BatchProofData(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])))[])` + /// `CosmosIcs23V1BatchProofData(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])))[])` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1058,7 +1058,7 @@ pub mod glue { pub struct CosmosIcs23V1BatchProofData { pub entries: ::std::vec::Vec, } - ///`CosmosIcs23V1CommitmentProofData((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])))[]),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[])))[],(uint8,bytes,bytes)[]))` + /// `CosmosIcs23V1CommitmentProofData((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])))[]),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[])))[],(uint8,bytes,bytes)[]))` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1075,7 +1075,7 @@ pub mod glue { pub batch: CosmosIcs23V1BatchProofData, pub compressed: CosmosIcs23V1CompressedBatchProofData, } - ///`CosmosIcs23V1CompressedBatchEntryData((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[])))` + /// `CosmosIcs23V1CompressedBatchEntryData((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[])))` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1090,7 +1090,7 @@ pub mod glue { pub exist: CosmosIcs23V1CompressedExistenceProofData, pub nonexist: CosmosIcs23V1CompressedNonExistenceProofData, } - ///`CosmosIcs23V1CompressedBatchProofData(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[])))[],(uint8,bytes,bytes)[])` + /// `CosmosIcs23V1CompressedBatchProofData(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[])))[],(uint8,bytes,bytes)[])` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1105,7 +1105,7 @@ pub mod glue { pub entries: ::std::vec::Vec, pub lookup_inners: ::std::vec::Vec, } - ///`CosmosIcs23V1CompressedExistenceProofData(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[])` + /// `CosmosIcs23V1CompressedExistenceProofData(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[])` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1122,7 +1122,7 @@ pub mod glue { pub leaf: CosmosIcs23V1LeafOpData, pub path: ::std::vec::Vec, } - ///`CosmosIcs23V1CompressedNonExistenceProofData(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]))` + /// `CosmosIcs23V1CompressedNonExistenceProofData(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]))` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1138,7 +1138,7 @@ pub mod glue { pub left: CosmosIcs23V1CompressedExistenceProofData, pub right: CosmosIcs23V1CompressedExistenceProofData, } - ///`CosmosIcs23V1ExistenceProofData(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])` + /// `CosmosIcs23V1ExistenceProofData(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1155,7 +1155,7 @@ pub mod glue { pub leaf: CosmosIcs23V1LeafOpData, pub path: ::std::vec::Vec, } - ///`CosmosIcs23V1InnerOpData(uint8,bytes,bytes)` + /// `CosmosIcs23V1InnerOpData(uint8,bytes,bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1171,7 +1171,7 @@ pub mod glue { pub prefix: ::ethers::core::types::Bytes, pub suffix: ::ethers::core::types::Bytes, } - ///`CosmosIcs23V1InnerSpecData(int32[],int32,int32,int32,bytes,uint8)` + /// `CosmosIcs23V1InnerSpecData(int32[],int32,int32,int32,bytes,uint8)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1190,7 +1190,7 @@ pub mod glue { pub empty_child: ::ethers::core::types::Bytes, pub hash: u8, } - ///`CosmosIcs23V1LeafOpData(uint8,uint8,uint8,uint8,bytes)` + /// `CosmosIcs23V1LeafOpData(uint8,uint8,uint8,uint8,bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1208,7 +1208,7 @@ pub mod glue { pub length: u8, pub prefix: ::ethers::core::types::Bytes, } - ///`CosmosIcs23V1NonExistenceProofData(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]))` + /// `CosmosIcs23V1NonExistenceProofData(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]))` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1224,7 +1224,7 @@ pub mod glue { pub left: CosmosIcs23V1ExistenceProofData, pub right: CosmosIcs23V1ExistenceProofData, } - ///`CosmosIcs23V1ProofSpecData((uint8,uint8,uint8,uint8,bytes),(int32[],int32,int32,int32,bytes,uint8),int32,int32)` + /// `CosmosIcs23V1ProofSpecData((uint8,uint8,uint8,uint8,bytes),(int32[],int32,int32,int32,bytes,uint8),int32,int32)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1241,7 +1241,7 @@ pub mod glue { pub max_depth: i32, pub min_depth: i32, } - ///`GoogleProtobufDurationData(int64,int32)` + /// `GoogleProtobufDurationData(int64,int32)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1256,7 +1256,7 @@ pub mod glue { pub seconds: i64, pub nanos: i32, } - ///`IbcCoreCommitmentV1MerkleProofData(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])))[]),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[])))[],(uint8,bytes,bytes)[]))[])` + /// `IbcCoreCommitmentV1MerkleProofData(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),(uint8,bytes,bytes)[])))[]),(((bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[]),(bytes,bytes,(uint8,uint8,uint8,uint8,bytes),int32[])))[],(uint8,bytes,bytes)[]))[])` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1270,7 +1270,7 @@ pub mod glue { pub struct IbcCoreCommitmentV1MerkleProofData { pub proofs: ::std::vec::Vec, } - ///`IbcCoreCommitmentV1MerkleRootData(bytes)` + /// `IbcCoreCommitmentV1MerkleRootData(bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1284,7 +1284,7 @@ pub mod glue { pub struct IbcCoreCommitmentV1MerkleRootData { pub hash: ::ethers::core::types::Bytes, } - ///`IbcLightclientsTendermintV1ClientStateData(string,(uint64,uint64),(int64,int32),(int64,int32),(int64,int32),(uint64,uint64),(uint64,uint64),((uint8,uint8,uint8,uint8,bytes),(int32[],int32,int32,int32,bytes,uint8),int32,int32)[],string[],bool,bool)` + /// `IbcLightclientsTendermintV1ClientStateData(string,(uint64,uint64),(int64,int32),(int64,int32),(int64,int32),(uint64,uint64),(uint64,uint64),((uint8,uint8,uint8,uint8,bytes),(int32[],int32,int32,int32,bytes,uint8),int32,int32)[],string[],bool,bool)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1308,7 +1308,7 @@ pub mod glue { pub allow_update_after_expiry: bool, pub allow_update_after_misbehaviour: bool, } - ///`IbcLightclientsTendermintV1ConsensusStateData((int64,int64),(bytes),bytes)` + /// `IbcLightclientsTendermintV1ConsensusStateData((int64,int64),(bytes),bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1324,7 +1324,7 @@ pub mod glue { pub root: IbcCoreCommitmentV1MerkleRootData, pub next_validators_hash: ::ethers::core::types::Bytes, } - ///`IbcLightclientsTendermintV1FractionData(uint64,uint64)` + /// `IbcLightclientsTendermintV1FractionData(uint64,uint64)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1339,7 +1339,7 @@ pub mod glue { pub numerator: u64, pub denominator: u64, } - ///`IbcLightclientsTendermintV1HeaderData((((uint64,uint64),string,int64,(int64,int64),(bytes,(uint32,bytes)),bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes),(int64,int32,(bytes,(uint32,bytes)),(uint8,bytes,(int64,int64),bytes)[])),((bytes,(bytes,bytes,bytes),int64,int64)[],(bytes,(bytes,bytes,bytes),int64,int64),int64),(uint64,uint64),((bytes,(bytes,bytes,bytes),int64,int64)[],(bytes,(bytes,bytes,bytes),int64,int64),int64))` + /// `IbcLightclientsTendermintV1HeaderData((((uint64,uint64),string,int64,(int64,int64),(bytes,(uint32,bytes)),bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes),(int64,int32,(bytes,(uint32,bytes)),(uint8,bytes,(int64,int64),bytes)[])),((bytes,(bytes,bytes,bytes),int64,int64)[],(bytes,(bytes,bytes,bytes),int64,int64),int64),(uint64,uint64),((bytes,(bytes,bytes,bytes),int64,int64)[],(bytes,(bytes,bytes,bytes),int64,int64),int64))` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1356,7 +1356,7 @@ pub mod glue { pub trusted_height: IbcCoreClientV1HeightData, pub trusted_validators: TendermintTypesValidatorSetData, } - ///`OptimizedConsensusState(uint64,bytes32,bytes32)` + /// `OptimizedConsensusState(uint64,bytes32,bytes32)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1372,7 +1372,7 @@ pub mod glue { pub app_hash: [u8; 32], pub next_validators_hash: [u8; 32], } - ///`ProcessedMoment(uint256,uint256)` + /// `ProcessedMoment(uint256,uint256)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1387,7 +1387,7 @@ pub mod glue { pub timestamp: ::ethers::core::types::U256, pub height: ::ethers::core::types::U256, } - ///`TendermintCryptoPublicKeyData(bytes,bytes,bytes)` + /// `TendermintCryptoPublicKeyData(bytes,bytes,bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1403,7 +1403,7 @@ pub mod glue { pub secp_25_6k_1: ::ethers::core::types::Bytes, pub bn_254: ::ethers::core::types::Bytes, } - ///`TendermintTypesBlockIDData(bytes,(uint32,bytes))` + /// `TendermintTypesBlockIDData(bytes,(uint32,bytes))` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1418,7 +1418,7 @@ pub mod glue { pub hash: ::ethers::core::types::Bytes, pub part_set_header: TendermintTypesPartSetHeaderData, } - ///`TendermintTypesCanonicalBlockIDData(bytes,(uint32,bytes))` + /// `TendermintTypesCanonicalBlockIDData(bytes,(uint32,bytes))` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1433,7 +1433,7 @@ pub mod glue { pub hash: ::ethers::core::types::Bytes, pub part_set_header: TendermintTypesCanonicalPartSetHeaderData, } - ///`TendermintTypesCanonicalPartSetHeaderData(uint32,bytes)` + /// `TendermintTypesCanonicalPartSetHeaderData(uint32,bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1448,7 +1448,7 @@ pub mod glue { pub total: u32, pub hash: ::ethers::core::types::Bytes, } - ///`TendermintTypesCanonicalVoteData(uint8,int64,int64,(bytes,(uint32,bytes)),string)` + /// `TendermintTypesCanonicalVoteData(uint8,int64,int64,(bytes,(uint32,bytes)),string)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1466,7 +1466,7 @@ pub mod glue { pub block_id: TendermintTypesCanonicalBlockIDData, pub chain_id: ::std::string::String, } - ///`TendermintTypesCommitData(int64,int32,(bytes,(uint32,bytes)),(uint8,bytes,(int64,int64),bytes)[])` + /// `TendermintTypesCommitData(int64,int32,(bytes,(uint32,bytes)),(uint8,bytes,(int64,int64),bytes)[])` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1483,7 +1483,7 @@ pub mod glue { pub block_id: TendermintTypesBlockIDData, pub signatures: ::std::vec::Vec, } - ///`TendermintTypesCommitSigData(uint8,bytes,(int64,int64),bytes)` + /// `TendermintTypesCommitSigData(uint8,bytes,(int64,int64),bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1500,7 +1500,7 @@ pub mod glue { pub timestamp: GoogleProtobufTimestampData, pub signature: ::ethers::core::types::Bytes, } - ///`TendermintTypesHeaderData((uint64,uint64),string,int64,(int64,int64),(bytes,(uint32,bytes)),bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes)` + /// `TendermintTypesHeaderData((uint64,uint64),string,int64,(int64,int64),(bytes,(uint32,bytes)),bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1527,7 +1527,7 @@ pub mod glue { pub evidence_hash: ::ethers::core::types::Bytes, pub proposer_address: ::ethers::core::types::Bytes, } - ///`TendermintTypesPartSetHeaderData(uint32,bytes)` + /// `TendermintTypesPartSetHeaderData(uint32,bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1542,7 +1542,7 @@ pub mod glue { pub total: u32, pub hash: ::ethers::core::types::Bytes, } - ///`TendermintTypesSignedHeaderData(((uint64,uint64),string,int64,(int64,int64),(bytes,(uint32,bytes)),bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes),(int64,int32,(bytes,(uint32,bytes)),(uint8,bytes,(int64,int64),bytes)[]))` + /// `TendermintTypesSignedHeaderData(((uint64,uint64),string,int64,(int64,int64),(bytes,(uint32,bytes)),bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes,bytes),(int64,int32,(bytes,(uint32,bytes)),(uint8,bytes,(int64,int64),bytes)[]))` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1557,7 +1557,7 @@ pub mod glue { pub header: TendermintTypesHeaderData, pub commit: TendermintTypesCommitData, } - ///`Data(bytes,(bytes,bytes,bytes),int64,int64)` + /// `Data(bytes,(bytes,bytes,bytes),int64,int64)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1574,7 +1574,7 @@ pub mod glue { pub voting_power: i64, pub proposer_priority: i64, } - ///`TendermintTypesValidatorSetData((bytes,(bytes,bytes,bytes),int64,int64)[],(bytes,(bytes,bytes,bytes),int64,int64),int64)` + /// `TendermintTypesValidatorSetData((bytes,(bytes,bytes,bytes),int64,int64)[],(bytes,(bytes,bytes,bytes),int64,int64),int64)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1590,7 +1590,7 @@ pub mod glue { pub proposer: Data, pub total_voting_power: i64, } - ///`TendermintVersionConsensusData(uint64,uint64)` + /// `TendermintVersionConsensusData(uint64,uint64)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1605,7 +1605,7 @@ pub mod glue { pub block: u64, pub app: u64, } - ///`UnionIbcLightclientsCometblsV1ClientStateData(string,uint64,uint64,uint64,(uint64,uint64),(uint64,uint64))` + /// `UnionIbcLightclientsCometblsV1ClientStateData(string,uint64,uint64,uint64,(uint64,uint64),(uint64,uint64))` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1624,7 +1624,7 @@ pub mod glue { pub frozen_height: IbcCoreClientV1HeightData, pub latest_height: IbcCoreClientV1HeightData, } - ///`UnionIbcLightclientsCometblsV1ConsensusStateData(uint64,(bytes),bytes)` + /// `UnionIbcLightclientsCometblsV1ConsensusStateData(uint64,(bytes),bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/generated/rust/contracts/src/i_light_client.rs b/generated/rust/contracts/src/i_light_client.rs index 2c9bad7a39..05a83c91de 100644 --- a/generated/rust/contracts/src/i_light_client.rs +++ b/generated/rust/contracts/src/i_light_client.rs @@ -415,7 +415,7 @@ pub mod i_light_client { fallback: false, } } - ///The parsed JSON ABI of the contract. + /// The parsed JSON ABI of the contract. #[cfg(feature = "providers")] pub static ILIGHTCLIENT_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); @@ -462,7 +462,7 @@ pub mod i_light_client { client, )) } - ///Calls the contract's `createClient` (0x2629636b) function + /// Calls the contract's `createClient` (0x2629636b) function pub fn create_client( &self, client_id: ::std::string::String, @@ -477,7 +477,7 @@ pub mod i_light_client { ) .expect("method not found (this should never happen)") } - ///Calls the contract's `getClientState` (0x76c81c42) function + /// Calls the contract's `getClientState` (0x76c81c42) function pub fn get_client_state( &self, client_id: ::std::string::String, @@ -486,7 +486,7 @@ pub mod i_light_client { .method_hash([118, 200, 28, 66], client_id) .expect("method not found (this should never happen)") } - ///Calls the contract's `getConsensusState` (0x6cf44bf4) function + /// Calls the contract's `getConsensusState` (0x6cf44bf4) function pub fn get_consensus_state( &self, client_id: ::std::string::String, @@ -496,7 +496,7 @@ pub mod i_light_client { .method_hash([108, 244, 75, 244], (client_id, height)) .expect("method not found (this should never happen)") } - ///Calls the contract's `getLatestHeight` (0x329681d0) function + /// Calls the contract's `getLatestHeight` (0x329681d0) function pub fn get_latest_height( &self, client_id: ::std::string::String, @@ -505,7 +505,7 @@ pub mod i_light_client { .method_hash([50, 150, 129, 208], client_id) .expect("method not found (this should never happen)") } - ///Calls the contract's `getTimestampAtHeight` (0x4b0bbdc4) function + /// Calls the contract's `getTimestampAtHeight` (0x4b0bbdc4) function pub fn get_timestamp_at_height( &self, client_id: ::std::string::String, @@ -515,7 +515,7 @@ pub mod i_light_client { .method_hash([75, 11, 189, 196], (client_id, height)) .expect("method not found (this should never happen)") } - ///Calls the contract's `updateClient` (0x6fbf8079) function + /// Calls the contract's `updateClient` (0x6fbf8079) function pub fn update_client( &self, client_id: ::std::string::String, @@ -528,7 +528,7 @@ pub mod i_light_client { .method_hash([111, 191, 128, 121], (client_id, client_message_bytes)) .expect("method not found (this should never happen)") } - ///Calls the contract's `verifyMembership` (0xf9bb5a51) function + /// Calls the contract's `verifyMembership` (0xf9bb5a51) function pub fn verify_membership( &self, client_id: ::std::string::String, @@ -556,7 +556,7 @@ pub mod i_light_client { ) .expect("method not found (this should never happen)") } - ///Calls the contract's `verifyNonMembership` (0x999fbbb3) function + /// Calls the contract's `verifyNonMembership` (0x999fbbb3) function pub fn verify_non_membership( &self, client_id: ::std::string::String, @@ -589,7 +589,7 @@ pub mod i_light_client { Self::new(contract.address(), contract.client()) } } - ///Container type for all input parameters for the `createClient` function with signature `createClient(string,bytes,bytes)` and selector `0x2629636b` + /// Container type for all input parameters for the `createClient` function with signature `createClient(string,bytes,bytes)` and selector `0x2629636b` #[derive( Clone, ::ethers::contract::EthCall, @@ -606,7 +606,7 @@ pub mod i_light_client { pub client_state_bytes: ::ethers::core::types::Bytes, pub consensus_state_bytes: ::ethers::core::types::Bytes, } - ///Container type for all input parameters for the `getClientState` function with signature `getClientState(string)` and selector `0x76c81c42` + /// Container type for all input parameters for the `getClientState` function with signature `getClientState(string)` and selector `0x76c81c42` #[derive( Clone, ::ethers::contract::EthCall, @@ -621,7 +621,7 @@ pub mod i_light_client { pub struct GetClientStateCall { pub client_id: ::std::string::String, } - ///Container type for all input parameters for the `getConsensusState` function with signature `getConsensusState(string,(uint64,uint64))` and selector `0x6cf44bf4` + /// Container type for all input parameters for the `getConsensusState` function with signature `getConsensusState(string,(uint64,uint64))` and selector `0x6cf44bf4` #[derive( Clone, ::ethers::contract::EthCall, @@ -640,7 +640,7 @@ pub mod i_light_client { pub client_id: ::std::string::String, pub height: IbcCoreClientV1HeightData, } - ///Container type for all input parameters for the `getLatestHeight` function with signature `getLatestHeight(string)` and selector `0x329681d0` + /// Container type for all input parameters for the `getLatestHeight` function with signature `getLatestHeight(string)` and selector `0x329681d0` #[derive( Clone, ::ethers::contract::EthCall, @@ -655,7 +655,7 @@ pub mod i_light_client { pub struct GetLatestHeightCall { pub client_id: ::std::string::String, } - ///Container type for all input parameters for the `getTimestampAtHeight` function with signature `getTimestampAtHeight(string,(uint64,uint64))` and selector `0x4b0bbdc4` + /// Container type for all input parameters for the `getTimestampAtHeight` function with signature `getTimestampAtHeight(string,(uint64,uint64))` and selector `0x4b0bbdc4` #[derive( Clone, ::ethers::contract::EthCall, @@ -674,7 +674,7 @@ pub mod i_light_client { pub client_id: ::std::string::String, pub height: IbcCoreClientV1HeightData, } - ///Container type for all input parameters for the `updateClient` function with signature `updateClient(string,bytes)` and selector `0x6fbf8079` + /// Container type for all input parameters for the `updateClient` function with signature `updateClient(string,bytes)` and selector `0x6fbf8079` #[derive( Clone, ::ethers::contract::EthCall, @@ -690,7 +690,7 @@ pub mod i_light_client { pub client_id: ::std::string::String, pub client_message_bytes: ::ethers::core::types::Bytes, } - ///Container type for all input parameters for the `verifyMembership` function with signature `verifyMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes,bytes)` and selector `0xf9bb5a51` + /// Container type for all input parameters for the `verifyMembership` function with signature `verifyMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes,bytes)` and selector `0xf9bb5a51` #[derive( Clone, ::ethers::contract::EthCall, @@ -715,7 +715,7 @@ pub mod i_light_client { pub path: ::ethers::core::types::Bytes, pub value: ::ethers::core::types::Bytes, } - ///Container type for all input parameters for the `verifyNonMembership` function with signature `verifyNonMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes)` and selector `0x999fbbb3` + /// Container type for all input parameters for the `verifyNonMembership` function with signature `verifyNonMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes)` and selector `0x999fbbb3` #[derive( Clone, ::ethers::contract::EthCall, @@ -739,7 +739,7 @@ pub mod i_light_client { pub prefix: ::ethers::core::types::Bytes, pub path: ::ethers::core::types::Bytes, } - ///Container type for all of the contract's call + /// Container type for all of the contract's call #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum ILightClientCalls { CreateClient(CreateClientCall), @@ -869,7 +869,7 @@ pub mod i_light_client { Self::VerifyNonMembership(value) } } - ///Container type for all return fields from the `createClient` function with signature `createClient(string,bytes,bytes)` and selector `0x2629636b` + /// Container type for all return fields from the `createClient` function with signature `createClient(string,bytes,bytes)` and selector `0x2629636b` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -885,7 +885,7 @@ pub mod i_light_client { pub update: ConsensusStateUpdate, pub ok: bool, } - ///Container type for all return fields from the `getClientState` function with signature `getClientState(string)` and selector `0x76c81c42` + /// Container type for all return fields from the `getClientState` function with signature `getClientState(string)` and selector `0x76c81c42` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -897,7 +897,7 @@ pub mod i_light_client { Hash, )] pub struct GetClientStateReturn(pub ::ethers::core::types::Bytes); - ///Container type for all return fields from the `getConsensusState` function with signature `getConsensusState(string,(uint64,uint64))` and selector `0x6cf44bf4` + /// Container type for all return fields from the `getConsensusState` function with signature `getConsensusState(string,(uint64,uint64))` and selector `0x6cf44bf4` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -909,7 +909,7 @@ pub mod i_light_client { Hash, )] pub struct GetConsensusStateReturn(pub ::ethers::core::types::Bytes); - ///Container type for all return fields from the `getLatestHeight` function with signature `getLatestHeight(string)` and selector `0x329681d0` + /// Container type for all return fields from the `getLatestHeight` function with signature `getLatestHeight(string)` and selector `0x329681d0` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -921,7 +921,7 @@ pub mod i_light_client { Hash, )] pub struct GetLatestHeightReturn(pub IbcCoreClientV1HeightData); - ///Container type for all return fields from the `getTimestampAtHeight` function with signature `getTimestampAtHeight(string,(uint64,uint64))` and selector `0x4b0bbdc4` + /// Container type for all return fields from the `getTimestampAtHeight` function with signature `getTimestampAtHeight(string,(uint64,uint64))` and selector `0x4b0bbdc4` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -933,7 +933,7 @@ pub mod i_light_client { Hash, )] pub struct GetTimestampAtHeightReturn(pub u64); - ///Container type for all return fields from the `updateClient` function with signature `updateClient(string,bytes)` and selector `0x6fbf8079` + /// Container type for all return fields from the `updateClient` function with signature `updateClient(string,bytes)` and selector `0x6fbf8079` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -948,7 +948,7 @@ pub mod i_light_client { pub client_state_commitment: [u8; 32], pub updates: ::std::vec::Vec, } - ///Container type for all return fields from the `verifyMembership` function with signature `verifyMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes,bytes)` and selector `0xf9bb5a51` + /// Container type for all return fields from the `verifyMembership` function with signature `verifyMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes,bytes)` and selector `0xf9bb5a51` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -960,7 +960,7 @@ pub mod i_light_client { Hash, )] pub struct VerifyMembershipReturn(pub bool); - ///Container type for all return fields from the `verifyNonMembership` function with signature `verifyNonMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes)` and selector `0x999fbbb3` + /// Container type for all return fields from the `verifyNonMembership` function with signature `verifyNonMembership(string,(uint64,uint64),uint64,uint64,bytes,bytes,bytes)` and selector `0x999fbbb3` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/generated/rust/contracts/src/ibc_channel_handshake.rs b/generated/rust/contracts/src/ibc_channel_handshake.rs index 31d5517dd6..62d62ed4ae 100644 --- a/generated/rust/contracts/src/ibc_channel_handshake.rs +++ b/generated/rust/contracts/src/ibc_channel_handshake.rs @@ -814,7 +814,7 @@ pub mod ibc_channel_handshake { fallback: false, } } - ///The parsed JSON ABI of the contract. + /// The parsed JSON ABI of the contract. #[cfg(feature = "providers")] pub static IBCCHANNELHANDSHAKE_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); @@ -914,7 +914,7 @@ pub mod ibc_channel_handshake { let deployer = ::ethers::contract::ContractDeployer::new(deployer); Ok(deployer) } - ///Calls the contract's `COMMITMENT_PREFIX` (0xa9550dac) function + /// Calls the contract's `COMMITMENT_PREFIX` (0xa9550dac) function pub fn commitment_prefix( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -922,7 +922,7 @@ pub mod ibc_channel_handshake { .method_hash([169, 85, 13, 172], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `capabilities` (0x5717bcf5) function + /// Calls the contract's `capabilities` (0x5717bcf5) function pub fn capabilities( &self, p0: ::std::string::String, @@ -931,7 +931,7 @@ pub mod ibc_channel_handshake { .method_hash([87, 23, 188, 245], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelCapabilityPath` (0x3bc3339f) function + /// Calls the contract's `channelCapabilityPath` (0x3bc3339f) function pub fn channel_capability_path( &self, port_id: ::std::string::String, @@ -941,7 +941,7 @@ pub mod ibc_channel_handshake { .method_hash([59, 195, 51, 159], (port_id, channel_id)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelCloseConfirm` (0x6e92edaf) function + /// Calls the contract's `channelCloseConfirm` (0x6e92edaf) function pub fn channel_close_confirm( &self, msg: MsgChannelCloseConfirm, @@ -950,7 +950,7 @@ pub mod ibc_channel_handshake { .method_hash([110, 146, 237, 175], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelCloseInit` (0x96549d92) function + /// Calls the contract's `channelCloseInit` (0x96549d92) function pub fn channel_close_init( &self, msg: MsgChannelCloseInit, @@ -959,7 +959,7 @@ pub mod ibc_channel_handshake { .method_hash([150, 84, 157, 146], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelOpenAck` (0xdeff27b9) function + /// Calls the contract's `channelOpenAck` (0xdeff27b9) function pub fn channel_open_ack( &self, msg: MsgChannelOpenAck, @@ -968,7 +968,7 @@ pub mod ibc_channel_handshake { .method_hash([222, 255, 39, 185], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelOpenConfirm` (0xf52deded) function + /// Calls the contract's `channelOpenConfirm` (0xf52deded) function pub fn channel_open_confirm( &self, msg: MsgChannelOpenConfirm, @@ -977,7 +977,7 @@ pub mod ibc_channel_handshake { .method_hash([245, 45, 237, 237], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelOpenInit` (0x25035747) function + /// Calls the contract's `channelOpenInit` (0x25035747) function pub fn channel_open_init( &self, msg: MsgChannelOpenInit, @@ -986,7 +986,7 @@ pub mod ibc_channel_handshake { .method_hash([37, 3, 87, 71], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelOpenTry` (0x8b627bca) function + /// Calls the contract's `channelOpenTry` (0x8b627bca) function pub fn channel_open_try( &self, msg: MsgChannelOpenTry, @@ -995,7 +995,7 @@ pub mod ibc_channel_handshake { .method_hash([139, 98, 123, 202], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channels` (0x5b3de260) function + /// Calls the contract's `channels` (0x5b3de260) function pub fn channels( &self, p0: ::std::string::String, @@ -1013,7 +1013,7 @@ pub mod ibc_channel_handshake { .method_hash([91, 61, 226, 96], (p0, p1)) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientImpls` (0xd1297b8d) function + /// Calls the contract's `clientImpls` (0xd1297b8d) function pub fn client_impls( &self, p0: ::std::string::String, @@ -1022,7 +1022,7 @@ pub mod ibc_channel_handshake { .method_hash([209, 41, 123, 141], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientRegistry` (0x990491a5) function + /// Calls the contract's `clientRegistry` (0x990491a5) function pub fn client_registry( &self, p0: ::std::string::String, @@ -1031,7 +1031,7 @@ pub mod ibc_channel_handshake { .method_hash([153, 4, 145, 165], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientTypes` (0xc2380105) function + /// Calls the contract's `clientTypes` (0xc2380105) function pub fn client_types( &self, p0: ::std::string::String, @@ -1040,7 +1040,7 @@ pub mod ibc_channel_handshake { .method_hash([194, 56, 1, 5], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `commitments` (0x839df945) function + /// Calls the contract's `commitments` (0x839df945) function pub fn commitments( &self, p0: [u8; 32], @@ -1049,7 +1049,7 @@ pub mod ibc_channel_handshake { .method_hash([131, 157, 249, 69], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `connections` (0x31973f00) function + /// Calls the contract's `connections` (0x31973f00) function pub fn connections( &self, p0: ::std::string::String, @@ -1066,7 +1066,7 @@ pub mod ibc_channel_handshake { .method_hash([49, 151, 63, 0], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `getClient` (0x7eb78932) function + /// Calls the contract's `getClient` (0x7eb78932) function pub fn get_client( &self, client_id: ::std::string::String, @@ -1075,7 +1075,7 @@ pub mod ibc_channel_handshake { .method_hash([126, 183, 137, 50], client_id) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextChannelSequencePath` (0x8669fd15) function + /// Calls the contract's `nextChannelSequencePath` (0x8669fd15) function pub fn next_channel_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1083,7 +1083,7 @@ pub mod ibc_channel_handshake { .method_hash([134, 105, 253, 21], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextClientSequencePath` (0x990c3888) function + /// Calls the contract's `nextClientSequencePath` (0x990c3888) function pub fn next_client_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1091,7 +1091,7 @@ pub mod ibc_channel_handshake { .method_hash([153, 12, 56, 136], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextConnectionSequencePath` (0x46807086) function + /// Calls the contract's `nextConnectionSequencePath` (0x46807086) function pub fn next_connection_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1099,42 +1099,42 @@ pub mod ibc_channel_handshake { .method_hash([70, 128, 112, 134], ()) .expect("method not found (this should never happen)") } - ///Gets the contract's `ChannelCloseConfirm` event + /// Gets the contract's `ChannelCloseConfirm` event pub fn channel_close_confirm_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ChannelCloseConfirmFilter> { self.0.event() } - ///Gets the contract's `ChannelCloseInit` event + /// Gets the contract's `ChannelCloseInit` event pub fn channel_close_init_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ChannelCloseInitFilter> { self.0.event() } - ///Gets the contract's `ChannelOpenAck` event + /// Gets the contract's `ChannelOpenAck` event pub fn channel_open_ack_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ChannelOpenAckFilter> { self.0.event() } - ///Gets the contract's `ChannelOpenConfirm` event + /// Gets the contract's `ChannelOpenConfirm` event pub fn channel_open_confirm_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ChannelOpenConfirmFilter> { self.0.event() } - ///Gets the contract's `ChannelOpenInit` event + /// Gets the contract's `ChannelOpenInit` event pub fn channel_open_init_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ChannelOpenInitFilter> { self.0.event() } - ///Gets the contract's `ChannelOpenTry` event + /// Gets the contract's `ChannelOpenTry` event pub fn channel_open_try_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ChannelOpenTryFilter> @@ -1158,7 +1158,7 @@ pub mod ibc_channel_handshake { Self::new(contract.address(), contract.client()) } } - ///Custom Error type `ErrCapabilityAlreadyClaimed` with signature `ErrCapabilityAlreadyClaimed()` and selector `0x463eec90` + /// Custom Error type `ErrCapabilityAlreadyClaimed` with signature `ErrCapabilityAlreadyClaimed()` and selector `0x463eec90` #[derive( Clone, ::ethers::contract::EthError, @@ -1174,7 +1174,7 @@ pub mod ibc_channel_handshake { abi = "ErrCapabilityAlreadyClaimed()" )] pub struct ErrCapabilityAlreadyClaimed; - ///Custom Error type `ErrClientNotFound` with signature `ErrClientNotFound()` and selector `0xb6c71f7d` + /// Custom Error type `ErrClientNotFound` with signature `ErrClientNotFound()` and selector `0xb6c71f7d` #[derive( Clone, ::ethers::contract::EthError, @@ -1187,7 +1187,7 @@ pub mod ibc_channel_handshake { )] #[etherror(name = "ErrClientNotFound", abi = "ErrClientNotFound()")] pub struct ErrClientNotFound; - ///Custom Error type `ErrConnNotSingleHop` with signature `ErrConnNotSingleHop()` and selector `0xd4377a90` + /// Custom Error type `ErrConnNotSingleHop` with signature `ErrConnNotSingleHop()` and selector `0xd4377a90` #[derive( Clone, ::ethers::contract::EthError, @@ -1200,7 +1200,7 @@ pub mod ibc_channel_handshake { )] #[etherror(name = "ErrConnNotSingleHop", abi = "ErrConnNotSingleHop()")] pub struct ErrConnNotSingleHop; - ///Custom Error type `ErrConnNotSingleVersion` with signature `ErrConnNotSingleVersion()` and selector `0xcc6fef24` + /// Custom Error type `ErrConnNotSingleVersion` with signature `ErrConnNotSingleVersion()` and selector `0xcc6fef24` #[derive( Clone, ::ethers::contract::EthError, @@ -1213,7 +1213,7 @@ pub mod ibc_channel_handshake { )] #[etherror(name = "ErrConnNotSingleVersion", abi = "ErrConnNotSingleVersion()")] pub struct ErrConnNotSingleVersion; - ///Custom Error type `ErrCounterpartyChannelNotEmpty` with signature `ErrCounterpartyChannelNotEmpty()` and selector `0x32699362` + /// Custom Error type `ErrCounterpartyChannelNotEmpty` with signature `ErrCounterpartyChannelNotEmpty()` and selector `0x32699362` #[derive( Clone, ::ethers::contract::EthError, @@ -1229,7 +1229,7 @@ pub mod ibc_channel_handshake { abi = "ErrCounterpartyChannelNotEmpty()" )] pub struct ErrCounterpartyChannelNotEmpty; - ///Custom Error type `ErrInvalidChannelState` with signature `ErrInvalidChannelState()` and selector `0x96d09146` + /// Custom Error type `ErrInvalidChannelState` with signature `ErrInvalidChannelState()` and selector `0x96d09146` #[derive( Clone, ::ethers::contract::EthError, @@ -1242,7 +1242,7 @@ pub mod ibc_channel_handshake { )] #[etherror(name = "ErrInvalidChannelState", abi = "ErrInvalidChannelState()")] pub struct ErrInvalidChannelState; - ///Custom Error type `ErrInvalidConnectionState` with signature `ErrInvalidConnectionState()` and selector `0x8ca98990` + /// Custom Error type `ErrInvalidConnectionState` with signature `ErrInvalidConnectionState()` and selector `0x8ca98990` #[derive( Clone, ::ethers::contract::EthError, @@ -1258,7 +1258,7 @@ pub mod ibc_channel_handshake { abi = "ErrInvalidConnectionState()" )] pub struct ErrInvalidConnectionState; - ///Custom Error type `ErrInvalidHexAddress` with signature `ErrInvalidHexAddress()` and selector `0xfe6f1570` + /// Custom Error type `ErrInvalidHexAddress` with signature `ErrInvalidHexAddress()` and selector `0xfe6f1570` #[derive( Clone, ::ethers::contract::EthError, @@ -1271,7 +1271,7 @@ pub mod ibc_channel_handshake { )] #[etherror(name = "ErrInvalidHexAddress", abi = "ErrInvalidHexAddress()")] pub struct ErrInvalidHexAddress; - ///Custom Error type `ErrInvalidProof` with signature `ErrInvalidProof()` and selector `0x14209932` + /// Custom Error type `ErrInvalidProof` with signature `ErrInvalidProof()` and selector `0x14209932` #[derive( Clone, ::ethers::contract::EthError, @@ -1284,7 +1284,7 @@ pub mod ibc_channel_handshake { )] #[etherror(name = "ErrInvalidProof", abi = "ErrInvalidProof()")] pub struct ErrInvalidProof; - ///Custom Error type `ErrUnsupportedFeature` with signature `ErrUnsupportedFeature()` and selector `0x5d191fae` + /// Custom Error type `ErrUnsupportedFeature` with signature `ErrUnsupportedFeature()` and selector `0x5d191fae` #[derive( Clone, ::ethers::contract::EthError, @@ -1297,7 +1297,7 @@ pub mod ibc_channel_handshake { )] #[etherror(name = "ErrUnsupportedFeature", abi = "ErrUnsupportedFeature()")] pub struct ErrUnsupportedFeature; - ///Container type for all of the contract's custom errors + /// Container type for all of the contract's custom errors #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum IBCChannelHandshakeErrors { ErrCapabilityAlreadyClaimed(ErrCapabilityAlreadyClaimed), @@ -1538,6 +1538,8 @@ pub mod ibc_channel_handshake { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent( name = "ChannelCloseConfirm", @@ -1556,6 +1558,8 @@ pub mod ibc_channel_handshake { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent(name = "ChannelCloseInit", abi = "ChannelCloseInit(string,string)")] pub struct ChannelCloseInitFilter { @@ -1571,6 +1575,8 @@ pub mod ibc_channel_handshake { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent( name = "ChannelOpenAck", @@ -1592,6 +1598,8 @@ pub mod ibc_channel_handshake { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent( name = "ChannelOpenConfirm", @@ -1613,6 +1621,8 @@ pub mod ibc_channel_handshake { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent( name = "ChannelOpenInit", @@ -1634,6 +1644,8 @@ pub mod ibc_channel_handshake { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent( name = "ChannelOpenTry", @@ -1647,8 +1659,17 @@ pub mod ibc_channel_handshake { pub connection_id: ::std::string::String, pub version: ::std::string::String, } - ///Container type for all of the contract's events - #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + /// Container type for all of the contract's events + #[derive( + Clone, + ::ethers::contract::EthAbiType, + Debug, + PartialEq, + Eq, + Hash, + ::serde::Serialize, + ::serde::Deserialize, + )] pub enum IBCChannelHandshakeEvents { ChannelCloseConfirmFilter(ChannelCloseConfirmFilter), ChannelCloseInitFilter(ChannelCloseInitFilter), @@ -1726,7 +1747,7 @@ pub mod ibc_channel_handshake { Self::ChannelOpenTryFilter(value) } } - ///Container type for all input parameters for the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` + /// Container type for all input parameters for the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` #[derive( Clone, ::ethers::contract::EthCall, @@ -1739,7 +1760,7 @@ pub mod ibc_channel_handshake { )] #[ethcall(name = "COMMITMENT_PREFIX", abi = "COMMITMENT_PREFIX()")] pub struct CommitmentPrefixCall; - ///Container type for all input parameters for the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` + /// Container type for all input parameters for the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` #[derive( Clone, ::ethers::contract::EthCall, @@ -1752,7 +1773,7 @@ pub mod ibc_channel_handshake { )] #[ethcall(name = "capabilities", abi = "capabilities(string)")] pub struct CapabilitiesCall(pub ::std::string::String); - ///Container type for all input parameters for the `channelCapabilityPath` function with signature `channelCapabilityPath(string,string)` and selector `0x3bc3339f` + /// Container type for all input parameters for the `channelCapabilityPath` function with signature `channelCapabilityPath(string,string)` and selector `0x3bc3339f` #[derive( Clone, ::ethers::contract::EthCall, @@ -1771,7 +1792,7 @@ pub mod ibc_channel_handshake { pub port_id: ::std::string::String, pub channel_id: ::std::string::String, } - ///Container type for all input parameters for the `channelCloseConfirm` function with signature `channelCloseConfirm((string,string,bytes,(uint64,uint64),address))` and selector `0x6e92edaf` + /// Container type for all input parameters for the `channelCloseConfirm` function with signature `channelCloseConfirm((string,string,bytes,(uint64,uint64),address))` and selector `0x6e92edaf` #[derive( Clone, ::ethers::contract::EthCall, @@ -1789,7 +1810,7 @@ pub mod ibc_channel_handshake { pub struct ChannelCloseConfirmCall { pub msg: MsgChannelCloseConfirm, } - ///Container type for all input parameters for the `channelCloseInit` function with signature `channelCloseInit((string,string,address))` and selector `0x96549d92` + /// Container type for all input parameters for the `channelCloseInit` function with signature `channelCloseInit((string,string,address))` and selector `0x96549d92` #[derive( Clone, ::ethers::contract::EthCall, @@ -1807,7 +1828,7 @@ pub mod ibc_channel_handshake { pub struct ChannelCloseInitCall { pub msg: MsgChannelCloseInit, } - ///Container type for all input parameters for the `channelOpenAck` function with signature `channelOpenAck((string,string,string,string,bytes,(uint64,uint64),address))` and selector `0xdeff27b9` + /// Container type for all input parameters for the `channelOpenAck` function with signature `channelOpenAck((string,string,string,string,bytes,(uint64,uint64),address))` and selector `0xdeff27b9` #[derive( Clone, ::ethers::contract::EthCall, @@ -1825,7 +1846,7 @@ pub mod ibc_channel_handshake { pub struct ChannelOpenAckCall { pub msg: MsgChannelOpenAck, } - ///Container type for all input parameters for the `channelOpenConfirm` function with signature `channelOpenConfirm((string,string,bytes,(uint64,uint64),address))` and selector `0xf52deded` + /// Container type for all input parameters for the `channelOpenConfirm` function with signature `channelOpenConfirm((string,string,bytes,(uint64,uint64),address))` and selector `0xf52deded` #[derive( Clone, ::ethers::contract::EthCall, @@ -1843,7 +1864,7 @@ pub mod ibc_channel_handshake { pub struct ChannelOpenConfirmCall { pub msg: MsgChannelOpenConfirm, } - ///Container type for all input parameters for the `channelOpenInit` function with signature `channelOpenInit((string,(uint8,uint8,(string,string),string[],string),address))` and selector `0x25035747` + /// Container type for all input parameters for the `channelOpenInit` function with signature `channelOpenInit((string,(uint8,uint8,(string,string),string[],string),address))` and selector `0x25035747` #[derive( Clone, ::ethers::contract::EthCall, @@ -1861,7 +1882,7 @@ pub mod ibc_channel_handshake { pub struct ChannelOpenInitCall { pub msg: MsgChannelOpenInit, } - ///Container type for all input parameters for the `channelOpenTry` function with signature `channelOpenTry((string,(uint8,uint8,(string,string),string[],string),string,bytes,(uint64,uint64),address))` and selector `0x8b627bca` + /// Container type for all input parameters for the `channelOpenTry` function with signature `channelOpenTry((string,(uint8,uint8,(string,string),string[],string),string,bytes,(uint64,uint64),address))` and selector `0x8b627bca` #[derive( Clone, ::ethers::contract::EthCall, @@ -1879,7 +1900,7 @@ pub mod ibc_channel_handshake { pub struct ChannelOpenTryCall { pub msg: MsgChannelOpenTry, } - ///Container type for all input parameters for the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` + /// Container type for all input parameters for the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` #[derive( Clone, ::ethers::contract::EthCall, @@ -1892,7 +1913,7 @@ pub mod ibc_channel_handshake { )] #[ethcall(name = "channels", abi = "channels(string,string)")] pub struct ChannelsCall(pub ::std::string::String, pub ::std::string::String); - ///Container type for all input parameters for the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` + /// Container type for all input parameters for the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` #[derive( Clone, ::ethers::contract::EthCall, @@ -1905,7 +1926,7 @@ pub mod ibc_channel_handshake { )] #[ethcall(name = "clientImpls", abi = "clientImpls(string)")] pub struct ClientImplsCall(pub ::std::string::String); - ///Container type for all input parameters for the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` + /// Container type for all input parameters for the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` #[derive( Clone, ::ethers::contract::EthCall, @@ -1918,7 +1939,7 @@ pub mod ibc_channel_handshake { )] #[ethcall(name = "clientRegistry", abi = "clientRegistry(string)")] pub struct ClientRegistryCall(pub ::std::string::String); - ///Container type for all input parameters for the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` + /// Container type for all input parameters for the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` #[derive( Clone, ::ethers::contract::EthCall, @@ -1931,7 +1952,7 @@ pub mod ibc_channel_handshake { )] #[ethcall(name = "clientTypes", abi = "clientTypes(string)")] pub struct ClientTypesCall(pub ::std::string::String); - ///Container type for all input parameters for the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` + /// Container type for all input parameters for the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` #[derive( Clone, ::ethers::contract::EthCall, @@ -1944,7 +1965,7 @@ pub mod ibc_channel_handshake { )] #[ethcall(name = "commitments", abi = "commitments(bytes32)")] pub struct CommitmentsCall(pub [u8; 32]); - ///Container type for all input parameters for the `connections` function with signature `connections(string)` and selector `0x31973f00` + /// Container type for all input parameters for the `connections` function with signature `connections(string)` and selector `0x31973f00` #[derive( Clone, ::ethers::contract::EthCall, @@ -1957,7 +1978,7 @@ pub mod ibc_channel_handshake { )] #[ethcall(name = "connections", abi = "connections(string)")] pub struct ConnectionsCall(pub ::std::string::String); - ///Container type for all input parameters for the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` + /// Container type for all input parameters for the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` #[derive( Clone, ::ethers::contract::EthCall, @@ -1972,7 +1993,7 @@ pub mod ibc_channel_handshake { pub struct GetClientCall { pub client_id: ::std::string::String, } - ///Container type for all input parameters for the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` + /// Container type for all input parameters for the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` #[derive( Clone, ::ethers::contract::EthCall, @@ -1985,7 +2006,7 @@ pub mod ibc_channel_handshake { )] #[ethcall(name = "nextChannelSequencePath", abi = "nextChannelSequencePath()")] pub struct NextChannelSequencePathCall; - ///Container type for all input parameters for the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` + /// Container type for all input parameters for the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` #[derive( Clone, ::ethers::contract::EthCall, @@ -1998,7 +2019,7 @@ pub mod ibc_channel_handshake { )] #[ethcall(name = "nextClientSequencePath", abi = "nextClientSequencePath()")] pub struct NextClientSequencePathCall; - ///Container type for all input parameters for the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` + /// Container type for all input parameters for the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` #[derive( Clone, ::ethers::contract::EthCall, @@ -2014,7 +2035,7 @@ pub mod ibc_channel_handshake { abi = "nextConnectionSequencePath()" )] pub struct NextConnectionSequencePathCall; - ///Container type for all of the contract's call + /// Container type for all of the contract's call #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum IBCChannelHandshakeCalls { CommitmentPrefix(CommitmentPrefixCall), @@ -2284,7 +2305,7 @@ pub mod ibc_channel_handshake { Self::NextConnectionSequencePath(value) } } - ///Container type for all return fields from the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` + /// Container type for all return fields from the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2296,7 +2317,7 @@ pub mod ibc_channel_handshake { Hash, )] pub struct CommitmentPrefixReturn(pub ::std::string::String); - ///Container type for all return fields from the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` + /// Container type for all return fields from the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2308,7 +2329,7 @@ pub mod ibc_channel_handshake { Hash, )] pub struct CapabilitiesReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `channelCapabilityPath` function with signature `channelCapabilityPath(string,string)` and selector `0x3bc3339f` + /// Container type for all return fields from the `channelCapabilityPath` function with signature `channelCapabilityPath(string,string)` and selector `0x3bc3339f` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2320,7 +2341,7 @@ pub mod ibc_channel_handshake { Hash, )] pub struct ChannelCapabilityPathReturn(pub ::std::string::String); - ///Container type for all return fields from the `channelOpenInit` function with signature `channelOpenInit((string,(uint8,uint8,(string,string),string[],string),address))` and selector `0x25035747` + /// Container type for all return fields from the `channelOpenInit` function with signature `channelOpenInit((string,(uint8,uint8,(string,string),string[],string),address))` and selector `0x25035747` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2332,7 +2353,7 @@ pub mod ibc_channel_handshake { Hash, )] pub struct ChannelOpenInitReturn(pub ::std::string::String); - ///Container type for all return fields from the `channelOpenTry` function with signature `channelOpenTry((string,(uint8,uint8,(string,string),string[],string),string,bytes,(uint64,uint64),address))` and selector `0x8b627bca` + /// Container type for all return fields from the `channelOpenTry` function with signature `channelOpenTry((string,(uint8,uint8,(string,string),string[],string),string,bytes,(uint64,uint64),address))` and selector `0x8b627bca` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2344,7 +2365,7 @@ pub mod ibc_channel_handshake { Hash, )] pub struct ChannelOpenTryReturn(pub ::std::string::String); - ///Container type for all return fields from the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` + /// Container type for all return fields from the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2361,7 +2382,7 @@ pub mod ibc_channel_handshake { pub counterparty: IbcCoreChannelV1CounterpartyData, pub version: ::std::string::String, } - ///Container type for all return fields from the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` + /// Container type for all return fields from the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2373,7 +2394,7 @@ pub mod ibc_channel_handshake { Hash, )] pub struct ClientImplsReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` + /// Container type for all return fields from the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2385,7 +2406,7 @@ pub mod ibc_channel_handshake { Hash, )] pub struct ClientRegistryReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` + /// Container type for all return fields from the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2397,7 +2418,7 @@ pub mod ibc_channel_handshake { Hash, )] pub struct ClientTypesReturn(pub ::std::string::String); - ///Container type for all return fields from the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` + /// Container type for all return fields from the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2409,7 +2430,7 @@ pub mod ibc_channel_handshake { Hash, )] pub struct CommitmentsReturn(pub [u8; 32]); - ///Container type for all return fields from the `connections` function with signature `connections(string)` and selector `0x31973f00` + /// Container type for all return fields from the `connections` function with signature `connections(string)` and selector `0x31973f00` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2426,7 +2447,7 @@ pub mod ibc_channel_handshake { pub counterparty: IbcCoreConnectionV1CounterpartyData, pub delay_period: u64, } - ///Container type for all return fields from the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` + /// Container type for all return fields from the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2438,7 +2459,7 @@ pub mod ibc_channel_handshake { Hash, )] pub struct GetClientReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` + /// Container type for all return fields from the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2450,7 +2471,7 @@ pub mod ibc_channel_handshake { Hash, )] pub struct NextChannelSequencePathReturn(pub [u8; 32]); - ///Container type for all return fields from the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` + /// Container type for all return fields from the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2462,7 +2483,7 @@ pub mod ibc_channel_handshake { Hash, )] pub struct NextClientSequencePathReturn(pub [u8; 32]); - ///Container type for all return fields from the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` + /// Container type for all return fields from the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/generated/rust/contracts/src/ibc_client.rs b/generated/rust/contracts/src/ibc_client.rs index f668f70159..299b170b6a 100644 --- a/generated/rust/contracts/src/ibc_client.rs +++ b/generated/rust/contracts/src/ibc_client.rs @@ -508,7 +508,7 @@ pub mod ibc_client { fallback: false, } } - ///The parsed JSON ABI of the contract. + /// The parsed JSON ABI of the contract. #[cfg(feature = "providers")] pub static IBCCLIENT_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); @@ -608,7 +608,7 @@ pub mod ibc_client { let deployer = ::ethers::contract::ContractDeployer::new(deployer); Ok(deployer) } - ///Calls the contract's `COMMITMENT_PREFIX` (0xa9550dac) function + /// Calls the contract's `COMMITMENT_PREFIX` (0xa9550dac) function pub fn commitment_prefix( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -616,7 +616,7 @@ pub mod ibc_client { .method_hash([169, 85, 13, 172], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `capabilities` (0x5717bcf5) function + /// Calls the contract's `capabilities` (0x5717bcf5) function pub fn capabilities( &self, p0: ::std::string::String, @@ -625,7 +625,7 @@ pub mod ibc_client { .method_hash([87, 23, 188, 245], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `channels` (0x5b3de260) function + /// Calls the contract's `channels` (0x5b3de260) function pub fn channels( &self, p0: ::std::string::String, @@ -643,7 +643,7 @@ pub mod ibc_client { .method_hash([91, 61, 226, 96], (p0, p1)) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientImpls` (0xd1297b8d) function + /// Calls the contract's `clientImpls` (0xd1297b8d) function pub fn client_impls( &self, p0: ::std::string::String, @@ -652,7 +652,7 @@ pub mod ibc_client { .method_hash([209, 41, 123, 141], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientRegistry` (0x990491a5) function + /// Calls the contract's `clientRegistry` (0x990491a5) function pub fn client_registry( &self, p0: ::std::string::String, @@ -661,7 +661,7 @@ pub mod ibc_client { .method_hash([153, 4, 145, 165], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientTypes` (0xc2380105) function + /// Calls the contract's `clientTypes` (0xc2380105) function pub fn client_types( &self, p0: ::std::string::String, @@ -670,7 +670,7 @@ pub mod ibc_client { .method_hash([194, 56, 1, 5], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `commitments` (0x839df945) function + /// Calls the contract's `commitments` (0x839df945) function pub fn commitments( &self, p0: [u8; 32], @@ -679,7 +679,7 @@ pub mod ibc_client { .method_hash([131, 157, 249, 69], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `connections` (0x31973f00) function + /// Calls the contract's `connections` (0x31973f00) function pub fn connections( &self, p0: ::std::string::String, @@ -696,7 +696,7 @@ pub mod ibc_client { .method_hash([49, 151, 63, 0], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `createClient` (0xfed12cbf) function + /// Calls the contract's `createClient` (0xfed12cbf) function pub fn create_client( &self, msg: MsgCreateClient, @@ -705,7 +705,7 @@ pub mod ibc_client { .method_hash([254, 209, 44, 191], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `getClient` (0x7eb78932) function + /// Calls the contract's `getClient` (0x7eb78932) function pub fn get_client( &self, client_id: ::std::string::String, @@ -714,7 +714,7 @@ pub mod ibc_client { .method_hash([126, 183, 137, 50], client_id) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextChannelSequencePath` (0x8669fd15) function + /// Calls the contract's `nextChannelSequencePath` (0x8669fd15) function pub fn next_channel_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -722,7 +722,7 @@ pub mod ibc_client { .method_hash([134, 105, 253, 21], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextClientSequencePath` (0x990c3888) function + /// Calls the contract's `nextClientSequencePath` (0x990c3888) function pub fn next_client_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -730,7 +730,7 @@ pub mod ibc_client { .method_hash([153, 12, 56, 136], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextConnectionSequencePath` (0x46807086) function + /// Calls the contract's `nextConnectionSequencePath` (0x46807086) function pub fn next_connection_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -738,7 +738,7 @@ pub mod ibc_client { .method_hash([70, 128, 112, 134], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `registerClient` (0x18c19870) function + /// Calls the contract's `registerClient` (0x18c19870) function pub fn register_client( &self, client_type: ::std::string::String, @@ -748,7 +748,7 @@ pub mod ibc_client { .method_hash([24, 193, 152, 112], (client_type, client)) .expect("method not found (this should never happen)") } - ///Calls the contract's `updateClient` (0xf5dd3745) function + /// Calls the contract's `updateClient` (0xf5dd3745) function pub fn update_client( &self, msg: MsgUpdateClient, @@ -757,21 +757,21 @@ pub mod ibc_client { .method_hash([245, 221, 55, 69], (msg,)) .expect("method not found (this should never happen)") } - ///Gets the contract's `ClientCreated` event + /// Gets the contract's `ClientCreated` event pub fn client_created_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ClientCreatedFilter> { self.0.event() } - ///Gets the contract's `ClientRegistered` event + /// Gets the contract's `ClientRegistered` event pub fn client_registered_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ClientRegisteredFilter> { self.0.event() } - ///Gets the contract's `ClientUpdated` event + /// Gets the contract's `ClientUpdated` event pub fn client_updated_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ClientUpdatedFilter> @@ -792,7 +792,7 @@ pub mod ibc_client { Self::new(contract.address(), contract.client()) } } - ///Custom Error type `ErrClientMustNotBeSelf` with signature `ErrClientMustNotBeSelf()` and selector `0x468ef787` + /// Custom Error type `ErrClientMustNotBeSelf` with signature `ErrClientMustNotBeSelf()` and selector `0x468ef787` #[derive( Clone, ::ethers::contract::EthError, @@ -805,7 +805,7 @@ pub mod ibc_client { )] #[etherror(name = "ErrClientMustNotBeSelf", abi = "ErrClientMustNotBeSelf()")] pub struct ErrClientMustNotBeSelf; - ///Custom Error type `ErrClientNotFound` with signature `ErrClientNotFound()` and selector `0xb6c71f7d` + /// Custom Error type `ErrClientNotFound` with signature `ErrClientNotFound()` and selector `0xb6c71f7d` #[derive( Clone, ::ethers::contract::EthError, @@ -818,7 +818,7 @@ pub mod ibc_client { )] #[etherror(name = "ErrClientNotFound", abi = "ErrClientNotFound()")] pub struct ErrClientNotFound; - ///Custom Error type `ErrClientTypeAlreadyExists` with signature `ErrClientTypeAlreadyExists()` and selector `0x0c7cc9b9` + /// Custom Error type `ErrClientTypeAlreadyExists` with signature `ErrClientTypeAlreadyExists()` and selector `0x0c7cc9b9` #[derive( Clone, ::ethers::contract::EthError, @@ -834,7 +834,7 @@ pub mod ibc_client { abi = "ErrClientTypeAlreadyExists()" )] pub struct ErrClientTypeAlreadyExists; - ///Custom Error type `ErrClientTypeNotFound` with signature `ErrClientTypeNotFound()` and selector `0xaa478af9` + /// Custom Error type `ErrClientTypeNotFound` with signature `ErrClientTypeNotFound()` and selector `0xaa478af9` #[derive( Clone, ::ethers::contract::EthError, @@ -847,7 +847,7 @@ pub mod ibc_client { )] #[etherror(name = "ErrClientTypeNotFound", abi = "ErrClientTypeNotFound()")] pub struct ErrClientTypeNotFound; - ///Custom Error type `ErrFailedToCreateClient` with signature `ErrFailedToCreateClient()` and selector `0x8b9f95b2` + /// Custom Error type `ErrFailedToCreateClient` with signature `ErrFailedToCreateClient()` and selector `0x8b9f95b2` #[derive( Clone, ::ethers::contract::EthError, @@ -860,7 +860,7 @@ pub mod ibc_client { )] #[etherror(name = "ErrFailedToCreateClient", abi = "ErrFailedToCreateClient()")] pub struct ErrFailedToCreateClient; - ///Custom Error type `ErrFailedToUpdateClient` with signature `ErrFailedToUpdateClient()` and selector `0xf1691139` + /// Custom Error type `ErrFailedToUpdateClient` with signature `ErrFailedToUpdateClient()` and selector `0xf1691139` #[derive( Clone, ::ethers::contract::EthError, @@ -873,7 +873,7 @@ pub mod ibc_client { )] #[etherror(name = "ErrFailedToUpdateClient", abi = "ErrFailedToUpdateClient()")] pub struct ErrFailedToUpdateClient; - ///Container type for all of the contract's custom errors + /// Container type for all of the contract's custom errors #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum IBCClientErrors { ErrClientMustNotBeSelf(ErrClientMustNotBeSelf), @@ -1046,6 +1046,8 @@ pub mod ibc_client { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent(name = "ClientCreated", abi = "ClientCreated(string)")] pub struct ClientCreatedFilter { @@ -1060,6 +1062,8 @@ pub mod ibc_client { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent(name = "ClientRegistered", abi = "ClientRegistered(string,address)")] pub struct ClientRegisteredFilter { @@ -1075,14 +1079,25 @@ pub mod ibc_client { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent(name = "ClientUpdated", abi = "ClientUpdated(string,(uint64,uint64))")] pub struct ClientUpdatedFilter { pub client_id: ::std::string::String, pub height: IbcCoreClientV1HeightData, } - ///Container type for all of the contract's events - #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + /// Container type for all of the contract's events + #[derive( + Clone, + ::ethers::contract::EthAbiType, + Debug, + PartialEq, + Eq, + Hash, + ::serde::Serialize, + ::serde::Deserialize, + )] pub enum IBCClientEvents { ClientCreatedFilter(ClientCreatedFilter), ClientRegisteredFilter(ClientRegisteredFilter), @@ -1128,7 +1143,7 @@ pub mod ibc_client { Self::ClientUpdatedFilter(value) } } - ///Container type for all input parameters for the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` + /// Container type for all input parameters for the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` #[derive( Clone, ::ethers::contract::EthCall, @@ -1141,7 +1156,7 @@ pub mod ibc_client { )] #[ethcall(name = "COMMITMENT_PREFIX", abi = "COMMITMENT_PREFIX()")] pub struct CommitmentPrefixCall; - ///Container type for all input parameters for the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` + /// Container type for all input parameters for the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` #[derive( Clone, ::ethers::contract::EthCall, @@ -1154,7 +1169,7 @@ pub mod ibc_client { )] #[ethcall(name = "capabilities", abi = "capabilities(string)")] pub struct CapabilitiesCall(pub ::std::string::String); - ///Container type for all input parameters for the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` + /// Container type for all input parameters for the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` #[derive( Clone, ::ethers::contract::EthCall, @@ -1167,7 +1182,7 @@ pub mod ibc_client { )] #[ethcall(name = "channels", abi = "channels(string,string)")] pub struct ChannelsCall(pub ::std::string::String, pub ::std::string::String); - ///Container type for all input parameters for the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` + /// Container type for all input parameters for the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` #[derive( Clone, ::ethers::contract::EthCall, @@ -1180,7 +1195,7 @@ pub mod ibc_client { )] #[ethcall(name = "clientImpls", abi = "clientImpls(string)")] pub struct ClientImplsCall(pub ::std::string::String); - ///Container type for all input parameters for the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` + /// Container type for all input parameters for the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` #[derive( Clone, ::ethers::contract::EthCall, @@ -1193,7 +1208,7 @@ pub mod ibc_client { )] #[ethcall(name = "clientRegistry", abi = "clientRegistry(string)")] pub struct ClientRegistryCall(pub ::std::string::String); - ///Container type for all input parameters for the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` + /// Container type for all input parameters for the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` #[derive( Clone, ::ethers::contract::EthCall, @@ -1206,7 +1221,7 @@ pub mod ibc_client { )] #[ethcall(name = "clientTypes", abi = "clientTypes(string)")] pub struct ClientTypesCall(pub ::std::string::String); - ///Container type for all input parameters for the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` + /// Container type for all input parameters for the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` #[derive( Clone, ::ethers::contract::EthCall, @@ -1219,7 +1234,7 @@ pub mod ibc_client { )] #[ethcall(name = "commitments", abi = "commitments(bytes32)")] pub struct CommitmentsCall(pub [u8; 32]); - ///Container type for all input parameters for the `connections` function with signature `connections(string)` and selector `0x31973f00` + /// Container type for all input parameters for the `connections` function with signature `connections(string)` and selector `0x31973f00` #[derive( Clone, ::ethers::contract::EthCall, @@ -1232,7 +1247,7 @@ pub mod ibc_client { )] #[ethcall(name = "connections", abi = "connections(string)")] pub struct ConnectionsCall(pub ::std::string::String); - ///Container type for all input parameters for the `createClient` function with signature `createClient((string,bytes,bytes,address))` and selector `0xfed12cbf` + /// Container type for all input parameters for the `createClient` function with signature `createClient((string,bytes,bytes,address))` and selector `0xfed12cbf` #[derive( Clone, ::ethers::contract::EthCall, @@ -1250,7 +1265,7 @@ pub mod ibc_client { pub struct CreateClientCall { pub msg: MsgCreateClient, } - ///Container type for all input parameters for the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` + /// Container type for all input parameters for the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` #[derive( Clone, ::ethers::contract::EthCall, @@ -1265,7 +1280,7 @@ pub mod ibc_client { pub struct GetClientCall { pub client_id: ::std::string::String, } - ///Container type for all input parameters for the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` + /// Container type for all input parameters for the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` #[derive( Clone, ::ethers::contract::EthCall, @@ -1278,7 +1293,7 @@ pub mod ibc_client { )] #[ethcall(name = "nextChannelSequencePath", abi = "nextChannelSequencePath()")] pub struct NextChannelSequencePathCall; - ///Container type for all input parameters for the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` + /// Container type for all input parameters for the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` #[derive( Clone, ::ethers::contract::EthCall, @@ -1291,7 +1306,7 @@ pub mod ibc_client { )] #[ethcall(name = "nextClientSequencePath", abi = "nextClientSequencePath()")] pub struct NextClientSequencePathCall; - ///Container type for all input parameters for the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` + /// Container type for all input parameters for the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` #[derive( Clone, ::ethers::contract::EthCall, @@ -1307,7 +1322,7 @@ pub mod ibc_client { abi = "nextConnectionSequencePath()" )] pub struct NextConnectionSequencePathCall; - ///Container type for all input parameters for the `registerClient` function with signature `registerClient(string,address)` and selector `0x18c19870` + /// Container type for all input parameters for the `registerClient` function with signature `registerClient(string,address)` and selector `0x18c19870` #[derive( Clone, ::ethers::contract::EthCall, @@ -1323,7 +1338,7 @@ pub mod ibc_client { pub client_type: ::std::string::String, pub client: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `updateClient` function with signature `updateClient((string,bytes,address))` and selector `0xf5dd3745` + /// Container type for all input parameters for the `updateClient` function with signature `updateClient((string,bytes,address))` and selector `0xf5dd3745` #[derive( Clone, ::ethers::contract::EthCall, @@ -1338,7 +1353,7 @@ pub mod ibc_client { pub struct UpdateClientCall { pub msg: MsgUpdateClient, } - ///Container type for all of the contract's call + /// Container type for all of the contract's call #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum IBCClientCalls { CommitmentPrefix(CommitmentPrefixCall), @@ -1548,7 +1563,7 @@ pub mod ibc_client { Self::UpdateClient(value) } } - ///Container type for all return fields from the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` + /// Container type for all return fields from the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1560,7 +1575,7 @@ pub mod ibc_client { Hash, )] pub struct CommitmentPrefixReturn(pub ::std::string::String); - ///Container type for all return fields from the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` + /// Container type for all return fields from the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1572,7 +1587,7 @@ pub mod ibc_client { Hash, )] pub struct CapabilitiesReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` + /// Container type for all return fields from the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1589,7 +1604,7 @@ pub mod ibc_client { pub counterparty: IbcCoreChannelV1CounterpartyData, pub version: ::std::string::String, } - ///Container type for all return fields from the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` + /// Container type for all return fields from the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1601,7 +1616,7 @@ pub mod ibc_client { Hash, )] pub struct ClientImplsReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` + /// Container type for all return fields from the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1613,7 +1628,7 @@ pub mod ibc_client { Hash, )] pub struct ClientRegistryReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` + /// Container type for all return fields from the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1625,7 +1640,7 @@ pub mod ibc_client { Hash, )] pub struct ClientTypesReturn(pub ::std::string::String); - ///Container type for all return fields from the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` + /// Container type for all return fields from the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1637,7 +1652,7 @@ pub mod ibc_client { Hash, )] pub struct CommitmentsReturn(pub [u8; 32]); - ///Container type for all return fields from the `connections` function with signature `connections(string)` and selector `0x31973f00` + /// Container type for all return fields from the `connections` function with signature `connections(string)` and selector `0x31973f00` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1654,7 +1669,7 @@ pub mod ibc_client { pub counterparty: IbcCoreConnectionV1CounterpartyData, pub delay_period: u64, } - ///Container type for all return fields from the `createClient` function with signature `createClient((string,bytes,bytes,address))` and selector `0xfed12cbf` + /// Container type for all return fields from the `createClient` function with signature `createClient((string,bytes,bytes,address))` and selector `0xfed12cbf` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1668,7 +1683,7 @@ pub mod ibc_client { pub struct CreateClientReturn { pub client_id: ::std::string::String, } - ///Container type for all return fields from the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` + /// Container type for all return fields from the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1680,7 +1695,7 @@ pub mod ibc_client { Hash, )] pub struct GetClientReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` + /// Container type for all return fields from the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1692,7 +1707,7 @@ pub mod ibc_client { Hash, )] pub struct NextChannelSequencePathReturn(pub [u8; 32]); - ///Container type for all return fields from the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` + /// Container type for all return fields from the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1704,7 +1719,7 @@ pub mod ibc_client { Hash, )] pub struct NextClientSequencePathReturn(pub [u8; 32]); - ///Container type for all return fields from the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` + /// Container type for all return fields from the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/generated/rust/contracts/src/ibc_connection.rs b/generated/rust/contracts/src/ibc_connection.rs index f6e5e3bac8..16b36c4b4f 100644 --- a/generated/rust/contracts/src/ibc_connection.rs +++ b/generated/rust/contracts/src/ibc_connection.rs @@ -707,7 +707,7 @@ pub mod ibc_connection { fallback: false, } } - ///The parsed JSON ABI of the contract. + /// The parsed JSON ABI of the contract. #[cfg(feature = "providers")] pub static IBCCONNECTION_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); @@ -807,7 +807,7 @@ pub mod ibc_connection { let deployer = ::ethers::contract::ContractDeployer::new(deployer); Ok(deployer) } - ///Calls the contract's `COMMITMENT_PREFIX` (0xa9550dac) function + /// Calls the contract's `COMMITMENT_PREFIX` (0xa9550dac) function pub fn commitment_prefix( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -815,7 +815,7 @@ pub mod ibc_connection { .method_hash([169, 85, 13, 172], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `capabilities` (0x5717bcf5) function + /// Calls the contract's `capabilities` (0x5717bcf5) function pub fn capabilities( &self, p0: ::std::string::String, @@ -824,7 +824,7 @@ pub mod ibc_connection { .method_hash([87, 23, 188, 245], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `channels` (0x5b3de260) function + /// Calls the contract's `channels` (0x5b3de260) function pub fn channels( &self, p0: ::std::string::String, @@ -842,7 +842,7 @@ pub mod ibc_connection { .method_hash([91, 61, 226, 96], (p0, p1)) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientImpls` (0xd1297b8d) function + /// Calls the contract's `clientImpls` (0xd1297b8d) function pub fn client_impls( &self, p0: ::std::string::String, @@ -851,7 +851,7 @@ pub mod ibc_connection { .method_hash([209, 41, 123, 141], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientRegistry` (0x990491a5) function + /// Calls the contract's `clientRegistry` (0x990491a5) function pub fn client_registry( &self, p0: ::std::string::String, @@ -860,7 +860,7 @@ pub mod ibc_connection { .method_hash([153, 4, 145, 165], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientTypes` (0xc2380105) function + /// Calls the contract's `clientTypes` (0xc2380105) function pub fn client_types( &self, p0: ::std::string::String, @@ -869,7 +869,7 @@ pub mod ibc_connection { .method_hash([194, 56, 1, 5], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `commitments` (0x839df945) function + /// Calls the contract's `commitments` (0x839df945) function pub fn commitments( &self, p0: [u8; 32], @@ -878,7 +878,7 @@ pub mod ibc_connection { .method_hash([131, 157, 249, 69], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `connectionOpenAck` (0xe7f32c0f) function + /// Calls the contract's `connectionOpenAck` (0xe7f32c0f) function pub fn connection_open_ack( &self, msg: MsgConnectionOpenAck, @@ -887,7 +887,7 @@ pub mod ibc_connection { .method_hash([231, 243, 44, 15], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `connectionOpenConfirm` (0x87c54dd4) function + /// Calls the contract's `connectionOpenConfirm` (0x87c54dd4) function pub fn connection_open_confirm( &self, msg: MsgConnectionOpenConfirm, @@ -896,7 +896,7 @@ pub mod ibc_connection { .method_hash([135, 197, 77, 212], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `connectionOpenInit` (0x8775f7f8) function + /// Calls the contract's `connectionOpenInit` (0x8775f7f8) function pub fn connection_open_init( &self, msg: MsgConnectionOpenInit, @@ -905,7 +905,7 @@ pub mod ibc_connection { .method_hash([135, 117, 247, 248], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `connectionOpenTry` (0x7b666dc1) function + /// Calls the contract's `connectionOpenTry` (0x7b666dc1) function pub fn connection_open_try( &self, msg: MsgConnectionOpenTry, @@ -914,7 +914,7 @@ pub mod ibc_connection { .method_hash([123, 102, 109, 193], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `connections` (0x31973f00) function + /// Calls the contract's `connections` (0x31973f00) function pub fn connections( &self, p0: ::std::string::String, @@ -931,7 +931,7 @@ pub mod ibc_connection { .method_hash([49, 151, 63, 0], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `getClient` (0x7eb78932) function + /// Calls the contract's `getClient` (0x7eb78932) function pub fn get_client( &self, client_id: ::std::string::String, @@ -940,7 +940,7 @@ pub mod ibc_connection { .method_hash([126, 183, 137, 50], client_id) .expect("method not found (this should never happen)") } - ///Calls the contract's `getCompatibleVersions` (0xc8e4bcb9) function + /// Calls the contract's `getCompatibleVersions` (0xc8e4bcb9) function pub fn get_compatible_versions( &self, ) -> ::ethers::contract::builders::ContractCall< @@ -951,7 +951,7 @@ pub mod ibc_connection { .method_hash([200, 228, 188, 185], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextChannelSequencePath` (0x8669fd15) function + /// Calls the contract's `nextChannelSequencePath` (0x8669fd15) function pub fn next_channel_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -959,7 +959,7 @@ pub mod ibc_connection { .method_hash([134, 105, 253, 21], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextClientSequencePath` (0x990c3888) function + /// Calls the contract's `nextClientSequencePath` (0x990c3888) function pub fn next_client_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -967,7 +967,7 @@ pub mod ibc_connection { .method_hash([153, 12, 56, 136], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextConnectionSequencePath` (0x46807086) function + /// Calls the contract's `nextConnectionSequencePath` (0x46807086) function pub fn next_connection_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -975,28 +975,28 @@ pub mod ibc_connection { .method_hash([70, 128, 112, 134], ()) .expect("method not found (this should never happen)") } - ///Gets the contract's `ConnectionOpenAck` event + /// Gets the contract's `ConnectionOpenAck` event pub fn connection_open_ack_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ConnectionOpenAckFilter> { self.0.event() } - ///Gets the contract's `ConnectionOpenConfirm` event + /// Gets the contract's `ConnectionOpenConfirm` event pub fn connection_open_confirm_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ConnectionOpenConfirmFilter> { self.0.event() } - ///Gets the contract's `ConnectionOpenInit` event + /// Gets the contract's `ConnectionOpenInit` event pub fn connection_open_init_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ConnectionOpenInitFilter> { self.0.event() } - ///Gets the contract's `ConnectionOpenTry` event + /// Gets the contract's `ConnectionOpenTry` event pub fn connection_open_try_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ConnectionOpenTryFilter> @@ -1020,7 +1020,7 @@ pub mod ibc_connection { Self::new(contract.address(), contract.client()) } } - ///Custom Error type `ErrClientNotFound` with signature `ErrClientNotFound()` and selector `0xb6c71f7d` + /// Custom Error type `ErrClientNotFound` with signature `ErrClientNotFound()` and selector `0xb6c71f7d` #[derive( Clone, ::ethers::contract::EthError, @@ -1033,7 +1033,7 @@ pub mod ibc_connection { )] #[etherror(name = "ErrClientNotFound", abi = "ErrClientNotFound()")] pub struct ErrClientNotFound; - ///Custom Error type `ErrConnectionAlreadyExists` with signature `ErrConnectionAlreadyExists()` and selector `0xf863275f` + /// Custom Error type `ErrConnectionAlreadyExists` with signature `ErrConnectionAlreadyExists()` and selector `0xf863275f` #[derive( Clone, ::ethers::contract::EthError, @@ -1049,7 +1049,7 @@ pub mod ibc_connection { abi = "ErrConnectionAlreadyExists()" )] pub struct ErrConnectionAlreadyExists; - ///Custom Error type `ErrInvalidConnectionState` with signature `ErrInvalidConnectionState()` and selector `0x8ca98990` + /// Custom Error type `ErrInvalidConnectionState` with signature `ErrInvalidConnectionState()` and selector `0x8ca98990` #[derive( Clone, ::ethers::contract::EthError, @@ -1065,7 +1065,7 @@ pub mod ibc_connection { abi = "ErrInvalidConnectionState()" )] pub struct ErrInvalidConnectionState; - ///Custom Error type `ErrInvalidProof` with signature `ErrInvalidProof()` and selector `0x14209932` + /// Custom Error type `ErrInvalidProof` with signature `ErrInvalidProof()` and selector `0x14209932` #[derive( Clone, ::ethers::contract::EthError, @@ -1078,7 +1078,7 @@ pub mod ibc_connection { )] #[etherror(name = "ErrInvalidProof", abi = "ErrInvalidProof()")] pub struct ErrInvalidProof; - ///Custom Error type `ErrNoCounterpartyVersion` with signature `ErrNoCounterpartyVersion()` and selector `0x33ca2894` + /// Custom Error type `ErrNoCounterpartyVersion` with signature `ErrNoCounterpartyVersion()` and selector `0x33ca2894` #[derive( Clone, ::ethers::contract::EthError, @@ -1091,7 +1091,7 @@ pub mod ibc_connection { )] #[etherror(name = "ErrNoCounterpartyVersion", abi = "ErrNoCounterpartyVersion()")] pub struct ErrNoCounterpartyVersion; - ///Custom Error type `ErrUnsupportedVersion` with signature `ErrUnsupportedVersion()` and selector `0xbcdf6cca` + /// Custom Error type `ErrUnsupportedVersion` with signature `ErrUnsupportedVersion()` and selector `0xbcdf6cca` #[derive( Clone, ::ethers::contract::EthError, @@ -1104,7 +1104,7 @@ pub mod ibc_connection { )] #[etherror(name = "ErrUnsupportedVersion", abi = "ErrUnsupportedVersion()")] pub struct ErrUnsupportedVersion; - ///Custom Error type `ErrValidateSelfClient` with signature `ErrValidateSelfClient()` and selector `0x58a3849b` + /// Custom Error type `ErrValidateSelfClient` with signature `ErrValidateSelfClient()` and selector `0x58a3849b` #[derive( Clone, ::ethers::contract::EthError, @@ -1117,7 +1117,7 @@ pub mod ibc_connection { )] #[etherror(name = "ErrValidateSelfClient", abi = "ErrValidateSelfClient()")] pub struct ErrValidateSelfClient; - ///Custom Error type `ErrVersionMustBeUnset` with signature `ErrVersionMustBeUnset()` and selector `0x82c28dca` + /// Custom Error type `ErrVersionMustBeUnset` with signature `ErrVersionMustBeUnset()` and selector `0x82c28dca` #[derive( Clone, ::ethers::contract::EthError, @@ -1130,7 +1130,7 @@ pub mod ibc_connection { )] #[etherror(name = "ErrVersionMustBeUnset", abi = "ErrVersionMustBeUnset()")] pub struct ErrVersionMustBeUnset; - ///Container type for all of the contract's custom errors + /// Container type for all of the contract's custom errors #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum IBCConnectionErrors { ErrClientNotFound(ErrClientNotFound), @@ -1337,6 +1337,8 @@ pub mod ibc_connection { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent( name = "ConnectionOpenAck", @@ -1357,6 +1359,8 @@ pub mod ibc_connection { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent( name = "ConnectionOpenConfirm", @@ -1377,6 +1381,8 @@ pub mod ibc_connection { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent( name = "ConnectionOpenInit", @@ -1396,6 +1402,8 @@ pub mod ibc_connection { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent( name = "ConnectionOpenTry", @@ -1407,8 +1415,17 @@ pub mod ibc_connection { pub counterparty_client_id: ::std::string::String, pub counterparty_connection_id: ::std::string::String, } - ///Container type for all of the contract's events - #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + /// Container type for all of the contract's events + #[derive( + Clone, + ::ethers::contract::EthAbiType, + Debug, + PartialEq, + Eq, + Hash, + ::serde::Serialize, + ::serde::Deserialize, + )] pub enum IBCConnectionEvents { ConnectionOpenAckFilter(ConnectionOpenAckFilter), ConnectionOpenConfirmFilter(ConnectionOpenConfirmFilter), @@ -1464,7 +1481,7 @@ pub mod ibc_connection { Self::ConnectionOpenTryFilter(value) } } - ///Container type for all input parameters for the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` + /// Container type for all input parameters for the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` #[derive( Clone, ::ethers::contract::EthCall, @@ -1477,7 +1494,7 @@ pub mod ibc_connection { )] #[ethcall(name = "COMMITMENT_PREFIX", abi = "COMMITMENT_PREFIX()")] pub struct CommitmentPrefixCall; - ///Container type for all input parameters for the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` + /// Container type for all input parameters for the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` #[derive( Clone, ::ethers::contract::EthCall, @@ -1490,7 +1507,7 @@ pub mod ibc_connection { )] #[ethcall(name = "capabilities", abi = "capabilities(string)")] pub struct CapabilitiesCall(pub ::std::string::String); - ///Container type for all input parameters for the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` + /// Container type for all input parameters for the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` #[derive( Clone, ::ethers::contract::EthCall, @@ -1503,7 +1520,7 @@ pub mod ibc_connection { )] #[ethcall(name = "channels", abi = "channels(string,string)")] pub struct ChannelsCall(pub ::std::string::String, pub ::std::string::String); - ///Container type for all input parameters for the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` + /// Container type for all input parameters for the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` #[derive( Clone, ::ethers::contract::EthCall, @@ -1516,7 +1533,7 @@ pub mod ibc_connection { )] #[ethcall(name = "clientImpls", abi = "clientImpls(string)")] pub struct ClientImplsCall(pub ::std::string::String); - ///Container type for all input parameters for the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` + /// Container type for all input parameters for the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` #[derive( Clone, ::ethers::contract::EthCall, @@ -1529,7 +1546,7 @@ pub mod ibc_connection { )] #[ethcall(name = "clientRegistry", abi = "clientRegistry(string)")] pub struct ClientRegistryCall(pub ::std::string::String); - ///Container type for all input parameters for the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` + /// Container type for all input parameters for the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` #[derive( Clone, ::ethers::contract::EthCall, @@ -1542,7 +1559,7 @@ pub mod ibc_connection { )] #[ethcall(name = "clientTypes", abi = "clientTypes(string)")] pub struct ClientTypesCall(pub ::std::string::String); - ///Container type for all input parameters for the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` + /// Container type for all input parameters for the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` #[derive( Clone, ::ethers::contract::EthCall, @@ -1555,7 +1572,7 @@ pub mod ibc_connection { )] #[ethcall(name = "commitments", abi = "commitments(bytes32)")] pub struct CommitmentsCall(pub [u8; 32]); - ///Container type for all input parameters for the `connectionOpenAck` function with signature `connectionOpenAck((string,bytes,(string,string[]),string,bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))` and selector `0xe7f32c0f` + /// Container type for all input parameters for the `connectionOpenAck` function with signature `connectionOpenAck((string,bytes,(string,string[]),string,bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))` and selector `0xe7f32c0f` #[derive( Clone, ::ethers::contract::EthCall, @@ -1573,7 +1590,7 @@ pub mod ibc_connection { pub struct ConnectionOpenAckCall { pub msg: MsgConnectionOpenAck, } - ///Container type for all input parameters for the `connectionOpenConfirm` function with signature `connectionOpenConfirm((string,bytes,(uint64,uint64),address))` and selector `0x87c54dd4` + /// Container type for all input parameters for the `connectionOpenConfirm` function with signature `connectionOpenConfirm((string,bytes,(uint64,uint64),address))` and selector `0x87c54dd4` #[derive( Clone, ::ethers::contract::EthCall, @@ -1591,7 +1608,7 @@ pub mod ibc_connection { pub struct ConnectionOpenConfirmCall { pub msg: MsgConnectionOpenConfirm, } - ///Container type for all input parameters for the `connectionOpenInit` function with signature `connectionOpenInit((string,(string,string[]),(string,string,(bytes)),uint64,address))` and selector `0x8775f7f8` + /// Container type for all input parameters for the `connectionOpenInit` function with signature `connectionOpenInit((string,(string,string[]),(string,string,(bytes)),uint64,address))` and selector `0x8775f7f8` #[derive( Clone, ::ethers::contract::EthCall, @@ -1609,7 +1626,7 @@ pub mod ibc_connection { pub struct ConnectionOpenInitCall { pub msg: MsgConnectionOpenInit, } - ///Container type for all input parameters for the `connectionOpenTry` function with signature `connectionOpenTry(((string,string,(bytes)),uint64,string,bytes,(string,string[])[],bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))` and selector `0x7b666dc1` + /// Container type for all input parameters for the `connectionOpenTry` function with signature `connectionOpenTry(((string,string,(bytes)),uint64,string,bytes,(string,string[])[],bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))` and selector `0x7b666dc1` #[derive( Clone, ::ethers::contract::EthCall, @@ -1627,7 +1644,7 @@ pub mod ibc_connection { pub struct ConnectionOpenTryCall { pub msg: MsgConnectionOpenTry, } - ///Container type for all input parameters for the `connections` function with signature `connections(string)` and selector `0x31973f00` + /// Container type for all input parameters for the `connections` function with signature `connections(string)` and selector `0x31973f00` #[derive( Clone, ::ethers::contract::EthCall, @@ -1640,7 +1657,7 @@ pub mod ibc_connection { )] #[ethcall(name = "connections", abi = "connections(string)")] pub struct ConnectionsCall(pub ::std::string::String); - ///Container type for all input parameters for the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` + /// Container type for all input parameters for the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` #[derive( Clone, ::ethers::contract::EthCall, @@ -1655,7 +1672,7 @@ pub mod ibc_connection { pub struct GetClientCall { pub client_id: ::std::string::String, } - ///Container type for all input parameters for the `getCompatibleVersions` function with signature `getCompatibleVersions()` and selector `0xc8e4bcb9` + /// Container type for all input parameters for the `getCompatibleVersions` function with signature `getCompatibleVersions()` and selector `0xc8e4bcb9` #[derive( Clone, ::ethers::contract::EthCall, @@ -1668,7 +1685,7 @@ pub mod ibc_connection { )] #[ethcall(name = "getCompatibleVersions", abi = "getCompatibleVersions()")] pub struct GetCompatibleVersionsCall; - ///Container type for all input parameters for the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` + /// Container type for all input parameters for the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` #[derive( Clone, ::ethers::contract::EthCall, @@ -1681,7 +1698,7 @@ pub mod ibc_connection { )] #[ethcall(name = "nextChannelSequencePath", abi = "nextChannelSequencePath()")] pub struct NextChannelSequencePathCall; - ///Container type for all input parameters for the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` + /// Container type for all input parameters for the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` #[derive( Clone, ::ethers::contract::EthCall, @@ -1694,7 +1711,7 @@ pub mod ibc_connection { )] #[ethcall(name = "nextClientSequencePath", abi = "nextClientSequencePath()")] pub struct NextClientSequencePathCall; - ///Container type for all input parameters for the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` + /// Container type for all input parameters for the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` #[derive( Clone, ::ethers::contract::EthCall, @@ -1710,7 +1727,7 @@ pub mod ibc_connection { abi = "nextConnectionSequencePath()" )] pub struct NextConnectionSequencePathCall; - ///Container type for all of the contract's call + /// Container type for all of the contract's call #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum IBCConnectionCalls { CommitmentPrefix(CommitmentPrefixCall), @@ -1954,7 +1971,7 @@ pub mod ibc_connection { Self::NextConnectionSequencePath(value) } } - ///Container type for all return fields from the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` + /// Container type for all return fields from the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1966,7 +1983,7 @@ pub mod ibc_connection { Hash, )] pub struct CommitmentPrefixReturn(pub ::std::string::String); - ///Container type for all return fields from the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` + /// Container type for all return fields from the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1978,7 +1995,7 @@ pub mod ibc_connection { Hash, )] pub struct CapabilitiesReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` + /// Container type for all return fields from the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -1995,7 +2012,7 @@ pub mod ibc_connection { pub counterparty: IbcCoreChannelV1CounterpartyData, pub version: ::std::string::String, } - ///Container type for all return fields from the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` + /// Container type for all return fields from the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2007,7 +2024,7 @@ pub mod ibc_connection { Hash, )] pub struct ClientImplsReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` + /// Container type for all return fields from the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2019,7 +2036,7 @@ pub mod ibc_connection { Hash, )] pub struct ClientRegistryReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` + /// Container type for all return fields from the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2031,7 +2048,7 @@ pub mod ibc_connection { Hash, )] pub struct ClientTypesReturn(pub ::std::string::String); - ///Container type for all return fields from the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` + /// Container type for all return fields from the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2043,7 +2060,7 @@ pub mod ibc_connection { Hash, )] pub struct CommitmentsReturn(pub [u8; 32]); - ///Container type for all return fields from the `connectionOpenInit` function with signature `connectionOpenInit((string,(string,string[]),(string,string,(bytes)),uint64,address))` and selector `0x8775f7f8` + /// Container type for all return fields from the `connectionOpenInit` function with signature `connectionOpenInit((string,(string,string[]),(string,string,(bytes)),uint64,address))` and selector `0x8775f7f8` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2055,7 +2072,7 @@ pub mod ibc_connection { Hash, )] pub struct ConnectionOpenInitReturn(pub ::std::string::String); - ///Container type for all return fields from the `connectionOpenTry` function with signature `connectionOpenTry(((string,string,(bytes)),uint64,string,bytes,(string,string[])[],bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))` and selector `0x7b666dc1` + /// Container type for all return fields from the `connectionOpenTry` function with signature `connectionOpenTry(((string,string,(bytes)),uint64,string,bytes,(string,string[])[],bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))` and selector `0x7b666dc1` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2067,7 +2084,7 @@ pub mod ibc_connection { Hash, )] pub struct ConnectionOpenTryReturn(pub ::std::string::String); - ///Container type for all return fields from the `connections` function with signature `connections(string)` and selector `0x31973f00` + /// Container type for all return fields from the `connections` function with signature `connections(string)` and selector `0x31973f00` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2084,7 +2101,7 @@ pub mod ibc_connection { pub counterparty: IbcCoreConnectionV1CounterpartyData, pub delay_period: u64, } - ///Container type for all return fields from the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` + /// Container type for all return fields from the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2096,7 +2113,7 @@ pub mod ibc_connection { Hash, )] pub struct GetClientReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `getCompatibleVersions` function with signature `getCompatibleVersions()` and selector `0xc8e4bcb9` + /// Container type for all return fields from the `getCompatibleVersions` function with signature `getCompatibleVersions()` and selector `0xc8e4bcb9` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2108,7 +2125,7 @@ pub mod ibc_connection { Hash, )] pub struct GetCompatibleVersionsReturn(pub ::std::vec::Vec); - ///Container type for all return fields from the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` + /// Container type for all return fields from the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2120,7 +2137,7 @@ pub mod ibc_connection { Hash, )] pub struct NextChannelSequencePathReturn(pub [u8; 32]); - ///Container type for all return fields from the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` + /// Container type for all return fields from the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2132,7 +2149,7 @@ pub mod ibc_connection { Hash, )] pub struct NextClientSequencePathReturn(pub [u8; 32]); - ///Container type for all return fields from the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` + /// Container type for all return fields from the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/generated/rust/contracts/src/ibc_handler.rs b/generated/rust/contracts/src/ibc_handler.rs index 3918b8d882..02f09eb891 100644 --- a/generated/rust/contracts/src/ibc_handler.rs +++ b/generated/rust/contracts/src/ibc_handler.rs @@ -1489,7 +1489,7 @@ pub mod ibc_handler { fallback: false, } } - ///The parsed JSON ABI of the contract. + /// The parsed JSON ABI of the contract. #[cfg(feature = "providers")] pub static IBCHANDLER_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); @@ -1536,7 +1536,7 @@ pub mod ibc_handler { client, )) } - ///Calls the contract's `COMMITMENT_PREFIX` (0xa9550dac) function + /// Calls the contract's `COMMITMENT_PREFIX` (0xa9550dac) function pub fn commitment_prefix( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1544,7 +1544,7 @@ pub mod ibc_handler { .method_hash([169, 85, 13, 172], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `UPGRADE_INTERFACE_VERSION` (0xad3cb1cc) function + /// Calls the contract's `UPGRADE_INTERFACE_VERSION` (0xad3cb1cc) function pub fn upgrade_interface_version( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1552,7 +1552,7 @@ pub mod ibc_handler { .method_hash([173, 60, 177, 204], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `acknowledgePacket` (0x07037704) function + /// Calls the contract's `acknowledgePacket` (0x07037704) function pub fn acknowledge_packet( &self, p0: MsgPacketAcknowledgement, @@ -1561,7 +1561,7 @@ pub mod ibc_handler { .method_hash([7, 3, 119, 4], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `capabilities` (0x5717bcf5) function + /// Calls the contract's `capabilities` (0x5717bcf5) function pub fn capabilities( &self, p0: ::std::string::String, @@ -1570,7 +1570,7 @@ pub mod ibc_handler { .method_hash([87, 23, 188, 245], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelCapabilityPath` (0x3bc3339f) function + /// Calls the contract's `channelCapabilityPath` (0x3bc3339f) function pub fn channel_capability_path( &self, port_id: ::std::string::String, @@ -1580,7 +1580,7 @@ pub mod ibc_handler { .method_hash([59, 195, 51, 159], (port_id, channel_id)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelCloseConfirm` (0x6e92edaf) function + /// Calls the contract's `channelCloseConfirm` (0x6e92edaf) function pub fn channel_close_confirm( &self, p0: MsgChannelCloseConfirm, @@ -1589,7 +1589,7 @@ pub mod ibc_handler { .method_hash([110, 146, 237, 175], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelCloseInit` (0x96549d92) function + /// Calls the contract's `channelCloseInit` (0x96549d92) function pub fn channel_close_init( &self, p0: MsgChannelCloseInit, @@ -1598,7 +1598,7 @@ pub mod ibc_handler { .method_hash([150, 84, 157, 146], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelOpenAck` (0xdeff27b9) function + /// Calls the contract's `channelOpenAck` (0xdeff27b9) function pub fn channel_open_ack( &self, p0: MsgChannelOpenAck, @@ -1607,7 +1607,7 @@ pub mod ibc_handler { .method_hash([222, 255, 39, 185], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelOpenConfirm` (0xf52deded) function + /// Calls the contract's `channelOpenConfirm` (0xf52deded) function pub fn channel_open_confirm( &self, p0: MsgChannelOpenConfirm, @@ -1616,7 +1616,7 @@ pub mod ibc_handler { .method_hash([245, 45, 237, 237], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelOpenInit` (0x25035747) function + /// Calls the contract's `channelOpenInit` (0x25035747) function pub fn channel_open_init( &self, p0: MsgChannelOpenInit, @@ -1625,7 +1625,7 @@ pub mod ibc_handler { .method_hash([37, 3, 87, 71], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelOpenTry` (0x8b627bca) function + /// Calls the contract's `channelOpenTry` (0x8b627bca) function pub fn channel_open_try( &self, p0: MsgChannelOpenTry, @@ -1634,7 +1634,7 @@ pub mod ibc_handler { .method_hash([139, 98, 123, 202], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channels` (0x5b3de260) function + /// Calls the contract's `channels` (0x5b3de260) function pub fn channels( &self, p0: ::std::string::String, @@ -1652,7 +1652,7 @@ pub mod ibc_handler { .method_hash([91, 61, 226, 96], (p0, p1)) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientImpls` (0xd1297b8d) function + /// Calls the contract's `clientImpls` (0xd1297b8d) function pub fn client_impls( &self, p0: ::std::string::String, @@ -1661,7 +1661,7 @@ pub mod ibc_handler { .method_hash([209, 41, 123, 141], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientRegistry` (0x990491a5) function + /// Calls the contract's `clientRegistry` (0x990491a5) function pub fn client_registry( &self, p0: ::std::string::String, @@ -1670,7 +1670,7 @@ pub mod ibc_handler { .method_hash([153, 4, 145, 165], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientTypes` (0xc2380105) function + /// Calls the contract's `clientTypes` (0xc2380105) function pub fn client_types( &self, p0: ::std::string::String, @@ -1679,7 +1679,7 @@ pub mod ibc_handler { .method_hash([194, 56, 1, 5], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `commitments` (0x839df945) function + /// Calls the contract's `commitments` (0x839df945) function pub fn commitments( &self, p0: [u8; 32], @@ -1688,7 +1688,7 @@ pub mod ibc_handler { .method_hash([131, 157, 249, 69], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `connectionOpenAck` (0xe7f32c0f) function + /// Calls the contract's `connectionOpenAck` (0xe7f32c0f) function pub fn connection_open_ack( &self, p0: MsgConnectionOpenAck, @@ -1697,7 +1697,7 @@ pub mod ibc_handler { .method_hash([231, 243, 44, 15], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `connectionOpenConfirm` (0x87c54dd4) function + /// Calls the contract's `connectionOpenConfirm` (0x87c54dd4) function pub fn connection_open_confirm( &self, p0: MsgConnectionOpenConfirm, @@ -1706,7 +1706,7 @@ pub mod ibc_handler { .method_hash([135, 197, 77, 212], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `connectionOpenInit` (0x8775f7f8) function + /// Calls the contract's `connectionOpenInit` (0x8775f7f8) function pub fn connection_open_init( &self, p0: MsgConnectionOpenInit, @@ -1715,7 +1715,7 @@ pub mod ibc_handler { .method_hash([135, 117, 247, 248], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `connectionOpenTry` (0x7b666dc1) function + /// Calls the contract's `connectionOpenTry` (0x7b666dc1) function pub fn connection_open_try( &self, p0: MsgConnectionOpenTry, @@ -1724,7 +1724,7 @@ pub mod ibc_handler { .method_hash([123, 102, 109, 193], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `connections` (0x31973f00) function + /// Calls the contract's `connections` (0x31973f00) function pub fn connections( &self, p0: ::std::string::String, @@ -1741,7 +1741,7 @@ pub mod ibc_handler { .method_hash([49, 151, 63, 0], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `createClient` (0xfed12cbf) function + /// Calls the contract's `createClient` (0xfed12cbf) function pub fn create_client( &self, p0: MsgCreateClient, @@ -1750,7 +1750,7 @@ pub mod ibc_handler { .method_hash([254, 209, 44, 191], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `getChannel` (0x3000217a) function + /// Calls the contract's `getChannel` (0x3000217a) function pub fn get_channel( &self, port_id: ::std::string::String, @@ -1760,7 +1760,7 @@ pub mod ibc_handler { .method_hash([48, 0, 33, 122], (port_id, channel_id)) .expect("method not found (this should never happen)") } - ///Calls the contract's `getClient` (0x7eb78932) function + /// Calls the contract's `getClient` (0x7eb78932) function pub fn get_client( &self, client_id: ::std::string::String, @@ -1769,7 +1769,7 @@ pub mod ibc_handler { .method_hash([126, 183, 137, 50], client_id) .expect("method not found (this should never happen)") } - ///Calls the contract's `getConnection` (0x27711a69) function + /// Calls the contract's `getConnection` (0x27711a69) function pub fn get_connection( &self, connection_id: ::std::string::String, @@ -1779,7 +1779,7 @@ pub mod ibc_handler { .method_hash([39, 113, 26, 105], connection_id) .expect("method not found (this should never happen)") } - ///Calls the contract's `initialize` (0x1459457a) function + /// Calls the contract's `initialize` (0x1459457a) function pub fn initialize( &self, ibc_client: ::ethers::core::types::Address, @@ -1795,7 +1795,7 @@ pub mod ibc_handler { ) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextChannelSequencePath` (0x8669fd15) function + /// Calls the contract's `nextChannelSequencePath` (0x8669fd15) function pub fn next_channel_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1803,7 +1803,7 @@ pub mod ibc_handler { .method_hash([134, 105, 253, 21], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextClientSequencePath` (0x990c3888) function + /// Calls the contract's `nextClientSequencePath` (0x990c3888) function pub fn next_client_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1811,7 +1811,7 @@ pub mod ibc_handler { .method_hash([153, 12, 56, 136], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextConnectionSequencePath` (0x46807086) function + /// Calls the contract's `nextConnectionSequencePath` (0x46807086) function pub fn next_connection_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1819,7 +1819,7 @@ pub mod ibc_handler { .method_hash([70, 128, 112, 134], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `owner` (0x8da5cb5b) function + /// Calls the contract's `owner` (0x8da5cb5b) function pub fn owner( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1827,19 +1827,19 @@ pub mod ibc_handler { .method_hash([141, 165, 203, 91], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `paused` (0x5c975abb) function + /// Calls the contract's `paused` (0x5c975abb) function pub fn paused(&self) -> ::ethers::contract::builders::ContractCall { self.0 .method_hash([92, 151, 90, 187], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `proxiableUUID` (0x52d1902d) function + /// Calls the contract's `proxiableUUID` (0x52d1902d) function pub fn proxiable_uuid(&self) -> ::ethers::contract::builders::ContractCall { self.0 .method_hash([82, 209, 144, 45], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `recvPacket` (0xe8f088c6) function + /// Calls the contract's `recvPacket` (0xe8f088c6) function pub fn recv_packet( &self, p0: MsgPacketRecv, @@ -1848,7 +1848,7 @@ pub mod ibc_handler { .method_hash([232, 240, 136, 198], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `registerClient` (0x18c19870) function + /// Calls the contract's `registerClient` (0x18c19870) function pub fn register_client( &self, p0: ::std::string::String, @@ -1858,13 +1858,13 @@ pub mod ibc_handler { .method_hash([24, 193, 152, 112], (p0, p1)) .expect("method not found (this should never happen)") } - ///Calls the contract's `renounceOwnership` (0x715018a6) function + /// Calls the contract's `renounceOwnership` (0x715018a6) function pub fn renounce_ownership(&self) -> ::ethers::contract::builders::ContractCall { self.0 .method_hash([113, 80, 24, 166], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `sendPacket` (0x6cf02d3f) function + /// Calls the contract's `sendPacket` (0x6cf02d3f) function pub fn send_packet( &self, p0: ::std::string::String, @@ -1876,7 +1876,7 @@ pub mod ibc_handler { .method_hash([108, 240, 45, 63], (p0, p1, p2, p3)) .expect("method not found (this should never happen)") } - ///Calls the contract's `timeoutPacket` (0xa04f91b2) function + /// Calls the contract's `timeoutPacket` (0xa04f91b2) function pub fn timeout_packet( &self, p0: MsgPacketTimeout, @@ -1885,7 +1885,7 @@ pub mod ibc_handler { .method_hash([160, 79, 145, 178], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `transferOwnership` (0xf2fde38b) function + /// Calls the contract's `transferOwnership` (0xf2fde38b) function pub fn transfer_ownership( &self, new_owner: ::ethers::core::types::Address, @@ -1894,7 +1894,7 @@ pub mod ibc_handler { .method_hash([242, 253, 227, 139], new_owner) .expect("method not found (this should never happen)") } - ///Calls the contract's `updateClient` (0xf5dd3745) function + /// Calls the contract's `updateClient` (0xf5dd3745) function pub fn update_client( &self, p0: MsgUpdateClient, @@ -1903,7 +1903,7 @@ pub mod ibc_handler { .method_hash([245, 221, 55, 69], (p0,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `upgradeImpls` (0xa9365006) function + /// Calls the contract's `upgradeImpls` (0xa9365006) function pub fn upgrade_impls( &self, ibc_client: ::ethers::core::types::Address, @@ -1918,7 +1918,7 @@ pub mod ibc_handler { ) .expect("method not found (this should never happen)") } - ///Calls the contract's `upgradeToAndCall` (0x4f1ef286) function + /// Calls the contract's `upgradeToAndCall` (0x4f1ef286) function pub fn upgrade_to_and_call( &self, new_implementation: ::ethers::core::types::Address, @@ -1928,7 +1928,7 @@ pub mod ibc_handler { .method_hash([79, 30, 242, 134], (new_implementation, data)) .expect("method not found (this should never happen)") } - ///Calls the contract's `writeAcknowledgement` (0xca956667) function + /// Calls the contract's `writeAcknowledgement` (0xca956667) function pub fn write_acknowledgement( &self, p0: IbcCoreChannelV1PacketData, @@ -1938,33 +1938,33 @@ pub mod ibc_handler { .method_hash([202, 149, 102, 103], (p0, p1)) .expect("method not found (this should never happen)") } - ///Gets the contract's `Initialized` event + /// Gets the contract's `Initialized` event pub fn initialized_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, InitializedFilter> { self.0.event() } - ///Gets the contract's `OwnershipTransferred` event + /// Gets the contract's `OwnershipTransferred` event pub fn ownership_transferred_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, OwnershipTransferredFilter> { self.0.event() } - ///Gets the contract's `Paused` event + /// Gets the contract's `Paused` event pub fn paused_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, PausedFilter> { self.0.event() } - ///Gets the contract's `Unpaused` event + /// Gets the contract's `Unpaused` event pub fn unpaused_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, UnpausedFilter> { self.0.event() } - ///Gets the contract's `Upgraded` event + /// Gets the contract's `Upgraded` event pub fn upgraded_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, UpgradedFilter> { @@ -1984,7 +1984,7 @@ pub mod ibc_handler { Self::new(contract.address(), contract.client()) } } - ///Custom Error type `AddressEmptyCode` with signature `AddressEmptyCode(address)` and selector `0x9996b315` + /// Custom Error type `AddressEmptyCode` with signature `AddressEmptyCode(address)` and selector `0x9996b315` #[derive( Clone, ::ethers::contract::EthError, @@ -1999,7 +1999,7 @@ pub mod ibc_handler { pub struct AddressEmptyCode { pub target: ::ethers::core::types::Address, } - ///Custom Error type `ERC1967InvalidImplementation` with signature `ERC1967InvalidImplementation(address)` and selector `0x4c9c8ce3` + /// Custom Error type `ERC1967InvalidImplementation` with signature `ERC1967InvalidImplementation(address)` and selector `0x4c9c8ce3` #[derive( Clone, ::ethers::contract::EthError, @@ -2017,7 +2017,7 @@ pub mod ibc_handler { pub struct ERC1967InvalidImplementation { pub implementation: ::ethers::core::types::Address, } - ///Custom Error type `ERC1967NonPayable` with signature `ERC1967NonPayable()` and selector `0xb398979f` + /// Custom Error type `ERC1967NonPayable` with signature `ERC1967NonPayable()` and selector `0xb398979f` #[derive( Clone, ::ethers::contract::EthError, @@ -2030,7 +2030,7 @@ pub mod ibc_handler { )] #[etherror(name = "ERC1967NonPayable", abi = "ERC1967NonPayable()")] pub struct ERC1967NonPayable; - ///Custom Error type `EnforcedPause` with signature `EnforcedPause()` and selector `0xd93c0665` + /// Custom Error type `EnforcedPause` with signature `EnforcedPause()` and selector `0xd93c0665` #[derive( Clone, ::ethers::contract::EthError, @@ -2043,7 +2043,7 @@ pub mod ibc_handler { )] #[etherror(name = "EnforcedPause", abi = "EnforcedPause()")] pub struct EnforcedPause; - ///Custom Error type `ErrClientNotFound` with signature `ErrClientNotFound()` and selector `0xb6c71f7d` + /// Custom Error type `ErrClientNotFound` with signature `ErrClientNotFound()` and selector `0xb6c71f7d` #[derive( Clone, ::ethers::contract::EthError, @@ -2056,7 +2056,7 @@ pub mod ibc_handler { )] #[etherror(name = "ErrClientNotFound", abi = "ErrClientNotFound()")] pub struct ErrClientNotFound; - ///Custom Error type `ExpectedPause` with signature `ExpectedPause()` and selector `0x8dfc202b` + /// Custom Error type `ExpectedPause` with signature `ExpectedPause()` and selector `0x8dfc202b` #[derive( Clone, ::ethers::contract::EthError, @@ -2069,7 +2069,7 @@ pub mod ibc_handler { )] #[etherror(name = "ExpectedPause", abi = "ExpectedPause()")] pub struct ExpectedPause; - ///Custom Error type `FailedInnerCall` with signature `FailedInnerCall()` and selector `0x1425ea42` + /// Custom Error type `FailedInnerCall` with signature `FailedInnerCall()` and selector `0x1425ea42` #[derive( Clone, ::ethers::contract::EthError, @@ -2082,7 +2082,7 @@ pub mod ibc_handler { )] #[etherror(name = "FailedInnerCall", abi = "FailedInnerCall()")] pub struct FailedInnerCall; - ///Custom Error type `InvalidInitialization` with signature `InvalidInitialization()` and selector `0xf92ee8a9` + /// Custom Error type `InvalidInitialization` with signature `InvalidInitialization()` and selector `0xf92ee8a9` #[derive( Clone, ::ethers::contract::EthError, @@ -2095,7 +2095,7 @@ pub mod ibc_handler { )] #[etherror(name = "InvalidInitialization", abi = "InvalidInitialization()")] pub struct InvalidInitialization; - ///Custom Error type `NotInitializing` with signature `NotInitializing()` and selector `0xd7e6bcf8` + /// Custom Error type `NotInitializing` with signature `NotInitializing()` and selector `0xd7e6bcf8` #[derive( Clone, ::ethers::contract::EthError, @@ -2108,7 +2108,7 @@ pub mod ibc_handler { )] #[etherror(name = "NotInitializing", abi = "NotInitializing()")] pub struct NotInitializing; - ///Custom Error type `OwnableInvalidOwner` with signature `OwnableInvalidOwner(address)` and selector `0x1e4fbdf7` + /// Custom Error type `OwnableInvalidOwner` with signature `OwnableInvalidOwner(address)` and selector `0x1e4fbdf7` #[derive( Clone, ::ethers::contract::EthError, @@ -2123,7 +2123,7 @@ pub mod ibc_handler { pub struct OwnableInvalidOwner { pub owner: ::ethers::core::types::Address, } - ///Custom Error type `OwnableUnauthorizedAccount` with signature `OwnableUnauthorizedAccount(address)` and selector `0x118cdaa7` + /// Custom Error type `OwnableUnauthorizedAccount` with signature `OwnableUnauthorizedAccount(address)` and selector `0x118cdaa7` #[derive( Clone, ::ethers::contract::EthError, @@ -2141,7 +2141,7 @@ pub mod ibc_handler { pub struct OwnableUnauthorizedAccount { pub account: ::ethers::core::types::Address, } - ///Custom Error type `UUPSUnauthorizedCallContext` with signature `UUPSUnauthorizedCallContext()` and selector `0xe07c8dba` + /// Custom Error type `UUPSUnauthorizedCallContext` with signature `UUPSUnauthorizedCallContext()` and selector `0xe07c8dba` #[derive( Clone, ::ethers::contract::EthError, @@ -2157,7 +2157,7 @@ pub mod ibc_handler { abi = "UUPSUnauthorizedCallContext()" )] pub struct UUPSUnauthorizedCallContext; - ///Custom Error type `UUPSUnsupportedProxiableUUID` with signature `UUPSUnsupportedProxiableUUID(bytes32)` and selector `0xaa1d49a4` + /// Custom Error type `UUPSUnsupportedProxiableUUID` with signature `UUPSUnsupportedProxiableUUID(bytes32)` and selector `0xaa1d49a4` #[derive( Clone, ::ethers::contract::EthError, @@ -2175,7 +2175,7 @@ pub mod ibc_handler { pub struct UUPSUnsupportedProxiableUUID { pub slot: [u8; 32], } - ///Container type for all of the contract's custom errors + /// Container type for all of the contract's custom errors #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum IBCHandlerErrors { AddressEmptyCode(AddressEmptyCode), @@ -2477,6 +2477,8 @@ pub mod ibc_handler { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent( name = "OwnershipTransferred", @@ -2531,7 +2533,7 @@ pub mod ibc_handler { #[ethevent(indexed)] pub implementation: ::ethers::core::types::Address, } - ///Container type for all of the contract's events + /// Container type for all of the contract's events #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum IBCHandlerEvents { InitializedFilter(InitializedFilter), @@ -2598,7 +2600,7 @@ pub mod ibc_handler { Self::UpgradedFilter(value) } } - ///Container type for all input parameters for the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` + /// Container type for all input parameters for the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` #[derive( Clone, ::ethers::contract::EthCall, @@ -2611,7 +2613,7 @@ pub mod ibc_handler { )] #[ethcall(name = "COMMITMENT_PREFIX", abi = "COMMITMENT_PREFIX()")] pub struct CommitmentPrefixCall; - ///Container type for all input parameters for the `UPGRADE_INTERFACE_VERSION` function with signature `UPGRADE_INTERFACE_VERSION()` and selector `0xad3cb1cc` + /// Container type for all input parameters for the `UPGRADE_INTERFACE_VERSION` function with signature `UPGRADE_INTERFACE_VERSION()` and selector `0xad3cb1cc` #[derive( Clone, ::ethers::contract::EthCall, @@ -2627,7 +2629,7 @@ pub mod ibc_handler { abi = "UPGRADE_INTERFACE_VERSION()" )] pub struct UpgradeInterfaceVersionCall; - ///Container type for all input parameters for the `acknowledgePacket` function with signature `acknowledgePacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,bytes,(uint64,uint64),address))` and selector `0x07037704` + /// Container type for all input parameters for the `acknowledgePacket` function with signature `acknowledgePacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,bytes,(uint64,uint64),address))` and selector `0x07037704` #[derive( Clone, ::ethers::contract::EthCall, @@ -2643,7 +2645,7 @@ pub mod ibc_handler { abi = "acknowledgePacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,bytes,(uint64,uint64),address))" )] pub struct AcknowledgePacketCall(pub MsgPacketAcknowledgement); - ///Container type for all input parameters for the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` + /// Container type for all input parameters for the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` #[derive( Clone, ::ethers::contract::EthCall, @@ -2656,7 +2658,7 @@ pub mod ibc_handler { )] #[ethcall(name = "capabilities", abi = "capabilities(string)")] pub struct CapabilitiesCall(pub ::std::string::String); - ///Container type for all input parameters for the `channelCapabilityPath` function with signature `channelCapabilityPath(string,string)` and selector `0x3bc3339f` + /// Container type for all input parameters for the `channelCapabilityPath` function with signature `channelCapabilityPath(string,string)` and selector `0x3bc3339f` #[derive( Clone, ::ethers::contract::EthCall, @@ -2675,7 +2677,7 @@ pub mod ibc_handler { pub port_id: ::std::string::String, pub channel_id: ::std::string::String, } - ///Container type for all input parameters for the `channelCloseConfirm` function with signature `channelCloseConfirm((string,string,bytes,(uint64,uint64),address))` and selector `0x6e92edaf` + /// Container type for all input parameters for the `channelCloseConfirm` function with signature `channelCloseConfirm((string,string,bytes,(uint64,uint64),address))` and selector `0x6e92edaf` #[derive( Clone, ::ethers::contract::EthCall, @@ -2691,7 +2693,7 @@ pub mod ibc_handler { abi = "channelCloseConfirm((string,string,bytes,(uint64,uint64),address))" )] pub struct ChannelCloseConfirmCall(pub MsgChannelCloseConfirm); - ///Container type for all input parameters for the `channelCloseInit` function with signature `channelCloseInit((string,string,address))` and selector `0x96549d92` + /// Container type for all input parameters for the `channelCloseInit` function with signature `channelCloseInit((string,string,address))` and selector `0x96549d92` #[derive( Clone, ::ethers::contract::EthCall, @@ -2707,7 +2709,7 @@ pub mod ibc_handler { abi = "channelCloseInit((string,string,address))" )] pub struct ChannelCloseInitCall(pub MsgChannelCloseInit); - ///Container type for all input parameters for the `channelOpenAck` function with signature `channelOpenAck((string,string,string,string,bytes,(uint64,uint64),address))` and selector `0xdeff27b9` + /// Container type for all input parameters for the `channelOpenAck` function with signature `channelOpenAck((string,string,string,string,bytes,(uint64,uint64),address))` and selector `0xdeff27b9` #[derive( Clone, ::ethers::contract::EthCall, @@ -2723,7 +2725,7 @@ pub mod ibc_handler { abi = "channelOpenAck((string,string,string,string,bytes,(uint64,uint64),address))" )] pub struct ChannelOpenAckCall(pub MsgChannelOpenAck); - ///Container type for all input parameters for the `channelOpenConfirm` function with signature `channelOpenConfirm((string,string,bytes,(uint64,uint64),address))` and selector `0xf52deded` + /// Container type for all input parameters for the `channelOpenConfirm` function with signature `channelOpenConfirm((string,string,bytes,(uint64,uint64),address))` and selector `0xf52deded` #[derive( Clone, ::ethers::contract::EthCall, @@ -2739,7 +2741,7 @@ pub mod ibc_handler { abi = "channelOpenConfirm((string,string,bytes,(uint64,uint64),address))" )] pub struct ChannelOpenConfirmCall(pub MsgChannelOpenConfirm); - ///Container type for all input parameters for the `channelOpenInit` function with signature `channelOpenInit((string,(uint8,uint8,(string,string),string[],string),address))` and selector `0x25035747` + /// Container type for all input parameters for the `channelOpenInit` function with signature `channelOpenInit((string,(uint8,uint8,(string,string),string[],string),address))` and selector `0x25035747` #[derive( Clone, ::ethers::contract::EthCall, @@ -2755,7 +2757,7 @@ pub mod ibc_handler { abi = "channelOpenInit((string,(uint8,uint8,(string,string),string[],string),address))" )] pub struct ChannelOpenInitCall(pub MsgChannelOpenInit); - ///Container type for all input parameters for the `channelOpenTry` function with signature `channelOpenTry((string,(uint8,uint8,(string,string),string[],string),string,bytes,(uint64,uint64),address))` and selector `0x8b627bca` + /// Container type for all input parameters for the `channelOpenTry` function with signature `channelOpenTry((string,(uint8,uint8,(string,string),string[],string),string,bytes,(uint64,uint64),address))` and selector `0x8b627bca` #[derive( Clone, ::ethers::contract::EthCall, @@ -2771,7 +2773,7 @@ pub mod ibc_handler { abi = "channelOpenTry((string,(uint8,uint8,(string,string),string[],string),string,bytes,(uint64,uint64),address))" )] pub struct ChannelOpenTryCall(pub MsgChannelOpenTry); - ///Container type for all input parameters for the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` + /// Container type for all input parameters for the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` #[derive( Clone, ::ethers::contract::EthCall, @@ -2784,7 +2786,7 @@ pub mod ibc_handler { )] #[ethcall(name = "channels", abi = "channels(string,string)")] pub struct ChannelsCall(pub ::std::string::String, pub ::std::string::String); - ///Container type for all input parameters for the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` + /// Container type for all input parameters for the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` #[derive( Clone, ::ethers::contract::EthCall, @@ -2797,7 +2799,7 @@ pub mod ibc_handler { )] #[ethcall(name = "clientImpls", abi = "clientImpls(string)")] pub struct ClientImplsCall(pub ::std::string::String); - ///Container type for all input parameters for the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` + /// Container type for all input parameters for the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` #[derive( Clone, ::ethers::contract::EthCall, @@ -2810,7 +2812,7 @@ pub mod ibc_handler { )] #[ethcall(name = "clientRegistry", abi = "clientRegistry(string)")] pub struct ClientRegistryCall(pub ::std::string::String); - ///Container type for all input parameters for the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` + /// Container type for all input parameters for the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` #[derive( Clone, ::ethers::contract::EthCall, @@ -2823,7 +2825,7 @@ pub mod ibc_handler { )] #[ethcall(name = "clientTypes", abi = "clientTypes(string)")] pub struct ClientTypesCall(pub ::std::string::String); - ///Container type for all input parameters for the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` + /// Container type for all input parameters for the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` #[derive( Clone, ::ethers::contract::EthCall, @@ -2836,7 +2838,7 @@ pub mod ibc_handler { )] #[ethcall(name = "commitments", abi = "commitments(bytes32)")] pub struct CommitmentsCall(pub [u8; 32]); - ///Container type for all input parameters for the `connectionOpenAck` function with signature `connectionOpenAck((string,bytes,(string,string[]),string,bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))` and selector `0xe7f32c0f` + /// Container type for all input parameters for the `connectionOpenAck` function with signature `connectionOpenAck((string,bytes,(string,string[]),string,bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))` and selector `0xe7f32c0f` #[derive( Clone, ::ethers::contract::EthCall, @@ -2852,7 +2854,7 @@ pub mod ibc_handler { abi = "connectionOpenAck((string,bytes,(string,string[]),string,bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))" )] pub struct ConnectionOpenAckCall(pub MsgConnectionOpenAck); - ///Container type for all input parameters for the `connectionOpenConfirm` function with signature `connectionOpenConfirm((string,bytes,(uint64,uint64),address))` and selector `0x87c54dd4` + /// Container type for all input parameters for the `connectionOpenConfirm` function with signature `connectionOpenConfirm((string,bytes,(uint64,uint64),address))` and selector `0x87c54dd4` #[derive( Clone, ::ethers::contract::EthCall, @@ -2868,7 +2870,7 @@ pub mod ibc_handler { abi = "connectionOpenConfirm((string,bytes,(uint64,uint64),address))" )] pub struct ConnectionOpenConfirmCall(pub MsgConnectionOpenConfirm); - ///Container type for all input parameters for the `connectionOpenInit` function with signature `connectionOpenInit((string,(string,string[]),(string,string,(bytes)),uint64,address))` and selector `0x8775f7f8` + /// Container type for all input parameters for the `connectionOpenInit` function with signature `connectionOpenInit((string,(string,string[]),(string,string,(bytes)),uint64,address))` and selector `0x8775f7f8` #[derive( Clone, ::ethers::contract::EthCall, @@ -2884,7 +2886,7 @@ pub mod ibc_handler { abi = "connectionOpenInit((string,(string,string[]),(string,string,(bytes)),uint64,address))" )] pub struct ConnectionOpenInitCall(pub MsgConnectionOpenInit); - ///Container type for all input parameters for the `connectionOpenTry` function with signature `connectionOpenTry(((string,string,(bytes)),uint64,string,bytes,(string,string[])[],bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))` and selector `0x7b666dc1` + /// Container type for all input parameters for the `connectionOpenTry` function with signature `connectionOpenTry(((string,string,(bytes)),uint64,string,bytes,(string,string[])[],bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))` and selector `0x7b666dc1` #[derive( Clone, ::ethers::contract::EthCall, @@ -2900,7 +2902,7 @@ pub mod ibc_handler { abi = "connectionOpenTry(((string,string,(bytes)),uint64,string,bytes,(string,string[])[],bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))" )] pub struct ConnectionOpenTryCall(pub MsgConnectionOpenTry); - ///Container type for all input parameters for the `connections` function with signature `connections(string)` and selector `0x31973f00` + /// Container type for all input parameters for the `connections` function with signature `connections(string)` and selector `0x31973f00` #[derive( Clone, ::ethers::contract::EthCall, @@ -2913,7 +2915,7 @@ pub mod ibc_handler { )] #[ethcall(name = "connections", abi = "connections(string)")] pub struct ConnectionsCall(pub ::std::string::String); - ///Container type for all input parameters for the `createClient` function with signature `createClient((string,bytes,bytes,address))` and selector `0xfed12cbf` + /// Container type for all input parameters for the `createClient` function with signature `createClient((string,bytes,bytes,address))` and selector `0xfed12cbf` #[derive( Clone, ::ethers::contract::EthCall, @@ -2929,7 +2931,7 @@ pub mod ibc_handler { abi = "createClient((string,bytes,bytes,address))" )] pub struct CreateClientCall(pub MsgCreateClient); - ///Container type for all input parameters for the `getChannel` function with signature `getChannel(string,string)` and selector `0x3000217a` + /// Container type for all input parameters for the `getChannel` function with signature `getChannel(string,string)` and selector `0x3000217a` #[derive( Clone, ::ethers::contract::EthCall, @@ -2945,7 +2947,7 @@ pub mod ibc_handler { pub port_id: ::std::string::String, pub channel_id: ::std::string::String, } - ///Container type for all input parameters for the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` + /// Container type for all input parameters for the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` #[derive( Clone, ::ethers::contract::EthCall, @@ -2960,7 +2962,7 @@ pub mod ibc_handler { pub struct GetClientCall { pub client_id: ::std::string::String, } - ///Container type for all input parameters for the `getConnection` function with signature `getConnection(string)` and selector `0x27711a69` + /// Container type for all input parameters for the `getConnection` function with signature `getConnection(string)` and selector `0x27711a69` #[derive( Clone, ::ethers::contract::EthCall, @@ -2975,7 +2977,7 @@ pub mod ibc_handler { pub struct GetConnectionCall { pub connection_id: ::std::string::String, } - ///Container type for all input parameters for the `initialize` function with signature `initialize(address,address,address,address,address)` and selector `0x1459457a` + /// Container type for all input parameters for the `initialize` function with signature `initialize(address,address,address,address,address)` and selector `0x1459457a` #[derive( Clone, ::ethers::contract::EthCall, @@ -2997,7 +2999,7 @@ pub mod ibc_handler { pub ibc_packet: ::ethers::core::types::Address, pub admin: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` + /// Container type for all input parameters for the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` #[derive( Clone, ::ethers::contract::EthCall, @@ -3010,7 +3012,7 @@ pub mod ibc_handler { )] #[ethcall(name = "nextChannelSequencePath", abi = "nextChannelSequencePath()")] pub struct NextChannelSequencePathCall; - ///Container type for all input parameters for the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` + /// Container type for all input parameters for the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` #[derive( Clone, ::ethers::contract::EthCall, @@ -3023,7 +3025,7 @@ pub mod ibc_handler { )] #[ethcall(name = "nextClientSequencePath", abi = "nextClientSequencePath()")] pub struct NextClientSequencePathCall; - ///Container type for all input parameters for the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` + /// Container type for all input parameters for the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` #[derive( Clone, ::ethers::contract::EthCall, @@ -3039,7 +3041,7 @@ pub mod ibc_handler { abi = "nextConnectionSequencePath()" )] pub struct NextConnectionSequencePathCall; - ///Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` + /// Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` #[derive( Clone, ::ethers::contract::EthCall, @@ -3052,7 +3054,7 @@ pub mod ibc_handler { )] #[ethcall(name = "owner", abi = "owner()")] pub struct OwnerCall; - ///Container type for all input parameters for the `paused` function with signature `paused()` and selector `0x5c975abb` + /// Container type for all input parameters for the `paused` function with signature `paused()` and selector `0x5c975abb` #[derive( Clone, ::ethers::contract::EthCall, @@ -3065,7 +3067,7 @@ pub mod ibc_handler { )] #[ethcall(name = "paused", abi = "paused()")] pub struct PausedCall; - ///Container type for all input parameters for the `proxiableUUID` function with signature `proxiableUUID()` and selector `0x52d1902d` + /// Container type for all input parameters for the `proxiableUUID` function with signature `proxiableUUID()` and selector `0x52d1902d` #[derive( Clone, ::ethers::contract::EthCall, @@ -3078,7 +3080,7 @@ pub mod ibc_handler { )] #[ethcall(name = "proxiableUUID", abi = "proxiableUUID()")] pub struct ProxiableUUIDCall; - ///Container type for all input parameters for the `recvPacket` function with signature `recvPacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),address))` and selector `0xe8f088c6` + /// Container type for all input parameters for the `recvPacket` function with signature `recvPacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),address))` and selector `0xe8f088c6` #[derive( Clone, ::ethers::contract::EthCall, @@ -3094,7 +3096,7 @@ pub mod ibc_handler { abi = "recvPacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),address))" )] pub struct RecvPacketCall(pub MsgPacketRecv); - ///Container type for all input parameters for the `registerClient` function with signature `registerClient(string,address)` and selector `0x18c19870` + /// Container type for all input parameters for the `registerClient` function with signature `registerClient(string,address)` and selector `0x18c19870` #[derive( Clone, ::ethers::contract::EthCall, @@ -3110,7 +3112,7 @@ pub mod ibc_handler { pub ::std::string::String, pub ::ethers::core::types::Address, ); - ///Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` + /// Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` #[derive( Clone, ::ethers::contract::EthCall, @@ -3123,7 +3125,7 @@ pub mod ibc_handler { )] #[ethcall(name = "renounceOwnership", abi = "renounceOwnership()")] pub struct RenounceOwnershipCall; - ///Container type for all input parameters for the `sendPacket` function with signature `sendPacket(string,(uint64,uint64),uint64,bytes)` and selector `0x6cf02d3f` + /// Container type for all input parameters for the `sendPacket` function with signature `sendPacket(string,(uint64,uint64),uint64,bytes)` and selector `0x6cf02d3f` #[derive( Clone, ::ethers::contract::EthCall, @@ -3144,7 +3146,7 @@ pub mod ibc_handler { pub u64, pub ::ethers::core::types::Bytes, ); - ///Container type for all input parameters for the `timeoutPacket` function with signature `timeoutPacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),uint64,address))` and selector `0xa04f91b2` + /// Container type for all input parameters for the `timeoutPacket` function with signature `timeoutPacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),uint64,address))` and selector `0xa04f91b2` #[derive( Clone, ::ethers::contract::EthCall, @@ -3160,7 +3162,7 @@ pub mod ibc_handler { abi = "timeoutPacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),uint64,address))" )] pub struct TimeoutPacketCall(pub MsgPacketTimeout); - ///Container type for all input parameters for the `transferOwnership` function with signature `transferOwnership(address)` and selector `0xf2fde38b` + /// Container type for all input parameters for the `transferOwnership` function with signature `transferOwnership(address)` and selector `0xf2fde38b` #[derive( Clone, ::ethers::contract::EthCall, @@ -3175,7 +3177,7 @@ pub mod ibc_handler { pub struct TransferOwnershipCall { pub new_owner: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `updateClient` function with signature `updateClient((string,bytes,address))` and selector `0xf5dd3745` + /// Container type for all input parameters for the `updateClient` function with signature `updateClient((string,bytes,address))` and selector `0xf5dd3745` #[derive( Clone, ::ethers::contract::EthCall, @@ -3188,7 +3190,7 @@ pub mod ibc_handler { )] #[ethcall(name = "updateClient", abi = "updateClient((string,bytes,address))")] pub struct UpdateClientCall(pub MsgUpdateClient); - ///Container type for all input parameters for the `upgradeImpls` function with signature `upgradeImpls(address,address,address,address)` and selector `0xa9365006` + /// Container type for all input parameters for the `upgradeImpls` function with signature `upgradeImpls(address,address,address,address)` and selector `0xa9365006` #[derive( Clone, ::ethers::contract::EthCall, @@ -3209,7 +3211,7 @@ pub mod ibc_handler { pub ibc_channel: ::ethers::core::types::Address, pub ibc_packet: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `upgradeToAndCall` function with signature `upgradeToAndCall(address,bytes)` and selector `0x4f1ef286` + /// Container type for all input parameters for the `upgradeToAndCall` function with signature `upgradeToAndCall(address,bytes)` and selector `0x4f1ef286` #[derive( Clone, ::ethers::contract::EthCall, @@ -3225,7 +3227,7 @@ pub mod ibc_handler { pub new_implementation: ::ethers::core::types::Address, pub data: ::ethers::core::types::Bytes, } - ///Container type for all input parameters for the `writeAcknowledgement` function with signature `writeAcknowledgement((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes)` and selector `0xca956667` + /// Container type for all input parameters for the `writeAcknowledgement` function with signature `writeAcknowledgement((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes)` and selector `0xca956667` #[derive( Clone, ::ethers::contract::EthCall, @@ -3244,7 +3246,7 @@ pub mod ibc_handler { pub IbcCoreChannelV1PacketData, pub ::ethers::core::types::Bytes, ); - ///Container type for all of the contract's call + /// Container type for all of the contract's call #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum IBCHandlerCalls { CommitmentPrefix(CommitmentPrefixCall), @@ -3803,7 +3805,7 @@ pub mod ibc_handler { Self::WriteAcknowledgement(value) } } - ///Container type for all return fields from the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` + /// Container type for all return fields from the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3815,7 +3817,7 @@ pub mod ibc_handler { Hash, )] pub struct CommitmentPrefixReturn(pub ::std::string::String); - ///Container type for all return fields from the `UPGRADE_INTERFACE_VERSION` function with signature `UPGRADE_INTERFACE_VERSION()` and selector `0xad3cb1cc` + /// Container type for all return fields from the `UPGRADE_INTERFACE_VERSION` function with signature `UPGRADE_INTERFACE_VERSION()` and selector `0xad3cb1cc` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3827,7 +3829,7 @@ pub mod ibc_handler { Hash, )] pub struct UpgradeInterfaceVersionReturn(pub ::std::string::String); - ///Container type for all return fields from the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` + /// Container type for all return fields from the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3839,7 +3841,7 @@ pub mod ibc_handler { Hash, )] pub struct CapabilitiesReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `channelCapabilityPath` function with signature `channelCapabilityPath(string,string)` and selector `0x3bc3339f` + /// Container type for all return fields from the `channelCapabilityPath` function with signature `channelCapabilityPath(string,string)` and selector `0x3bc3339f` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3851,7 +3853,7 @@ pub mod ibc_handler { Hash, )] pub struct ChannelCapabilityPathReturn(pub ::std::string::String); - ///Container type for all return fields from the `channelOpenInit` function with signature `channelOpenInit((string,(uint8,uint8,(string,string),string[],string),address))` and selector `0x25035747` + /// Container type for all return fields from the `channelOpenInit` function with signature `channelOpenInit((string,(uint8,uint8,(string,string),string[],string),address))` and selector `0x25035747` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3863,7 +3865,7 @@ pub mod ibc_handler { Hash, )] pub struct ChannelOpenInitReturn(pub ::std::string::String); - ///Container type for all return fields from the `channelOpenTry` function with signature `channelOpenTry((string,(uint8,uint8,(string,string),string[],string),string,bytes,(uint64,uint64),address))` and selector `0x8b627bca` + /// Container type for all return fields from the `channelOpenTry` function with signature `channelOpenTry((string,(uint8,uint8,(string,string),string[],string),string,bytes,(uint64,uint64),address))` and selector `0x8b627bca` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3875,7 +3877,7 @@ pub mod ibc_handler { Hash, )] pub struct ChannelOpenTryReturn(pub ::std::string::String); - ///Container type for all return fields from the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` + /// Container type for all return fields from the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3892,7 +3894,7 @@ pub mod ibc_handler { pub counterparty: IbcCoreChannelV1CounterpartyData, pub version: ::std::string::String, } - ///Container type for all return fields from the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` + /// Container type for all return fields from the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3904,7 +3906,7 @@ pub mod ibc_handler { Hash, )] pub struct ClientImplsReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` + /// Container type for all return fields from the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3916,7 +3918,7 @@ pub mod ibc_handler { Hash, )] pub struct ClientRegistryReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` + /// Container type for all return fields from the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3928,7 +3930,7 @@ pub mod ibc_handler { Hash, )] pub struct ClientTypesReturn(pub ::std::string::String); - ///Container type for all return fields from the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` + /// Container type for all return fields from the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3940,7 +3942,7 @@ pub mod ibc_handler { Hash, )] pub struct CommitmentsReturn(pub [u8; 32]); - ///Container type for all return fields from the `connectionOpenInit` function with signature `connectionOpenInit((string,(string,string[]),(string,string,(bytes)),uint64,address))` and selector `0x8775f7f8` + /// Container type for all return fields from the `connectionOpenInit` function with signature `connectionOpenInit((string,(string,string[]),(string,string,(bytes)),uint64,address))` and selector `0x8775f7f8` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3952,7 +3954,7 @@ pub mod ibc_handler { Hash, )] pub struct ConnectionOpenInitReturn(pub ::std::string::String); - ///Container type for all return fields from the `connectionOpenTry` function with signature `connectionOpenTry(((string,string,(bytes)),uint64,string,bytes,(string,string[])[],bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))` and selector `0x7b666dc1` + /// Container type for all return fields from the `connectionOpenTry` function with signature `connectionOpenTry(((string,string,(bytes)),uint64,string,bytes,(string,string[])[],bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address))` and selector `0x7b666dc1` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3964,7 +3966,7 @@ pub mod ibc_handler { Hash, )] pub struct ConnectionOpenTryReturn(pub ::std::string::String); - ///Container type for all return fields from the `connections` function with signature `connections(string)` and selector `0x31973f00` + /// Container type for all return fields from the `connections` function with signature `connections(string)` and selector `0x31973f00` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3981,7 +3983,7 @@ pub mod ibc_handler { pub counterparty: IbcCoreConnectionV1CounterpartyData, pub delay_period: u64, } - ///Container type for all return fields from the `createClient` function with signature `createClient((string,bytes,bytes,address))` and selector `0xfed12cbf` + /// Container type for all return fields from the `createClient` function with signature `createClient((string,bytes,bytes,address))` and selector `0xfed12cbf` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3993,7 +3995,7 @@ pub mod ibc_handler { Hash, )] pub struct CreateClientReturn(pub ::std::string::String); - ///Container type for all return fields from the `getChannel` function with signature `getChannel(string,string)` and selector `0x3000217a` + /// Container type for all return fields from the `getChannel` function with signature `getChannel(string,string)` and selector `0x3000217a` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -4005,7 +4007,7 @@ pub mod ibc_handler { Hash, )] pub struct GetChannelReturn(pub IbcCoreChannelV1ChannelData); - ///Container type for all return fields from the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` + /// Container type for all return fields from the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -4017,7 +4019,7 @@ pub mod ibc_handler { Hash, )] pub struct GetClientReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `getConnection` function with signature `getConnection(string)` and selector `0x27711a69` + /// Container type for all return fields from the `getConnection` function with signature `getConnection(string)` and selector `0x27711a69` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -4029,7 +4031,7 @@ pub mod ibc_handler { Hash, )] pub struct GetConnectionReturn(pub IbcCoreConnectionV1ConnectionEndData); - ///Container type for all return fields from the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` + /// Container type for all return fields from the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -4041,7 +4043,7 @@ pub mod ibc_handler { Hash, )] pub struct NextChannelSequencePathReturn(pub [u8; 32]); - ///Container type for all return fields from the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` + /// Container type for all return fields from the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -4053,7 +4055,7 @@ pub mod ibc_handler { Hash, )] pub struct NextClientSequencePathReturn(pub [u8; 32]); - ///Container type for all return fields from the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` + /// Container type for all return fields from the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -4065,7 +4067,7 @@ pub mod ibc_handler { Hash, )] pub struct NextConnectionSequencePathReturn(pub [u8; 32]); - ///Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` + /// Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -4077,7 +4079,7 @@ pub mod ibc_handler { Hash, )] pub struct OwnerReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `paused` function with signature `paused()` and selector `0x5c975abb` + /// Container type for all return fields from the `paused` function with signature `paused()` and selector `0x5c975abb` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -4089,7 +4091,7 @@ pub mod ibc_handler { Hash, )] pub struct PausedReturn(pub bool); - ///Container type for all return fields from the `proxiableUUID` function with signature `proxiableUUID()` and selector `0x52d1902d` + /// Container type for all return fields from the `proxiableUUID` function with signature `proxiableUUID()` and selector `0x52d1902d` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -4101,7 +4103,7 @@ pub mod ibc_handler { Hash, )] pub struct ProxiableUUIDReturn(pub [u8; 32]); - ///Container type for all return fields from the `sendPacket` function with signature `sendPacket(string,(uint64,uint64),uint64,bytes)` and selector `0x6cf02d3f` + /// Container type for all return fields from the `sendPacket` function with signature `sendPacket(string,(uint64,uint64),uint64,bytes)` and selector `0x6cf02d3f` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/generated/rust/contracts/src/ibc_packet.rs b/generated/rust/contracts/src/ibc_packet.rs index 727839686a..15bc1b0479 100644 --- a/generated/rust/contracts/src/ibc_packet.rs +++ b/generated/rust/contracts/src/ibc_packet.rs @@ -930,7 +930,7 @@ pub mod ibc_packet { fallback: false, } } - ///The parsed JSON ABI of the contract. + /// The parsed JSON ABI of the contract. #[cfg(feature = "providers")] pub static IBCPACKET_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); @@ -1030,7 +1030,7 @@ pub mod ibc_packet { let deployer = ::ethers::contract::ContractDeployer::new(deployer); Ok(deployer) } - ///Calls the contract's `COMMITMENT_PREFIX` (0xa9550dac) function + /// Calls the contract's `COMMITMENT_PREFIX` (0xa9550dac) function pub fn commitment_prefix( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1038,7 +1038,7 @@ pub mod ibc_packet { .method_hash([169, 85, 13, 172], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `acknowledgePacket` (0x07037704) function + /// Calls the contract's `acknowledgePacket` (0x07037704) function pub fn acknowledge_packet( &self, msg: MsgPacketAcknowledgement, @@ -1047,7 +1047,7 @@ pub mod ibc_packet { .method_hash([7, 3, 119, 4], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `capabilities` (0x5717bcf5) function + /// Calls the contract's `capabilities` (0x5717bcf5) function pub fn capabilities( &self, p0: ::std::string::String, @@ -1056,7 +1056,7 @@ pub mod ibc_packet { .method_hash([87, 23, 188, 245], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `channelCapabilityPath` (0x3bc3339f) function + /// Calls the contract's `channelCapabilityPath` (0x3bc3339f) function pub fn channel_capability_path( &self, port_id: ::std::string::String, @@ -1066,7 +1066,7 @@ pub mod ibc_packet { .method_hash([59, 195, 51, 159], (port_id, channel_id)) .expect("method not found (this should never happen)") } - ///Calls the contract's `channels` (0x5b3de260) function + /// Calls the contract's `channels` (0x5b3de260) function pub fn channels( &self, p0: ::std::string::String, @@ -1084,7 +1084,7 @@ pub mod ibc_packet { .method_hash([91, 61, 226, 96], (p0, p1)) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientImpls` (0xd1297b8d) function + /// Calls the contract's `clientImpls` (0xd1297b8d) function pub fn client_impls( &self, p0: ::std::string::String, @@ -1093,7 +1093,7 @@ pub mod ibc_packet { .method_hash([209, 41, 123, 141], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientRegistry` (0x990491a5) function + /// Calls the contract's `clientRegistry` (0x990491a5) function pub fn client_registry( &self, p0: ::std::string::String, @@ -1102,7 +1102,7 @@ pub mod ibc_packet { .method_hash([153, 4, 145, 165], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `clientTypes` (0xc2380105) function + /// Calls the contract's `clientTypes` (0xc2380105) function pub fn client_types( &self, p0: ::std::string::String, @@ -1111,7 +1111,7 @@ pub mod ibc_packet { .method_hash([194, 56, 1, 5], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `commitments` (0x839df945) function + /// Calls the contract's `commitments` (0x839df945) function pub fn commitments( &self, p0: [u8; 32], @@ -1120,7 +1120,7 @@ pub mod ibc_packet { .method_hash([131, 157, 249, 69], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `connections` (0x31973f00) function + /// Calls the contract's `connections` (0x31973f00) function pub fn connections( &self, p0: ::std::string::String, @@ -1137,7 +1137,7 @@ pub mod ibc_packet { .method_hash([49, 151, 63, 0], p0) .expect("method not found (this should never happen)") } - ///Calls the contract's `getClient` (0x7eb78932) function + /// Calls the contract's `getClient` (0x7eb78932) function pub fn get_client( &self, client_id: ::std::string::String, @@ -1146,7 +1146,7 @@ pub mod ibc_packet { .method_hash([126, 183, 137, 50], client_id) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextChannelSequencePath` (0x8669fd15) function + /// Calls the contract's `nextChannelSequencePath` (0x8669fd15) function pub fn next_channel_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1154,7 +1154,7 @@ pub mod ibc_packet { .method_hash([134, 105, 253, 21], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextClientSequencePath` (0x990c3888) function + /// Calls the contract's `nextClientSequencePath` (0x990c3888) function pub fn next_client_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1162,7 +1162,7 @@ pub mod ibc_packet { .method_hash([153, 12, 56, 136], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `nextConnectionSequencePath` (0x46807086) function + /// Calls the contract's `nextConnectionSequencePath` (0x46807086) function pub fn next_connection_sequence_path( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1170,7 +1170,7 @@ pub mod ibc_packet { .method_hash([70, 128, 112, 134], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `recvPacket` (0xe8f088c6) function + /// Calls the contract's `recvPacket` (0xe8f088c6) function pub fn recv_packet( &self, msg: MsgPacketRecv, @@ -1179,7 +1179,7 @@ pub mod ibc_packet { .method_hash([232, 240, 136, 198], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `sendPacket` (0x6cf02d3f) function + /// Calls the contract's `sendPacket` (0x6cf02d3f) function pub fn send_packet( &self, source_channel: ::std::string::String, @@ -1194,7 +1194,7 @@ pub mod ibc_packet { ) .expect("method not found (this should never happen)") } - ///Calls the contract's `timeoutPacket` (0xa04f91b2) function + /// Calls the contract's `timeoutPacket` (0xa04f91b2) function pub fn timeout_packet( &self, msg: MsgPacketTimeout, @@ -1203,7 +1203,7 @@ pub mod ibc_packet { .method_hash([160, 79, 145, 178], (msg,)) .expect("method not found (this should never happen)") } - ///Calls the contract's `writeAcknowledgement` (0xca956667) function + /// Calls the contract's `writeAcknowledgement` (0xca956667) function pub fn write_acknowledgement( &self, packet: IbcCoreChannelV1PacketData, @@ -1213,33 +1213,33 @@ pub mod ibc_packet { .method_hash([202, 149, 102, 103], (packet, acknowledgement)) .expect("method not found (this should never happen)") } - ///Gets the contract's `AcknowledgePacket` event + /// Gets the contract's `AcknowledgePacket` event pub fn acknowledge_packet_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, AcknowledgePacketFilter> { self.0.event() } - ///Gets the contract's `RecvPacket` event + /// Gets the contract's `RecvPacket` event pub fn recv_packet_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, RecvPacketFilter> { self.0.event() } - ///Gets the contract's `SendPacket` event + /// Gets the contract's `SendPacket` event pub fn send_packet_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, SendPacketFilter> { self.0.event() } - ///Gets the contract's `TimeoutPacket` event + /// Gets the contract's `TimeoutPacket` event pub fn timeout_packet_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, TimeoutPacketFilter> { self.0.event() } - ///Gets the contract's `WriteAcknowledgement` event + /// Gets the contract's `WriteAcknowledgement` event pub fn write_acknowledgement_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, WriteAcknowledgementFilter> @@ -1260,7 +1260,7 @@ pub mod ibc_packet { Self::new(contract.address(), contract.client()) } } - ///Custom Error type `ErrAcknowledgementAlreadyExists` with signature `ErrAcknowledgementAlreadyExists()` and selector `0x5c6d7711` + /// Custom Error type `ErrAcknowledgementAlreadyExists` with signature `ErrAcknowledgementAlreadyExists()` and selector `0x5c6d7711` #[derive( Clone, ::ethers::contract::EthError, @@ -1276,7 +1276,7 @@ pub mod ibc_packet { abi = "ErrAcknowledgementAlreadyExists()" )] pub struct ErrAcknowledgementAlreadyExists; - ///Custom Error type `ErrAcknowledgementIsEmpty` with signature `ErrAcknowledgementIsEmpty()` and selector `0x2430f403` + /// Custom Error type `ErrAcknowledgementIsEmpty` with signature `ErrAcknowledgementIsEmpty()` and selector `0x2430f403` #[derive( Clone, ::ethers::contract::EthError, @@ -1292,7 +1292,7 @@ pub mod ibc_packet { abi = "ErrAcknowledgementIsEmpty()" )] pub struct ErrAcknowledgementIsEmpty; - ///Custom Error type `ErrClientNotFound` with signature `ErrClientNotFound()` and selector `0xb6c71f7d` + /// Custom Error type `ErrClientNotFound` with signature `ErrClientNotFound()` and selector `0xb6c71f7d` #[derive( Clone, ::ethers::contract::EthError, @@ -1305,7 +1305,7 @@ pub mod ibc_packet { )] #[etherror(name = "ErrClientNotFound", abi = "ErrClientNotFound()")] pub struct ErrClientNotFound; - ///Custom Error type `ErrDestinationAndCounterpartyChannelMismatch` with signature `ErrDestinationAndCounterpartyChannelMismatch()` and selector `0x9387f5d0` + /// Custom Error type `ErrDestinationAndCounterpartyChannelMismatch` with signature `ErrDestinationAndCounterpartyChannelMismatch()` and selector `0x9387f5d0` #[derive( Clone, ::ethers::contract::EthError, @@ -1321,7 +1321,7 @@ pub mod ibc_packet { abi = "ErrDestinationAndCounterpartyChannelMismatch()" )] pub struct ErrDestinationAndCounterpartyChannelMismatch; - ///Custom Error type `ErrDestinationAndCounterpartyPortMismatch` with signature `ErrDestinationAndCounterpartyPortMismatch()` and selector `0xa6076043` + /// Custom Error type `ErrDestinationAndCounterpartyPortMismatch` with signature `ErrDestinationAndCounterpartyPortMismatch()` and selector `0xa6076043` #[derive( Clone, ::ethers::contract::EthError, @@ -1337,7 +1337,7 @@ pub mod ibc_packet { abi = "ErrDestinationAndCounterpartyPortMismatch()" )] pub struct ErrDestinationAndCounterpartyPortMismatch; - ///Custom Error type `ErrHeightTimeout` with signature `ErrHeightTimeout()` and selector `0xa9cfb705` + /// Custom Error type `ErrHeightTimeout` with signature `ErrHeightTimeout()` and selector `0xa9cfb705` #[derive( Clone, ::ethers::contract::EthError, @@ -1350,7 +1350,7 @@ pub mod ibc_packet { )] #[etherror(name = "ErrHeightTimeout", abi = "ErrHeightTimeout()")] pub struct ErrHeightTimeout; - ///Custom Error type `ErrInvalidChannelState` with signature `ErrInvalidChannelState()` and selector `0x96d09146` + /// Custom Error type `ErrInvalidChannelState` with signature `ErrInvalidChannelState()` and selector `0x96d09146` #[derive( Clone, ::ethers::contract::EthError, @@ -1363,7 +1363,7 @@ pub mod ibc_packet { )] #[etherror(name = "ErrInvalidChannelState", abi = "ErrInvalidChannelState()")] pub struct ErrInvalidChannelState; - ///Custom Error type `ErrInvalidConnectionState` with signature `ErrInvalidConnectionState()` and selector `0x8ca98990` + /// Custom Error type `ErrInvalidConnectionState` with signature `ErrInvalidConnectionState()` and selector `0x8ca98990` #[derive( Clone, ::ethers::contract::EthError, @@ -1379,7 +1379,7 @@ pub mod ibc_packet { abi = "ErrInvalidConnectionState()" )] pub struct ErrInvalidConnectionState; - ///Custom Error type `ErrInvalidPacketCommitment` with signature `ErrInvalidPacketCommitment()` and selector `0x438a8d16` + /// Custom Error type `ErrInvalidPacketCommitment` with signature `ErrInvalidPacketCommitment()` and selector `0x438a8d16` #[derive( Clone, ::ethers::contract::EthError, @@ -1395,7 +1395,7 @@ pub mod ibc_packet { abi = "ErrInvalidPacketCommitment()" )] pub struct ErrInvalidPacketCommitment; - ///Custom Error type `ErrInvalidProof` with signature `ErrInvalidProof()` and selector `0x14209932` + /// Custom Error type `ErrInvalidProof` with signature `ErrInvalidProof()` and selector `0x14209932` #[derive( Clone, ::ethers::contract::EthError, @@ -1408,7 +1408,7 @@ pub mod ibc_packet { )] #[etherror(name = "ErrInvalidProof", abi = "ErrInvalidProof()")] pub struct ErrInvalidProof; - ///Custom Error type `ErrInvalidTimeoutHeight` with signature `ErrInvalidTimeoutHeight()` and selector `0xc8e1d264` + /// Custom Error type `ErrInvalidTimeoutHeight` with signature `ErrInvalidTimeoutHeight()` and selector `0xc8e1d264` #[derive( Clone, ::ethers::contract::EthError, @@ -1421,7 +1421,7 @@ pub mod ibc_packet { )] #[etherror(name = "ErrInvalidTimeoutHeight", abi = "ErrInvalidTimeoutHeight()")] pub struct ErrInvalidTimeoutHeight; - ///Custom Error type `ErrInvalidTimeoutTimestamp` with signature `ErrInvalidTimeoutTimestamp()` and selector `0xe6277ce0` + /// Custom Error type `ErrInvalidTimeoutTimestamp` with signature `ErrInvalidTimeoutTimestamp()` and selector `0xe6277ce0` #[derive( Clone, ::ethers::contract::EthError, @@ -1437,7 +1437,7 @@ pub mod ibc_packet { abi = "ErrInvalidTimeoutTimestamp()" )] pub struct ErrInvalidTimeoutTimestamp; - ///Custom Error type `ErrLatestHeightNotFound` with signature `ErrLatestHeightNotFound()` and selector `0xe53d4e37` + /// Custom Error type `ErrLatestHeightNotFound` with signature `ErrLatestHeightNotFound()` and selector `0xe53d4e37` #[derive( Clone, ::ethers::contract::EthError, @@ -1450,7 +1450,7 @@ pub mod ibc_packet { )] #[etherror(name = "ErrLatestHeightNotFound", abi = "ErrLatestHeightNotFound()")] pub struct ErrLatestHeightNotFound; - ///Custom Error type `ErrLatestTimestampNotFound` with signature `ErrLatestTimestampNotFound()` and selector `0x9b6c9adc` + /// Custom Error type `ErrLatestTimestampNotFound` with signature `ErrLatestTimestampNotFound()` and selector `0x9b6c9adc` #[derive( Clone, ::ethers::contract::EthError, @@ -1466,7 +1466,7 @@ pub mod ibc_packet { abi = "ErrLatestTimestampNotFound()" )] pub struct ErrLatestTimestampNotFound; - ///Custom Error type `ErrModuleNotFound` with signature `ErrModuleNotFound()` and selector `0xc6830cff` + /// Custom Error type `ErrModuleNotFound` with signature `ErrModuleNotFound()` and selector `0xc6830cff` #[derive( Clone, ::ethers::contract::EthError, @@ -1479,7 +1479,7 @@ pub mod ibc_packet { )] #[etherror(name = "ErrModuleNotFound", abi = "ErrModuleNotFound()")] pub struct ErrModuleNotFound; - ///Custom Error type `ErrNextSequenceMustBeGreaterThanTimeoutSequence` with signature `ErrNextSequenceMustBeGreaterThanTimeoutSequence()` and selector `0xe758ef82` + /// Custom Error type `ErrNextSequenceMustBeGreaterThanTimeoutSequence` with signature `ErrNextSequenceMustBeGreaterThanTimeoutSequence()` and selector `0xe758ef82` #[derive( Clone, ::ethers::contract::EthError, @@ -1495,7 +1495,7 @@ pub mod ibc_packet { abi = "ErrNextSequenceMustBeGreaterThanTimeoutSequence()" )] pub struct ErrNextSequenceMustBeGreaterThanTimeoutSequence; - ///Custom Error type `ErrPacketAlreadyReceived` with signature `ErrPacketAlreadyReceived()` and selector `0xa46bbab4` + /// Custom Error type `ErrPacketAlreadyReceived` with signature `ErrPacketAlreadyReceived()` and selector `0xa46bbab4` #[derive( Clone, ::ethers::contract::EthError, @@ -1508,7 +1508,7 @@ pub mod ibc_packet { )] #[etherror(name = "ErrPacketAlreadyReceived", abi = "ErrPacketAlreadyReceived()")] pub struct ErrPacketAlreadyReceived; - ///Custom Error type `ErrPacketCommitmentNotFound` with signature `ErrPacketCommitmentNotFound()` and selector `0x4d7cfc57` + /// Custom Error type `ErrPacketCommitmentNotFound` with signature `ErrPacketCommitmentNotFound()` and selector `0x4d7cfc57` #[derive( Clone, ::ethers::contract::EthError, @@ -1524,7 +1524,7 @@ pub mod ibc_packet { abi = "ErrPacketCommitmentNotFound()" )] pub struct ErrPacketCommitmentNotFound; - ///Custom Error type `ErrPacketSequenceNextSequenceMismatch` with signature `ErrPacketSequenceNextSequenceMismatch()` and selector `0x402a84a3` + /// Custom Error type `ErrPacketSequenceNextSequenceMismatch` with signature `ErrPacketSequenceNextSequenceMismatch()` and selector `0x402a84a3` #[derive( Clone, ::ethers::contract::EthError, @@ -1540,7 +1540,7 @@ pub mod ibc_packet { abi = "ErrPacketSequenceNextSequenceMismatch()" )] pub struct ErrPacketSequenceNextSequenceMismatch; - ///Custom Error type `ErrPacketWithoutTimeout` with signature `ErrPacketWithoutTimeout()` and selector `0x5734400c` + /// Custom Error type `ErrPacketWithoutTimeout` with signature `ErrPacketWithoutTimeout()` and selector `0x5734400c` #[derive( Clone, ::ethers::contract::EthError, @@ -1553,7 +1553,7 @@ pub mod ibc_packet { )] #[etherror(name = "ErrPacketWithoutTimeout", abi = "ErrPacketWithoutTimeout()")] pub struct ErrPacketWithoutTimeout; - ///Custom Error type `ErrSourceAndCounterpartyChannelMismatch` with signature `ErrSourceAndCounterpartyChannelMismatch()` and selector `0x77668ed1` + /// Custom Error type `ErrSourceAndCounterpartyChannelMismatch` with signature `ErrSourceAndCounterpartyChannelMismatch()` and selector `0x77668ed1` #[derive( Clone, ::ethers::contract::EthError, @@ -1569,7 +1569,7 @@ pub mod ibc_packet { abi = "ErrSourceAndCounterpartyChannelMismatch()" )] pub struct ErrSourceAndCounterpartyChannelMismatch; - ///Custom Error type `ErrSourceAndCounterpartyPortMismatch` with signature `ErrSourceAndCounterpartyPortMismatch()` and selector `0xda885c1d` + /// Custom Error type `ErrSourceAndCounterpartyPortMismatch` with signature `ErrSourceAndCounterpartyPortMismatch()` and selector `0xda885c1d` #[derive( Clone, ::ethers::contract::EthError, @@ -1585,7 +1585,7 @@ pub mod ibc_packet { abi = "ErrSourceAndCounterpartyPortMismatch()" )] pub struct ErrSourceAndCounterpartyPortMismatch; - ///Custom Error type `ErrTimeoutHeightNotReached` with signature `ErrTimeoutHeightNotReached()` and selector `0x12c51c64` + /// Custom Error type `ErrTimeoutHeightNotReached` with signature `ErrTimeoutHeightNotReached()` and selector `0x12c51c64` #[derive( Clone, ::ethers::contract::EthError, @@ -1601,7 +1601,7 @@ pub mod ibc_packet { abi = "ErrTimeoutHeightNotReached()" )] pub struct ErrTimeoutHeightNotReached; - ///Custom Error type `ErrTimeoutTimestampNotReached` with signature `ErrTimeoutTimestampNotReached()` and selector `0x8551d235` + /// Custom Error type `ErrTimeoutTimestampNotReached` with signature `ErrTimeoutTimestampNotReached()` and selector `0x8551d235` #[derive( Clone, ::ethers::contract::EthError, @@ -1617,7 +1617,7 @@ pub mod ibc_packet { abi = "ErrTimeoutTimestampNotReached()" )] pub struct ErrTimeoutTimestampNotReached; - ///Custom Error type `ErrTimestampTimeout` with signature `ErrTimestampTimeout()` and selector `0xa4821270` + /// Custom Error type `ErrTimestampTimeout` with signature `ErrTimestampTimeout()` and selector `0xa4821270` #[derive( Clone, ::ethers::contract::EthError, @@ -1630,7 +1630,7 @@ pub mod ibc_packet { )] #[etherror(name = "ErrTimestampTimeout", abi = "ErrTimestampTimeout()")] pub struct ErrTimestampTimeout; - ///Custom Error type `ErrUnauthorized` with signature `ErrUnauthorized()` and selector `0xcc12cef6` + /// Custom Error type `ErrUnauthorized` with signature `ErrUnauthorized()` and selector `0xcc12cef6` #[derive( Clone, ::ethers::contract::EthError, @@ -1643,7 +1643,7 @@ pub mod ibc_packet { )] #[etherror(name = "ErrUnauthorized", abi = "ErrUnauthorized()")] pub struct ErrUnauthorized; - ///Custom Error type `ErrUnknownChannelOrdering` with signature `ErrUnknownChannelOrdering()` and selector `0x6cc79c02` + /// Custom Error type `ErrUnknownChannelOrdering` with signature `ErrUnknownChannelOrdering()` and selector `0x6cc79c02` #[derive( Clone, ::ethers::contract::EthError, @@ -1659,7 +1659,7 @@ pub mod ibc_packet { abi = "ErrUnknownChannelOrdering()" )] pub struct ErrUnknownChannelOrdering; - ///Container type for all of the contract's custom errors + /// Container type for all of the contract's custom errors #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum IBCPacketErrors { ErrAcknowledgementAlreadyExists(ErrAcknowledgementAlreadyExists), @@ -2300,6 +2300,8 @@ pub mod ibc_packet { PartialEq, Eq, Hash, + ::serde::Serialize, + ::serde::Deserialize, )] #[ethevent( name = "TimeoutPacket", @@ -2328,8 +2330,17 @@ pub mod ibc_packet { pub packet: IbcCoreChannelV1PacketData, pub acknowledgement: ::ethers::core::types::Bytes, } - ///Container type for all of the contract's events - #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] + /// Container type for all of the contract's events + #[derive( + Clone, + ::ethers::contract::EthAbiType, + Debug, + PartialEq, + Eq, + Hash, + ::serde::Serialize, + ::serde::Deserialize, + )] pub enum IBCPacketEvents { AcknowledgePacketFilter(AcknowledgePacketFilter), RecvPacketFilter(RecvPacketFilter), @@ -2395,7 +2406,7 @@ pub mod ibc_packet { Self::WriteAcknowledgementFilter(value) } } - ///Container type for all input parameters for the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` + /// Container type for all input parameters for the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` #[derive( Clone, ::ethers::contract::EthCall, @@ -2408,7 +2419,7 @@ pub mod ibc_packet { )] #[ethcall(name = "COMMITMENT_PREFIX", abi = "COMMITMENT_PREFIX()")] pub struct CommitmentPrefixCall; - ///Container type for all input parameters for the `acknowledgePacket` function with signature `acknowledgePacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,bytes,(uint64,uint64),address))` and selector `0x07037704` + /// Container type for all input parameters for the `acknowledgePacket` function with signature `acknowledgePacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,bytes,(uint64,uint64),address))` and selector `0x07037704` #[derive( Clone, ::ethers::contract::EthCall, @@ -2426,7 +2437,7 @@ pub mod ibc_packet { pub struct AcknowledgePacketCall { pub msg: MsgPacketAcknowledgement, } - ///Container type for all input parameters for the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` + /// Container type for all input parameters for the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` #[derive( Clone, ::ethers::contract::EthCall, @@ -2439,7 +2450,7 @@ pub mod ibc_packet { )] #[ethcall(name = "capabilities", abi = "capabilities(string)")] pub struct CapabilitiesCall(pub ::std::string::String); - ///Container type for all input parameters for the `channelCapabilityPath` function with signature `channelCapabilityPath(string,string)` and selector `0x3bc3339f` + /// Container type for all input parameters for the `channelCapabilityPath` function with signature `channelCapabilityPath(string,string)` and selector `0x3bc3339f` #[derive( Clone, ::ethers::contract::EthCall, @@ -2458,7 +2469,7 @@ pub mod ibc_packet { pub port_id: ::std::string::String, pub channel_id: ::std::string::String, } - ///Container type for all input parameters for the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` + /// Container type for all input parameters for the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` #[derive( Clone, ::ethers::contract::EthCall, @@ -2471,7 +2482,7 @@ pub mod ibc_packet { )] #[ethcall(name = "channels", abi = "channels(string,string)")] pub struct ChannelsCall(pub ::std::string::String, pub ::std::string::String); - ///Container type for all input parameters for the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` + /// Container type for all input parameters for the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` #[derive( Clone, ::ethers::contract::EthCall, @@ -2484,7 +2495,7 @@ pub mod ibc_packet { )] #[ethcall(name = "clientImpls", abi = "clientImpls(string)")] pub struct ClientImplsCall(pub ::std::string::String); - ///Container type for all input parameters for the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` + /// Container type for all input parameters for the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` #[derive( Clone, ::ethers::contract::EthCall, @@ -2497,7 +2508,7 @@ pub mod ibc_packet { )] #[ethcall(name = "clientRegistry", abi = "clientRegistry(string)")] pub struct ClientRegistryCall(pub ::std::string::String); - ///Container type for all input parameters for the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` + /// Container type for all input parameters for the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` #[derive( Clone, ::ethers::contract::EthCall, @@ -2510,7 +2521,7 @@ pub mod ibc_packet { )] #[ethcall(name = "clientTypes", abi = "clientTypes(string)")] pub struct ClientTypesCall(pub ::std::string::String); - ///Container type for all input parameters for the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` + /// Container type for all input parameters for the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` #[derive( Clone, ::ethers::contract::EthCall, @@ -2523,7 +2534,7 @@ pub mod ibc_packet { )] #[ethcall(name = "commitments", abi = "commitments(bytes32)")] pub struct CommitmentsCall(pub [u8; 32]); - ///Container type for all input parameters for the `connections` function with signature `connections(string)` and selector `0x31973f00` + /// Container type for all input parameters for the `connections` function with signature `connections(string)` and selector `0x31973f00` #[derive( Clone, ::ethers::contract::EthCall, @@ -2536,7 +2547,7 @@ pub mod ibc_packet { )] #[ethcall(name = "connections", abi = "connections(string)")] pub struct ConnectionsCall(pub ::std::string::String); - ///Container type for all input parameters for the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` + /// Container type for all input parameters for the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` #[derive( Clone, ::ethers::contract::EthCall, @@ -2551,7 +2562,7 @@ pub mod ibc_packet { pub struct GetClientCall { pub client_id: ::std::string::String, } - ///Container type for all input parameters for the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` + /// Container type for all input parameters for the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` #[derive( Clone, ::ethers::contract::EthCall, @@ -2564,7 +2575,7 @@ pub mod ibc_packet { )] #[ethcall(name = "nextChannelSequencePath", abi = "nextChannelSequencePath()")] pub struct NextChannelSequencePathCall; - ///Container type for all input parameters for the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` + /// Container type for all input parameters for the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` #[derive( Clone, ::ethers::contract::EthCall, @@ -2577,7 +2588,7 @@ pub mod ibc_packet { )] #[ethcall(name = "nextClientSequencePath", abi = "nextClientSequencePath()")] pub struct NextClientSequencePathCall; - ///Container type for all input parameters for the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` + /// Container type for all input parameters for the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` #[derive( Clone, ::ethers::contract::EthCall, @@ -2593,7 +2604,7 @@ pub mod ibc_packet { abi = "nextConnectionSequencePath()" )] pub struct NextConnectionSequencePathCall; - ///Container type for all input parameters for the `recvPacket` function with signature `recvPacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),address))` and selector `0xe8f088c6` + /// Container type for all input parameters for the `recvPacket` function with signature `recvPacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),address))` and selector `0xe8f088c6` #[derive( Clone, ::ethers::contract::EthCall, @@ -2611,7 +2622,7 @@ pub mod ibc_packet { pub struct RecvPacketCall { pub msg: MsgPacketRecv, } - ///Container type for all input parameters for the `sendPacket` function with signature `sendPacket(string,(uint64,uint64),uint64,bytes)` and selector `0x6cf02d3f` + /// Container type for all input parameters for the `sendPacket` function with signature `sendPacket(string,(uint64,uint64),uint64,bytes)` and selector `0x6cf02d3f` #[derive( Clone, ::ethers::contract::EthCall, @@ -2632,7 +2643,7 @@ pub mod ibc_packet { pub timeout_timestamp: u64, pub data: ::ethers::core::types::Bytes, } - ///Container type for all input parameters for the `timeoutPacket` function with signature `timeoutPacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),uint64,address))` and selector `0xa04f91b2` + /// Container type for all input parameters for the `timeoutPacket` function with signature `timeoutPacket(((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),uint64,address))` and selector `0xa04f91b2` #[derive( Clone, ::ethers::contract::EthCall, @@ -2650,7 +2661,7 @@ pub mod ibc_packet { pub struct TimeoutPacketCall { pub msg: MsgPacketTimeout, } - ///Container type for all input parameters for the `writeAcknowledgement` function with signature `writeAcknowledgement((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes)` and selector `0xca956667` + /// Container type for all input parameters for the `writeAcknowledgement` function with signature `writeAcknowledgement((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes)` and selector `0xca956667` #[derive( Clone, ::ethers::contract::EthCall, @@ -2669,7 +2680,7 @@ pub mod ibc_packet { pub packet: IbcCoreChannelV1PacketData, pub acknowledgement: ::ethers::core::types::Bytes, } - ///Container type for all of the contract's call + /// Container type for all of the contract's call #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum IBCPacketCalls { CommitmentPrefix(CommitmentPrefixCall), @@ -2919,7 +2930,7 @@ pub mod ibc_packet { Self::WriteAcknowledgement(value) } } - ///Container type for all return fields from the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` + /// Container type for all return fields from the `COMMITMENT_PREFIX` function with signature `COMMITMENT_PREFIX()` and selector `0xa9550dac` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2931,7 +2942,7 @@ pub mod ibc_packet { Hash, )] pub struct CommitmentPrefixReturn(pub ::std::string::String); - ///Container type for all return fields from the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` + /// Container type for all return fields from the `capabilities` function with signature `capabilities(string)` and selector `0x5717bcf5` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2943,7 +2954,7 @@ pub mod ibc_packet { Hash, )] pub struct CapabilitiesReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `channelCapabilityPath` function with signature `channelCapabilityPath(string,string)` and selector `0x3bc3339f` + /// Container type for all return fields from the `channelCapabilityPath` function with signature `channelCapabilityPath(string,string)` and selector `0x3bc3339f` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2955,7 +2966,7 @@ pub mod ibc_packet { Hash, )] pub struct ChannelCapabilityPathReturn(pub ::std::string::String); - ///Container type for all return fields from the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` + /// Container type for all return fields from the `channels` function with signature `channels(string,string)` and selector `0x5b3de260` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2972,7 +2983,7 @@ pub mod ibc_packet { pub counterparty: IbcCoreChannelV1CounterpartyData, pub version: ::std::string::String, } - ///Container type for all return fields from the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` + /// Container type for all return fields from the `clientImpls` function with signature `clientImpls(string)` and selector `0xd1297b8d` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2984,7 +2995,7 @@ pub mod ibc_packet { Hash, )] pub struct ClientImplsReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` + /// Container type for all return fields from the `clientRegistry` function with signature `clientRegistry(string)` and selector `0x990491a5` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -2996,7 +3007,7 @@ pub mod ibc_packet { Hash, )] pub struct ClientRegistryReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` + /// Container type for all return fields from the `clientTypes` function with signature `clientTypes(string)` and selector `0xc2380105` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3008,7 +3019,7 @@ pub mod ibc_packet { Hash, )] pub struct ClientTypesReturn(pub ::std::string::String); - ///Container type for all return fields from the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` + /// Container type for all return fields from the `commitments` function with signature `commitments(bytes32)` and selector `0x839df945` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3020,7 +3031,7 @@ pub mod ibc_packet { Hash, )] pub struct CommitmentsReturn(pub [u8; 32]); - ///Container type for all return fields from the `connections` function with signature `connections(string)` and selector `0x31973f00` + /// Container type for all return fields from the `connections` function with signature `connections(string)` and selector `0x31973f00` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3037,7 +3048,7 @@ pub mod ibc_packet { pub counterparty: IbcCoreConnectionV1CounterpartyData, pub delay_period: u64, } - ///Container type for all return fields from the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` + /// Container type for all return fields from the `getClient` function with signature `getClient(string)` and selector `0x7eb78932` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3049,7 +3060,7 @@ pub mod ibc_packet { Hash, )] pub struct GetClientReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` + /// Container type for all return fields from the `nextChannelSequencePath` function with signature `nextChannelSequencePath()` and selector `0x8669fd15` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3061,7 +3072,7 @@ pub mod ibc_packet { Hash, )] pub struct NextChannelSequencePathReturn(pub [u8; 32]); - ///Container type for all return fields from the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` + /// Container type for all return fields from the `nextClientSequencePath` function with signature `nextClientSequencePath()` and selector `0x990c3888` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3073,7 +3084,7 @@ pub mod ibc_packet { Hash, )] pub struct NextClientSequencePathReturn(pub [u8; 32]); - ///Container type for all return fields from the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` + /// Container type for all return fields from the `nextConnectionSequencePath` function with signature `nextConnectionSequencePath()` and selector `0x46807086` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3085,7 +3096,7 @@ pub mod ibc_packet { Hash, )] pub struct NextConnectionSequencePathReturn(pub [u8; 32]); - ///Container type for all return fields from the `sendPacket` function with signature `sendPacket(string,(uint64,uint64),uint64,bytes)` and selector `0x6cf02d3f` + /// Container type for all return fields from the `sendPacket` function with signature `sendPacket(string,(uint64,uint64),uint64,bytes)` and selector `0x6cf02d3f` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/generated/rust/contracts/src/multicall.rs b/generated/rust/contracts/src/multicall.rs index 3b6db4e78f..e5f412dd7f 100644 --- a/generated/rust/contracts/src/multicall.rs +++ b/generated/rust/contracts/src/multicall.rs @@ -77,7 +77,7 @@ pub mod multicall { fallback: false, } } - ///The parsed JSON ABI of the contract. + /// The parsed JSON ABI of the contract. #[cfg(feature = "providers")] pub static MULTICALL_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); @@ -177,7 +177,7 @@ pub mod multicall { let deployer = ::ethers::contract::ContractDeployer::new(deployer); Ok(deployer) } - ///Calls the contract's `multicall` (0xe8bbf5d7) function + /// Calls the contract's `multicall` (0xe8bbf5d7) function pub fn multicall( &self, calls: ::std::vec::Vec, @@ -186,7 +186,7 @@ pub mod multicall { .method_hash([232, 187, 245, 215], calls) .expect("method not found (this should never happen)") } - ///Gets the contract's `MulticallResult` event + /// Gets the contract's `MulticallResult` event pub fn multicall_result_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, MulticallResultFilter> @@ -220,7 +220,7 @@ pub mod multicall { )] #[ethevent(name = "MulticallResult", abi = "MulticallResult((bool,bytes)[])")] pub struct MulticallResultFilter(pub ::std::vec::Vec); - ///Container type for all input parameters for the `multicall` function with signature `multicall((address,bool,bytes)[])` and selector `0xe8bbf5d7` + /// Container type for all input parameters for the `multicall` function with signature `multicall((address,bool,bytes)[])` and selector `0xe8bbf5d7` #[derive( Clone, ::ethers::contract::EthCall, @@ -235,7 +235,7 @@ pub mod multicall { pub struct MulticallCall { pub calls: ::std::vec::Vec, } - ///Container type for all return fields from the `multicall` function with signature `multicall((address,bool,bytes)[])` and selector `0xe8bbf5d7` + /// Container type for all return fields from the `multicall` function with signature `multicall((address,bool,bytes)[])` and selector `0xe8bbf5d7` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -249,7 +249,7 @@ pub mod multicall { pub struct MulticallReturn { pub return_data: ::std::vec::Vec, } - ///`Call3(address,bool,bytes)` + /// `Call3(address,bool,bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -265,7 +265,7 @@ pub mod multicall { pub allow_failure: bool, pub call_data: ::ethers::core::types::Bytes, } - ///`Result(bool,bytes)` + /// `Result(bool,bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/generated/rust/contracts/src/shared_types.rs b/generated/rust/contracts/src/shared_types.rs index 16360c9fa4..e3fdd84394 100644 --- a/generated/rust/contracts/src/shared_types.rs +++ b/generated/rust/contracts/src/shared_types.rs @@ -1,4 +1,4 @@ -///`ConsensusStateUpdate(bytes32,(uint64,uint64))` +/// `ConsensusStateUpdate(bytes32,(uint64,uint64))` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -13,7 +13,7 @@ pub struct ConsensusStateUpdate { pub consensus_state_commitment: [u8; 32], pub height: IbcCoreClientV1HeightData, } -///`GoogleProtobufTimestampData(int64,int64)` +/// `GoogleProtobufTimestampData(int64,int64)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -28,7 +28,7 @@ pub struct GoogleProtobufTimestampData { pub secs: i64, pub nanos: i64, } -///`MsgChannelCloseConfirm(string,string,bytes,(uint64,uint64),address)` +/// `MsgChannelCloseConfirm(string,string,bytes,(uint64,uint64),address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -46,7 +46,7 @@ pub struct MsgChannelCloseConfirm { pub proof_height: IbcCoreClientV1HeightData, pub relayer: ::ethers::core::types::Address, } -///`MsgChannelCloseInit(string,string,address)` +/// `MsgChannelCloseInit(string,string,address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -62,7 +62,7 @@ pub struct MsgChannelCloseInit { pub channel_id: ::std::string::String, pub relayer: ::ethers::core::types::Address, } -///`MsgChannelOpenAck(string,string,string,string,bytes,(uint64,uint64),address)` +/// `MsgChannelOpenAck(string,string,string,string,bytes,(uint64,uint64),address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -82,7 +82,7 @@ pub struct MsgChannelOpenAck { pub proof_height: IbcCoreClientV1HeightData, pub relayer: ::ethers::core::types::Address, } -///`MsgChannelOpenConfirm(string,string,bytes,(uint64,uint64),address)` +/// `MsgChannelOpenConfirm(string,string,bytes,(uint64,uint64),address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -100,7 +100,7 @@ pub struct MsgChannelOpenConfirm { pub proof_height: IbcCoreClientV1HeightData, pub relayer: ::ethers::core::types::Address, } -///`MsgChannelOpenInit(string,(uint8,uint8,(string,string),string[],string),address)` +/// `MsgChannelOpenInit(string,(uint8,uint8,(string,string),string[],string),address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -116,7 +116,7 @@ pub struct MsgChannelOpenInit { pub channel: IbcCoreChannelV1ChannelData, pub relayer: ::ethers::core::types::Address, } -///`MsgChannelOpenTry(string,(uint8,uint8,(string,string),string[],string),string,bytes,(uint64,uint64),address)` +/// `MsgChannelOpenTry(string,(uint8,uint8,(string,string),string[],string),string,bytes,(uint64,uint64),address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -135,7 +135,7 @@ pub struct MsgChannelOpenTry { pub proof_height: IbcCoreClientV1HeightData, pub relayer: ::ethers::core::types::Address, } -///`MsgConnectionOpenAck(string,bytes,(string,string[]),string,bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address)` +/// `MsgConnectionOpenAck(string,bytes,(string,string[]),string,bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -158,7 +158,7 @@ pub struct MsgConnectionOpenAck { pub consensus_height: IbcCoreClientV1HeightData, pub relayer: ::ethers::core::types::Address, } -///`MsgConnectionOpenConfirm(string,bytes,(uint64,uint64),address)` +/// `MsgConnectionOpenConfirm(string,bytes,(uint64,uint64),address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -175,7 +175,7 @@ pub struct MsgConnectionOpenConfirm { pub proof_height: IbcCoreClientV1HeightData, pub relayer: ::ethers::core::types::Address, } -///`MsgConnectionOpenInit(string,(string,string[]),(string,string,(bytes)),uint64,address)` +/// `MsgConnectionOpenInit(string,(string,string[]),(string,string,(bytes)),uint64,address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -193,7 +193,7 @@ pub struct MsgConnectionOpenInit { pub delay_period: u64, pub relayer: ::ethers::core::types::Address, } -///`MsgConnectionOpenTry((string,string,(bytes)),uint64,string,bytes,(string,string[])[],bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address)` +/// `MsgConnectionOpenTry((string,string,(bytes)),uint64,string,bytes,(string,string[])[],bytes,bytes,bytes,(uint64,uint64),(uint64,uint64),address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -217,7 +217,7 @@ pub struct MsgConnectionOpenTry { pub consensus_height: IbcCoreClientV1HeightData, pub relayer: ::ethers::core::types::Address, } -///`MsgCreateClient(string,bytes,bytes,address)` +/// `MsgCreateClient(string,bytes,bytes,address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -234,7 +234,7 @@ pub struct MsgCreateClient { pub consensus_state_bytes: ::ethers::core::types::Bytes, pub relayer: ::ethers::core::types::Address, } -///`MsgPacketAcknowledgement((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,bytes,(uint64,uint64),address)` +/// `MsgPacketAcknowledgement((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,bytes,(uint64,uint64),address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -252,7 +252,7 @@ pub struct MsgPacketAcknowledgement { pub proof_height: IbcCoreClientV1HeightData, pub relayer: ::ethers::core::types::Address, } -///`MsgPacketRecv((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),address)` +/// `MsgPacketRecv((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -269,7 +269,7 @@ pub struct MsgPacketRecv { pub proof_height: IbcCoreClientV1HeightData, pub relayer: ::ethers::core::types::Address, } -///`MsgPacketTimeout((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),uint64,address)` +/// `MsgPacketTimeout((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,(uint64,uint64),uint64,address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -287,7 +287,7 @@ pub struct MsgPacketTimeout { pub next_sequence_recv: u64, pub relayer: ::ethers::core::types::Address, } -///`MsgUpdateClient(string,bytes,address)` +/// `MsgUpdateClient(string,bytes,address)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -303,7 +303,7 @@ pub struct MsgUpdateClient { pub client_message: ::ethers::core::types::Bytes, pub relayer: ::ethers::core::types::Address, } -///`IbcCoreChannelV1ChannelData(uint8,uint8,(string,string),string[],string)` +/// `IbcCoreChannelV1ChannelData(uint8,uint8,(string,string),string[],string)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -321,7 +321,7 @@ pub struct IbcCoreChannelV1ChannelData { pub connection_hops: ::std::vec::Vec<::std::string::String>, pub version: ::std::string::String, } -///`IbcCoreChannelV1CounterpartyData(string,string)` +/// `IbcCoreChannelV1CounterpartyData(string,string)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -336,7 +336,7 @@ pub struct IbcCoreChannelV1CounterpartyData { pub port_id: ::std::string::String, pub channel_id: ::std::string::String, } -///`IbcCoreChannelV1PacketData(uint64,string,string,string,string,bytes,(uint64,uint64),uint64)` +/// `IbcCoreChannelV1PacketData(uint64,string,string,string,string,bytes,(uint64,uint64),uint64)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -359,7 +359,7 @@ pub struct IbcCoreChannelV1PacketData { pub timeout_height: IbcCoreClientV1HeightData, pub timeout_timestamp: u64, } -///`IbcCoreClientV1HeightData(uint64,uint64)` +/// `IbcCoreClientV1HeightData(uint64,uint64)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -376,7 +376,7 @@ pub struct IbcCoreClientV1HeightData { pub revision_number: u64, pub revision_height: u64, } -///`IbcCoreCommitmentV1MerklePrefixData(bytes)` +/// `IbcCoreCommitmentV1MerklePrefixData(bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -390,7 +390,7 @@ pub struct IbcCoreClientV1HeightData { pub struct IbcCoreCommitmentV1MerklePrefixData { pub key_prefix: ::ethers::core::types::Bytes, } -///`IbcCoreConnectionV1ConnectionEndData(string,(string,string[])[],uint8,(string,string,(bytes)),uint64)` +/// `IbcCoreConnectionV1ConnectionEndData(string,(string,string[])[],uint8,(string,string,(bytes)),uint64)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -408,7 +408,7 @@ pub struct IbcCoreConnectionV1ConnectionEndData { pub counterparty: IbcCoreConnectionV1CounterpartyData, pub delay_period: u64, } -///`IbcCoreConnectionV1CounterpartyData(string,string,(bytes))` +/// `IbcCoreConnectionV1CounterpartyData(string,string,(bytes))` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -424,7 +424,7 @@ pub struct IbcCoreConnectionV1CounterpartyData { pub connection_id: ::std::string::String, pub prefix: IbcCoreCommitmentV1MerklePrefixData, } -///`IbcCoreConnectionV1VersionData(string,string[])` +/// `IbcCoreConnectionV1VersionData(string,string[])` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -439,7 +439,7 @@ pub struct IbcCoreConnectionV1VersionData { pub identifier: ::std::string::String, pub features: ::std::vec::Vec<::std::string::String>, } -///`UnionIbcLightclientsCometblsV1HeaderData((int64,(int64,int64),bytes,bytes,bytes),(uint64,uint64),bytes)` +/// `UnionIbcLightclientsCometblsV1HeaderData((int64,(int64,int64),bytes,bytes,bytes),(uint64,uint64),bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -455,7 +455,7 @@ pub struct UnionIbcLightclientsCometblsV1HeaderData { pub trusted_height: IbcCoreClientV1HeightData, pub zero_knowledge_proof: ::ethers::core::types::Bytes, } -///`UnionIbcLightclientsCometblsV1LightHeaderData(int64,(int64,int64),bytes,bytes,bytes)` +/// `UnionIbcLightclientsCometblsV1LightHeaderData(int64,(int64,int64),bytes,bytes,bytes)` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/generated/rust/contracts/src/ucs01_relay.rs b/generated/rust/contracts/src/ucs01_relay.rs index 004d1fae07..6e1ecee1d2 100644 --- a/generated/rust/contracts/src/ucs01_relay.rs +++ b/generated/rust/contracts/src/ucs01_relay.rs @@ -1251,7 +1251,7 @@ pub mod ucs01_relay { fallback: false, } } - ///The parsed JSON ABI of the contract. + /// The parsed JSON ABI of the contract. #[cfg(feature = "providers")] pub static UCS01RELAY_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); @@ -1351,7 +1351,7 @@ pub mod ucs01_relay { let deployer = ::ethers::contract::ContractDeployer::new(deployer); Ok(deployer) } - ///Calls the contract's `UPGRADE_INTERFACE_VERSION` (0xad3cb1cc) function + /// Calls the contract's `UPGRADE_INTERFACE_VERSION` (0xad3cb1cc) function pub fn upgrade_interface_version( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1359,7 +1359,7 @@ pub mod ucs01_relay { .method_hash([173, 60, 177, 204], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `getDenomAddress` (0x3a74ce26) function + /// Calls the contract's `getDenomAddress` (0x3a74ce26) function pub fn get_denom_address( &self, source_channel: ::std::string::String, @@ -1369,7 +1369,7 @@ pub mod ucs01_relay { .method_hash([58, 116, 206, 38], (source_channel, denom)) .expect("method not found (this should never happen)") } - ///Calls the contract's `getOutstanding` (0x2b66b116) function + /// Calls the contract's `getOutstanding` (0x2b66b116) function pub fn get_outstanding( &self, source_channel: ::std::string::String, @@ -1379,7 +1379,7 @@ pub mod ucs01_relay { .method_hash([43, 102, 177, 22], (source_channel, token)) .expect("method not found (this should never happen)") } - ///Calls the contract's `ibcAddress` (0x696a9bf4) function + /// Calls the contract's `ibcAddress` (0x696a9bf4) function pub fn ibc_address( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1387,7 +1387,7 @@ pub mod ucs01_relay { .method_hash([105, 106, 155, 244], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `initialize` (0x485cc955) function + /// Calls the contract's `initialize` (0x485cc955) function pub fn initialize( &self, ibc_handler: ::ethers::core::types::Address, @@ -1397,7 +1397,7 @@ pub mod ucs01_relay { .method_hash([72, 92, 201, 85], (ibc_handler, admin)) .expect("method not found (this should never happen)") } - ///Calls the contract's `onAcknowledgementPacket` (0xfb8b532e) function + /// Calls the contract's `onAcknowledgementPacket` (0xfb8b532e) function pub fn on_acknowledgement_packet( &self, ibc_packet: IbcCoreChannelV1PacketData, @@ -1408,7 +1408,7 @@ pub mod ucs01_relay { .method_hash([251, 139, 83, 46], (ibc_packet, acknowledgement, p2)) .expect("method not found (this should never happen)") } - ///Calls the contract's `onChanCloseConfirm` (0x3f41c9ea) function + /// Calls the contract's `onChanCloseConfirm` (0x3f41c9ea) function pub fn on_chan_close_confirm( &self, p0: ::std::string::String, @@ -1419,7 +1419,7 @@ pub mod ucs01_relay { .method_hash([63, 65, 201, 234], (p0, p1, p2)) .expect("method not found (this should never happen)") } - ///Calls the contract's `onChanCloseInit` (0x7538ed68) function + /// Calls the contract's `onChanCloseInit` (0x7538ed68) function pub fn on_chan_close_init( &self, p0: ::std::string::String, @@ -1430,7 +1430,7 @@ pub mod ucs01_relay { .method_hash([117, 56, 237, 104], (p0, p1, p2)) .expect("method not found (this should never happen)") } - ///Calls the contract's `onChanOpenAck` (0x60ca56eb) function + /// Calls the contract's `onChanOpenAck` (0x60ca56eb) function pub fn on_chan_open_ack( &self, p0: ::std::string::String, @@ -1446,7 +1446,7 @@ pub mod ucs01_relay { ) .expect("method not found (this should never happen)") } - ///Calls the contract's `onChanOpenConfirm` (0xf8288cc6) function + /// Calls the contract's `onChanOpenConfirm` (0xf8288cc6) function pub fn on_chan_open_confirm( &self, p0: ::std::string::String, @@ -1457,7 +1457,7 @@ pub mod ucs01_relay { .method_hash([248, 40, 140, 198], (p0, p1, p2)) .expect("method not found (this should never happen)") } - ///Calls the contract's `onChanOpenInit` (0xf2f83f7a) function + /// Calls the contract's `onChanOpenInit` (0xf2f83f7a) function pub fn on_chan_open_init( &self, order: u8, @@ -1475,7 +1475,7 @@ pub mod ucs01_relay { ) .expect("method not found (this should never happen)") } - ///Calls the contract's `onChanOpenTry` (0x218d1e3e) function + /// Calls the contract's `onChanOpenTry` (0x218d1e3e) function pub fn on_chan_open_try( &self, order: u8, @@ -1503,7 +1503,7 @@ pub mod ucs01_relay { ) .expect("method not found (this should never happen)") } - ///Calls the contract's `onRecvPacket` (0x2301c6f5) function + /// Calls the contract's `onRecvPacket` (0x2301c6f5) function pub fn on_recv_packet( &self, ibc_packet: IbcCoreChannelV1PacketData, @@ -1513,7 +1513,7 @@ pub mod ucs01_relay { .method_hash([35, 1, 198, 245], (ibc_packet, relayer)) .expect("method not found (this should never happen)") } - ///Calls the contract's `onRecvPacketProcessing` (0xbd950f89) function + /// Calls the contract's `onRecvPacketProcessing` (0xbd950f89) function pub fn on_recv_packet_processing( &self, ibc_packet: IbcCoreChannelV1PacketData, @@ -1523,7 +1523,7 @@ pub mod ucs01_relay { .method_hash([189, 149, 15, 137], (ibc_packet, p1)) .expect("method not found (this should never happen)") } - ///Calls the contract's `onTimeoutPacket` (0x52c7157d) function + /// Calls the contract's `onTimeoutPacket` (0x52c7157d) function pub fn on_timeout_packet( &self, ibc_packet: IbcCoreChannelV1PacketData, @@ -1533,7 +1533,7 @@ pub mod ucs01_relay { .method_hash([82, 199, 21, 125], (ibc_packet, p1)) .expect("method not found (this should never happen)") } - ///Calls the contract's `owner` (0x8da5cb5b) function + /// Calls the contract's `owner` (0x8da5cb5b) function pub fn owner( &self, ) -> ::ethers::contract::builders::ContractCall { @@ -1541,25 +1541,25 @@ pub mod ucs01_relay { .method_hash([141, 165, 203, 91], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `paused` (0x5c975abb) function + /// Calls the contract's `paused` (0x5c975abb) function pub fn paused(&self) -> ::ethers::contract::builders::ContractCall { self.0 .method_hash([92, 151, 90, 187], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `proxiableUUID` (0x52d1902d) function + /// Calls the contract's `proxiableUUID` (0x52d1902d) function pub fn proxiable_uuid(&self) -> ::ethers::contract::builders::ContractCall { self.0 .method_hash([82, 209, 144, 45], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `renounceOwnership` (0x715018a6) function + /// Calls the contract's `renounceOwnership` (0x715018a6) function pub fn renounce_ownership(&self) -> ::ethers::contract::builders::ContractCall { self.0 .method_hash([113, 80, 24, 166], ()) .expect("method not found (this should never happen)") } - ///Calls the contract's `send` (0xa5b7e178) function + /// Calls the contract's `send` (0xa5b7e178) function pub fn send( &self, source_channel: ::std::string::String, @@ -1583,7 +1583,7 @@ pub mod ucs01_relay { ) .expect("method not found (this should never happen)") } - ///Calls the contract's `transferOwnership` (0xf2fde38b) function + /// Calls the contract's `transferOwnership` (0xf2fde38b) function pub fn transfer_ownership( &self, new_owner: ::ethers::core::types::Address, @@ -1592,7 +1592,7 @@ pub mod ucs01_relay { .method_hash([242, 253, 227, 139], new_owner) .expect("method not found (this should never happen)") } - ///Calls the contract's `updateMetadata` (0xec1bd897) function + /// Calls the contract's `updateMetadata` (0xec1bd897) function pub fn update_metadata( &self, denom: ::ethers::core::types::Address, @@ -1607,7 +1607,7 @@ pub mod ucs01_relay { ) .expect("method not found (this should never happen)") } - ///Calls the contract's `upgradeToAndCall` (0x4f1ef286) function + /// Calls the contract's `upgradeToAndCall` (0x4f1ef286) function pub fn upgrade_to_and_call( &self, new_implementation: ::ethers::core::types::Address, @@ -1617,58 +1617,58 @@ pub mod ucs01_relay { .method_hash([79, 30, 242, 134], (new_implementation, data)) .expect("method not found (this should never happen)") } - ///Gets the contract's `DenomCreated` event + /// Gets the contract's `DenomCreated` event pub fn denom_created_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, DenomCreatedFilter> { self.0.event() } - ///Gets the contract's `Initialized` event + /// Gets the contract's `Initialized` event pub fn initialized_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, InitializedFilter> { self.0.event() } - ///Gets the contract's `OwnershipTransferred` event + /// Gets the contract's `OwnershipTransferred` event pub fn ownership_transferred_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, OwnershipTransferredFilter> { self.0.event() } - ///Gets the contract's `Paused` event + /// Gets the contract's `Paused` event pub fn paused_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, PausedFilter> { self.0.event() } - ///Gets the contract's `Received` event + /// Gets the contract's `Received` event pub fn received_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, ReceivedFilter> { self.0.event() } - ///Gets the contract's `Refunded` event + /// Gets the contract's `Refunded` event pub fn refunded_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, RefundedFilter> { self.0.event() } - ///Gets the contract's `Sent` event + /// Gets the contract's `Sent` event pub fn sent_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, SentFilter> { self.0.event() } - ///Gets the contract's `Unpaused` event + /// Gets the contract's `Unpaused` event pub fn unpaused_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, UnpausedFilter> { self.0.event() } - ///Gets the contract's `Upgraded` event + /// Gets the contract's `Upgraded` event pub fn upgraded_filter( &self, ) -> ::ethers::contract::builders::Event<::std::sync::Arc, M, UpgradedFilter> { @@ -1688,7 +1688,7 @@ pub mod ucs01_relay { Self::new(contract.address(), contract.client()) } } - ///Custom Error type `AddressEmptyCode` with signature `AddressEmptyCode(address)` and selector `0x9996b315` + /// Custom Error type `AddressEmptyCode` with signature `AddressEmptyCode(address)` and selector `0x9996b315` #[derive( Clone, ::ethers::contract::EthError, @@ -1703,7 +1703,7 @@ pub mod ucs01_relay { pub struct AddressEmptyCode { pub target: ::ethers::core::types::Address, } - ///Custom Error type `AddressInsufficientBalance` with signature `AddressInsufficientBalance(address)` and selector `0xcd786059` + /// Custom Error type `AddressInsufficientBalance` with signature `AddressInsufficientBalance(address)` and selector `0xcd786059` #[derive( Clone, ::ethers::contract::EthError, @@ -1721,7 +1721,7 @@ pub mod ucs01_relay { pub struct AddressInsufficientBalance { pub account: ::ethers::core::types::Address, } - ///Custom Error type `ERC1967InvalidImplementation` with signature `ERC1967InvalidImplementation(address)` and selector `0x4c9c8ce3` + /// Custom Error type `ERC1967InvalidImplementation` with signature `ERC1967InvalidImplementation(address)` and selector `0x4c9c8ce3` #[derive( Clone, ::ethers::contract::EthError, @@ -1739,7 +1739,7 @@ pub mod ucs01_relay { pub struct ERC1967InvalidImplementation { pub implementation: ::ethers::core::types::Address, } - ///Custom Error type `ERC1967NonPayable` with signature `ERC1967NonPayable()` and selector `0xb398979f` + /// Custom Error type `ERC1967NonPayable` with signature `ERC1967NonPayable()` and selector `0xb398979f` #[derive( Clone, ::ethers::contract::EthError, @@ -1752,7 +1752,7 @@ pub mod ucs01_relay { )] #[etherror(name = "ERC1967NonPayable", abi = "ERC1967NonPayable()")] pub struct ERC1967NonPayable; - ///Custom Error type `EnforcedPause` with signature `EnforcedPause()` and selector `0xd93c0665` + /// Custom Error type `EnforcedPause` with signature `EnforcedPause()` and selector `0xd93c0665` #[derive( Clone, ::ethers::contract::EthError, @@ -1765,7 +1765,7 @@ pub mod ucs01_relay { )] #[etherror(name = "EnforcedPause", abi = "EnforcedPause()")] pub struct EnforcedPause; - ///Custom Error type `ErrInvalidAcknowledgement` with signature `ErrInvalidAcknowledgement()` and selector `0x6ec7d33f` + /// Custom Error type `ErrInvalidAcknowledgement` with signature `ErrInvalidAcknowledgement()` and selector `0x6ec7d33f` #[derive( Clone, ::ethers::contract::EthError, @@ -1781,7 +1781,7 @@ pub mod ucs01_relay { abi = "ErrInvalidAcknowledgement()" )] pub struct ErrInvalidAcknowledgement; - ///Custom Error type `ErrInvalidAmount` with signature `ErrInvalidAmount()` and selector `0xb3726016` + /// Custom Error type `ErrInvalidAmount` with signature `ErrInvalidAmount()` and selector `0xb3726016` #[derive( Clone, ::ethers::contract::EthError, @@ -1794,7 +1794,7 @@ pub mod ucs01_relay { )] #[etherror(name = "ErrInvalidAmount", abi = "ErrInvalidAmount()")] pub struct ErrInvalidAmount; - ///Custom Error type `ErrInvalidBytesAddress` with signature `ErrInvalidBytesAddress()` and selector `0x78718c3b` + /// Custom Error type `ErrInvalidBytesAddress` with signature `ErrInvalidBytesAddress()` and selector `0x78718c3b` #[derive( Clone, ::ethers::contract::EthError, @@ -1807,7 +1807,7 @@ pub mod ucs01_relay { )] #[etherror(name = "ErrInvalidBytesAddress", abi = "ErrInvalidBytesAddress()")] pub struct ErrInvalidBytesAddress; - ///Custom Error type `ErrInvalidCounterpartyProtocolVersion` with signature `ErrInvalidCounterpartyProtocolVersion()` and selector `0xbb928590` + /// Custom Error type `ErrInvalidCounterpartyProtocolVersion` with signature `ErrInvalidCounterpartyProtocolVersion()` and selector `0xbb928590` #[derive( Clone, ::ethers::contract::EthError, @@ -1823,7 +1823,7 @@ pub mod ucs01_relay { abi = "ErrInvalidCounterpartyProtocolVersion()" )] pub struct ErrInvalidCounterpartyProtocolVersion; - ///Custom Error type `ErrInvalidHexAddress` with signature `ErrInvalidHexAddress()` and selector `0xfe6f1570` + /// Custom Error type `ErrInvalidHexAddress` with signature `ErrInvalidHexAddress()` and selector `0xfe6f1570` #[derive( Clone, ::ethers::contract::EthError, @@ -1836,7 +1836,7 @@ pub mod ucs01_relay { )] #[etherror(name = "ErrInvalidHexAddress", abi = "ErrInvalidHexAddress()")] pub struct ErrInvalidHexAddress; - ///Custom Error type `ErrInvalidProtocolOrdering` with signature `ErrInvalidProtocolOrdering()` and selector `0xb8526e65` + /// Custom Error type `ErrInvalidProtocolOrdering` with signature `ErrInvalidProtocolOrdering()` and selector `0xb8526e65` #[derive( Clone, ::ethers::contract::EthError, @@ -1852,7 +1852,7 @@ pub mod ucs01_relay { abi = "ErrInvalidProtocolOrdering()" )] pub struct ErrInvalidProtocolOrdering; - ///Custom Error type `ErrInvalidProtocolVersion` with signature `ErrInvalidProtocolVersion()` and selector `0x3d3f7720` + /// Custom Error type `ErrInvalidProtocolVersion` with signature `ErrInvalidProtocolVersion()` and selector `0x3d3f7720` #[derive( Clone, ::ethers::contract::EthError, @@ -1868,7 +1868,7 @@ pub mod ucs01_relay { abi = "ErrInvalidProtocolVersion()" )] pub struct ErrInvalidProtocolVersion; - ///Custom Error type `ErrNotIBC` with signature `ErrNotIBC()` and selector `0xe54f8f9d` + /// Custom Error type `ErrNotIBC` with signature `ErrNotIBC()` and selector `0xe54f8f9d` #[derive( Clone, ::ethers::contract::EthError, @@ -1881,7 +1881,7 @@ pub mod ucs01_relay { )] #[etherror(name = "ErrNotIBC", abi = "ErrNotIBC()")] pub struct ErrNotIBC; - ///Custom Error type `ErrUnauthorized` with signature `ErrUnauthorized()` and selector `0xcc12cef6` + /// Custom Error type `ErrUnauthorized` with signature `ErrUnauthorized()` and selector `0xcc12cef6` #[derive( Clone, ::ethers::contract::EthError, @@ -1894,7 +1894,7 @@ pub mod ucs01_relay { )] #[etherror(name = "ErrUnauthorized", abi = "ErrUnauthorized()")] pub struct ErrUnauthorized; - ///Custom Error type `ErrUnstoppable` with signature `ErrUnstoppable()` and selector `0x0637c796` + /// Custom Error type `ErrUnstoppable` with signature `ErrUnstoppable()` and selector `0x0637c796` #[derive( Clone, ::ethers::contract::EthError, @@ -1907,7 +1907,7 @@ pub mod ucs01_relay { )] #[etherror(name = "ErrUnstoppable", abi = "ErrUnstoppable()")] pub struct ErrUnstoppable; - ///Custom Error type `ExpectedPause` with signature `ExpectedPause()` and selector `0x8dfc202b` + /// Custom Error type `ExpectedPause` with signature `ExpectedPause()` and selector `0x8dfc202b` #[derive( Clone, ::ethers::contract::EthError, @@ -1920,7 +1920,7 @@ pub mod ucs01_relay { )] #[etherror(name = "ExpectedPause", abi = "ExpectedPause()")] pub struct ExpectedPause; - ///Custom Error type `FailedInnerCall` with signature `FailedInnerCall()` and selector `0x1425ea42` + /// Custom Error type `FailedInnerCall` with signature `FailedInnerCall()` and selector `0x1425ea42` #[derive( Clone, ::ethers::contract::EthError, @@ -1933,7 +1933,7 @@ pub mod ucs01_relay { )] #[etherror(name = "FailedInnerCall", abi = "FailedInnerCall()")] pub struct FailedInnerCall; - ///Custom Error type `InvalidInitialization` with signature `InvalidInitialization()` and selector `0xf92ee8a9` + /// Custom Error type `InvalidInitialization` with signature `InvalidInitialization()` and selector `0xf92ee8a9` #[derive( Clone, ::ethers::contract::EthError, @@ -1946,7 +1946,7 @@ pub mod ucs01_relay { )] #[etherror(name = "InvalidInitialization", abi = "InvalidInitialization()")] pub struct InvalidInitialization; - ///Custom Error type `NotInitializing` with signature `NotInitializing()` and selector `0xd7e6bcf8` + /// Custom Error type `NotInitializing` with signature `NotInitializing()` and selector `0xd7e6bcf8` #[derive( Clone, ::ethers::contract::EthError, @@ -1959,7 +1959,7 @@ pub mod ucs01_relay { )] #[etherror(name = "NotInitializing", abi = "NotInitializing()")] pub struct NotInitializing; - ///Custom Error type `OwnableInvalidOwner` with signature `OwnableInvalidOwner(address)` and selector `0x1e4fbdf7` + /// Custom Error type `OwnableInvalidOwner` with signature `OwnableInvalidOwner(address)` and selector `0x1e4fbdf7` #[derive( Clone, ::ethers::contract::EthError, @@ -1974,7 +1974,7 @@ pub mod ucs01_relay { pub struct OwnableInvalidOwner { pub owner: ::ethers::core::types::Address, } - ///Custom Error type `OwnableUnauthorizedAccount` with signature `OwnableUnauthorizedAccount(address)` and selector `0x118cdaa7` + /// Custom Error type `OwnableUnauthorizedAccount` with signature `OwnableUnauthorizedAccount(address)` and selector `0x118cdaa7` #[derive( Clone, ::ethers::contract::EthError, @@ -1992,7 +1992,7 @@ pub mod ucs01_relay { pub struct OwnableUnauthorizedAccount { pub account: ::ethers::core::types::Address, } - ///Custom Error type `SafeERC20FailedOperation` with signature `SafeERC20FailedOperation(address)` and selector `0x5274afe7` + /// Custom Error type `SafeERC20FailedOperation` with signature `SafeERC20FailedOperation(address)` and selector `0x5274afe7` #[derive( Clone, ::ethers::contract::EthError, @@ -2010,7 +2010,7 @@ pub mod ucs01_relay { pub struct SafeERC20FailedOperation { pub token: ::ethers::core::types::Address, } - ///Custom Error type `UUPSUnauthorizedCallContext` with signature `UUPSUnauthorizedCallContext()` and selector `0xe07c8dba` + /// Custom Error type `UUPSUnauthorizedCallContext` with signature `UUPSUnauthorizedCallContext()` and selector `0xe07c8dba` #[derive( Clone, ::ethers::contract::EthError, @@ -2026,7 +2026,7 @@ pub mod ucs01_relay { abi = "UUPSUnauthorizedCallContext()" )] pub struct UUPSUnauthorizedCallContext; - ///Custom Error type `UUPSUnsupportedProxiableUUID` with signature `UUPSUnsupportedProxiableUUID(bytes32)` and selector `0xaa1d49a4` + /// Custom Error type `UUPSUnsupportedProxiableUUID` with signature `UUPSUnsupportedProxiableUUID(bytes32)` and selector `0xaa1d49a4` #[derive( Clone, ::ethers::contract::EthError, @@ -2044,7 +2044,7 @@ pub mod ucs01_relay { pub struct UUPSUnsupportedProxiableUUID { pub slot: [u8; 32], } - ///Container type for all of the contract's custom errors + /// Container type for all of the contract's custom errors #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum UCS01RelayErrors { AddressEmptyCode(AddressEmptyCode), @@ -2689,7 +2689,7 @@ pub mod ucs01_relay { #[ethevent(indexed)] pub implementation: ::ethers::core::types::Address, } - ///Container type for all of the contract's events + /// Container type for all of the contract's events #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum UCS01RelayEvents { DenomCreatedFilter(DenomCreatedFilter), @@ -2796,7 +2796,7 @@ pub mod ucs01_relay { Self::UpgradedFilter(value) } } - ///Container type for all input parameters for the `UPGRADE_INTERFACE_VERSION` function with signature `UPGRADE_INTERFACE_VERSION()` and selector `0xad3cb1cc` + /// Container type for all input parameters for the `UPGRADE_INTERFACE_VERSION` function with signature `UPGRADE_INTERFACE_VERSION()` and selector `0xad3cb1cc` #[derive( Clone, ::ethers::contract::EthCall, @@ -2812,7 +2812,7 @@ pub mod ucs01_relay { abi = "UPGRADE_INTERFACE_VERSION()" )] pub struct UpgradeInterfaceVersionCall; - ///Container type for all input parameters for the `getDenomAddress` function with signature `getDenomAddress(string,string)` and selector `0x3a74ce26` + /// Container type for all input parameters for the `getDenomAddress` function with signature `getDenomAddress(string,string)` and selector `0x3a74ce26` #[derive( Clone, ::ethers::contract::EthCall, @@ -2828,7 +2828,7 @@ pub mod ucs01_relay { pub source_channel: ::std::string::String, pub denom: ::std::string::String, } - ///Container type for all input parameters for the `getOutstanding` function with signature `getOutstanding(string,address)` and selector `0x2b66b116` + /// Container type for all input parameters for the `getOutstanding` function with signature `getOutstanding(string,address)` and selector `0x2b66b116` #[derive( Clone, ::ethers::contract::EthCall, @@ -2844,7 +2844,7 @@ pub mod ucs01_relay { pub source_channel: ::std::string::String, pub token: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `ibcAddress` function with signature `ibcAddress()` and selector `0x696a9bf4` + /// Container type for all input parameters for the `ibcAddress` function with signature `ibcAddress()` and selector `0x696a9bf4` #[derive( Clone, ::ethers::contract::EthCall, @@ -2857,7 +2857,7 @@ pub mod ucs01_relay { )] #[ethcall(name = "ibcAddress", abi = "ibcAddress()")] pub struct IbcAddressCall; - ///Container type for all input parameters for the `initialize` function with signature `initialize(address,address)` and selector `0x485cc955` + /// Container type for all input parameters for the `initialize` function with signature `initialize(address,address)` and selector `0x485cc955` #[derive( Clone, ::ethers::contract::EthCall, @@ -2873,7 +2873,7 @@ pub mod ucs01_relay { pub ibc_handler: ::ethers::core::types::Address, pub admin: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `onAcknowledgementPacket` function with signature `onAcknowledgementPacket((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,address)` and selector `0xfb8b532e` + /// Container type for all input parameters for the `onAcknowledgementPacket` function with signature `onAcknowledgementPacket((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),bytes,address)` and selector `0xfb8b532e` #[derive( Clone, ::ethers::contract::EthCall, @@ -2893,7 +2893,7 @@ pub mod ucs01_relay { pub acknowledgement: ::ethers::core::types::Bytes, pub p2: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `onChanCloseConfirm` function with signature `onChanCloseConfirm(string,string,address)` and selector `0x3f41c9ea` + /// Container type for all input parameters for the `onChanCloseConfirm` function with signature `onChanCloseConfirm(string,string,address)` and selector `0x3f41c9ea` #[derive( Clone, ::ethers::contract::EthCall, @@ -2913,7 +2913,7 @@ pub mod ucs01_relay { pub ::std::string::String, pub ::ethers::core::types::Address, ); - ///Container type for all input parameters for the `onChanCloseInit` function with signature `onChanCloseInit(string,string,address)` and selector `0x7538ed68` + /// Container type for all input parameters for the `onChanCloseInit` function with signature `onChanCloseInit(string,string,address)` and selector `0x7538ed68` #[derive( Clone, ::ethers::contract::EthCall, @@ -2933,7 +2933,7 @@ pub mod ucs01_relay { pub ::std::string::String, pub ::ethers::core::types::Address, ); - ///Container type for all input parameters for the `onChanOpenAck` function with signature `onChanOpenAck(string,string,string,string,address)` and selector `0x60ca56eb` + /// Container type for all input parameters for the `onChanOpenAck` function with signature `onChanOpenAck(string,string,string,string,address)` and selector `0x60ca56eb` #[derive( Clone, ::ethers::contract::EthCall, @@ -2955,7 +2955,7 @@ pub mod ucs01_relay { pub counterparty_version: ::std::string::String, pub relayer: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `onChanOpenConfirm` function with signature `onChanOpenConfirm(string,string,address)` and selector `0xf8288cc6` + /// Container type for all input parameters for the `onChanOpenConfirm` function with signature `onChanOpenConfirm(string,string,address)` and selector `0xf8288cc6` #[derive( Clone, ::ethers::contract::EthCall, @@ -2975,7 +2975,7 @@ pub mod ucs01_relay { pub ::std::string::String, pub ::ethers::core::types::Address, ); - ///Container type for all input parameters for the `onChanOpenInit` function with signature `onChanOpenInit(uint8,string[],string,string,(string,string),string,address)` and selector `0xf2f83f7a` + /// Container type for all input parameters for the `onChanOpenInit` function with signature `onChanOpenInit(uint8,string[],string,string,(string,string),string,address)` and selector `0xf2f83f7a` #[derive( Clone, ::ethers::contract::EthCall, @@ -2999,7 +2999,7 @@ pub mod ucs01_relay { pub version: ::std::string::String, pub relayer: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `onChanOpenTry` function with signature `onChanOpenTry(uint8,string[],string,string,(string,string),string,string,address)` and selector `0x218d1e3e` + /// Container type for all input parameters for the `onChanOpenTry` function with signature `onChanOpenTry(uint8,string[],string,string,(string,string),string,string,address)` and selector `0x218d1e3e` #[derive( Clone, ::ethers::contract::EthCall, @@ -3024,7 +3024,7 @@ pub mod ucs01_relay { pub counterparty_version: ::std::string::String, pub relayer: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `onRecvPacket` function with signature `onRecvPacket((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),address)` and selector `0x2301c6f5` + /// Container type for all input parameters for the `onRecvPacket` function with signature `onRecvPacket((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),address)` and selector `0x2301c6f5` #[derive( Clone, ::ethers::contract::EthCall, @@ -3043,7 +3043,7 @@ pub mod ucs01_relay { pub ibc_packet: IbcCoreChannelV1PacketData, pub relayer: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `onRecvPacketProcessing` function with signature `onRecvPacketProcessing((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),address)` and selector `0xbd950f89` + /// Container type for all input parameters for the `onRecvPacketProcessing` function with signature `onRecvPacketProcessing((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),address)` and selector `0xbd950f89` #[derive( Clone, ::ethers::contract::EthCall, @@ -3062,7 +3062,7 @@ pub mod ucs01_relay { pub ibc_packet: IbcCoreChannelV1PacketData, pub p1: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `onTimeoutPacket` function with signature `onTimeoutPacket((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),address)` and selector `0x52c7157d` + /// Container type for all input parameters for the `onTimeoutPacket` function with signature `onTimeoutPacket((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),address)` and selector `0x52c7157d` #[derive( Clone, ::ethers::contract::EthCall, @@ -3081,7 +3081,7 @@ pub mod ucs01_relay { pub ibc_packet: IbcCoreChannelV1PacketData, pub p1: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` + /// Container type for all input parameters for the `owner` function with signature `owner()` and selector `0x8da5cb5b` #[derive( Clone, ::ethers::contract::EthCall, @@ -3094,7 +3094,7 @@ pub mod ucs01_relay { )] #[ethcall(name = "owner", abi = "owner()")] pub struct OwnerCall; - ///Container type for all input parameters for the `paused` function with signature `paused()` and selector `0x5c975abb` + /// Container type for all input parameters for the `paused` function with signature `paused()` and selector `0x5c975abb` #[derive( Clone, ::ethers::contract::EthCall, @@ -3107,7 +3107,7 @@ pub mod ucs01_relay { )] #[ethcall(name = "paused", abi = "paused()")] pub struct PausedCall; - ///Container type for all input parameters for the `proxiableUUID` function with signature `proxiableUUID()` and selector `0x52d1902d` + /// Container type for all input parameters for the `proxiableUUID` function with signature `proxiableUUID()` and selector `0x52d1902d` #[derive( Clone, ::ethers::contract::EthCall, @@ -3120,7 +3120,7 @@ pub mod ucs01_relay { )] #[ethcall(name = "proxiableUUID", abi = "proxiableUUID()")] pub struct ProxiableUUIDCall; - ///Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` + /// Container type for all input parameters for the `renounceOwnership` function with signature `renounceOwnership()` and selector `0x715018a6` #[derive( Clone, ::ethers::contract::EthCall, @@ -3133,7 +3133,7 @@ pub mod ucs01_relay { )] #[ethcall(name = "renounceOwnership", abi = "renounceOwnership()")] pub struct RenounceOwnershipCall; - ///Container type for all input parameters for the `send` function with signature `send(string,bytes,(address,uint128)[],string,(uint64,uint64),uint64)` and selector `0xa5b7e178` + /// Container type for all input parameters for the `send` function with signature `send(string,bytes,(address,uint128)[],string,(uint64,uint64),uint64)` and selector `0xa5b7e178` #[derive( Clone, ::ethers::contract::EthCall, @@ -3156,7 +3156,7 @@ pub mod ucs01_relay { pub timeout_height: IbcCoreClientV1HeightData, pub timeout_timestamp: u64, } - ///Container type for all input parameters for the `transferOwnership` function with signature `transferOwnership(address)` and selector `0xf2fde38b` + /// Container type for all input parameters for the `transferOwnership` function with signature `transferOwnership(address)` and selector `0xf2fde38b` #[derive( Clone, ::ethers::contract::EthCall, @@ -3171,7 +3171,7 @@ pub mod ucs01_relay { pub struct TransferOwnershipCall { pub new_owner: ::ethers::core::types::Address, } - ///Container type for all input parameters for the `updateMetadata` function with signature `updateMetadata(address,string,string,uint8)` and selector `0xec1bd897` + /// Container type for all input parameters for the `updateMetadata` function with signature `updateMetadata(address,string,string,uint8)` and selector `0xec1bd897` #[derive( Clone, ::ethers::contract::EthCall, @@ -3192,7 +3192,7 @@ pub mod ucs01_relay { pub new_symbol: ::std::string::String, pub new_decimals: u8, } - ///Container type for all input parameters for the `upgradeToAndCall` function with signature `upgradeToAndCall(address,bytes)` and selector `0x4f1ef286` + /// Container type for all input parameters for the `upgradeToAndCall` function with signature `upgradeToAndCall(address,bytes)` and selector `0x4f1ef286` #[derive( Clone, ::ethers::contract::EthCall, @@ -3208,7 +3208,7 @@ pub mod ucs01_relay { pub new_implementation: ::ethers::core::types::Address, pub data: ::ethers::core::types::Bytes, } - ///Container type for all of the contract's call + /// Container type for all of the contract's call #[derive(Clone, ::ethers::contract::EthAbiType, Debug, PartialEq, Eq, Hash)] pub enum UCS01RelayCalls { UpgradeInterfaceVersion(UpgradeInterfaceVersionCall), @@ -3525,7 +3525,7 @@ pub mod ucs01_relay { Self::UpgradeToAndCall(value) } } - ///Container type for all return fields from the `UPGRADE_INTERFACE_VERSION` function with signature `UPGRADE_INTERFACE_VERSION()` and selector `0xad3cb1cc` + /// Container type for all return fields from the `UPGRADE_INTERFACE_VERSION` function with signature `UPGRADE_INTERFACE_VERSION()` and selector `0xad3cb1cc` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3537,7 +3537,7 @@ pub mod ucs01_relay { Hash, )] pub struct UpgradeInterfaceVersionReturn(pub ::std::string::String); - ///Container type for all return fields from the `getDenomAddress` function with signature `getDenomAddress(string,string)` and selector `0x3a74ce26` + /// Container type for all return fields from the `getDenomAddress` function with signature `getDenomAddress(string,string)` and selector `0x3a74ce26` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3549,7 +3549,7 @@ pub mod ucs01_relay { Hash, )] pub struct GetDenomAddressReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `getOutstanding` function with signature `getOutstanding(string,address)` and selector `0x2b66b116` + /// Container type for all return fields from the `getOutstanding` function with signature `getOutstanding(string,address)` and selector `0x2b66b116` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3561,7 +3561,7 @@ pub mod ucs01_relay { Hash, )] pub struct GetOutstandingReturn(pub ::ethers::core::types::U256); - ///Container type for all return fields from the `ibcAddress` function with signature `ibcAddress()` and selector `0x696a9bf4` + /// Container type for all return fields from the `ibcAddress` function with signature `ibcAddress()` and selector `0x696a9bf4` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3573,7 +3573,7 @@ pub mod ucs01_relay { Hash, )] pub struct IbcAddressReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `onRecvPacket` function with signature `onRecvPacket((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),address)` and selector `0x2301c6f5` + /// Container type for all return fields from the `onRecvPacket` function with signature `onRecvPacket((uint64,string,string,string,string,bytes,(uint64,uint64),uint64),address)` and selector `0x2301c6f5` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3585,7 +3585,7 @@ pub mod ucs01_relay { Hash, )] pub struct OnRecvPacketReturn(pub ::ethers::core::types::Bytes); - ///Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` + /// Container type for all return fields from the `owner` function with signature `owner()` and selector `0x8da5cb5b` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3597,7 +3597,7 @@ pub mod ucs01_relay { Hash, )] pub struct OwnerReturn(pub ::ethers::core::types::Address); - ///Container type for all return fields from the `paused` function with signature `paused()` and selector `0x5c975abb` + /// Container type for all return fields from the `paused` function with signature `paused()` and selector `0x5c975abb` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3609,7 +3609,7 @@ pub mod ucs01_relay { Hash, )] pub struct PausedReturn(pub bool); - ///Container type for all return fields from the `proxiableUUID` function with signature `proxiableUUID()` and selector `0x52d1902d` + /// Container type for all return fields from the `proxiableUUID` function with signature `proxiableUUID()` and selector `0x52d1902d` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -3621,7 +3621,7 @@ pub mod ucs01_relay { Hash, )] pub struct ProxiableUUIDReturn(pub [u8; 32]); - ///`LocalToken(address,uint128)` + /// `LocalToken(address,uint128)` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/generated/rust/protos/Cargo.toml b/generated/rust/protos/Cargo.toml index 5076f1c47c..cd87cafd8b 100644 --- a/generated/rust/protos/Cargo.toml +++ b/generated/rust/protos/Cargo.toml @@ -335,7 +335,7 @@ proto_full = [ "union+ibc+lightclients+ethereum+v1", ] "union+ibc+lightclients+linea+v1" = ["ibc+core+client+v1", "union+ibc+lightclients+ethereum+v1"] -"union+ibc+lightclients+movement+v1" = ["ibc+core+client+v1"] +"union+ibc+lightclients+movement+v1" = ["ibc+core+client+v1", "union+ibc+lightclients+ethereum+v1"] "union+ibc+lightclients+scroll+v1" = ["ibc+core+client+v1", "union+ibc+lightclients+ethereum+v1"] "union+ics23+v1" = [] "union+staking+v1" = ["cosmos+staking+v1beta1"] diff --git a/generated/rust/protos/src/tendermint.abci.rs b/generated/rust/protos/src/tendermint.abci.rs index 2bec939c96..8afd529061 100644 --- a/generated/rust/protos/src/tendermint.abci.rs +++ b/generated/rust/protos/src/tendermint.abci.rs @@ -926,6 +926,7 @@ impl ::prost::Name for ExtendedCommitInfo { /// Event allows application developers to attach additional information to /// ResponseFinalizeBlock and ResponseCheckTx. /// Later, transactions may be queried using these events. +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Event { @@ -942,6 +943,7 @@ impl ::prost::Name for Event { } } /// EventAttribute is a single key-value pair, associated with an event. +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct EventAttribute { @@ -963,12 +965,14 @@ impl ::prost::Name for EventAttribute { /// ExecTxResult contains results of executing one individual transaction. /// /// * Its structure is equivalent to #ResponseDeliverTx which will be deprecated/deleted +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ExecTxResult { #[prost(uint32, tag = "1")] pub code: u32, #[prost(bytes = "vec", tag = "2")] + #[cfg_attr(feature = "serde", serde(with = "::serde_utils::base64_opt_default"))] pub data: ::prost::alloc::vec::Vec, /// nondeterministic #[prost(string, tag = "3")] @@ -977,8 +981,10 @@ pub struct ExecTxResult { #[prost(string, tag = "4")] pub info: ::prost::alloc::string::String, #[prost(int64, tag = "5")] + #[cfg_attr(feature = "serde", serde(with = "::serde_utils::string"))] pub gas_wanted: i64, #[prost(int64, tag = "6")] + #[cfg_attr(feature = "serde", serde(with = "::serde_utils::string"))] pub gas_used: i64, /// nondeterministic #[prost(message, repeated, tag = "7")] diff --git a/generated/rust/protos/src/tendermint.crypto.rs b/generated/rust/protos/src/tendermint.crypto.rs index f4ed059dad..8c0c429336 100644 --- a/generated/rust/protos/src/tendermint.crypto.rs +++ b/generated/rust/protos/src/tendermint.crypto.rs @@ -1,14 +1,19 @@ // @generated +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Proof { #[prost(int64, tag = "1")] + #[cfg_attr(feature = "serde", serde(with = "::serde_utils::string"))] pub total: i64, #[prost(int64, tag = "2")] + #[cfg_attr(feature = "serde", serde(with = "::serde_utils::string"))] pub index: i64, #[prost(bytes = "vec", tag = "3")] + #[cfg_attr(feature = "serde", serde(with = "::serde_utils::base64"))] pub leaf_hash: ::prost::alloc::vec::Vec, #[prost(bytes = "vec", repeated, tag = "4")] + #[cfg_attr(feature = "serde", serde(with = "::serde_utils::inner_base64"))] pub aunts: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, } impl ::prost::Name for Proof { diff --git a/generated/rust/protos/src/tendermint.types.rs b/generated/rust/protos/src/tendermint.types.rs index 97232a2c95..33e158daf3 100644 --- a/generated/rust/protos/src/tendermint.types.rs +++ b/generated/rust/protos/src/tendermint.types.rs @@ -596,12 +596,15 @@ impl ::prost::Name for BlockMeta { } } /// TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree. +#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct TxProof { #[prost(bytes = "vec", tag = "1")] + #[cfg_attr(feature = "serde", serde(with = "::serde_utils::hex_upper_unprefixed"))] pub root_hash: ::prost::alloc::vec::Vec, #[prost(bytes = "vec", tag = "2")] + #[cfg_attr(feature = "serde", serde(with = "::serde_utils::base64"))] pub data: ::prost::alloc::vec::Vec, #[prost(message, optional, tag = "3")] pub proof: ::core::option::Option, diff --git a/generated/rust/protos/src/union.ibc.lightclients.movement.v1.rs b/generated/rust/protos/src/union.ibc.lightclients.movement.v1.rs index adefe6ef98..c65407de8d 100644 --- a/generated/rust/protos/src/union.ibc.lightclients.movement.v1.rs +++ b/generated/rust/protos/src/union.ibc.lightclients.movement.v1.rs @@ -246,8 +246,8 @@ impl ::prost::Name for PublicKey { pub struct AggregateSignature { #[prost(bytes = "vec", tag = "1")] pub validator_bitmask: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag = "2")] - pub sig: ::core::option::Option, + #[prost(bytes = "vec", tag = "2")] + pub sig: ::prost::alloc::vec::Vec, } impl ::prost::Name for AggregateSignature { const NAME: &'static str = "AggregateSignature"; @@ -258,19 +258,6 @@ impl ::prost::Name for AggregateSignature { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Signature { - #[prost(bytes = "vec", tag = "1")] - pub sig: ::prost::alloc::vec::Vec, -} -impl ::prost::Name for Signature { - const NAME: &'static str = "Signature"; - const PACKAGE: &'static str = "union.ibc.lightclients.movement.v1"; - fn full_name() -> ::prost::alloc::string::String { - ::prost::alloc::format!("union.ibc.lightclients.movement.v1.{}", Self::NAME) - } -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] pub struct EpochChangeProof { #[prost(message, repeated, tag = "1")] pub ledger_info_with_sigs: ::prost::alloc::vec::Vec, diff --git a/hubble/Cargo.toml b/hubble/Cargo.toml index 2d91de825f..947926a899 100644 --- a/hubble/Cargo.toml +++ b/hubble/Cargo.toml @@ -18,43 +18,43 @@ name = "hubble" path = "src/main.rs" [dependencies] -alloy = { version = "0.1", features = ["full"] } -axum = { workspace = true, features = ["macros", "tokio"] } -backon = "0.4.4" -base64 = { workspace = true } -chain-utils = { workspace = true } -chrono = { workspace = true, features = ["clock"] } -clap = { workspace = true, features = ["derive", "env", "error-context"] } -color-eyre = { workspace = true, features = ["default"] } -cometbft-rpc = { workspace = true } -const-hex = "1.12.0" -contracts.workspace = true -futures = { workspace = true, features = ["async-await"] } -hex.workspace = true -itertools = "0.13.0" -lazy_static = { workspace = true } -num-traits = "0.2.19" -prometheus = { version = "0.13.3", features = ["process"] } -prost.workspace = true -protos = { workspace = true, features = ["client"] } -regex = "1.10.5" -reqwest = { workspace = true, features = ["json", "blocking"] } -scroll-api.workspace = true -serde = { workspace = true, features = ["derive"] } -serde-aux = "4.5.0" -serde_json = { workspace = true } -sqlx = { workspace = true, features = ["postgres", "runtime-tokio", "tls-rustls", "time", "macros", "json", "bigdecimal"] } -tendermint = { workspace = true, features = ["std"] } -tendermint-rpc = { workspace = true, features = ["http-client", "tokio"] } -thiserror = { workspace = true } -time = { workspace = true, features = ["serde"] } -tokio = { workspace = true, features = ["full"] } -tonic = { workspace = true, features = ["transport", "tls", "tls-roots", "tls-webpki-roots"] } -tracing = { workspace = true } -tracing-subscriber = { workspace = true, features = ["env-filter", "json", "tracing-log"] } -unionlabs = { workspace = true, features = ["ethabi"] } -url = { version = "2.4.1", features = ["serde"] } -valuable = { version = "0.1.0", features = ["derive"] } +alloy = { version = "0.1", features = ["full"] } +axum = { workspace = true, features = ["macros", "tokio"] } +backon = "0.4.4" +base64 = { workspace = true } +chain-utils = { workspace = true } +chrono = { workspace = true, features = ["clock"] } +clap = { workspace = true, features = ["derive", "env", "error-context"] } +color-eyre = { workspace = true, features = ["default"] } +cometbft-rpc = { workspace = true } +const-hex = "1.12.0" +contracts = { workspace = true } +futures = { workspace = true, features = ["async-await"] } +hex = { workspace = true } +itertools = "0.13.0" +lazy_static = { workspace = true } +num-traits = "0.2.19" +prometheus = { version = "0.13.3", features = ["process"] } +prost = { workspace = true } +protos = { workspace = true, features = ["client"] } +regex = "1.10.5" +reqwest = { workspace = true, features = ["json", "blocking"] } +scroll-api = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-aux = "4.5.0" +serde_json = { workspace = true } +sqlx = { workspace = true, features = ["postgres", "runtime-tokio", "tls-rustls", "time", "macros", "json", "bigdecimal"] } +tendermint = { workspace = true, features = ["std"] } +tendermint-rpc = { workspace = true, features = ["http-client", "tokio"] } +thiserror = { workspace = true } +time = { workspace = true, features = ["serde"] } +tokio = { workspace = true, features = ["full"] } +tonic = { workspace = true, features = ["transport", "tls", "tls-roots", "tls-webpki-roots"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["env-filter", "json", "tracing-log"] } +unionlabs = { workspace = true, features = ["ethabi"] } +url = { version = "2.4.1", features = ["serde"] } +valuable = { version = "0.1.0", features = ["derive"] } [target.'cfg(not(target_env = "msvc"))'.dependencies] tikv-jemallocator = "0.5" diff --git a/hubble/src/bera.rs b/hubble/src/bera.rs index f2605e0994..10339d1fbe 100644 --- a/hubble/src/bera.rs +++ b/hubble/src/bera.rs @@ -2,7 +2,7 @@ use std::time::Duration; use backon::{ConstantBuilder, ExponentialBuilder, Retryable}; use color_eyre::{eyre::eyre, Result}; -use cometbft_rpc::{AbciQueryResponse, Client}; +use cometbft_rpc::{types::AbciQueryResponse, Client}; use tracing::info; use unionlabs::{ berachain::BerachainChainSpec, encoding::DecodeAs, @@ -62,7 +62,7 @@ impl Bera { "store/beacon/key", data, Some( - (slot - 1) + (slot as i64 - 1) .try_into() .expect("converting slot to abci_query slot"), ), diff --git a/hubble/src/chain_id_query.rs b/hubble/src/chain_id_query.rs index d1105b6138..fa12d8bc9e 100644 --- a/hubble/src/chain_id_query.rs +++ b/hubble/src/chain_id_query.rs @@ -13,9 +13,7 @@ use tendermint_rpc::{Client, HttpClient}; use tracing::warn; use unionlabs::{ encoding::{DecodeAs, EthAbi, Proto}, - parse_wasm_client_type, - traits::ClientState, - WasmClientType, + parse_wasm_client_type, WasmClientType, }; sol! { contract IbcHandler { @@ -129,7 +127,7 @@ pub async fn tx(db: PgPool, indexers: Indexers) { continue; } }; - cs.chain_id().to_string() + cs.chain_id.to_string() } WasmClientType::Cometbls => { let cs = match unionlabs::ibc::lightclients::cometbls::client_state::ClientState::decode_as::(&cs.data) { @@ -140,7 +138,7 @@ pub async fn tx(db: PgPool, indexers: Indexers) { } }; - cs.chain_id().to_string() + cs.chain_id } WasmClientType::Tendermint => { let cs = match unionlabs::ibc::lightclients::tendermint::client_state::ClientState::decode_as::(&cs.data) { @@ -151,7 +149,7 @@ pub async fn tx(db: PgPool, indexers: Indexers) { } }; - cs.chain_id().to_string() + cs.chain_id } WasmClientType::Scroll => { let cs = match unionlabs::ibc::lightclients::scroll::client_state::ClientState::decode_as::(&cs.data) { @@ -162,7 +160,7 @@ pub async fn tx(db: PgPool, indexers: Indexers) { } }; - cs.chain_id().to_string() + cs.chain_id.to_string() } WasmClientType::Arbitrum => { let cs = match unionlabs::ibc::lightclients::arbitrum::client_state::ClientState::decode_as::(&cs.data) { @@ -173,7 +171,7 @@ pub async fn tx(db: PgPool, indexers: Indexers) { } }; - cs.chain_id().to_string() + cs.chain_id.to_string() } WasmClientType::Linea => todo!("We still need to add linea"), WasmClientType::Berachain => { @@ -186,7 +184,7 @@ pub async fn tx(db: PgPool, indexers: Indexers) { } }; - cs.chain_id().to_string() + cs.execution_chain_id.to_string() } WasmClientType::EvmInCosmos => { todo!() diff --git a/lib/aptos-rpc/Cargo.toml b/lib/aptos-rpc/Cargo.toml new file mode 100644 index 0000000000..02fa9f5a8d --- /dev/null +++ b/lib/aptos-rpc/Cargo.toml @@ -0,0 +1,27 @@ +[package] +edition = { workspace = true } +license-file = { workspace = true } +name = "aptos-rpc" +repository = { workspace = true } +version = "0.1.0" + +[lints] +workspace = true + +[dependencies] +hex = { workspace = true, features = ["alloc"] } +macros = { workspace = true } +reqwest = { workspace = true, features = ["rustls-tls", "json"] } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +serde_json = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } +tracing = { workspace = true } +unionlabs = { workspace = true } + +[features] +default = [] + +[dev-dependencies] +tracing-subscriber = { workspace = true } diff --git a/lib/aptos-rpc/src/lib.rs b/lib/aptos-rpc/src/lib.rs new file mode 100644 index 0000000000..77e3396749 --- /dev/null +++ b/lib/aptos-rpc/src/lib.rs @@ -0,0 +1,7 @@ +#[derive(Debug, Clone)] +pub struct AptosRpcClient { + // client: Client, + // base_url: String, +} + +impl AptosRpcClient {} diff --git a/lib/aptos-verifier/Cargo.toml b/lib/aptos-verifier/Cargo.toml index cc91ed6ed3..540b1cc66a 100644 --- a/lib/aptos-verifier/Cargo.toml +++ b/lib/aptos-verifier/Cargo.toml @@ -1,9 +1,9 @@ [package] -edition.workspace = true -license-file.workspace = true -name = "aptos-verifier" -repository.workspace = true -version = "0.1.0" +edition = { workspace = true } +license-file = { workspace = true } +name = "aptos-verifier" +repository = { workspace = true } +version = "0.1.0" [dependencies] bcs = { git = "https://github.com/aptos-labs/bcs.git", rev = "d31fab9d81748e2594be5cd5cdf845786a30562d" } diff --git a/lib/aptos-verifier/src/error.rs b/lib/aptos-verifier/src/error.rs index f2d4e24719..4f3dd080e9 100644 --- a/lib/aptos-verifier/src/error.rs +++ b/lib/aptos-verifier/src/error.rs @@ -1,14 +1,11 @@ -use unionlabs::aptos::hash_value::HashValue; +use unionlabs::hash::H256; use crate::MAX_ACCUMULATOR_PROOF_DEPTH; #[derive(Debug, Clone, PartialEq, thiserror::Error)] pub enum Error { #[error("root hash mismatch, expected ({expected}) given ({given})")] - RootHashMismatch { - expected: HashValue, - given: HashValue, - }, + RootHashMismatch { expected: H256, given: H256 }, #[error("accumulator proof hash has more than maximum ({MAX_ACCUMULATOR_PROOF_DEPTH}) siblings ({0})")] MaxSiblingsExceeded(usize), #[error("storage verification error")] @@ -20,13 +17,13 @@ pub enum StorageVerificationError { #[error("accumulator proof hash has more than maximum ({0}) siblings ({1})")] MaxSiblingsExceeded(usize, usize), #[error("leaf key mismatch (({0}), ({1}))")] - LeafKeyMismatch(HashValue, HashValue), + LeafKeyMismatch(H256, H256), #[error("leaf value mismatch (({0}), ({1}))")] - LeafValueMismatch(HashValue, HashValue), + LeafValueMismatch(H256, H256), #[error("expected membership verification")] ExpectedMembershipVerification, #[error("expected non-membership verification")] ExpectedNonMembershipVerification, #[error("root hash mismatch (({0}, {1}))")] - RootHashMismatch(HashValue, HashValue), + RootHashMismatch(H256, H256), } diff --git a/lib/aptos-verifier/src/lib.rs b/lib/aptos-verifier/src/lib.rs index 62594f4595..bcbd642e59 100644 --- a/lib/aptos-verifier/src/lib.rs +++ b/lib/aptos-verifier/src/lib.rs @@ -1,3 +1,5 @@ +// TODO: hasher.chain_update() can be used throughout this file + pub mod error; pub use error::Error; @@ -6,17 +8,17 @@ use hex_literal::hex; use sha3::{Digest, Sha3_256}; use unionlabs::{ aptos::{ - hash_value::HashValue, sparse_merkle_proof::{SparseMerkleLeafNode, SparseMerkleProof}, transaction_info::TransactionInfo, transaction_proof::TransactionInfoWithProof, }, encoding::{DecodeAs, Proto}, + hash::H256, }; pub(crate) const MAX_ACCUMULATOR_PROOF_DEPTH: usize = 63; // "SPARSE_MERKLE_PLACEHOLDER_HASH" -pub(crate) const SPARSE_MERKLE_PLACEHOLDER_HASH: HashValue = HashValue(hex!( +pub(crate) const SPARSE_MERKLE_PLACEHOLDER_HASH: H256 = H256(hex!( "00005350415253455F4D45524B4C455F504C414345484F4C4445525F48415348" )); @@ -24,7 +26,7 @@ pub(crate) const SPARSE_MERKLE_PLACEHOLDER_HASH: HashValue = HashValue(hex!( /// the accumulator whose root hash is `expected_root_hash` using the provided proof. pub fn verify_tx_state( tx_info: &TransactionInfoWithProof, - expected_root_hash: HashValue, + expected_root_hash: H256, element_index: u64, ) -> Result<(), Error> { let element_hash = hash_tx_info(&tx_info.transaction_info); @@ -67,16 +69,16 @@ pub fn verify_tx_state( pub fn verify_existence_proof( proof: &[u8], - expected_root_hash: HashValue, - element_key: HashValue, - element_hash: HashValue, + expected_root_hash: H256, + element_key: H256, + element_hash: H256, ) -> Result<(), Error> { let proof = SparseMerkleProof::decode_as::(proof).unwrap(); - if proof.siblings.len() > HashValue::LENGTH_IN_BITS { + if proof.siblings.len() > H256::BITS_LEN { // "Sparse Merkle Tree proof has more than {} ({} + {}) siblings.", return Err(StorageVerificationError::MaxSiblingsExceeded( - HashValue::LENGTH_IN_BITS, + H256::BITS_LEN, proof.siblings.len(), ) .into()); @@ -111,7 +113,7 @@ pub fn verify_existence_proof( element_key .iter_bits() .rev() - .skip(HashValue::LENGTH_IN_BITS - proof.siblings.len()), + .skip(H256::BITS_LEN - proof.siblings.len()), ) .fold(current_hash, |hash, (sibling_hash, bit)| { if bit { @@ -132,7 +134,7 @@ pub fn verify_existence_proof( Ok(()) } -fn hash_tx_info(tx_info: &TransactionInfo) -> HashValue { +fn hash_tx_info(tx_info: &TransactionInfo) -> H256 { let mut state = Sha3_256::new(); state.update( Sha3_256::new() @@ -140,10 +142,11 @@ fn hash_tx_info(tx_info: &TransactionInfo) -> HashValue { .finalize(), ); bcs::serialize_into(&mut state, tx_info).expect("expected to be able to serialize"); - HashValue(state.finalize().into()) + + state.finalize().into() } -fn hash_sparse_merkle_leaf_node(leaf: &SparseMerkleLeafNode) -> HashValue { +fn hash_sparse_merkle_leaf_node(leaf: &SparseMerkleLeafNode) -> H256 { let mut state = Sha3_256::new(); state.update( Sha3_256::new() @@ -152,10 +155,10 @@ fn hash_sparse_merkle_leaf_node(leaf: &SparseMerkleLeafNode) -> HashValue { ); state.update(leaf.key.as_ref()); state.update(leaf.value_hash.as_ref()); - HashValue(state.finalize().into()) + state.finalize().into() } -fn hash_inner_node(left_child: HashValue, right_child: HashValue) -> HashValue { +fn hash_inner_node(left_child: H256, right_child: H256) -> H256 { let mut state = Sha3_256::new(); state.update( Sha3_256::new() @@ -164,23 +167,23 @@ fn hash_inner_node(left_child: HashValue, right_child: HashValue) -> HashValue { ); state.update(left_child.as_ref()); state.update(right_child.as_ref()); - HashValue(state.finalize().into()) + state.finalize().into() } pub struct SparseMerkleInternalNode { - left_child: HashValue, - right_child: HashValue, + left_child: H256, + right_child: H256, } impl SparseMerkleInternalNode { - pub fn new(left_child: HashValue, right_child: HashValue) -> Self { + pub fn new(left_child: H256, right_child: H256) -> Self { Self { left_child, right_child, } } - pub fn hash(&self) -> HashValue { + pub fn hash(&self) -> H256 { let mut state = Sha3_256::new(); state.update( Sha3_256::new() @@ -189,6 +192,6 @@ impl SparseMerkleInternalNode { ); state.update(self.left_child.as_ref()); state.update(self.right_child.as_ref()); - HashValue(state.finalize().into()) + state.finalize().into() } } diff --git a/lib/arbitrum-verifier/Cargo.toml b/lib/arbitrum-verifier/Cargo.toml index 3cc20fe2cb..b597057e30 100644 --- a/lib/arbitrum-verifier/Cargo.toml +++ b/lib/arbitrum-verifier/Cargo.toml @@ -12,17 +12,17 @@ workspace = true # test-include = ["lib/arbitrum-verifier/tests"] [dependencies] -ethereum-verifier = { workspace = true } -ethers-core.workspace = true -hex = { workspace = true } -hex-literal.workspace = true -rlp = { workspace = true } -serde = { workspace = true } -serde-utils = { workspace = true } -serde_json = { workspace = true } -sha3 = { workspace = true } -thiserror = { workspace = true } -unionlabs = { workspace = true } +ethereum-verifier = { workspace = true } +ethers-core = { workspace = true } +hex = { workspace = true } +hex-literal = { workspace = true } +rlp = { workspace = true } +serde = { workspace = true } +serde-utils = { workspace = true } +serde_json = { workspace = true } +sha3 = { workspace = true } +thiserror = { workspace = true } +unionlabs = { workspace = true } [dev-dependencies] error_reporter = "1.0.0" diff --git a/lib/beacon-api/Cargo.toml b/lib/beacon-api/Cargo.toml index 5f9fdd76e2..aec93e1569 100644 --- a/lib/beacon-api/Cargo.toml +++ b/lib/beacon-api/Cargo.toml @@ -7,15 +7,17 @@ version = "0.1.0" workspace = true [dependencies] -hex = { workspace = true, features = ["alloc"] } -reqwest = { workspace = true, features = ["rustls-tls", "json"] } -serde = { workspace = true, features = ["derive"] } -serde-utils = { workspace = true } -serde_json = { workspace = true } -thiserror.workspace = true -tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } -tracing = { workspace = true } -unionlabs = { workspace = true } +enumorph = { workspace = true } +hex = { workspace = true, features = ["alloc"] } +macros = { workspace = true } +reqwest = { workspace = true, features = ["rustls-tls", "json"] } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +serde_json = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } +tracing = { workspace = true } +unionlabs = { workspace = true } [features] default = [] diff --git a/lib/beacon-api/examples/tests.rs b/lib/beacon-api/examples/tests.rs index 9e3822b75a..6ef010e1d6 100644 --- a/lib/beacon-api/examples/tests.rs +++ b/lib/beacon-api/examples/tests.rs @@ -1,5 +1,4 @@ use beacon_api::client::{BeaconApiClient, BlockId}; -use unionlabs::ethereum::config::Mainnet; #[tokio::main] async fn main() { @@ -9,13 +8,13 @@ async fn main() { } async fn do_main() { - let client = - BeaconApiClient::::new("https://lodestar-sepolia.chainsafe.io".to_string()) - .await - .unwrap(); + let client = BeaconApiClient::new("https://lodestar-sepolia.chainsafe.io".to_string()) + .await + .unwrap(); // genesis let block = client.block(BlockId::Slot(5772606)).await.unwrap(); + dbg!(block); // client.header(BlockId::Genesis).await.unwrap(); diff --git a/lib/beacon-api/src/client.rs b/lib/beacon-api/src/client.rs index 4c08d8cbf3..6119a43830 100644 --- a/lib/beacon-api/src/client.rs +++ b/lib/beacon-api/src/client.rs @@ -1,18 +1,17 @@ //! Beacon API client, implemented as per https://ethereum.github.io/beacon-APIs/releases/v2.4.1/beacon-node-oapi.json -use std::{fmt::Display, marker::PhantomData}; +use std::fmt::Display; use reqwest::{Client, StatusCode}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use tracing::{debug, info, trace}; use unionlabs::{ - ethereum::{ - beacon::{GenesisData, LightClientBootstrap, LightClientFinalityUpdate}, - config::ChainSpec, - SignedBeaconBlock, + ethereum::beacon::{ + genesis_data::GenesisData, light_client_bootstrap::UnboundedLightClientBootstrap, + light_client_finality_update::UnboundedLightClientFinalityUpdate, + signed_beacon_block::UnboundedSignedBeaconBlock, }, hash::H256, - typenum::Unsigned, }; use crate::{ @@ -20,13 +19,12 @@ use crate::{ types::{BeaconHeaderData, LightClientUpdatesResponse, Spec}, }; -type Result = core::result::Result; +pub type Result = core::result::Result; #[derive(Debug, Clone)] -pub struct BeaconApiClient { +pub struct BeaconApiClient { client: Client, base_url: String, - _marker: PhantomData, } #[derive(Debug, thiserror::Error)] @@ -37,23 +35,23 @@ pub enum NewError { Error(#[from] Error), } -impl BeaconApiClient { +impl BeaconApiClient { pub async fn new(base_url: String) -> core::result::Result { let this = Self { client: reqwest::Client::new(), base_url, - _marker: PhantomData, }; - let spec = this.spec().await?; + // TODO: Do checks against a spec? + let _spec = this.spec().await?; - if spec.data.seconds_per_slot != C::SECONDS_PER_SLOT::U64 { - return Err(NewError::IncorrectChainSpec); - } + // if spec.data.seconds_per_slot != C::SECONDS_PER_SLOT::U64 { + // return Err(NewError::IncorrectChainSpec); + // } - if spec.data.slots_per_epoch != C::SLOTS_PER_EPOCH::U64 { - return Err(NewError::IncorrectChainSpec); - } + // if spec.data.slots_per_epoch != C::SLOTS_PER_EPOCH::U64 { + // return Err(NewError::IncorrectChainSpec); + // } Ok(this) } @@ -62,7 +60,9 @@ impl BeaconApiClient { self.get_json("/eth/v1/config/spec").await } - pub async fn finality_update(&self) -> Result, Version>> { + pub async fn finality_update( + &self, + ) -> Result> { self.get_json("/eth/v1/beacon/light_client/finality_update") .await } @@ -78,7 +78,7 @@ impl BeaconApiClient { pub async fn block( &self, block_id: BlockId, - ) -> Result, BeaconBlockExtra>> { + ) -> Result> { self.get_json(format!("/eth/v2/beacon/blocks/{block_id}")) .await } @@ -86,7 +86,7 @@ impl BeaconApiClient { pub async fn bootstrap( &self, finalized_root: H256, - ) -> Result>> { + ) -> Result> { self.get_json(format!( "/eth/v1/beacon/light_client/bootstrap/{finalized_root}" )) @@ -104,7 +104,7 @@ impl BeaconApiClient { &self, start_period: u64, count: u64, - ) -> Result> { + ) -> Result { self.get_json(format!( "/eth/v1/beacon/light_client/updates?start_period={start_period}&count={count}" )) @@ -127,7 +127,10 @@ impl BeaconApiClient { Ok(height) } - pub async fn bootstrap_for_slot(&self, slot: u64) -> Result>> { + pub async fn bootstrap_for_slot( + &self, + slot: u64, + ) -> Result> { // NOTE(benluelo): While this is technically two actions, I consider it to be one // action - if the beacon chain doesn't have the header, it won't have the bootstrap // either. It would be nice if the beacon chain exposed "fetch bootstrap by slot" @@ -135,9 +138,10 @@ impl BeaconApiClient { let mut amount_of_slots_back: u64 = 0; - let floored_slot = slot - / (C::SLOTS_PER_EPOCH::U64 * C::EPOCHS_PER_SYNC_COMMITTEE_PERIOD::U64) - * (C::SLOTS_PER_EPOCH::U64 * C::EPOCHS_PER_SYNC_COMMITTEE_PERIOD::U64); + let spec = self.spec().await?.data; + + let floored_slot = slot / (spec.slots_per_epoch * spec.epochs_per_sync_committee_period) + * (spec.slots_per_epoch * spec.epochs_per_sync_committee_period); info!("fetching bootstrap at {}", floored_slot); @@ -178,25 +182,6 @@ impl BeaconApiClient { } } - // pub async fn get_light_client_updates_simple< - // const SYNC_COMMITTEE_SIZE: usize, - // const BYTES_PER_LOGS_BLOOM: usize, - // const MAX_EXTRA_DATA_BYTES: usize, - // >( - // &self, - // start_period: SyncCommitteePeriod, - // count: u64, - // ) -> Result< - // LightClientUpdatesResponse, - // > { - // let count = if count < 1 { 1 } else { count }; - // self.get_json(format!( - // "/eth/v1/beacon/light_client/updates?start_period={}&count={}", - // start_period, count - // )) - // .await - // } - // Helper functions async fn get_json(&self, path: impl Into) -> Result { @@ -252,6 +237,15 @@ pub struct Response { pub extra: Extra, } +impl Response { + pub fn map_data(self, f: impl FnOnce(Data) -> T) -> Response { + Response { + data: f(self.data), + extra: self.extra, + } + } +} + #[derive(Debug, Serialize, Deserialize)] pub struct Nil {} diff --git a/lib/beacon-api/src/types.rs b/lib/beacon-api/src/types.rs index de01bce63d..9f15a1b19e 100644 --- a/lib/beacon-api/src/types.rs +++ b/lib/beacon-api/src/types.rs @@ -137,26 +137,23 @@ pub struct BeaconHeaderSignature { use serde::{Deserialize, Serialize}; use unionlabs::{ bls::BlsSignature, - ethereum::{ - config::{ChainSpec, PresetBaseKind}, - Version, - }, + ethereum::{config::PresetBaseKind, Version}, hash::H256, ibc::lightclients::ethereum::{ beacon_block_header::BeaconBlockHeader, fork::Fork, fork_parameters::ForkParameters, - light_client_update::LightClientUpdate, + light_client_update::UnboundedLightClientUpdate, }, }; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(bound(serialize = "", deserialize = ""), deny_unknown_fields)] -pub struct LightClientUpdatesResponse(pub Vec>); +pub struct LightClientUpdatesResponse(pub Vec); #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(bound(serialize = "", deserialize = ""), deny_unknown_fields)] -pub struct LightClientUpdateResponse { +pub struct LightClientUpdateResponse { pub version: String, - pub data: LightClientUpdate, + pub data: UnboundedLightClientUpdate, } // #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] @@ -204,7 +201,7 @@ pub struct LightClientUpdateResponse { // } // } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub struct Spec { pub preset_base: PresetBaseKind, @@ -277,8 +274,10 @@ pub struct Spec { // MAX_ATTESTATIONS: 128, // MAX_DEPOSITS: 16, // MAX_VOLUNTARY_EXITS: 16, - // SYNC_COMMITTEE_SIZE: 512, - // EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 256, + #[serde(with = "::serde_utils::string")] + pub sync_committee_size: u64, + #[serde(with = "::serde_utils::string")] + pub epochs_per_sync_committee_period: u64, // INACTIVITY_PENALTY_QUOTIENT_ALTAIR: 50331648, // MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: 64, // PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: 2, @@ -297,7 +296,7 @@ pub struct Spec { // FIELD_ELEMENTS_PER_BLOB: 4096, // MAX_BLOBS_PER_BLOCK: 4, #[serde(with = "::serde_utils::string")] - genesis_slot: u64, + pub genesis_slot: u64, // GENESIS_EPOCH: 0, // FAR_FUTURE_EPOCH: 18446744073709551615, // BASE_REWARDS_PER_EPOCH: 4, @@ -338,7 +337,7 @@ pub struct Spec { } impl Spec { - pub fn into_fork_parameters(self) -> ForkParameters { + pub fn to_fork_parameters(&self) -> ForkParameters { ForkParameters { genesis_fork_version: self.genesis_fork_version, genesis_slot: self.genesis_slot, @@ -360,4 +359,8 @@ impl Spec { }, } } + + pub fn period(&self) -> u64 { + self.epochs_per_sync_committee_period * self.slots_per_epoch + } } diff --git a/lib/block-message/Cargo.toml b/lib/block-message/Cargo.toml deleted file mode 100644 index 86da7264d8..0000000000 --- a/lib/block-message/Cargo.toml +++ /dev/null @@ -1,58 +0,0 @@ -[package] -edition = { workspace = true } -license-file = { workspace = true } -name = "block-message" -repository = { workspace = true } -resolver = "2" -version = "0.1.0" - -[lints] -workspace = true - -[dependencies] -arbitrary = { workspace = true, optional = true, features = ["derive"] } -beacon-api = { workspace = true } -chain-utils = { workspace = true } -contracts = { workspace = true, features = ["providers"] } -dashmap = { workspace = true } -enumorph = { workspace = true } -ethers = { workspace = true, features = ["rustls", "ws"] } -frame-support-procedural = { workspace = true } -frunk = { workspace = true } -futures = { workspace = true } -hex = { workspace = true } -macros = { workspace = true } -num-bigint = { workspace = true } -prost = { workspace = true } -protos = { workspace = true, features = ["proto_full", "client"] } -queue-msg = { workspace = true } -serde = { workspace = true, features = ["derive"] } -serde-utils = { workspace = true } -serde_json = { workspace = true } -tendermint = { workspace = true } -tendermint-proto = { workspace = true } -tendermint-rpc = { workspace = true, features = ["http-client", "websocket-client"] } -thiserror = { workspace = true } -tokio = { workspace = true, features = ["time"] } -tonic = { workspace = true, features = ["transport", "tls", "tls-roots", "tls-webpki-roots"] } -tracing = { workspace = true } -typenum = { workspace = true } -unionlabs = { workspace = true, features = ["ethabi"] } - -[dev-dependencies] -hex-literal = { workspace = true } -serde_json = { workspace = true } - -[features] -default = [] - -arbitrary = [ - "dep:arbitrary", - "queue-msg/arbitrary", - "tendermint/arbitrary", - "tendermint/std", - "unionlabs/arbitrary", - "chain-utils/arbitrary", - "contracts/arbitrary", - # "ethers/arbitrary", -] diff --git a/lib/block-message/src/aggregate.rs b/lib/block-message/src/aggregate.rs deleted file mode 100644 index 2d4491de78..0000000000 --- a/lib/block-message/src/aggregate.rs +++ /dev/null @@ -1,102 +0,0 @@ -use std::collections::VecDeque; - -use frunk::{hlist_pat, HList}; -use macros::apply; -use queue_msg::{ - aggregation::{do_aggregate, UseAggregate}, - fetch, queue_msg, HandleAggregate, Op, QueueError, QueueMessage, -}; -use tracing::instrument; -use unionlabs::ibc::core::client::height::IsHeight; - -use crate::{ - any_chain, any_enum, - data::{AnyData, LatestHeight}, - fetch::{AnyFetch, Fetch, FetchBlockRange}, - id, AnyChainIdentified, BlockMessage, ChainExt, DoAggregate, Identified, IsAggregateData, -}; - -#[apply(any_enum)] -#[any = AnyAggregate] -#[specific = ChainSpecificAggregate] -pub enum Aggregate { - FetchBlockRange(AggregateFetchBlockRange), - #[serde(untagged)] - ChainSpecific(ChainSpecificAggregate), -} - -impl HandleAggregate for AnyChainIdentified { - #[instrument(skip_all, fields(chain_id = %self.chain_id()))] - fn handle( - self, - data: VecDeque<::Data>, - ) -> Result, QueueError> { - let aggregate = self; - - any_chain! { - |aggregate| Ok(aggregate.handle(data)) - } - } -} - -impl Identified> { - pub fn handle(self, data: VecDeque>) -> Op - where - Identified: DoAggregate, - - Identified>: IsAggregateData, - - AnyChainIdentified: From>>, - { - let chain_id = self.chain_id; - - match self.t { - Aggregate::ChainSpecific(ChainSpecificAggregate(aggregate)) => { - as DoAggregate>::do_aggregate( - id(chain_id, aggregate), - data, - ) - } - Aggregate::FetchBlockRange(aggregate) => do_aggregate(id(chain_id, aggregate), data), - } - } -} - -#[queue_msg] -pub struct ChainSpecificAggregate(pub C::Aggregate); - -#[queue_msg] -pub struct AggregateFetchBlockRange { - pub from_height: C::Height, -} - -impl UseAggregate for Identified> -where - Identified>: IsAggregateData, - - AnyChainIdentified: From>>, -{ - type AggregatedData = HList![Identified>]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: AggregateFetchBlockRange { from_height }, - }: Self, - hlist_pat![Identified { - chain_id: latest_height_chain_id, - t: LatestHeight(to_height), - }]: Self::AggregatedData, - ) -> Op { - assert!(to_height.revision_height() > from_height.revision_number()); - assert_eq!(this_chain_id, latest_height_chain_id); - - fetch(Identified::::new( - this_chain_id, - FetchBlockRange { - from_height, - to_height, - }, - )) - } -} diff --git a/lib/block-message/src/chain.rs b/lib/block-message/src/chain.rs deleted file mode 100644 index 72e437e309..0000000000 --- a/lib/block-message/src/chain.rs +++ /dev/null @@ -1,120 +0,0 @@ -// https://github.com/rust-lang/rust/issues/35853#issuecomment-415993963 -macro_rules! with_dollar_sign { - ($($body:tt)*) => { - macro_rules! __with_dollar_sign { $($body)* } - __with_dollar_sign!($); - } -} - -macro_rules! try_from_block_poll_msg { - ( - chain = $Chain:ty, - generics = ($($generics:tt)*), - msgs = $Enum:ident( - $($Variant:ident($Ty:ty),)+ - ), - $(where = ($($where:tt)+))? - ) => { - with_dollar_sign! { - ($d:tt) => { - macro_rules! with_generics { - ( - chain = $d Chain:ty, - msgs = $d Enum:ident( - $d ($d Variant:ident($d Ty:ty),)+ - ), - ) => { - $d ( - impl <$($generics)*> TryFrom> for Identified<$d Chain, $d Ty> - where - Identified<$d Chain, Data<$d Chain>>: TryFrom, Error = AnyChainIdentified> + Into>, - $($($where)+)? - { - type Error = Op; - fn try_from(value: Op) -> Result, Op> { - match value { - Op::Data(data) => { - let Identified { - chain_id, - t, - } = data.try_into().map_err(Op::Data)?; - - match t { - crate::data::Data::ChainSpecific( - crate::data::ChainSpecificData($d Enum::$d Variant( - t, - ))) => Ok(Identified::new(chain_id, t)), - _ => Err(Op::Data(Into::>::into(Identified::<$d Chain, _>::new(chain_id, t)))) - } - - }, - _ => Err(value), - } - } - } - - impl <$($generics)*> From> for crate::AnyChainIdentified - where - AnyChainIdentified: From>>, - $($($where)+)? - { - fn from(Identified { chain_id, t, }: Identified<$d Chain, $d Ty>) -> crate::AnyChainIdentified { - crate::AnyChainIdentified::::from(Identified::<$d Chain, _>::new( - chain_id, - Data::ChainSpecific(crate::data::ChainSpecificData($d Enum::$d Variant( - t, - ))), - )) - } - } - - impl <$($generics)*> TryFrom> for Identified<$d Chain, $d Ty> - where - Identified<$d Chain, Data<$d Chain>>: TryFrom, Error = AnyChainIdentified> + Into>, - $($($where)+)? - { - type Error = crate::AnyChainIdentified; - - fn try_from(value: crate::AnyChainIdentified) -> Result, crate::AnyChainIdentified> { - let Identified::<$d Chain, _> { - chain_id, - t, - } = value.try_into()?; - - match t { - Data::ChainSpecific(crate::data::ChainSpecificData($d Enum::$d Variant( - t, - ))) => Ok(Identified::new(chain_id, t)), - _ => Err(Into::>::into(Identified::new(chain_id, t))) - } - } - } - )+ - - // impl From<<$d Chain as Chain>::$d LcMsg> for $d Specific<$d Chain> { - // fn from(msg: <$d Chain as Chain>::$d LcMsg) -> Self { - // Self(msg) - // } - // } - }; - } - } - } - - with_generics!( - chain = $Chain, - msgs = $Enum( - $($Variant($Ty),)+ - ), - ); - }; -} - -pub mod arbitrum; -pub mod berachain; -pub mod cosmos; -pub mod ethereum; -pub mod scroll; -pub mod union; - -pub mod cosmos_sdk; diff --git a/lib/block-message/src/chain/arbitrum.rs b/lib/block-message/src/chain/arbitrum.rs deleted file mode 100644 index e329fd3bab..0000000000 --- a/lib/block-message/src/chain/arbitrum.rs +++ /dev/null @@ -1,140 +0,0 @@ -use std::collections::VecDeque; - -use chain_utils::{ - arbitrum::{Arbitrum, ARBITRUM_REVISION_NUMBER}, - ethereum::{AnyEthereum, EthereumConsensusChain}, -}; -use enumorph::Enumorph; -use queue_msg::{aggregation::do_aggregate, fetch, queue_msg, Op}; -use unionlabs::{ibc::core::client::height::IsHeight, traits::Chain}; - -use crate::{ - aggregate::{Aggregate, AnyAggregate}, - chain::ethereum::{ - fetch_beacon_block_range, fetch_channel, fetch_get_logs, AggregateWithChannel, ChannelData, - ConnectionData, FetchBeaconBlockRange, FetchChannel, FetchEvents, FetchGetLogs, - }, - data::{AnyData, ChainEvent, Data}, - fetch::{AnyFetch, DoFetch, DoFetchBlockRange, Fetch, FetchBlockRange}, - id, AnyChainIdentified, BlockMessage, ChainExt, DoAggregate, Identified, IsAggregateData, -}; - -impl ChainExt for Arbitrum { - type Data = ArbitrumData; - type Fetch = ArbitrumFetch; - type Aggregate = ArbitrumAggregate; -} - -impl DoFetchBlockRange for Arbitrum -where - AnyChainIdentified: From>>, -{ - fn fetch_block_range(c: &Arbitrum, range: FetchBlockRange) -> Op { - fetch(id( - c.chain_id(), - Fetch::::specific(FetchEvents { - from_height: range.from_height, - to_height: range.to_height, - }), - )) - } -} - -impl DoFetch for ArbitrumFetch -where - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, -{ - async fn do_fetch(c: &Arbitrum, msg: Self) -> Op { - match msg { - Self::FetchEvents(FetchEvents { - from_height, - to_height, - }) => fetch(id( - c.chain_id(), - Fetch::::specific(FetchBeaconBlockRange { - from_slot: from_height.revision_height, - to_slot: to_height.revision_height, - }), - )), - Self::FetchGetLogs(get_logs) => { - fetch_get_logs(c, get_logs, ARBITRUM_REVISION_NUMBER).await - } - Self::FetchBeaconBlockRange(beacon_block_range) => match &c.l1 { - AnyEthereum::Mainnet(eth) => { - fetch_beacon_block_range(c, beacon_block_range, ð.beacon_api_client).await - } - AnyEthereum::Minimal(eth) => { - fetch_beacon_block_range(c, beacon_block_range, ð.beacon_api_client).await - } - }, - Self::FetchChannel(FetchChannel { height, path }) => { - fetch_channel( - c, - path, - c.execution_height_of_beacon_slot(height.revision_height()) - .await, - ) - .await - } - } - } -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum ArbitrumFetch { - FetchEvents(FetchEvents), - FetchGetLogs(FetchGetLogs), - FetchBeaconBlockRange(FetchBeaconBlockRange), - - FetchChannel(FetchChannel), -} - -#[queue_msg] -pub struct FetchBatchIndex { - beacon_slot: u64, - batch_index: u64, -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum ArbitrumAggregate { - AggregateWithChannel(AggregateWithChannel), -} - -impl DoAggregate for Identified -where - AnyChainIdentified: From>>, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, -{ - fn do_aggregate( - Identified { chain_id, t }: Self, - data: VecDeque>, - ) -> Op { - match t { - ArbitrumAggregate::AggregateWithChannel(msg) => do_aggregate(id(chain_id, msg), data), - } - } -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum ArbitrumData { - Channel(ChannelData), - Connection(ConnectionData), -} - -const _: () = { - try_from_block_poll_msg! { - chain = Arbitrum, - generics = (), - msgs = ArbitrumData( - Channel(ChannelData), - Connection(ConnectionData), - ), - } -}; diff --git a/lib/block-message/src/chain/berachain.rs b/lib/block-message/src/chain/berachain.rs deleted file mode 100644 index 58ec87c6e2..0000000000 --- a/lib/block-message/src/chain/berachain.rs +++ /dev/null @@ -1,231 +0,0 @@ -use std::collections::VecDeque; - -use chain_utils::{ - berachain::Berachain, - ethereum::{EthereumConsensusChain, IBCHandlerEvents}, -}; -use enumorph::Enumorph; -use ethers::{contract::EthLogDecode, providers::Middleware, types::Filter}; -use futures::StreamExt; -use queue_msg::{aggregation::do_aggregate, conc, fetch, noop, queue_msg, Op}; -use tracing::{debug, info, warn}; -use unionlabs::{ - ibc::core::client::height::IsHeight, - traits::{Chain, HeightOf}, -}; - -use crate::{ - aggregate::{Aggregate, AnyAggregate}, - chain::ethereum::{ - fetch_channel, mk_aggregate_event, AggregateWithChannel, ChannelData, ConnectionData, - FetchChannel, - }, - data::{AnyData, ChainEvent, Data}, - fetch::{AnyFetch, DoFetch, DoFetchBlockRange, Fetch, FetchBlockRange}, - id, AnyChainIdentified, BlockMessage, ChainExt, DoAggregate, Identified, IsAggregateData, -}; - -impl ChainExt for Berachain { - type Data = BerachainData; - type Fetch = BerachainFetch; - type Aggregate = BerachainAggregate; -} - -impl DoFetchBlockRange for Berachain -where - AnyChainIdentified: From>>, -{ - fn fetch_block_range(c: &Berachain, range: FetchBlockRange) -> Op { - fetch(id( - c.chain_id(), - Fetch::::specific(FetchBlocks { - from_height: range.from_height, - to_height: range.to_height, - }), - )) - } -} - -impl DoFetch for BerachainFetch -where - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, -{ - async fn do_fetch(c: &Berachain, msg: Self) -> Op { - match msg { - Self::FetchBlockEvents(FetchBlockEvents { height }) => { - info!(%height, "fetching block events"); - - let block_number = c - .execution_height_of_beacon_slot(height.revision_height) - .await; - - debug!("cometbft height {height} is evm block number {block_number}"); - - if height.revision_height > 1 { - let previous_block_number = c - .execution_height_of_beacon_slot(height.revision_height - 1) - .await; - - if block_number == previous_block_number { - debug!(slot = %height.revision_height, "slot was missed"); - return noop(); - } - } - - conc( - futures::stream::iter( - c.provider - .get_logs( - &Filter::new() - .address(ethers::types::H160::from(c.ibc_handler_address)) - .from_block(block_number) - .to_block(block_number), - ) - .await - .unwrap(), - ) - .filter_map(|log| async { - let tx_hash = log - .transaction_hash - .expect("log should have transaction_hash") - .into(); - - debug!(?log, "raw log"); - - match IBCHandlerEvents::decode_log(&log.into()) { - Ok(event) => { - debug!(?event, "found IBCHandler event"); - Some( - mk_aggregate_event(c, event, height, tx_hash, |event_height| { - c.execution_height_of_beacon_slot( - event_height.revision_height, - ) - }) - .await, - ) - } - Err(e) => { - warn!("could not decode evm event {}", e); - None - } - } - }) - .collect::>() - .await, - ) - } - Self::FetchBlocks(FetchBlocks { - from_height, - to_height, - }) => { - assert!(from_height.revision_height() < to_height.revision_height()); - - if to_height.revision_height() - from_height.revision_height() == 1 { - fetch(id( - c.chain_id(), - Fetch::::specific(FetchBlockEvents { - height: from_height, - }), - )) - } else { - // this is exclusive on `to`, so fetch the `from` block and "discard" the `to` block - // the assumption is that another message with `to..N` will be queued, which then following - // this logic will fetch `to`. - - let new_from_height = from_height.increment(); - - conc( - [fetch(id( - c.chain_id(), - Fetch::::specific(FetchBlockEvents { - height: from_height, - }), - ))] - .into_iter() - .chain((new_from_height != to_height).then(|| { - fetch(id( - c.chain_id(), - Fetch::::specific(FetchBlocks { - from_height: new_from_height, - to_height, - }), - )) - })), - ) - } - } - Self::FetchChannel(FetchChannel { height, path }) => { - fetch_channel( - c, - path, - c.execution_height_of_beacon_slot(height.revision_height()) - .await, - ) - .await - } - } - } -} - -#[queue_msg] -pub struct FetchBlockEvents { - pub height: HeightOf, -} - -#[queue_msg] -pub struct FetchBlocks { - pub from_height: HeightOf, - pub to_height: HeightOf, -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum BerachainFetch { - FetchBlocks(FetchBlocks), - FetchBlockEvents(FetchBlockEvents), - - FetchChannel(FetchChannel), -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum BerachainAggregate { - AggregateWithChannel(AggregateWithChannel), -} - -impl DoAggregate for Identified -where - AnyChainIdentified: From>>, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, -{ - fn do_aggregate( - Identified { chain_id, t }: Self, - data: VecDeque>, - ) -> Op { - match t { - BerachainAggregate::AggregateWithChannel(msg) => do_aggregate(id(chain_id, msg), data), - } - } -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum BerachainData { - Channel(ChannelData), - Connection(ConnectionData), -} - -const _: () = { - try_from_block_poll_msg! { - chain = Berachain, - generics = (), - msgs = BerachainData( - Channel(ChannelData), - Connection(ConnectionData), - ), - } -}; diff --git a/lib/block-message/src/chain/cosmos.rs b/lib/block-message/src/chain/cosmos.rs deleted file mode 100644 index b25e07e59b..0000000000 --- a/lib/block-message/src/chain/cosmos.rs +++ /dev/null @@ -1,5 +0,0 @@ -use chain_utils::cosmos::Cosmos; - -use crate::chain::cosmos_sdk::CosmosSdkChainSealed; - -impl CosmosSdkChainSealed for Cosmos {} diff --git a/lib/block-message/src/chain/cosmos_sdk.rs b/lib/block-message/src/chain/cosmos_sdk.rs deleted file mode 100644 index c3dfe27e5d..0000000000 --- a/lib/block-message/src/chain/cosmos_sdk.rs +++ /dev/null @@ -1,464 +0,0 @@ -use std::{collections::VecDeque, marker::PhantomData, num::NonZeroU32}; - -use chain_utils::cosmos_sdk::{CosmosSdkChainExt, CosmosSdkChainIbcExt}; -use frunk::{hlist_pat, HList}; -use futures::FutureExt; -use queue_msg::{ - aggregate, - aggregation::{do_aggregate, UseAggregate}, - conc, data, fetch, noop, queue_msg, Op, -}; -use tendermint_rpc::Client; -use tracing::{info, warn}; -use unionlabs::{ - events::{ - AcknowledgePacket, ChannelOpenAck, ChannelOpenConfirm, ChannelOpenInit, ChannelOpenTry, - ClientMisbehaviour, ConnectionOpenAck, ConnectionOpenConfirm, ConnectionOpenInit, - ConnectionOpenTry, CreateClient, IbcEvent, RecvPacket, SendPacket, SubmitEvidence, - TimeoutPacket, UpdateClient, WriteAcknowledgement, - }, - hash::H256, - ibc::core::client::height::IsHeight, - id::ConnectionId, - option_unwrap, - tendermint::abci::{event::Event, event_attribute::EventAttribute}, - traits::{ClientIdOf, HeightOf}, -}; - -use crate::{ - aggregate::{Aggregate, AnyAggregate}, - data::{AnyData, ChainEvent, Data}, - fetch::{AnyFetch, DoFetch, DoFetchBlockRange, Fetch, FetchBlockRange}, - id, AnyChainIdentified, BlockMessage, ChainExt, DoAggregate, Identified, IsAggregateData, -}; - -pub trait CosmosSdkChainSealed: ChainExt + CosmosSdkChainIbcExt + CosmosSdkChainExt {} - -impl ChainExt for C { - type Data = CosmosSdkData; - type Fetch = CosmosSdkFetch; - type Aggregate = CosmosSdkAggregate; -} - -const _: fn() = || { - unionlabs::impl_maybe_arbitrary::>(); -}; - -impl>> DoFetchBlockRange for C -where - AnyChainIdentified: From>>, -{ - fn fetch_block_range( - c: &C, - FetchBlockRange { - from_height, - to_height, - }: FetchBlockRange, - ) -> Op { - fetch(id( - c.chain_id(), - Fetch::::specific(FetchBlocks { - from_height, - to_height, - }), - )) - } -} - -const PER_PAGE_LIMIT: u8 = 10; - -impl DoFetch for CosmosSdkFetch -where - C: CosmosSdkChainSealed< - Fetch = CosmosSdkFetch, - Aggregate = CosmosSdkAggregate, - Data = CosmosSdkData, - >, - - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, -{ - async fn do_fetch(c: &C, this: Self) -> Op { - match this { - CosmosSdkFetch::FetchTransactions(FetchTransactions { height, page }) => { - info!(%height, %page, "fetching events in block"); - - let response = c - .tm_client() - .tx_search( - tendermint_rpc::query::Query::eq("tx.height", height.revision_height()), - false, - page.get(), - PER_PAGE_LIMIT, - tendermint_rpc::Order::Descending, - ) - .await - .unwrap(); - - conc( - response - .txs - .into_iter() - // .inspect(|x| { - // dbg!(x); - // }) - .flat_map(|txr| { - txr.tx_result.events.into_iter().filter_map(move |event| { - IbcEvent::, _, _>::try_from_tendermint_event(Event { - ty: event.kind, - attributes: event - .attributes - .into_iter() - .map(|attr| EventAttribute { - key: attr.key_str().expect("key in event").to_string(), - value: attr - .value_str() - .expect("value in event") - .to_string(), - index: attr.index(), - }) - .collect(), - }) - .transpose() - .unwrap() - .map(|x: IbcEvent<_, _, _>| (x, txr.hash)) - }) - }) - .map(|(ibc_event, tx_hash)| { - match ibc_event { - IbcEvent::SubmitEvidence(SubmitEvidence { .. }) => { - // TODO: Not sure how to handle this one, since it only contains the hash - // union - // .code_id_of_client_id(client_id) - // .then(|checksum| union.client_type_of_code_id(checksum)) - // .await - panic!() - } - IbcEvent::CreateClient(CreateClient { ref client_id, .. }) - | IbcEvent::UpdateClient(UpdateClient { ref client_id, .. }) - | IbcEvent::ClientMisbehaviour(ClientMisbehaviour { - ref client_id, - .. - }) - | IbcEvent::ConnectionOpenInit(ConnectionOpenInit { - ref client_id, - .. - }) - | IbcEvent::ConnectionOpenTry(ConnectionOpenTry { - ref client_id, - .. - }) - | IbcEvent::ConnectionOpenAck(ConnectionOpenAck { - ref client_id, - .. - }) - | IbcEvent::ConnectionOpenConfirm(ConnectionOpenConfirm { - ref client_id, - .. - }) => aggregate( - [fetch(id( - c.chain_id(), - Fetch::::specific(ClientTypeFromClientId { - client_id: client_id.clone(), - }), - ))], - [], - id( - c.chain_id(), - Aggregate::::specific( - AggregateEventWithClientType:: { - tx_hash: tendermint_hash_to_h256(tx_hash), - height, - event: ibc_event, - }, - ), - ), - ), - - IbcEvent::ChannelOpenInit(ChannelOpenInit { - ref connection_id, - .. - }) - | IbcEvent::ChannelOpenTry(ChannelOpenTry { - ref connection_id, - .. - }) - | IbcEvent::ChannelOpenAck(ChannelOpenAck { - ref connection_id, - .. - }) - | IbcEvent::ChannelOpenConfirm(ChannelOpenConfirm { - ref connection_id, - .. - }) - | IbcEvent::WriteAcknowledgement(WriteAcknowledgement { - ref connection_id, - .. - }) - | IbcEvent::RecvPacket(RecvPacket { - ref connection_id, .. - }) - | IbcEvent::SendPacket(SendPacket { - ref connection_id, .. - }) - | IbcEvent::AcknowledgePacket(AcknowledgePacket { - ref connection_id, - .. - }) - | IbcEvent::TimeoutPacket(TimeoutPacket { - ref connection_id, - .. - }) => aggregate( - [fetch(id( - c.chain_id(), - Fetch::specific(ClientTypeFromConnectionId { - connection_id: connection_id.clone(), - }), - ))], - [], - id( - c.chain_id(), - Aggregate::::specific(AggregateEventWithClientType { - tx_hash: tendermint_hash_to_h256(tx_hash), - height, - event: ibc_event, - }), - ), - ), - } - }) - .chain( - ((page.get() * PER_PAGE_LIMIT as u32) < response.total_count).then( - || { - queue_msg::fetch(id( - c.chain_id(), - Fetch::specific(FetchTransactions { - height, - page: page.checked_add(1).unwrap(), - }), - )) - }, - ), - ), - ) - } - CosmosSdkFetch::FetchClientTypeFromConnectionId(ClientTypeFromConnectionId { - connection_id, - }) => fetch(id( - c.chain_id(), - Fetch::specific(ClientTypeFromClientId { - client_id: c.client_id_of_connection(connection_id.clone()).await, - }), - )), - CosmosSdkFetch::FetchClientTypeFromClientId(ClientTypeFromClientId { client_id }) => { - data(id( - c.chain_id(), - Data::::specific(ClientType { - client_type: match client_id.to_string().rsplit_once('-').unwrap().0 { - "07-tendermint" => unionlabs::ClientType::Tendermint, - "08-wasm" => unionlabs::ClientType::Wasm( - match c - .checksum_of_client_id(client_id.clone()) - .then(|checksum| c.client_type_of_checksum(checksum)) - .await - { - Some(ty) => ty, - None => { - warn!(%client_id, "unknown client type for 08-wasm client"); - // this early return is kind of dirty but it works - return noop(); - } - }, - ), - "11-cometbls" => unionlabs::ClientType::_11Cometbls, - ty => panic!("unsupported client type {ty}"), - }, - __marker: PhantomData, - }), - )) - } - CosmosSdkFetch::FetchBlocks(FetchBlocks { - from_height, - to_height, - }) => { - assert!(from_height.revision_height() < to_height.revision_height()); - - if to_height.revision_height() - from_height.revision_height() == 1 { - fetch(id( - c.chain_id(), - Fetch::::specific(FetchTransactions { - height: from_height, - page: const { option_unwrap!(NonZeroU32::new(1_u32)) }, - }), - )) - } else { - // this is exclusive on `to`, so fetch the `from` block and "discard" the `to` block - // the assumption is that another message with `to..N` will be queued, which then following - // this logic will fetch `to`. - - let new_from_height = from_height.increment(); - - conc( - [fetch(id( - c.chain_id(), - Fetch::::specific(FetchTransactions { - height: from_height, - page: const { option_unwrap!(NonZeroU32::new(1_u32)) }, - }), - ))] - .into_iter() - .chain((new_from_height != to_height).then(|| { - fetch(id( - c.chain_id(), - Fetch::::specific(FetchBlocks { - from_height: new_from_height, - to_height, - }), - )) - })), - ) - } - } - } - } -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum CosmosSdkData { - ClientType(ClientType), -} - -const _: () = { - try_from_block_poll_msg! { - chain = C, - generics = (C: CosmosSdkChainSealed), - msgs = CosmosSdkData( - ClientType(ClientType), - ), - where = (C: ChainExt>) - } -}; - -#[queue_msg] -pub struct ClientType<#[cover] C: CosmosSdkChainSealed> { - pub client_type: unionlabs::ClientType, -} - -// FETCH - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum CosmosSdkFetch { - FetchBlocks(FetchBlocks), - FetchTransactions(FetchTransactions), - FetchClientTypeFromConnectionId(ClientTypeFromConnectionId), - FetchClientTypeFromClientId(ClientTypeFromClientId), -} - -#[queue_msg] -pub struct FetchBlocks { - pub from_height: HeightOf, - pub to_height: HeightOf, -} - -#[queue_msg] -pub struct FetchTransactions { - pub height: HeightOf, - pub page: NonZeroU32, -} - -#[queue_msg] -pub struct ClientTypeFromConnectionId { - pub connection_id: ConnectionId, -} - -#[queue_msg] -pub struct ClientTypeFromClientId { - pub client_id: C::ClientId, -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum CosmosSdkAggregate { - AggregateEventWithClientType(AggregateEventWithClientType), -} - -#[queue_msg] -pub struct AggregateEventWithClientType { - pub tx_hash: H256, - pub height: C::Height, - pub event: IbcEvent, -} - -impl UseAggregate for Identified> -where - C: CosmosSdkChainSealed, - Identified>: IsAggregateData, - AnyChainIdentified: From>>, -{ - type AggregatedData = HList![ - Identified>, - ]; - - fn aggregate( - Identified { - chain_id, - t: - AggregateEventWithClientType { - tx_hash, - height, - event, - }, - }: Self, - hlist_pat![Identified { - chain_id: client_type_chain_id, - t: ClientType { - client_type, - __marker: _ - }, - }]: Self::AggregatedData, - ) -> Op { - assert_eq!(chain_id, client_type_chain_id); - - data(id( - chain_id, - ChainEvent { - client_type, - tx_hash, - // don't ask - height: height.increment(), - event, - }, - )) - } -} - -impl DoAggregate for Identified> -where - C: CosmosSdkChainSealed, - - Identified>: IsAggregateData, - - Identified>: UseAggregate, - AnyChainIdentified: From>>, -{ - fn do_aggregate( - Identified { chain_id, t: data }: Self, - aggregate_data: VecDeque>, - ) -> Op { - match data { - CosmosSdkAggregate::AggregateEventWithClientType(data) => { - do_aggregate(id(chain_id, data), aggregate_data) - } - } - } -} - -fn tendermint_hash_to_h256(hash: tendermint::Hash) -> H256 { - match hash { - tendermint::Hash::Sha256(hash) => hash.into(), - tendermint::Hash::None => panic!("empty hash???"), - } -} diff --git a/lib/block-message/src/chain/ethereum.rs b/lib/block-message/src/chain/ethereum.rs deleted file mode 100644 index 9e0ce61980..0000000000 --- a/lib/block-message/src/chain/ethereum.rs +++ /dev/null @@ -1,899 +0,0 @@ -use std::{collections::VecDeque, marker::PhantomData}; - -use beacon_api::client::BeaconApiClient; -use chain_utils::ethereum::{ - Ethereum, EthereumConsensusChain, EthereumIbcChain, IBCHandlerEvents, IbcHandlerExt, - ETHEREUM_REVISION_NUMBER, -}; -use contracts::{ - ibc_channel_handshake::IBCChannelHandshakeEvents, - ibc_client::{ClientCreatedFilter, ClientUpdatedFilter, IBCClientEvents}, - ibc_connection::IBCConnectionEvents, - ibc_packet::{ - AcknowledgePacketFilter, IBCPacketEvents, RecvPacketFilter, SendPacketFilter, - WriteAcknowledgementFilter, - }, -}; -use enumorph::Enumorph; -use ethers::{contract::EthLogDecode, providers::Middleware, types::Filter}; -use frunk::{hlist_pat, HList}; -use futures::{stream::FuturesUnordered, TryStreamExt}; -use queue_msg::{ - aggregate, - aggregation::{do_aggregate, UseAggregate}, - conc, data, fetch, noop, queue_msg, Op, -}; -use serde::{Deserialize, Serialize}; -use tracing::{debug, info, warn}; -use unionlabs::{ - ethereum::config::ChainSpec, - events::{ - AcknowledgePacket, ChannelOpenAck, ChannelOpenConfirm, ChannelOpenInit, ChannelOpenTry, - ConnectionOpenAck, ConnectionOpenConfirm, ConnectionOpenInit, ConnectionOpenTry, - CreateClient, IbcEvent, RecvPacket, SendPacket, UpdateClient, WriteAcknowledgement, - }, - hash::H256, - ibc::{ - core::{ - channel::channel::Channel, - client::height::{Height, IsHeight}, - connection::connection_end::ConnectionEnd, - }, - lightclients::cometbls, - }, - ics24::ChannelEndPath, - id::ClientIdValidator, - traits::{Chain, ChainIdOf, ClientIdOf, HeightOf}, - validated::ValidateT, -}; - -use crate::{ - aggregate::{Aggregate, AnyAggregate}, - data::{AnyData, ChainEvent, Data}, - fetch::{AnyFetch, DoFetch, DoFetchBlockRange, Fetch, FetchBlockRange}, - id, AnyChainIdentified, BlockMessage, ChainExt, DoAggregate, Identified, IsAggregateData, -}; - -pub trait EthereumChainExt = - ChainExt + chain_utils::ethereum::EthereumIbcChainExt + chain_utils::ethereum::EthereumChain; - -impl ChainExt for Ethereum { - type Data = EthereumData; - type Fetch = EthereumFetch; - type Aggregate = EthereumAggregate; -} - -impl DoFetchBlockRange> for Ethereum -where - AnyChainIdentified: From, Fetch>>>, -{ - fn fetch_block_range(c: &Ethereum, range: FetchBlockRange>) -> Op { - fetch(id( - c.chain_id(), - Fetch::>::specific(FetchEvents { - from_height: range.from_height, - to_height: range.to_height, - }), - )) - } -} - -impl DoFetch> for EthereumFetch -where - AnyChainIdentified: From, Data>>>, - AnyChainIdentified: From, Aggregate>>>, - AnyChainIdentified: From, Fetch>>>, -{ - async fn do_fetch(c: &Ethereum, msg: Self) -> Op { - match msg { - Self::FetchEvents(FetchEvents { - from_height, - to_height, - }) => fetch(id( - c.chain_id(), - Fetch::>::specific(FetchBeaconBlockRange { - from_slot: from_height.revision_height, - to_slot: to_height.revision_height, - }), - )), - Self::FetchGetLogs(get_logs) => { - fetch_get_logs(c, get_logs, ETHEREUM_REVISION_NUMBER).await - } - Self::FetchBeaconBlockRange(beacon_block_range) => { - fetch_beacon_block_range(c, beacon_block_range, &c.beacon_api_client).await - } - Self::FetchChannel(FetchChannel { height, path }) => { - fetch_channel( - c, - path, - c.execution_height_of_beacon_slot(height.revision_height()) - .await, - ) - .await - } - } - } -} - -pub(crate) async fn fetch_get_logs( - c: &Hc, - FetchGetLogs { from_slot, to_slot }: FetchGetLogs, - revision_number: u64, -) -> Op -where - Hc: EthereumConsensusChain - + EthereumChainExt< - Height = Height, - Aggregate: From>, - Fetch: From>, - >, - - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, -{ - debug!(%from_slot, %to_slot, "fetching logs in beacon block range"); - - let event_height = Height { - revision_number, - revision_height: to_slot, - }; - - let from_block = c.execution_height_of_beacon_slot(from_slot).await; - let to_block = c.execution_height_of_beacon_slot(to_slot).await; - - if from_block == to_block { - info!(%from_block, %to_block, %from_slot, %to_slot, "beacon block range is empty"); - noop() - } else { - const ETH_GET_LOGS_BATCH_SIZE: u64 = 100; - - info!(%from_block, %to_block, "fetching block range"); - - let mut from_block = from_block; - - let mut msgs = vec![]; - let join_set = FuturesUnordered::new(); - - for (from_block, to_block) in std::iter::from_fn(move || { - if from_block < to_block { - // NOTE: These -1s are very important, else events will be double fetched - if to_block - from_block < ETH_GET_LOGS_BATCH_SIZE { - Some((from_block, { - from_block = to_block; - from_block - 1 - })) - } else { - Some((from_block, { - from_block += ETH_GET_LOGS_BATCH_SIZE; - from_block - 1 - })) - } - } else { - None - } - }) { - info!(%from_block, %to_block, %from_slot, %to_slot, "fetching logs in range"); - - let provider = c.provider(); - let ibc_handler_address = c.ibc_handler_address(); - - join_set.push(async move { - provider - .get_logs( - &Filter::new() - .address(ethers::types::H160::from(ibc_handler_address)) - .from_block(from_block) - .to_block(to_block), - ) - .await - }); - } - - for logs in join_set - .try_collect::>() - .await - .expect("unable to fetch logs") - { - for log in logs { - let tx_hash = log - .transaction_hash - .expect("log should have transaction_hash") - .into(); - - debug!(?log, "raw log"); - - match IBCHandlerEvents::decode_log(&log.into()) { - Ok(event) => { - debug!(?event, "found IBCHandler event"); - msgs.push( - mk_aggregate_event(c, event, event_height, tx_hash, |event_height| { - c.execution_height_of_beacon_slot(event_height.revision_height()) - }) - .await, - ) - } - Err(e) => { - warn!("could not decode evm event {}", e); - } - } - } - } - - info!( - %from_block, - %to_block, - - %from_slot, - %to_slot, - - slot_range_len = %(to_slot - from_slot), - block_range_len = %(to_block - from_block), - - total = %msgs.len(), - - "fetched logs in block range" - ); - - conc(msgs) - } -} - -pub(crate) async fn fetch_beacon_block_range( - c: &Hc, - FetchBeaconBlockRange { from_slot, to_slot }: FetchBeaconBlockRange, - beacon_api_client: &BeaconApiClient, -) -> Op -where - C: ChainSpec, - Hc: ChainExt + From> + EthereumIbcChain, - - AnyChainIdentified: From>>, -{ - debug!(%from_slot, %to_slot, "fetching beacon block range"); - - assert!(from_slot < to_slot); - - if to_slot - from_slot == 1 { - fetch(id( - c.chain_id(), - Fetch::::specific(FetchGetLogs { from_slot, to_slot }), - )) - } else { - // attempt to shrink from..to - // note that this is *exclusive* on `to` - for slot in (from_slot + 1)..to_slot { - info!(%slot, "querying slot"); - - match beacon_api_client - .block(beacon_api::client::BlockId::Slot(slot)) - .await - { - Err(beacon_api::errors::Error::NotFound(beacon_api::errors::NotFoundError { - message, - error, - status_code, - })) => { - info!(%slot, %message, %error, %status_code, "beacon block not found for slot"); - continue; - } - Err(err) => { - panic!("error fetching beacon block for slot {slot}: {err}") - } - Ok(_) => { - return conc([ - fetch(id( - c.chain_id(), - Fetch::::specific(FetchGetLogs { - from_slot, - to_slot: slot, - }), - )), - fetch(id( - c.chain_id(), - Fetch::::specific(FetchBeaconBlockRange { - from_slot: slot, - to_slot, - }), - )), - ]); - } - } - } - - // if the range is not shrinkable (i.e. all blocks between `from` and `to` are missing, but `from` and `to` both exist), fetch logs between `from` and `to` - fetch(id( - c.chain_id(), - Fetch::::specific(FetchGetLogs { from_slot, to_slot }), - )) - } -} - -pub(crate) async fn fetch_channel( - c: &Hc, - path: ChannelEndPath, - execution_height: u64, -) -> Op -where - Hc: EthereumChainExt>>, - - AnyChainIdentified: From>>, -{ - debug!(%execution_height, %path, "fetching channel"); - - data(id( - c.chain_id(), - Data::::specific(ChannelData { - channel: c - .ibc_handler() - .get_channel(path.port_id.to_string(), path.channel_id.to_string()) - .block(execution_height) - .await - .unwrap() - .try_into() - .unwrap(), - __marker: PhantomData, - }), - )) -} - -pub async fn mk_aggregate_event( - c: &Hc, - event: IBCHandlerEvents, - event_height: Hc::Height, - tx_hash: H256, - // normalize the height from the "public facing" height to the execution height of this chain. - normalize_height: F, -) -> Op -where - Hc: EthereumChainExt>, Fetch: From>>, - - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, - - F: FnOnce(Hc::Height) -> Fut, - Fut: futures::Future, -{ - match event { - IBCHandlerEvents::PacketEvent(IBCPacketEvents::AcknowledgePacketFilter(raw_event)) => { - with_channel::( - c.chain_id(), - raw_event.packet.source_port.clone(), - raw_event.packet.source_channel.clone(), - event_height, - tx_hash, - raw_event, - ) - } - IBCHandlerEvents::ChannelEvent(IBCChannelHandshakeEvents::ChannelCloseConfirmFilter(_)) - | IBCHandlerEvents::ChannelEvent(IBCChannelHandshakeEvents::ChannelCloseInitFilter(_)) => { - todo!() - } - IBCHandlerEvents::ChannelEvent(IBCChannelHandshakeEvents::ChannelOpenAckFilter( - raw_event, - )) => data(id( - c.chain_id(), - ChainEvent { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height: event_height, - event: IbcEvent::ChannelOpenAck(ChannelOpenAck { - port_id: raw_event.port_id.parse().unwrap(), - channel_id: raw_event.channel_id.parse().unwrap(), - counterparty_port_id: raw_event.counterparty_port_id.parse().unwrap(), - counterparty_channel_id: raw_event.counterparty_channel_id.parse().unwrap(), - connection_id: raw_event.connection_id.parse().unwrap(), - }), - }, - )), - IBCHandlerEvents::ChannelEvent(IBCChannelHandshakeEvents::ChannelOpenConfirmFilter( - raw_event, - )) => data(id( - c.chain_id(), - ChainEvent { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height: event_height, - event: IbcEvent::ChannelOpenConfirm(ChannelOpenConfirm { - port_id: raw_event.port_id.parse().unwrap(), - channel_id: raw_event.channel_id.parse().unwrap(), - counterparty_port_id: raw_event.counterparty_port_id.parse().unwrap(), - counterparty_channel_id: raw_event.counterparty_channel_id.parse().unwrap(), - connection_id: raw_event.connection_id.parse().unwrap(), - }), - }, - )), - IBCHandlerEvents::ChannelEvent(IBCChannelHandshakeEvents::ChannelOpenInitFilter( - raw_event, - )) => data(id( - c.chain_id(), - ChainEvent { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height: event_height, - event: IbcEvent::ChannelOpenInit(ChannelOpenInit { - port_id: raw_event.port_id.parse().unwrap(), - channel_id: raw_event.channel_id.parse().unwrap(), - counterparty_port_id: raw_event.counterparty_port_id.parse().unwrap(), - connection_id: raw_event.connection_id.parse().unwrap(), - version: raw_event.version, - }), - }, - )), - IBCHandlerEvents::ChannelEvent(IBCChannelHandshakeEvents::ChannelOpenTryFilter( - raw_event, - )) => data(id( - c.chain_id(), - ChainEvent { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height: event_height, - event: IbcEvent::ChannelOpenTry(ChannelOpenTry { - port_id: raw_event.port_id.parse().unwrap(), - channel_id: raw_event.channel_id.parse().unwrap(), - counterparty_port_id: raw_event.counterparty_port_id.parse().unwrap(), - counterparty_channel_id: raw_event.counterparty_channel_id.parse().unwrap(), - connection_id: raw_event.connection_id.parse().unwrap(), - version: raw_event.version, - }), - }, - )), - IBCHandlerEvents::ConnectionEvent(IBCConnectionEvents::ConnectionOpenAckFilter( - raw_event, - )) => data(id( - c.chain_id(), - ChainEvent { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height: event_height, - event: IbcEvent::ConnectionOpenAck(ConnectionOpenAck { - connection_id: raw_event.connection_id.parse().unwrap(), - client_id: raw_event.client_id.parse().unwrap(), - counterparty_client_id: raw_event.counterparty_client_id.parse().unwrap(), - counterparty_connection_id: raw_event - .counterparty_connection_id - .parse() - .unwrap(), - }), - }, - )), - IBCHandlerEvents::ConnectionEvent(IBCConnectionEvents::ConnectionOpenConfirmFilter( - raw_event, - )) => data(id( - c.chain_id(), - ChainEvent { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height: event_height, - event: IbcEvent::ConnectionOpenConfirm(ConnectionOpenConfirm { - connection_id: raw_event.connection_id.parse().unwrap(), - client_id: raw_event.client_id.parse().unwrap(), - counterparty_client_id: raw_event.counterparty_client_id.parse().unwrap(), - counterparty_connection_id: raw_event - .counterparty_connection_id - .parse() - .unwrap(), - }), - }, - )), - IBCHandlerEvents::ConnectionEvent(IBCConnectionEvents::ConnectionOpenInitFilter( - raw_event, - )) => data(id( - c.chain_id(), - ChainEvent { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height: event_height, - event: IbcEvent::ConnectionOpenInit(ConnectionOpenInit { - connection_id: raw_event.connection_id.parse().unwrap(), - client_id: raw_event.client_id.parse().unwrap(), - counterparty_client_id: raw_event.counterparty_client_id.parse().unwrap(), - }), - }, - )), - IBCHandlerEvents::ConnectionEvent(IBCConnectionEvents::ConnectionOpenTryFilter( - raw_event, - )) => data(id( - c.chain_id(), - ChainEvent { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height: event_height, - event: IbcEvent::ConnectionOpenTry(ConnectionOpenTry { - connection_id: raw_event.connection_id.parse().unwrap(), - client_id: raw_event.client_id.parse().unwrap(), - counterparty_client_id: raw_event.counterparty_client_id.parse().unwrap(), - counterparty_connection_id: raw_event - .counterparty_connection_id - .parse() - .unwrap(), - }), - }, - )), - IBCHandlerEvents::ClientEvent(IBCClientEvents::ClientCreatedFilter( - ClientCreatedFilter { client_id }, - )) => { - let client_type = c - .ibc_handler() - .client_types(client_id.clone()) - .await - .unwrap(); - - let client_state = c - .ibc_handler() - .get_client_state::( - client_id - .clone() - .validate::() - .unwrap() - .try_into() - .unwrap(), - normalize_height(event_height).await, - ) - .await; - - data(id( - c.chain_id(), - ChainEvent:: { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height: event_height, - event: IbcEvent::CreateClient(CreateClient { - client_id: client_id.parse().unwrap(), - client_type, - consensus_height: client_state.latest_height, - }), - }, - )) - } - IBCHandlerEvents::ClientEvent(IBCClientEvents::ClientRegisteredFilter(_)) => noop(), - IBCHandlerEvents::ClientEvent(IBCClientEvents::ClientUpdatedFilter( - ClientUpdatedFilter { - client_id, - height: consensus_height, - }, - )) => { - let client_type = c - .ibc_handler() - .client_types(client_id.clone()) - .await - .unwrap(); - - data(id( - c.chain_id(), - ChainEvent:: { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height: event_height, - event: IbcEvent::UpdateClient(UpdateClient { - client_id: client_id.parse().unwrap(), - client_type, - consensus_heights: vec![consensus_height.into()], - }), - }, - )) - } - IBCHandlerEvents::PacketEvent(IBCPacketEvents::RecvPacketFilter(raw_event)) => { - with_channel( - c.chain_id(), - raw_event.packet.destination_port.clone(), - raw_event.packet.destination_channel.clone(), - event_height, - tx_hash, - raw_event, - ) - } - IBCHandlerEvents::PacketEvent(IBCPacketEvents::SendPacketFilter(raw_event)) => { - with_channel( - c.chain_id(), - raw_event.source_port.clone(), - raw_event.source_channel.clone(), - event_height, - tx_hash, - raw_event, - ) - } - IBCHandlerEvents::PacketEvent(IBCPacketEvents::WriteAcknowledgementFilter(raw_event)) => { - with_channel( - c.chain_id(), - raw_event.packet.destination_port.clone(), - raw_event.packet.destination_channel.clone(), - event_height, - tx_hash, - raw_event, - ) - } - IBCHandlerEvents::PacketEvent(IBCPacketEvents::TimeoutPacketFilter(_)) => noop(), - IBCHandlerEvents::OwnableEvent(_) => noop(), - } -} - -pub fn with_channel( - chain_id: ChainIdOf, - port_id: String, - channel_id: String, - event_height: HeightOf, - tx_hash: H256, - raw_event: T, -) -> Op -where - Hc: ChainExt>, Fetch: From>> - + EthereumIbcChain, - - AggregateWithChannel: From>, - - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, -{ - aggregate( - [fetch(id( - chain_id.clone(), - Fetch::::specific(FetchChannel { - height: event_height, - path: ChannelEndPath { - port_id: port_id.parse().unwrap(), - channel_id: channel_id.parse().unwrap(), - }, - }), - ))], - [], - id( - chain_id, - Aggregate::::specific(AggregateWithChannel::from(EventInfo { - height: event_height, - tx_hash, - raw_event, - })), - ), - ) -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum EthereumFetch { - FetchEvents(FetchEvents>), - FetchGetLogs(FetchGetLogs), - FetchBeaconBlockRange(FetchBeaconBlockRange), - - FetchChannel(FetchChannel>), -} - -#[queue_msg] -pub struct FetchEvents { - pub from_height: HeightOf, - pub to_height: HeightOf, -} - -#[queue_msg] -pub struct FetchGetLogs { - pub from_slot: u64, - pub to_slot: u64, -} - -#[queue_msg] -/// NOTE: This isn't just fetching one block because sometimes beacon slots are missed. We need to be able to fetch a range of slots to account for this. -/// The range is `[from_slot..to_slot)`, so to fetch a single block `N`, the range would be `N..N+1`. -pub struct FetchBeaconBlockRange { - pub from_slot: u64, - pub to_slot: u64, -} - -#[queue_msg] -// TODO: Move to Data? -pub struct FetchChannel { - pub height: Hc::Height, - pub path: ChannelEndPath, -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum EthereumAggregate { - AggregateWithChannel(AggregateWithChannel>), -} - -impl DoAggregate for Identified, EthereumAggregate> -where - AnyChainIdentified: From, ChainEvent>>>, - - Identified, ChannelData>>: IsAggregateData, - Identified, ConnectionData>>: IsAggregateData, -{ - fn do_aggregate( - Identified { chain_id, t }: Self, - data: VecDeque>, - ) -> Op { - match t { - EthereumAggregate::AggregateWithChannel(msg) => { - do_aggregate(id::, _>(chain_id, msg), data) - } - } - } -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum AggregateWithChannel { - PacketAcknowledgement(EventInfo), - WriteAcknowledgement(EventInfo), - SendPacket(EventInfo), - RecvPacket(EventInfo), -} - -#[derive(macros::Debug, Serialize, Deserialize)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[serde( - rename_all = "snake_case", - deny_unknown_fields, - bound( - serialize = "T: Serialize", - deserialize = "T: serde::de::DeserializeOwned" - ) -)] -// REVIEW: Use something like derivative/ derive_where/ educe -pub struct EventInfo { - height: Hc::Height, - tx_hash: H256, - raw_event: T, -} - -impl PartialEq for EventInfo { - fn eq(&self, other: &Self) -> bool { - self.height == other.height - && self.tx_hash == other.tx_hash - && self.raw_event == other.raw_event - } -} - -impl Clone for EventInfo { - fn clone(&self) -> Self { - Self { - height: self.height, - tx_hash: self.tx_hash, - raw_event: self.raw_event.clone(), - } - } -} - -// NOTE: Currently, we assume that EthereumChains will only connect to Union, and as such hardcode the client_type to be Cometbls. This avoids an extra fetch and aggregation to figure out the client type. -impl UseAggregate - for Identified> -where - Identified>: IsAggregateData, - - AnyChainIdentified: From>>, -{ - type AggregatedData = HList![Identified>]; - - fn aggregate( - Identified { t: msg, chain_id }: Self, - hlist_pat![Identified { - chain_id: channel_data_chain_id, - t: ChannelData { - channel, - __marker: _ - } - }]: Self::AggregatedData, - ) -> Op { - assert_eq!(chain_id, channel_data_chain_id); - - let event = match msg { - AggregateWithChannel::PacketAcknowledgement(EventInfo { - height, - tx_hash, - raw_event, - }) => ChainEvent { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height, - event: IbcEvent::AcknowledgePacket(AcknowledgePacket { - packet_timeout_height: raw_event.packet.timeout_height.into(), - packet_timeout_timestamp: raw_event.packet.timeout_timestamp, - packet_sequence: raw_event.packet.sequence.try_into().unwrap(), - packet_src_port: raw_event.packet.source_port.parse().unwrap(), - packet_src_channel: raw_event.packet.source_channel.parse().unwrap(), - packet_dst_port: raw_event.packet.destination_port.parse().unwrap(), - packet_dst_channel: raw_event.packet.destination_channel.parse().unwrap(), - packet_channel_ordering: channel.ordering, - connection_id: channel.connection_hops[0].clone(), - }), - }, - AggregateWithChannel::SendPacket(EventInfo { - height, - tx_hash, - raw_event, - }) => { - ChainEvent { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height, - event: IbcEvent::SendPacket(SendPacket { - packet_data_hex: raw_event.data.to_vec(), - packet_timeout_height: raw_event.timeout_height.into(), - packet_timeout_timestamp: raw_event.timeout_timestamp, - packet_sequence: raw_event.sequence.try_into().unwrap(), - packet_src_port: raw_event.source_port.parse().unwrap(), - packet_src_channel: raw_event.source_channel.parse().unwrap(), - // REVIEW: Should we query the packet instead? Or is that the same info? Is it even possible to - // query packets from the evm? - packet_dst_port: channel.counterparty.port_id, - packet_dst_channel: channel.counterparty.channel_id.parse().unwrap(), - packet_channel_ordering: channel.ordering, - connection_id: channel.connection_hops[0].clone(), - }), - } - } - AggregateWithChannel::RecvPacket(EventInfo { - height, - tx_hash, - raw_event, - }) => ChainEvent { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height, - event: IbcEvent::RecvPacket(RecvPacket { - packet_data_hex: raw_event.packet.data.to_vec(), - packet_timeout_height: raw_event.packet.timeout_height.into(), - packet_timeout_timestamp: raw_event.packet.timeout_timestamp, - packet_sequence: raw_event.packet.sequence.try_into().unwrap(), - packet_src_port: raw_event.packet.source_port.parse().unwrap(), - packet_src_channel: raw_event.packet.source_channel.parse().unwrap(), - packet_dst_port: raw_event.packet.destination_port.parse().unwrap(), - packet_dst_channel: raw_event.packet.destination_channel.parse().unwrap(), - packet_channel_ordering: channel.ordering, - connection_id: channel.connection_hops[0].clone(), - }), - }, - AggregateWithChannel::WriteAcknowledgement(EventInfo { - height, - tx_hash, - raw_event, - }) => ChainEvent { - client_type: unionlabs::ClientType::Cometbls, - tx_hash, - height, - event: IbcEvent::WriteAcknowledgement(WriteAcknowledgement { - packet_data_hex: raw_event.packet.data.to_vec(), - packet_timeout_height: raw_event.packet.timeout_height.into(), - packet_timeout_timestamp: raw_event.packet.timeout_timestamp, - packet_sequence: raw_event.packet.sequence.try_into().unwrap(), - packet_src_port: raw_event.packet.source_port.parse().unwrap(), - packet_src_channel: raw_event.packet.source_channel.parse().unwrap(), - packet_dst_port: raw_event.packet.destination_port.parse().unwrap(), - packet_dst_channel: raw_event.packet.destination_channel.parse().unwrap(), - packet_ack_hex: raw_event.acknowledgement.to_vec(), - connection_id: channel.connection_hops[0].clone(), - }), - }, - }; - - data(id::(chain_id, event)) - } -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum EthereumData { - Channel(ChannelData>), - Connection(ConnectionData>), -} - -const _: () = { - try_from_block_poll_msg! { - chain = Ethereum, - generics = (C: ChainSpec), - msgs = EthereumData( - Channel(ChannelData>), - Connection(ConnectionData>), - ), - } -}; - -#[queue_msg] -pub struct ChannelData<#[cover] Hc: ChainExt> { - pub channel: Channel, -} - -#[queue_msg] -// REVIEW: Use something other than string here? -pub struct ConnectionData(pub ConnectionEnd, String, String>); diff --git a/lib/block-message/src/chain/scroll.rs b/lib/block-message/src/chain/scroll.rs deleted file mode 100644 index e1b0928270..0000000000 --- a/lib/block-message/src/chain/scroll.rs +++ /dev/null @@ -1,135 +0,0 @@ -use std::collections::VecDeque; - -use chain_utils::{ - ethereum::EthereumConsensusChain, - scroll::{Scroll, SCROLL_REVISION_NUMBER}, -}; -use enumorph::Enumorph; -use queue_msg::{aggregation::do_aggregate, fetch, queue_msg, Op}; -use unionlabs::{ibc::core::client::height::IsHeight, traits::Chain}; - -use crate::{ - aggregate::{Aggregate, AnyAggregate}, - chain::ethereum::{ - fetch_beacon_block_range, fetch_channel, fetch_get_logs, AggregateWithChannel, ChannelData, - ConnectionData, FetchBeaconBlockRange, FetchChannel, FetchEvents, FetchGetLogs, - }, - data::{AnyData, ChainEvent, Data}, - fetch::{AnyFetch, DoFetch, DoFetchBlockRange, Fetch, FetchBlockRange}, - id, AnyChainIdentified, BlockMessage, ChainExt, DoAggregate, Identified, IsAggregateData, -}; - -impl ChainExt for Scroll { - type Data = ScrollData; - type Fetch = ScrollFetch; - type Aggregate = ScrollAggregate; -} - -impl DoFetchBlockRange for Scroll -where - AnyChainIdentified: From>>, -{ - fn fetch_block_range(c: &Scroll, range: FetchBlockRange) -> Op { - fetch(id( - c.chain_id(), - Fetch::::specific(FetchEvents { - from_height: range.from_height, - to_height: range.to_height, - }), - )) - } -} - -impl DoFetch for ScrollFetch -where - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, -{ - async fn do_fetch(c: &Scroll, msg: Self) -> Op { - match msg { - ScrollFetch::FetchEvents(FetchEvents { - from_height, - to_height, - }) => fetch(id( - c.chain_id(), - Fetch::::specific(FetchBeaconBlockRange { - from_slot: from_height.revision_height, - to_slot: to_height.revision_height, - }), - )), - ScrollFetch::FetchGetLogs(get_logs) => { - fetch_get_logs(c, get_logs, SCROLL_REVISION_NUMBER).await - } - ScrollFetch::FetchBeaconBlockRange(beacon_block_range) => { - fetch_beacon_block_range(c, beacon_block_range, &c.l1.beacon_api_client).await - } - ScrollFetch::FetchChannel(FetchChannel { height, path }) => { - fetch_channel( - c, - path, - c.execution_height_of_beacon_slot(height.revision_height()) - .await, - ) - .await - } - } - } -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum ScrollFetch { - FetchEvents(FetchEvents), - FetchGetLogs(FetchGetLogs), - FetchBeaconBlockRange(FetchBeaconBlockRange), - - FetchChannel(FetchChannel), -} - -#[queue_msg] -pub struct FetchBatchIndex { - beacon_slot: u64, - batch_index: u64, -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum ScrollAggregate { - AggregateWithChannel(AggregateWithChannel), -} - -impl DoAggregate for Identified -where - AnyChainIdentified: From>>, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, -{ - fn do_aggregate( - Identified { chain_id, t }: Self, - data: VecDeque>, - ) -> Op { - match t { - ScrollAggregate::AggregateWithChannel(msg) => do_aggregate(id(chain_id, msg), data), - } - } -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum ScrollData { - Channel(ChannelData), - Connection(ConnectionData), -} - -const _: () = { - try_from_block_poll_msg! { - chain = Scroll, - generics = (), - msgs = ScrollData( - Channel(ChannelData), - Connection(ConnectionData), - ), - } -}; diff --git a/lib/block-message/src/chain/union.rs b/lib/block-message/src/chain/union.rs deleted file mode 100644 index 6ca823d40c..0000000000 --- a/lib/block-message/src/chain/union.rs +++ /dev/null @@ -1,5 +0,0 @@ -use chain_utils::union::Union; - -use crate::chain::cosmos_sdk::CosmosSdkChainSealed; - -impl CosmosSdkChainSealed for Union {} diff --git a/lib/block-message/src/data.rs b/lib/block-message/src/data.rs deleted file mode 100644 index ea62485fda..0000000000 --- a/lib/block-message/src/data.rs +++ /dev/null @@ -1,43 +0,0 @@ -use macros::apply; -use queue_msg::{data, queue_msg, HandleData, Op, QueueError, QueueMessage}; -use tracing::instrument; -use unionlabs::{events::IbcEvent, hash::H256, ClientType}; - -use crate::{any_enum, AnyChainIdentified, BlockMessage, ChainExt}; - -#[apply(any_enum)] -#[any = AnyData] -#[specific = ChainSpecificData] -pub enum Data { - IbcEvent(ChainEvent), - LatestHeight(LatestHeight), - - #[serde(untagged)] - ChainSpecific(ChainSpecificData), -} - -// Passthrough since we don't want to handle any top-level data, just bubble it up to the top level. -impl HandleData for AnyChainIdentified { - #[instrument(skip_all, fields(chain_id = %self.chain_id()))] - fn handle( - self, - _store: &::Store, - ) -> Result, QueueError> { - Ok(data(self)) - } -} - -#[queue_msg] -pub struct ChainSpecificData(pub C::Data); - -#[queue_msg] -pub struct ChainEvent { - pub client_type: ClientType, - pub tx_hash: H256, - // the 'provable height' of the event - pub height: C::Height, - pub event: IbcEvent, -} - -#[queue_msg] -pub struct LatestHeight(pub C::Height); diff --git a/lib/block-message/src/fetch.rs b/lib/block-message/src/fetch.rs deleted file mode 100644 index 94f2a37325..0000000000 --- a/lib/block-message/src/fetch.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::fmt::Debug; - -use chain_utils::GetChain; -use futures::Future; -use macros::apply; -use queue_msg::{ - aggregate, conc, fetch, queue_msg, wait, HandleFetch, Op, QueueError, QueueMessage, -}; -use tracing::instrument; -use unionlabs::ibc::core::client::height::IsHeight; - -use crate::{ - aggregate::{Aggregate, AggregateFetchBlockRange, AnyAggregate}, - any_chain, any_enum, - wait::{AnyWait, Wait, WaitForHeight}, - AnyChainIdentified, BlockMessage, ChainExt, Identified, -}; - -#[apply(any_enum)] -#[any = AnyFetch] -#[specific = ChainSpecificFetch] -pub enum Fetch { - FetchBlock(FetchBlock), - FetchBlockRange(FetchBlockRange), - - #[serde(untagged)] - ChainSpecific(ChainSpecificFetch), -} - -fn assert_send(t: T) -> T { - t -} - -impl HandleFetch for AnyChainIdentified { - #[instrument(skip_all, fields(chain_id = %self.chain_id()))] - async fn handle( - self, - store: &::Store, - ) -> Result, QueueError> { - let fetch = self; - - assert_send(any_chain! { - |fetch| { - Ok(store - .with_chain(&fetch.chain_id, move |c| fetch.t.handle(c)) - .map_err(|e| QueueError::Fatal(Box::new(e)))? - .await) - } - }) - } -} - -impl Fetch -where - C: ChainExt + DoFetchBlockRange, - C::Fetch: DoFetch, - // AnyChainIdentified: From)>, - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, -{ - pub async fn handle(self, c: C) -> Op { - match self { - Fetch::FetchBlock(FetchBlock { height }) => aggregate( - [wait(Identified::::new( - c.chain_id(), - WaitForHeight { - height: height.increment(), - }, - ))], - [], - Identified::::new( - c.chain_id(), - AggregateFetchBlockRange { - from_height: height, - }, - ), - ), - Fetch::FetchBlockRange(range) => conc([ - C::fetch_block_range(&c, range.clone()), - fetch(Identified::::new( - c.chain_id(), - FetchBlock { - height: range.to_height, - }, - )), - ]), - Fetch::ChainSpecific(cs) => C::Fetch::do_fetch(&c, cs.0).await, - } - } -} - -pub trait DoFetch: Sized + Debug + Clone + PartialEq { - fn do_fetch(c: &C, _: Self) -> impl Future>; -} - -pub trait DoFetchBlockRange: ChainExt { - fn fetch_block_range(c: &C, range: FetchBlockRange) -> Op; -} - -#[queue_msg] -pub struct FetchBlockRange { - pub from_height: C::Height, - pub to_height: C::Height, -} - -#[queue_msg] -pub struct FetchBlock { - pub height: C::Height, -} - -#[queue_msg] -pub struct ChainSpecificFetch(pub C::Fetch); diff --git a/lib/block-message/src/lib.rs b/lib/block-message/src/lib.rs deleted file mode 100644 index 315f0c32a4..0000000000 --- a/lib/block-message/src/lib.rs +++ /dev/null @@ -1,236 +0,0 @@ -#![feature(trait_alias)] - -use std::{collections::VecDeque, fmt::Debug}; - -use chain_utils::{ - arbitrum::Arbitrum, berachain::Berachain, cosmos::Cosmos, ethereum::Ethereum, scroll::Scroll, - union::Union, Chains, -}; -use frame_support_procedural::{CloneNoBound, DebugNoBound, PartialEqNoBound}; -use queue_msg::{Op, OpT, QueueMessage}; -use serde::{Deserialize, Serialize}; -use unionlabs::{ - ethereum::config::{Mainnet, Minimal}, - never::Never, - traits::{Chain, ChainIdOf}, - MaybeArbitrary, -}; - -use crate::{aggregate::AnyAggregate, data::AnyData, fetch::AnyFetch, wait::AnyWait}; - -pub mod aggregate; -pub mod data; -pub mod fetch; -pub mod wait; - -pub mod chain; - -pub trait ChainExt: Chain { - type Data: OpT; - type Fetch: OpT; - type Aggregate: OpT; -} - -pub enum BlockMessage {} - -impl QueueMessage for BlockMessage { - type Event = Never; - type Data = AnyChainIdentified; - type Fetch = AnyChainIdentified; - type Effect = Never; - type Wait = AnyChainIdentified; - type Aggregate = AnyChainIdentified; - - type Store = Chains; -} - -#[derive( - DebugNoBound, CloneNoBound, PartialEqNoBound, Serialize, Deserialize, enumorph::Enumorph, -)] -#[cfg_attr( - feature = "arbitrary", - derive(arbitrary::Arbitrary), - arbitrary(bound = "T: AnyChain") -)] -#[serde( - tag = "@type", - content = "@value", - rename_all = "kebab-case", - bound(serialize = "", deserialize = "") -)] -pub enum AnyChainIdentified { - Union(Identified>), - Cosmos(Identified>), - EthMainnet(Identified, InnerOf>>), - EthMinimal(Identified, InnerOf>>), - Scroll(Identified>), - Arbitrum(Identified>), - Berachain(Identified>), -} - -impl AnyChainIdentified { - fn chain_id(&self) -> String { - let i = self; - - any_chain! { - |i| i.chain_id.to_string() - } - } -} - -pub trait AnyChain { - type Inner: Debug - + Clone - + PartialEq - + Serialize - + for<'de> Deserialize<'de> - + MaybeArbitrary; -} - -pub type InnerOf = ::Inner; - -#[derive(DebugNoBound, PartialEqNoBound, CloneNoBound, Serialize, Deserialize)] -#[serde( - bound( - serialize = "T: ::serde::Serialize", - deserialize = "T: for<'d> Deserialize<'d>" - ), - deny_unknown_fields -)] -#[cfg_attr( - feature = "arbitrary", - derive(arbitrary::Arbitrary), - arbitrary(bound = "") -)] -pub struct Identified { - pub chain_id: ChainIdOf, - pub t: T, -} - -impl Identified { - pub fn new(chain_id: ChainIdOf, t: T) -> Self { - Self { chain_id, t } - } -} - -pub fn id( - chain_id: ChainIdOf, - t: T, -) -> Identified { - Identified::new(chain_id, t) -} - -macro_rules! any_enum { - ( - $(#[doc = $outer_doc:literal])* - #[any = $Any:ident] - $(#[specific = $Specific:ident])? - pub enum $Enum:ident { - $( - $(#[doc = $doc:literal])* - $(#[serde($untagged:ident)])* - $Variant:ident( - $(#[$variant_inner_meta:meta])* - $VariantInner:ty - ), - )* - } - ) => { - #[::queue_msg::queue_msg] - #[derive(::enumorph::Enumorph)] - $(#[doc = $outer_doc])* - pub enum $Enum { - $( - $(#[doc = $doc])* - $(#[serde($untagged)])* - $Variant( - $(#[$variant_inner_meta])* - $VariantInner - ), - )* - } - - pub enum $Any {} - impl crate::AnyChain for $Any { - type Inner = $Enum; - } - - const _: () = { - use crate::{AnyChainIdentified, Identified}; - - $( - impl From> - for AnyChainIdentified<$Any> - where - $VariantInner: Into<$Enum>, - AnyChainIdentified<$Any>: From>>, - { - fn from( - Identified { - chain_id, - t, - }: Identified, - ) -> Self { - Self::from(Identified::new( - chain_id, - <$Enum>::from(t), - )) - } - } - - impl TryFrom> for Identified - where - Identified>: TryFrom, Error = AnyChainIdentified<$Any>> - + Into>, - { - type Error = AnyChainIdentified<$Any>; - - fn try_from(value: AnyChainIdentified<$Any>) -> Result { - let Identified { - chain_id, - t, - } = >>::try_from(value)?; - - Ok(Identified::new( - chain_id.clone(), - <$VariantInner>::try_from(t).map_err(|x: $Enum| { - Into::>::into(Identified::new(chain_id, x)) - })?, - )) - } - } - )* - }; - - $( - impl $Enum { - pub fn specific(t: impl Into) -> $Enum { - $Specific(t.into()).into() - } - } - )? - }; -} -pub(crate) use any_enum; - -pub trait IsAggregateData = TryFrom, Error = AnyChainIdentified> - + Into>; - -pub trait DoAggregate: Sized + Debug + Clone + PartialEq { - fn do_aggregate(_: Self, _: VecDeque>) -> Op; -} - -macro_rules! any_chain { - (|$msg:ident| $expr:expr) => { - match $msg { - AnyChainIdentified::EthMainnet($msg) => $expr, - AnyChainIdentified::EthMinimal($msg) => $expr, - AnyChainIdentified::Union($msg) => $expr, - AnyChainIdentified::Cosmos($msg) => $expr, - AnyChainIdentified::Scroll($msg) => $expr, - AnyChainIdentified::Arbitrum($msg) => $expr, - AnyChainIdentified::Berachain($msg) => $expr, - } - }; -} -pub(crate) use any_chain; diff --git a/lib/block-message/src/wait.rs b/lib/block-message/src/wait.rs deleted file mode 100644 index acbd6b89b6..0000000000 --- a/lib/block-message/src/wait.rs +++ /dev/null @@ -1,76 +0,0 @@ -use chain_utils::{Chains, GetChain}; -use macros::apply; -use queue_msg::{data, defer_absolute, now, queue_msg, seq, wait, HandleWait, Op, QueueError}; -use tracing::{debug, instrument}; -use unionlabs::{ibc::core::client::height::IsHeight, traits::HeightOf}; - -use crate::{ - any_chain, any_enum, - data::{AnyData, Data, LatestHeight}, - AnyChainIdentified, BlockMessage, ChainExt, Identified, -}; - -#[apply(any_enum)] -#[any = AnyWait] -pub enum Wait { - Height(WaitForHeight), -} - -impl Wait -where - AnyChainIdentified: From>>, - AnyChainIdentified: From>>, -{ - async fn handle(self, c: C) -> Op { - match self { - Wait::Height(WaitForHeight { height }) => { - let chain_height = c.query_latest_height().await.unwrap(); - - assert_eq!( - chain_height.revision_number(), - height.revision_number(), - "chain_height: {chain_height}, height: {height}", - ); - - debug!("latest height is {chain_height}, waiting for {height}"); - - if chain_height.revision_height() >= height.revision_height() { - data(Identified::::new( - c.chain_id(), - LatestHeight(chain_height), - )) - } else { - seq([ - // REVIEW: Defer until `now + chain.block_time()`? Would require a new method on chain - defer_absolute(now() + 1), - wait(Identified::::new( - c.chain_id(), - WaitForHeight { height }, - )), - ]) - } - } - } - } -} - -impl HandleWait for AnyChainIdentified { - #[instrument(skip_all, fields(chain_id = %self.chain_id()))] - async fn handle(self, store: &Chains) -> Result, QueueError> { - let wait = self; - - any_chain! { - |wait| { - Ok(store - .with_chain(&wait.chain_id, move |c| async move { wait.t.handle(c).await }) - .map_err(|e| QueueError::Fatal(Box::new(e)))? - .await) - } - } - } -} - -#[queue_msg] -pub struct WaitForHeight { - pub height: HeightOf, -} diff --git a/lib/chain-utils/Cargo.toml b/lib/chain-utils/Cargo.toml index 2c21718850..8aa64b0aff 100644 --- a/lib/chain-utils/Cargo.toml +++ b/lib/chain-utils/Cargo.toml @@ -14,7 +14,6 @@ protos = { workspace = true, features = ["default", "client"] } serde-utils = { workspace = true } unionlabs = { workspace = true, features = ["default"] } -arbitrary = { workspace = true, optional = true, features = ["derive"] } bip32 = { workspace = true, features = ["secp256k1"] } chrono = { workspace = true, features = ["alloc"] } cometbft-rpc = { workspace = true } @@ -44,7 +43,6 @@ tracing = { workspace = true } typenum = { workspace = true, features = ["const-generics", "no_std"] } [features] -arbitrary = ["dep:arbitrary"] [dev-dependencies] hex-literal = { workspace = true } diff --git a/lib/chain-utils/src/arbitrum.rs b/lib/chain-utils/src/arbitrum.rs index 9130175ad7..1ed158b07e 100644 --- a/lib/chain-utils/src/arbitrum.rs +++ b/lib/chain-utils/src/arbitrum.rs @@ -5,33 +5,31 @@ use ethers::{ contract::{EthAbiCodec, EthAbiType, EthDisplay, EthEvent}, providers::{Middleware, Provider, ProviderError, Ws, WsClientError}, }; -use futures::TryFutureExt; use serde::{Deserialize, Serialize}; use tracing::{debug, instrument}; use unionlabs::{ bounded::BoundedU32, - encoding::EthAbi, - ethereum::config::Mainnet, google::protobuf::any::Any, hash::{H160, H256}, ibc::{ core::client::height::Height, - lightclients::{arbitrum, ethereum::storage_proof::StorageProof}, + lightclients::{ + arbitrum, + ethereum::{self, storage_proof::StorageProof}, + }, }, - id::ClientId, - traits::{Chain, ChainIdOf, ClientIdOf, FromStrExact}, + traits::FromStrExact, uint::U256, + validated::ValidateT, }; use crate::{ ethereum::{ - self, balance_of_signers, get_proof, AnyEthereum, AnyEthereumError, Ethereum, - EthereumConsensusChain, EthereumIbcChain, EthereumKeyring, EthereumSignerMiddleware, - EthereumSignersConfig, ReadWrite, Readonly, + balance_of_signers, AnyEthereum, AnyEthereumError, EthereumConsensusChain, + EthereumIbcChain, EthereumKeyring, EthereumSignerMiddleware, EthereumSignersConfig, + ReadWrite, Readonly, }, keyring::{ChainKeyring, ConcurrentKeyring, KeyringConfig, SignerBalance}, - union::Union, - wasm::Wasm, }; pub const ARBITRUM_REVISION_NUMBER: u64 = 0; @@ -54,7 +52,7 @@ pub struct Arbitrum { pub l1_nodes_slot: U256, pub l1_nodes_confirm_data_offset: U256, - pub l1_client_id: ClientIdOf>, + pub l1_client_id: U256, /// GRPC url of Union, used to query the L1 state with [`Self::l1_client_id`]. pub union_grpc_url: String, } @@ -79,8 +77,8 @@ pub struct Config { pub l1_nodes_confirm_data_offset: U256, pub l1_next_node_num_slot_offset_bytes: BoundedU32<0, 24>, - pub l1_client_id: ClientIdOf>, - pub l1: ethereum::Config, + pub l1_client_id: U256, + pub l1: crate::ethereum::Config, pub union_grpc_url: String, } @@ -228,8 +226,9 @@ impl EthereumConsensusChain for Arbitrum { block.number.unwrap().0[0] } - async fn get_proof(&self, address: H160, location: U256, block: u64) -> StorageProof { - get_proof(self, address, location, block).await + async fn get_proof(&self, _address: H160, _location: U256, _block: u64) -> StorageProof { + todo!() + // get_proof(self, address, location, block).await } } @@ -308,33 +307,10 @@ impl FromStrExact for ArbitrumChainType { const EXPECTING: &'static str = "arbitrum"; } -impl Chain for Arbitrum { - type ChainType = ArbitrumChainType; - - type SelfClientState = arbitrum::client_state::ClientState; - type SelfConsensusState = arbitrum::consensus_state::ConsensusState; - type Header = arbitrum::header::Header; - - type StoredClientState = Tr::SelfClientState; - type StoredConsensusState = Tr::SelfConsensusState; - - type Height = Height; - - type ClientId = ClientId; - - type IbcStateEncoding = EthAbi; - - type StateProof = StorageProof; - - type ClientType = String; - - type Error = Box; - - fn chain_id(&self) -> ChainIdOf { - self.chain_id - } - - async fn query_latest_height(&self) -> Result { +impl Arbitrum { + pub async fn query_latest_height( + &self, + ) -> Result> { // the latest height of arbitrum is the latest height of the l1 light client on union let l1_client_state = protos::ibc::core::client::v1::query_client::QueryClient::connect( @@ -350,32 +326,37 @@ impl Chain for Arbitrum { .ok_or("client state missing???")?; // don't worry about it - let Any(l1_client_state) = - < as Chain>::StoredClientState>>::try_from( - l1_client_state, - ) - .unwrap(); - - Ok(match &self.l1 { - AnyEthereum::Mainnet(eth) => eth.make_height(l1_client_state.data.latest_slot), - AnyEthereum::Minimal(eth) => eth.make_height(l1_client_state.data.latest_slot), - }) - } + let Any(_l1_client_state) = , + >>::try_from(l1_client_state) + .unwrap(); + + // Ok(match &self.l1 { + // AnyEthereum::Mainnet(eth) => eth.make_height(l1_client_state.data.latest_slot), + // AnyEthereum::Minimal(eth) => eth.make_height(l1_client_state.data.latest_slot), + // }) - async fn query_latest_height_as_destination(&self) -> Result { todo!() } - async fn query_latest_timestamp(&self) -> Result { - match &self.l1 { - AnyEthereum::Mainnet(eth) => eth.query_latest_timestamp().map_err(Into::into).await, - AnyEthereum::Minimal(eth) => eth.query_latest_timestamp().map_err(Into::into).await, - } - } + // async fn query_latest_height_as_destination(&self) -> Result { + // todo!() + // } + + // pub async fn query_latest_timestamp( + // &self, + // ) -> Result> { + // match &self.l1 { + // AnyEthereum::Mainnet(eth) => eth.query_latest_timestamp().map_err(Into::into).await, + // AnyEthereum::Minimal(eth) => eth.query_latest_timestamp().map_err(Into::into).await, + // } + // } - async fn self_client_state(&self, height: Self::Height) -> Self::SelfClientState { + pub async fn self_client_state(&self, height: Height) -> arbitrum::client_state::ClientState { arbitrum::client_state::ClientState { - l1_client_id: self.l1_client_id.clone(), + l1_client_id: self.l1_client_id.clone().to_string().validate().unwrap(), chain_id: self.chain_id, l1_latest_slot: height.revision_height, l1_contract_address: self.l1_contract_address, @@ -392,7 +373,10 @@ impl Chain for Arbitrum { } } - async fn self_consensus_state(&self, height: Self::Height) -> Self::SelfConsensusState { + pub async fn self_consensus_state( + &self, + height: Height, + ) -> arbitrum::consensus_state::ConsensusState { let arbitrum_height = ethers::types::BlockId::Number(ethers::types::BlockNumber::Number( self.execution_height_of_beacon_slot(height.revision_height) .await diff --git a/lib/chain-utils/src/berachain.rs b/lib/chain-utils/src/berachain.rs index 0a9a18ebb9..f8fe7034e8 100644 --- a/lib/chain-utils/src/berachain.rs +++ b/lib/chain-utils/src/berachain.rs @@ -3,7 +3,7 @@ use std::{ sync::Arc, }; -use cometbft_rpc::AbciQueryResponse; +use cometbft_rpc::types::AbciQueryResponse; use contracts::ibc_handler::IBCHandler; use ethers::providers::{Middleware, Provider, ProviderError, Ws, WsClientError}; use ics23::ibc_api::SDK_SPECS; @@ -13,7 +13,7 @@ use unionlabs::{ BerachainChainSpec, LATEST_BEACON_BLOCK_HEADER_PREFIX, LATEST_EXECUTION_PAYLOAD_HEADER_PREFIX, }, - encoding::{DecodeAs, EthAbi, Ssz}, + encoding::{DecodeAs, Ssz}, ethereum::IBC_HANDLER_COMMITMENTS_SLOT, google::protobuf::duration::Duration, hash::H160, @@ -28,18 +28,18 @@ use unionlabs::{ tendermint::fraction::Fraction, }, }, - id::ClientId, option_unwrap, result_unwrap, - traits::{Chain, ChainIdOf, FromStrExact, HeightOf}, + traits::FromStrExact, uint::U256, }; use crate::{ ethereum::{ - self, balance_of_signers, EthereumConsensusChain, EthereumIbcChain, - EthereumSignerMiddleware, EthereumSignersConfig, ReadWrite, + balance_of_signers, EthereumConsensusChain, EthereumIbcChain, EthereumSignerMiddleware, + EthereumSignersConfig, ReadWrite, }, keyring::{ChainKeyring, ConcurrentKeyring, SignerBalance}, + BoxDynError, }; // FLOW: @@ -110,34 +110,9 @@ impl FromStrExact for BerachainChainType { const EXPECTING: &'static str = "berachain"; } -impl Chain for Berachain { - type ChainType = BerachainChainType; - type SelfClientState = berachain::client_state::ClientState; - type SelfConsensusState = berachain::consensus_state::ConsensusState; - - type StoredClientState = Tr::SelfClientState; - type StoredConsensusState = Tr::SelfConsensusState; - - type Header = berachain::header::Header; - - type Height = Height; - - type ClientId = ClientId; - - type ClientType = String; - - type Error = ethers::providers::ProviderError; - - type IbcStateEncoding = EthAbi; - - type StateProof = StorageProof; - - /// We expose the execution chain id instead of the consensus chain id since the execution chain id is the "public facing" one. - fn chain_id(&self) -> ChainIdOf { - self.execution_chain_id - } - - async fn query_latest_height(&self) -> Result, Self::Error> { +#[allow(dead_code)] +impl Berachain { + async fn query_latest_height(&self) -> Result { Ok(Height { revision_number: self.consensus_chain_revision, revision_height: self @@ -154,11 +129,7 @@ impl Chain for Berachain { }) } - async fn query_latest_height_as_destination(&self) -> Result { - self.query_latest_height().await - } - - async fn query_latest_timestamp(&self) -> Result { + async fn query_latest_timestamp(&self) -> Result { Ok(self .provider .get_block(self.provider.get_block_number().await?) @@ -169,7 +140,7 @@ impl Chain for Berachain { .unwrap()) } - async fn self_client_state(&self, height: Height) -> Self::SelfClientState { + async fn self_client_state(&self, height: Height) -> berachain::client_state::ClientState { let commit = self .tm_client .commit(Some(height.revision_height.try_into().unwrap())) @@ -206,7 +177,10 @@ impl Chain for Berachain { } } - async fn self_consensus_state(&self, height: Height) -> Self::SelfConsensusState { + async fn self_consensus_state( + &self, + height: Height, + ) -> berachain::consensus_state::ConsensusState { let execution_header = self .execution_header_at_beacon_slot(height.revision_height) .await; @@ -261,8 +235,9 @@ impl EthereumConsensusChain for Berachain { .block_number } - async fn get_proof(&self, address: H160, location: U256, block: u64) -> StorageProof { - ethereum::get_proof(self, address, location, block).await + async fn get_proof(&self, _address: H160, _location: U256, _block: u64) -> StorageProof { + todo!() + // ethereum::get_proof(self, address, location, block).await } } @@ -362,7 +337,7 @@ impl Berachain { .abci_query( "store/beacon/key", data, - Some((slot - 1).try_into().unwrap()), + Some((slot as i64 - 1).try_into().unwrap()), prove, ) .await diff --git a/lib/chain-utils/src/cosmos.rs b/lib/chain-utils/src/cosmos.rs index 1803f0d1fb..573c0896e3 100644 --- a/lib/chain-utils/src/cosmos.rs +++ b/lib/chain-utils/src/cosmos.rs @@ -1,31 +1,11 @@ -use std::{ - num::{NonZeroU64, ParseIntError}, - sync::Arc, -}; +use std::{num::ParseIntError, sync::Arc}; use bip32::secp256k1::ecdsa; -use futures::Future; -use ics23::ibc_api::SDK_SPECS; use protos::cosmos::auth::v1beta1::Bech32PrefixRequest; use serde::{Deserialize, Serialize}; use tendermint_rpc::{Client, WebSocketClient, WebSocketClientUrl}; use unionlabs::{ - bounded::{BoundedI32, BoundedI64}, - constants::metric::NANOS_PER_SECOND, - encoding::Proto, - google::protobuf::any::Any, - hash::H256, - ibc::{ - core::{ - client::height::Height, - commitment::{merkle_proof::MerkleProof, merkle_root::MerkleRoot}, - }, - lightclients::tendermint::{self, fraction::Fraction}, - }, - id::ClientId, - option_unwrap, result_unwrap, - signer::CosmosSigner, - traits::{Chain, ClientState, FromStrExact}, + hash::H256, ibc::core::client::height::Height, signer::CosmosSigner, traits::FromStrExact, WasmClientType, }; @@ -105,168 +85,6 @@ impl FromStrExact for CosmosChainType { const EXPECTING: &'static str = "cosmos"; } -impl Chain for Cosmos { - type ChainType = CosmosChainType; - - type SelfClientState = tendermint::client_state::ClientState; - type SelfConsensusState = tendermint::consensus_state::ConsensusState; - - type StoredClientState = Any; - type StoredConsensusState = Any; - - type Header = tendermint::header::Header; - - type Height = Height; - - type ClientId = ClientId; - - type ClientType = String; - - type Error = tendermint_rpc::Error; - - type IbcStateEncoding = Proto; - - type StateProof = MerkleProof; - - fn chain_id(&self) -> ::ChainId { - self.chain_id.clone() - } - - async fn query_latest_height(&self) -> Result { - self.tm_client - .latest_block() - .await - .map(|response| self.make_height(response.block.header.height.value())) - } - - fn query_latest_height_as_destination( - &self, - ) -> impl Future> + '_ { - self.query_latest_height() - } - - async fn query_latest_timestamp(&self) -> Result { - self.tm_client - .latest_block() - .await - .map(|response| response.block.header.time.unix_timestamp()) - } - - async fn self_client_state(&self, height: Height) -> Self::SelfClientState { - let params = protos::cosmos::staking::v1beta1::query_client::QueryClient::connect( - self.grpc_url.clone(), - ) - .await - .unwrap() - .params(protos::cosmos::staking::v1beta1::QueryParamsRequest {}) - .await - .unwrap() - .into_inner() - .params - .unwrap(); - - let commit = self - .tm_client - .commit(u32::try_from(height.revision_height).unwrap()) - .await - .unwrap(); - - let height = commit.signed_header.header.height; - - let unbonding_period = std::time::Duration::new( - params - .unbonding_time - .clone() - .unwrap() - .seconds - .try_into() - .unwrap(), - params - .unbonding_time - .clone() - .unwrap() - .nanos - .try_into() - .unwrap(), - ); - - tendermint::client_state::ClientState { - chain_id: self.chain_id(), - // https://github.com/cometbft/cometbft/blob/da0e55604b075bac9e1d5866cb2e62eaae386dd9/light/verifier.go#L16 - trust_level: Fraction { - numerator: 1, - denominator: const { option_unwrap!(NonZeroU64::new(3)) }, - }, - // https://github.com/cosmos/relayer/blob/23d1e5c864b35d133cad6a0ef06970a2b1e1b03f/relayer/chains/cosmos/provider.go#L177 - trusting_period: unionlabs::google::protobuf::duration::Duration::new( - (unbonding_period * 85 / 100).as_secs().try_into().unwrap(), - (unbonding_period * 85 / 100) - .subsec_nanos() - .try_into() - .unwrap(), - ) - .unwrap(), - unbonding_period: unionlabs::google::protobuf::duration::Duration::new( - unbonding_period.as_secs().try_into().unwrap(), - unbonding_period.subsec_nanos().try_into().unwrap(), - ) - .unwrap(), - // https://github.com/cosmos/relayer/blob/23d1e5c864b35d133cad6a0ef06970a2b1e1b03f/relayer/chains/cosmos/provider.go#L177 - max_clock_drift: const { - result_unwrap!(unionlabs::google::protobuf::duration::Duration::new( - 60 * 10, - 0 - )) - }, - frozen_height: None, - latest_height: Height { - revision_number: self.chain_revision, - revision_height: height.value(), - }, - proof_specs: SDK_SPECS.into(), - upgrade_path: vec!["upgrade".into(), "upgradedIBCState".into()], - } - } - - async fn self_consensus_state(&self, height: Height) -> Self::SelfConsensusState { - let commit = self - .tm_client - .commit(u32::try_from(height.revision_height).unwrap()) - .await - .unwrap(); - - tendermint::consensus_state::ConsensusState { - root: MerkleRoot { - hash: commit - .signed_header - .header - .app_hash - .as_bytes() - .to_vec() - .try_into() - .unwrap(), - }, - next_validators_hash: commit - .signed_header - .header - .next_validators_hash - .as_bytes() - .to_vec() - .try_into() - .unwrap(), - timestamp: { - let timestamp_nanos = commit.signed_header.header.time.unix_timestamp_nanos(); - let seconds = timestamp_nanos / NANOS_PER_SECOND as i128; - let nanos = timestamp_nanos % NANOS_PER_SECOND as i128; - unionlabs::google::protobuf::timestamp::Timestamp { - seconds: BoundedI64::new(seconds.try_into().unwrap()).unwrap(), - nanos: BoundedI32::new(nanos.try_into().unwrap()).unwrap(), - } - }, - } - } -} - #[derive(Debug, thiserror::Error)] pub enum CosmosInitError { #[error("tendermint rpc error")] @@ -274,7 +92,6 @@ pub enum CosmosInitError { #[error( "unable to parse chain id: expected format `-`, found `{found}`" )] - // TODO: Once the `Id` trait in unionlabs is cleaned up to no longer use static id types, this error should just wrap `IdParseError` ChainIdParse { found: String, #[source] diff --git a/lib/chain-utils/src/cosmos_sdk.rs b/lib/chain-utils/src/cosmos_sdk.rs index 3e38e02126..5af336dcd5 100644 --- a/lib/chain-utils/src/cosmos_sdk.rs +++ b/lib/chain-utils/src/cosmos_sdk.rs @@ -19,10 +19,9 @@ use unionlabs::{ encoding::{EncodeAs, Proto}, google::protobuf::any::Any, hash::H256, - id::ConnectionId, + id::{ClientId, ConnectionId}, parse_wasm_client_type, signer::CosmosSigner, - traits::Chain, ErrorReporter, MaybeRecoverableError, WasmClientType, }; @@ -49,10 +48,10 @@ pub struct GasConfig { impl GasConfig { pub fn mk_fee(&self, gas: u64) -> Fee { // gas limit = provided gas * multiplier, clamped between min_gas and max_gas - let gas_limit = u128_mul_f64(gas.into(), self.gas_multiplier) + let gas_limit = u128_saturating_mul_f64(gas.into(), self.gas_multiplier) .clamp(self.min_gas.into(), self.max_gas.into()); - let amount = u128_mul_f64(gas.into(), self.gas_price); + let amount = u128_saturating_mul_f64(gas.into(), self.gas_price); Fee { amount: vec![Coin { @@ -79,9 +78,7 @@ pub trait CosmosSdkChain { } #[allow(async_fn_in_trait)] -pub trait CosmosSdkChainIbcExt: - CosmosSdkChain + CosmosSdkChainRpcs + Chain -{ +pub trait CosmosSdkChainIbcExt: CosmosSdkChain + CosmosSdkChainRpcs { async fn client_type_of_checksum(&self, checksum: H256) -> Option { if let Some(ty) = self.checksum_cache().get(&checksum) { debug!( @@ -136,7 +133,7 @@ pub trait CosmosSdkChainIbcExt: } } - async fn checksum_of_client_id(&self, client_id: Self::ClientId) -> H256 { + async fn checksum_of_client_id(&self, client_id: ClientId) -> H256 { let client_state = protos::ibc::core::client::v1::query_client::QueryClient::connect( self.grpc_url().clone(), ) @@ -163,7 +160,7 @@ pub trait CosmosSdkChainIbcExt: .unwrap() } - async fn client_id_of_connection(&self, connection_id: ConnectionId) -> Self::ClientId { + async fn client_id_of_connection(&self, connection_id: ConnectionId) -> ClientId { protos::ibc::core::connection::v1::query_client::QueryClient::connect( self.grpc_url().clone(), ) @@ -372,7 +369,8 @@ pub trait CosmosSdkChainExt: CosmosSdkChainRpcs { .unwrap(); let tx_body = TxBody { - messages: messages.clone().into_iter().collect(), + // TODO: Use RawAny in the signature of this function and broadcast_tx_commit + messages: messages.clone().into_iter().map(Into::into).collect(), memo, timeout_height: 0, extension_options: vec![], @@ -493,25 +491,23 @@ pub async fn fetch_balances( out_vec } -fn u128_mul_f64(u: u128, f: f64) -> u128 { +fn u128_saturating_mul_f64(u: u128, f: f64) -> u128 { (num_rational::BigRational::from_integer(u.into()) * num_rational::BigRational::from_float(f).expect("finite")) .to_integer() .try_into() - .expect("overflow") + .unwrap_or(u128::MAX) + // .expect("overflow") } #[test] fn test_u128_mul_f64() { - let val = u128_mul_f64(100, 1.1); + let val = u128_saturating_mul_f64(100, 1.1); assert_eq!(val, 110); } -impl> - CosmosSdkChainIbcExt for T -{ -} +impl CosmosSdkChainIbcExt for T {} impl CosmosSdkChainExt for T {} @@ -869,5 +865,39 @@ pub mod cosmos_sdk_error { ErrPacketNotSent = errorsmod.Register(SubModuleName, 25, "packet has not been sent") ErrInvalidTimeout = errorsmod.Register(SubModuleName, 26, "invalid packet timeout") ) + + // https://github.com/cosmos/ibc-go/blob/main/modules/light-clients/08-wasm/types/errors.go + #[err(name = IbcWasmError, codespace = "08-wasm")] + var ( + ErrInvalid = errorsmod.Register(ModuleName, 2, "invalid") + ErrInvalidData = errorsmod.Register(ModuleName, 3, "invalid data") + ErrInvalidChecksum = errorsmod.Register(ModuleName, 4, "invalid checksum") + ErrInvalidClientMessage = errorsmod.Register(ModuleName, 5, "invalid client message") + ErrRetrieveClientID = errorsmod.Register(ModuleName, 6, "failed to retrieve client id") + // Wasm specific + ErrWasmEmptyCode = errorsmod.Register(ModuleName, 7, "empty wasm code") + ErrWasmCodeTooLarge = errorsmod.Register(ModuleName, 8, "wasm code too large") + ErrWasmCodeExists = errorsmod.Register(ModuleName, 9, "wasm code already exists") + ErrWasmChecksumNotFound = errorsmod.Register(ModuleName, 10, "wasm checksum not found") + ErrWasmSubMessagesNotAllowed = errorsmod.Register(ModuleName, 11, "execution of sub messages is not allowed") + ErrWasmEventsNotAllowed = errorsmod.Register(ModuleName, 12, "returning events from a contract is not allowed") + ErrWasmAttributesNotAllowed = errorsmod.Register(ModuleName, 13, "returning attributes from a contract is not allowed") + ErrWasmContractCallFailed = errorsmod.Register(ModuleName, 14, "wasm contract call failed") + ErrWasmInvalidResponseData = errorsmod.Register(ModuleName, 15, "wasm contract returned invalid response data") + ErrWasmInvalidContractModification = errorsmod.Register(ModuleName, 16, "wasm contract made invalid state modifications") + ErrVMError = errorsmod.Register(ModuleName, 17, "wasm VM error") + ) + + // https://github.com/cosmos/ibc-go/blob/5ef01dae21dd60df22715b8e99bf641087a98879/modules/capability/types/errors.go + #[err(name = Capability, codespace = "capability")] + var ( + ErrInvalidCapabilityName = errorsmod.Register(ModuleName, 2, "capability name not valid") + ErrNilCapability = errorsmod.Register(ModuleName, 3, "provided capability is nil") + ErrCapabilityTaken = errorsmod.Register(ModuleName, 4, "capability name already taken") + ErrOwnerClaimed = errorsmod.Register(ModuleName, 5, "given owner already claimed capability") + ErrCapabilityNotOwned = errorsmod.Register(ModuleName, 6, "capability not owned by module") + ErrCapabilityNotFound = errorsmod.Register(ModuleName, 7, "capability not found") + ErrCapabilityOwnersNotFound = errorsmod.Register(ModuleName, 8, "owners not found for capability") + ) } } diff --git a/lib/chain-utils/src/ethereum.rs b/lib/chain-utils/src/ethereum.rs index 1f1e593927..a2198d90d6 100644 --- a/lib/chain-utils/src/ethereum.rs +++ b/lib/chain-utils/src/ethereum.rs @@ -1,49 +1,47 @@ -use std::{fmt::Debug, marker::PhantomData, ops::Div, sync::Arc}; +use std::{fmt::Debug, marker::PhantomData, sync::Arc}; use beacon_api::client::BeaconApiClient; use contracts::{ cometbls_client::CometblsClientErrors, + glue::{IbcCoreChannelV1ChannelData, IbcCoreConnectionV1ConnectionEndData}, i_light_client::ILightClient, ibc_channel_handshake::{IBCChannelHandshakeErrors, IBCChannelHandshakeEvents}, - ibc_client::{IBCClientErrors, IBCClientEvents}, + ibc_client::{ErrClientNotFound, IBCClientErrors, IBCClientEvents}, ibc_connection::{IBCConnectionErrors, IBCConnectionEvents}, ibc_handler::{IBCHandler, OwnershipTransferredFilter}, ibc_packet::{IBCPacketErrors, IBCPacketEvents}, }; use ethers::{ - abi::{AbiDecode, AbiEncode}, - contract::{ContractError, EthLogDecode}, + abi::AbiDecode, + contract::{ContractError, EthError, EthLogDecode}, core::k256::ecdsa, middleware::{NonceManagerMiddleware, SignerMiddleware}, - providers::{Middleware, Provider, ProviderError, Ws, WsClientError}, + providers::{Middleware, Provider, Ws}, signers::{LocalWallet, Wallet}, - utils::{keccak256, secret_key_to_address}, + utils::secret_key_to_address, }; use frame_support_procedural::{CloneNoBound, DebugNoBound}; use futures::Future; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use tracing::debug; -use typenum::Unsigned; +use serde_utils::Hex; +use tracing::{debug, instrument}; use unionlabs::{ - encoding::{Decode, EthAbi}, ethereum::{ config::{ChainSpec, Mainnet, Minimal}, - IBC_HANDLER_COMMITMENTS_SLOT, + ibc_commitment_key, IBC_HANDLER_COMMITMENTS_SLOT, }, hash::{H160, H256}, - ibc::{ - core::client::height::{Height, IsHeight}, - lightclients::ethereum::{self, storage_proof::StorageProof}, - }, + ibc::lightclients::ethereum::storage_proof::StorageProof, ics24::{ AcknowledgementPath, ChannelEndPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, ConnectionPath, IbcPath, NextClientSequencePath, - NextConnectionSequencePath, NextSequenceRecvPath, ReceiptPath, + NextConnectionSequencePath, NextSequenceAckPath, NextSequenceRecvPath, + NextSequenceSendPath, ReceiptPath, }, - id::ClientId, iter, - traits::{Chain, ClientIdOf, ClientState, FromStrExact, HeightOf}, + traits::FromStrExact, uint::U256, + ErrorReporter, }; use crate::keyring::{ChainKeyring, ConcurrentKeyring, KeyringConfig, KeyringEntry, SignerBalance}; @@ -53,9 +51,6 @@ pub type EthereumKeyring = ConcurrentKeyring>, Wallet>; -pub trait EthereumChain = - Chain; - // NOTE: ClientType bound is temporary until I figure out a better way to deal with client types /// A chain running the EVM and our solidity IBC stack. This can be any Ethereum L1 or L2, or a chain running the EVM in a different environment (such as Berachain). pub trait EthereumIbcChain { @@ -113,8 +108,9 @@ impl EthereumConsensusChain for Ethereum execution_height } - async fn get_proof(&self, address: H160, location: U256, block: u64) -> StorageProof { - get_proof(self, address, location, block).await + async fn get_proof(&self, _address: H160, _location: U256, _block: u64) -> StorageProof { + todo!() + // get_proof(self, address, location, block).await } } @@ -129,8 +125,9 @@ pub struct Ethereum { pub keyring: S::Out, pub provider: Arc>, - pub beacon_api_client: BeaconApiClient, + pub beacon_api_client: BeaconApiClient, pub max_gas_price: Option, + __marker: PhantomData C>, } #[derive(DebugNoBound, CloneNoBound, enumorph::Enumorph)] @@ -172,35 +169,37 @@ impl EthereumConsensusChain for AnyEthereum { } impl AnyEthereum { - pub async fn new(config: Config) -> Result { - match Ethereum::::new(config.clone()).await { - Ok(eth) => return Ok(eth.into()), - Err(EthereumInitError::Beacon(beacon_api::client::NewError::IncorrectChainSpec)) => {} - Err(err) => { - return Err(AnyEthereumError::Mainnet(err)); - } - } + pub async fn new(_config: Config) -> Result { + // match Ethereum::::new(config.clone()).await { + // Ok(eth) => return Ok(eth.into()), + // Err(EthereumInitError::Beacon(beacon_api::client::NewError::IncorrectChainSpec)) => {} + // Err(err) => { + // return Err(AnyEthereumError::Mainnet(err)); + // } + // } - match Ethereum::::new(config).await { - Ok(eth) => return Ok(eth.into()), - Err(EthereumInitError::Beacon(beacon_api::client::NewError::IncorrectChainSpec)) => {} - Err(err) => { - return Err(AnyEthereumError::Minimal(err)); - } - } + // match Ethereum::::new(config).await { + // Ok(eth) => return Ok(eth.into()), + // Err(EthereumInitError::Beacon(beacon_api::client::NewError::IncorrectChainSpec)) => {} + // Err(err) => { + // return Err(AnyEthereumError::Minimal(err)); + // } + // } + + // Err(AnyEthereumError::UnknownChainSpec) - Err(AnyEthereumError::UnknownChainSpec) + todo!() } } #[derive(Debug, thiserror::Error)] pub enum AnyEthereumError { - #[error("error creating minimal beacon client")] - Minimal(#[source] EthereumInitError), - #[error("error creating mainnet beacon client")] - Mainnet(#[source] EthereumInitError), - #[error("unknown chain spec")] - UnknownChainSpec, + // #[error("error creating minimal beacon client")] + // Minimal(#[source] EthereumInitError), + // #[error("error creating mainnet beacon client")] + // Mainnet(#[source] EthereumInitError), + // #[error("unknown chain spec")] + // UnknownChainSpec, } #[derive(DebugNoBound, CloneNoBound, Serialize, Deserialize)] @@ -376,7 +375,7 @@ macro_rules! try_decode { }; } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum IBCHandlerEvents { PacketEvent(IBCPacketEvents), ConnectionEvent(IBCConnectionEvents), @@ -423,334 +422,30 @@ impl AbiDecode for IbcHandlerErrors { } } -impl Chain for Ethereum { - type ChainType = EthereumChainType; - - type SelfClientState = ethereum::client_state::ClientState; - type SelfConsensusState = ethereum::consensus_state::ConsensusState; - - type StoredClientState = Tr::SelfClientState; - type StoredConsensusState = Tr::SelfConsensusState; - - type Header = ethereum::header::Header; - - type Height = Height; - - type ClientId = EthereumClientId; - - type IbcStateEncoding = EthAbi; - - type ClientType = String; - - type Error = beacon_api::errors::Error; - - type StateProof = StorageProof; - - fn chain_id(&self) -> ::ChainId { - self.chain_id - } - - async fn query_latest_height(&self) -> Result { - self.beacon_api_client - .finality_update() - .await - .map(|response| self.make_height(response.data.attested_header.beacon.slot)) - } - - async fn query_latest_height_as_destination(&self) -> Result { - let height = self - .beacon_api_client - .block(beacon_api::client::BlockId::Head) - .await? - .data - .message - .slot; - - // HACK: we introduced this because we were using alchemy for the - // execution endpoint and our custom beacon endpoint that rely on - // its own execution chain. Alchemy was a bit delayed and the - // execution height for the beacon head wasn't existing for few - // secs. We wait for an extra beacon head to let alchemy catch up. - // We should be able to remove that once we rely on an execution - // endpoint that is itself used by the beacon endpoint (no different - // POV). - loop { - let next_height = self - .beacon_api_client - .block(beacon_api::client::BlockId::Head) - .await? - .data - .message - .slot; - if next_height > height { - break; - } - - tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; - } - - Ok(self.make_height(height)) - } - - async fn query_latest_timestamp(&self) -> Result { - Ok(self - .beacon_api_client - .finality_update() - .await? - .data - .attested_header - .execution - .timestamp - .try_into() - .unwrap()) - } - - async fn self_client_state(&self, beacon_height: Height) -> Self::SelfClientState { - let genesis = self.beacon_api_client.genesis().await.unwrap().data; - - ethereum::client_state::ClientState { - chain_id: self.chain_id, - genesis_validators_root: genesis.genesis_validators_root, - genesis_time: genesis.genesis_time, - fork_parameters: self - .beacon_api_client - .spec() - .await - .unwrap() - .data - .into_fork_parameters(), - // REVIEW: Is this a preset config param? Or a per-chain config? - seconds_per_slot: C::SECONDS_PER_SLOT::U64, - slots_per_epoch: C::SLOTS_PER_EPOCH::U64, - epochs_per_sync_committee_period: C::EPOCHS_PER_SYNC_COMMITTEE_PERIOD::U64, - latest_slot: beacon_height.revision_height, - min_sync_committee_participants: 0, - frozen_height: Height { - revision_number: 0, - revision_height: 0, - }, - ibc_commitment_slot: IBC_HANDLER_COMMITMENTS_SLOT, - ibc_contract_address: self.ibc_handler_address, - } - } - - async fn self_consensus_state(&self, beacon_height: Height) -> Self::SelfConsensusState { - let trusted_header = self - .beacon_api_client - .header(beacon_api::client::BlockId::Slot( - beacon_height.revision_height, - )) - .await - .unwrap() - .data; - - let bootstrap = self - .beacon_api_client - .bootstrap(trusted_header.root) - .await - .unwrap() - .data; - - assert!(bootstrap.header.beacon.slot == beacon_height.revision_height); - - let light_client_update = { - let current_period = beacon_height.revision_height.div(C::PERIOD::U64); - - debug!(%current_period); - - let light_client_updates = self - .beacon_api_client - .light_client_updates(current_period, 1) - .await - .unwrap(); - - let [light_client_update] = &*light_client_updates.0 else { - panic!() - }; - - light_client_update.data.clone() - }; - - // Normalize to nanos in order to be compliant with cosmos - let timestamp = bootstrap.header.execution.timestamp * 1_000_000_000; - ethereum::consensus_state::ConsensusState { - slot: bootstrap.header.beacon.slot, - state_root: bootstrap.header.execution.state_root, - storage_root: self - .provider - .get_proof( - ethers::types::H160::from(self.ibc_handler_address.0), - vec![], - Some(bootstrap.header.execution.block_number.into()), - ) - .await - .unwrap() - .storage_hash - .0 - .into(), - timestamp, - current_sync_committee: bootstrap.current_sync_committee.aggregate_pubkey, - next_sync_committee: light_client_update - .next_sync_committee - .map(|nsc| nsc.aggregate_pubkey), - } - } -} - -#[derive(Debug, thiserror::Error)] -pub enum EthereumInitError { - #[error("unable to connect to websocket")] - Ws(#[from] WsClientError), - #[error("provider error")] - Provider(#[from] ProviderError), - #[error("beacon error")] - Beacon(#[from] beacon_api::client::NewError), -} - -impl Ethereum { - pub async fn new(config: Config) -> Result { - let provider = Provider::new(Ws::connect(config.eth_rpc_api).await?); - - let chain_id = provider.get_chainid().await?; - - Ok(Self { - chain_id: U256(chain_id), - keyring: S::new( - config.keyring, - config.ibc_handler_address, - chain_id.as_u64(), - provider.clone(), - ), - ibc_handler_address: config.ibc_handler_address, - multicall_address: config.multicall_address, - provider: Arc::new(provider), - beacon_api_client: BeaconApiClient::new(config.eth_beacon_rpc_api).await?, - max_gas_price: config.max_gas_price, - }) - } -} - -/// Fetch an eth_getProof call on an Ethereum-based chain that has the exact same response type as Ethereum. -pub async fn get_proof( - hc: &Hc, - address: H160, - location: U256, - block: u64, -) -> StorageProof { - let proof = hc - .provider() - .get_proof( - ethers::types::H160::from(address), - vec![location.to_be_bytes().into()], - Some(block.into()), - ) - .await - .unwrap(); - - let proof = match <[_; 1]>::try_from(proof.storage_proof) { - Ok([proof]) => proof, - Err(invalid) => { - panic!("received invalid response from eth_getProof, expected length of 1 but got `{invalid:#?}`"); - } - }; - - StorageProof { - key: U256::from_be_bytes(proof.key.to_fixed_bytes()), - value: proof.value.into(), - proof: proof - .proof - .into_iter() - .map(|bytes| bytes.to_vec()) - .collect(), - } -} - -impl Ethereum { - pub fn make_height(&self, height: impl Into) -> Height { - // REVIEW: Consider using the fork revision? - { - Height { - revision_number: ETHEREUM_REVISION_NUMBER, - revision_height: height.into(), - } - } - } -} - pub trait IbcHandlerExt { - fn ibc_state_read( + fn ibc_state_read

( &self, execution_block_number: u64, path: P, ) -> impl Future>> + Send where - P: EthereumStateRead + 'static, - Hc: EthereumChain + EthereumIbcChain, - Tr: Chain; - - fn get_client_state( - &self, - client_id: ClientIdOf, - execution_block_number: u64, - ) -> impl Future - where - Hc: EthereumChain + EthereumIbcChain, - ClientState: Decode; + P: EthereumStateRead + 'static; } impl IbcHandlerExt for IBCHandler { - async fn ibc_state_read( + async fn ibc_state_read

( &self, execution_block_number: u64, path: P, ) -> Result> where - P: EthereumStateRead + 'static, - Hc: EthereumChain + EthereumIbcChain, - Tr: Chain, + P: EthereumStateRead + 'static, { Ok(path.read(self, execution_block_number).await) } - - async fn get_client_state( - &self, - client_id: ClientIdOf, - execution_block_number: u64, - ) -> ClientState - where - Hc: EthereumChain + EthereumIbcChain, - ClientState: Decode, - { - let client_address = self - .get_client(client_id.to_string()) - .block(execution_block_number) - .call() - .await - .unwrap(); - - let bytes = ILightClient::new(client_address, self.client()) - .get_client_state(client_id.to_string()) - .block(execution_block_number) - .call() - .await - .unwrap(); - - >::decode(&bytes).unwrap() - } -} - -pub type EthereumClientId = ClientId; - -pub fn next_epoch_timestamp(slot: u64, genesis_timestamp: u64) -> u64 { - let next_epoch_slot = slot + (C::SLOTS_PER_EPOCH::U64 - (slot % C::SLOTS_PER_EPOCH::U64)); - genesis_timestamp + (next_epoch_slot * C::SECONDS_PER_SLOT::U64) } -pub trait EthereumStateRead: IbcPath -where - Hc: EthereumChain + EthereumIbcChain, - Tr: Chain, -{ +pub trait EthereumStateRead: IbcPath { fn read( self, ibc_handler: &IBCHandler, @@ -758,145 +453,200 @@ where ) -> impl Future + Send + '_; } -impl EthereumStateRead for ClientStatePath> -where - Hc: EthereumChain + EthereumIbcChain, - Tr: Chain, - Self::Value: Decode, -{ +impl EthereumStateRead for ClientStatePath { async fn read( self, ibc_handler: &IBCHandler, execution_block_number: u64, ) -> Self::Value { - ibc_handler - .get_client_state::(self.client_id, execution_block_number) - .await + Hex( + match ibc_handler + .get_client(self.client_id.to_string()) + .block(execution_block_number) + .call() + .await + { + Ok(client_address) => { + let client_state_bytes = + &ILightClient::new(client_address, ibc_handler.client()) + .get_client_state(self.client_id.to_string()) + .block(execution_block_number) + .call() + .await + .unwrap(); + + // TODO: Ensure this invariant is documented in the solidity IBC stack + if client_state_bytes.iter().all(|b| *b == 0) { + vec![] + } else { + client_state_bytes.to_vec() + } + } + Err(err) + if err + .as_revert() + .is_some_and(|bz| bz[..] == ErrClientNotFound::selector()) => + { + vec![] + } + Err(err) => { + panic!("error fetching client state: {}", ErrorReporter(err)) + } + }, + ) } } -impl EthereumStateRead for ClientConsensusStatePath, HeightOf> -where - Hc: EthereumChain + EthereumIbcChain, - Tr: Chain, - Self::Value: Decode, -{ +impl EthereumStateRead for ClientConsensusStatePath { async fn read( self, ibc_handler: &IBCHandler, execution_block_number: u64, ) -> Self::Value { - let client_address = ibc_handler - .get_client(self.client_id.to_string()) - .block(execution_block_number) - .call() - .await - .unwrap(); - - let bytes = ILightClient::new(client_address, ibc_handler.client()) - .get_consensus_state(self.client_id.to_string(), self.height.into_height().into()) - .block(execution_block_number) - .call() - .await - .unwrap(); - - >::decode(&bytes).unwrap() + Hex( + match ibc_handler + .get_client(self.client_id.to_string()) + .block(execution_block_number) + .call() + .await + { + Ok(client_address) => { + let consensus_state_bytes = + &ILightClient::new(client_address, ibc_handler.client()) + .get_consensus_state(self.client_id.to_string(), self.height.into()) + .block(execution_block_number) + .call() + .await + .unwrap(); + + // TODO: Ensure this invariant is documented in the solidity IBC stack + if consensus_state_bytes.iter().all(|b| *b == 0) { + vec![] + } else { + consensus_state_bytes.to_vec() + } + } + Err(err) + if err + .as_revert() + .is_some_and(|bz| bz[..] == ErrClientNotFound::selector()) => + { + vec![] + } + Err(err) => { + panic!("error fetching client state: {}", ErrorReporter(err)) + } + }, + ) } } -impl EthereumStateRead for ConnectionPath -where - Hc: EthereumChain + EthereumIbcChain, - Tr: Chain, -{ +impl EthereumStateRead for ConnectionPath { async fn read( self, ibc_handler: &IBCHandler, execution_block_number: u64, ) -> Self::Value { - ibc_handler + let connection: IbcCoreConnectionV1ConnectionEndData = ibc_handler .get_connection(self.connection_id.to_string()) .block(execution_block_number) .call() .await - .unwrap() - .try_into() - .unwrap() + .unwrap(); + + if connection == IbcCoreConnectionV1ConnectionEndData::default() { + None + } else { + Some(connection.try_into().unwrap()) + } } } -impl EthereumStateRead for ChannelEndPath -where - Hc: EthereumChain + EthereumIbcChain, - Tr: Chain, -{ +impl EthereumStateRead for ChannelEndPath { + #[instrument( + skip_all, + fields( + port_id = %self.port_id, + channel_id = %self.channel_id, + %execution_block_number, + ibc_handler_address = %H160::from(ibc_handler.address()), + ) + )] async fn read( self, ibc_handler: &IBCHandler, execution_block_number: u64, ) -> Self::Value { - let raw = ibc_handler + let channel: IbcCoreChannelV1ChannelData = ibc_handler .get_channel(self.port_id.to_string(), self.channel_id.to_string()) .block(execution_block_number) .call() .await .unwrap(); - raw.try_into().unwrap() + if channel == IbcCoreChannelV1ChannelData::default() { + None + } else { + Some(channel.try_into().unwrap()) + } } } -impl EthereumStateRead for CommitmentPath -where - Hc: EthereumChain + EthereumIbcChain, - Tr: Chain, -{ +impl EthereumStateRead for CommitmentPath { async fn read( self, ibc_handler: &IBCHandler, execution_block_number: u64, ) -> Self::Value { - ibc_handler + let commitment: H256 = ibc_handler .client() .get_storage_at( ibc_handler.address(), - commitment_key::(self).into(), + ibc_commitment_key(&self.to_string(), IBC_HANDLER_COMMITMENTS_SLOT) + .to_be_bytes() + .into(), Some(execution_block_number.into()), ) .await .unwrap() - .into() + .into(); + + if commitment == H256::ZERO { + None + } else { + Some(commitment) + } } } -impl EthereumStateRead for AcknowledgementPath -where - Hc: EthereumChain + EthereumIbcChain, - Tr: Chain, -{ +impl EthereumStateRead for AcknowledgementPath { async fn read( self, ibc_handler: &IBCHandler, execution_block_number: u64, ) -> Self::Value { - ibc_handler + let ack_commitment: H256 = ibc_handler .client() .get_storage_at( ibc_handler.address(), - commitment_key::(self).into(), + ibc_commitment_key(&self.to_string(), IBC_HANDLER_COMMITMENTS_SLOT) + .to_be_bytes() + .into(), Some(execution_block_number.into()), ) .await .unwrap() - .into() + .into(); + + if ack_commitment == H256::ZERO { + None + } else { + Some(ack_commitment) + } } } -impl EthereumStateRead for NextConnectionSequencePath -where - Hc: EthereumChain + EthereumIbcChain, - Tr: Chain, -{ +impl EthereumStateRead for NextConnectionSequencePath { async fn read( self, ibc_handler: &IBCHandler, @@ -907,7 +657,9 @@ where .client() .get_storage_at( ibc_handler.address(), - commitment_key::(self).into(), + ibc_commitment_key(&self.to_string(), IBC_HANDLER_COMMITMENTS_SLOT) + .to_be_bytes() + .into(), Some(execution_block_number.into()), ) .await @@ -919,11 +671,7 @@ where } } -impl EthereumStateRead for NextClientSequencePath -where - Hc: EthereumChain + EthereumIbcChain, - Tr: Chain, -{ +impl EthereumStateRead for NextClientSequencePath { async fn read( self, ibc_handler: &IBCHandler, @@ -934,7 +682,9 @@ where .client() .get_storage_at( ibc_handler.address(), - commitment_key::(self).into(), + ibc_commitment_key(&self.to_string(), IBC_HANDLER_COMMITMENTS_SLOT) + .to_be_bytes() + .into(), Some(execution_block_number.into()), ) .await @@ -946,11 +696,7 @@ where } } -impl EthereumStateRead for ReceiptPath -where - Hc: EthereumChain + EthereumIbcChain, - Tr: Chain, -{ +impl EthereumStateRead for ReceiptPath { async fn read( self, ibc_handler: &IBCHandler, @@ -961,7 +707,9 @@ where .client() .get_storage_at( ibc_handler.address(), - commitment_key::(self).into(), + ibc_commitment_key(&self.to_string(), IBC_HANDLER_COMMITMENTS_SLOT) + .to_be_bytes() + .into(), Some(execution_block_number.into()), ) .await @@ -977,11 +725,7 @@ where } } -impl EthereumStateRead for NextSequenceRecvPath -where - Hc: EthereumChain + EthereumIbcChain, - Tr: Chain, -{ +impl EthereumStateRead for NextSequenceRecvPath { async fn read( self, ibc_handler: &IBCHandler, @@ -992,7 +736,9 @@ where .client() .get_storage_at( ibc_handler.address(), - commitment_key::(self).into(), + ibc_commitment_key(&self.to_string(), IBC_HANDLER_COMMITMENTS_SLOT) + .to_be_bytes() + .into(), Some(execution_block_number.into()), ) .await @@ -1003,25 +749,50 @@ where } } -#[test] -fn eth_chain_type() { - assert_eq!( - < as Chain>::ChainType as FromStrExact>::EXPECTING, - "eth-mainnet", - ); - assert_eq!( - < as Chain>::ChainType as FromStrExact>::EXPECTING, - "eth-minimal", - ); +impl EthereumStateRead for NextSequenceSendPath { + async fn read( + self, + ibc_handler: &IBCHandler, + execution_block_number: u64, + ) -> Self::Value { + u64::try_from(U256::from_be_bytes( + ibc_handler + .client() + .get_storage_at( + ibc_handler.address(), + ibc_commitment_key(&self.to_string(), IBC_HANDLER_COMMITMENTS_SLOT) + .to_be_bytes() + .into(), + Some(execution_block_number.into()), + ) + .await + .unwrap() + .0, + )) + .unwrap() + } } -// TODO: Remove this in favor of the one in unionlabs -pub fn commitment_key(path: impl IbcPath) -> H256 { - keccak256( - keccak256(path.to_string()) - .into_iter() - .chain(AbiEncode::encode(IBC_HANDLER_COMMITMENTS_SLOT)) - .collect::>(), - ) - .into() +impl EthereumStateRead for NextSequenceAckPath { + async fn read( + self, + ibc_handler: &IBCHandler, + execution_block_number: u64, + ) -> Self::Value { + u64::try_from(U256::from_be_bytes( + ibc_handler + .client() + .get_storage_at( + ibc_handler.address(), + ibc_commitment_key(&self.to_string(), IBC_HANDLER_COMMITMENTS_SLOT) + .to_be_bytes() + .into(), + Some(execution_block_number.into()), + ) + .await + .unwrap() + .0, + )) + .unwrap() + } } diff --git a/lib/chain-utils/src/lib.rs b/lib/chain-utils/src/lib.rs index bc2bba8101..971d89cf23 100644 --- a/lib/chain-utils/src/lib.rs +++ b/lib/chain-utils/src/lib.rs @@ -1,29 +1,4 @@ #![feature(trait_alias)] -// #![warn(clippy::pedantic)] - -use std::collections::HashMap; - -use enumorph::Enumorph; -use serde::{Deserialize, Serialize}; -use tracing::warn; -use unionlabs::{ - ethereum::config::{ChainSpec, Mainnet, Minimal, PresetBaseKind}, - hash::H160, - traits::{Chain, ChainIdOf, FromStrExact}, - uint::U256, - ClientType, WasmClientType, -}; - -use crate::{ - arbitrum::{Arbitrum, ArbitrumInitError}, - berachain::{Berachain, BerachainInitError}, - cosmos::{Cosmos, CosmosInitError}, - ethereum::{Ethereum, EthereumInitError}, - keyring::KeyringConfig, - scroll::{Scroll, ScrollInitError}, - union::{Union, UnionInitError}, - wasm::Wasm, -}; pub mod arbitrum; pub mod berachain; @@ -34,351 +9,8 @@ pub mod union; pub mod cosmos_sdk; -pub mod wasm; - pub mod private_key; pub mod keyring; -pub trait GetChain { - fn get_chain(&self, chain_id: &ChainIdOf) -> Option; - - fn with_chain<'a, T, F>( - &'a self, - chain_id: &'a ChainIdOf, - f: F, - ) -> Result> - where - T: 'static, - F: FnOnce(C) -> T + 'a, - { - match self.get_chain(chain_id) { - Some(chain) => Ok(f(chain)), - None => { - warn!(%chain_id, chain_type = %::ChainType::EXPECTING, "chain not found"); - Err(ChainNotFoundError { - chain_id: chain_id.clone(), - }) - } - } - } -} - -#[derive(Debug, thiserror::Error)] -#[error("chain {} not found (type: {})", chain_id, ::ChainType::EXPECTING)] -pub struct ChainNotFoundError { - chain_id: ChainIdOf, -} - -#[derive(Debug, Clone, Default)] -pub struct Chains { - pub chains: HashMap, -} - -impl GetChain for Chains { - fn get_chain(&self, chain_id: &ChainIdOf) -> Option { - self.chains - .get(chain_id) - .cloned() - .map(|chain| chain.try_into().expect("chain is correct type")) - } -} - -impl GetChain for Chains { - fn get_chain(&self, chain_id: &ChainIdOf) -> Option { - self.chains - .get(chain_id) - .cloned() - .map(|chain| chain.try_into().expect("chain is correct type")) - } -} - -impl GetChain for Chains { - fn get_chain(&self, chain_id: &ChainIdOf) -> Option { - self.chains - .get(&chain_id.to_string()) - .cloned() - .map(|chain| chain.try_into().expect("chain is correct type")) - } -} - -impl GetChain for Chains { - fn get_chain(&self, chain_id: &ChainIdOf) -> Option { - self.chains - .get(&chain_id.to_string()) - .cloned() - .map(|chain| chain.try_into().expect("chain is correct type")) - } -} - -impl GetChain for Chains { - fn get_chain(&self, chain_id: &ChainIdOf) -> Option { - self.chains - .get(&chain_id.to_string()) - .cloned() - .map(|chain| chain.try_into().expect("chain is correct type")) - } -} - -impl GetChain> for Chains { - fn get_chain(&self, chain_id: &ChainIdOf>) -> Option> { - self.chains - .get(chain_id) - .cloned() - .map(|chain| chain.try_into().expect("chain is correct type")) - .map(Wasm) - } -} - -impl GetChain> for Chains { - fn get_chain(&self, chain_id: &ChainIdOf>) -> Option> { - self.chains - .get(chain_id) - .cloned() - .map(|chain| chain.try_into().expect("chain is correct type")) - .map(Wasm) - } -} - -impl GetChain> for Chains { - fn get_chain(&self, chain_id: &ChainIdOf>) -> Option> { - self.chains - .get(&chain_id.to_string()) - .cloned() - .map(|chain| chain.try_into().expect("chain is correct type")) - } -} - -impl GetChain> for Chains { - fn get_chain(&self, chain_id: &ChainIdOf>) -> Option> { - self.chains - .get(&chain_id.to_string()) - .cloned() - .map(|chain| chain.try_into().expect("chain is correct type")) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "snake_case", tag = "chain_type")] -pub enum ChainConfigType { - Union(union::Config), - Cosmos(cosmos::Config), - Ethereum(EthereumChainConfig), - Scroll(scroll::Config), - Arbitrum(arbitrum::Config), - Berachain(berachain::Config), -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct EthereumChainConfig { - pub preset_base: PresetBaseKind, - - /// The address of the `IBCHandler` smart contract. - pub ibc_handler_address: H160, - pub multicall_address: H160, - - /// The signers that will be used to submit transactions by voyager. - pub keyring: KeyringConfig, - - // TODO(benluelo): Use `Url` or something similar - /// The RPC endpoint for the execution chain. - pub eth_rpc_api: String, - /// The RPC endpoint for the beacon chain. - pub eth_beacon_rpc_api: String, - - #[serde(default)] - pub max_gas_price: Option, -} - -#[derive(Debug, Clone, Enumorph)] -pub enum AnyChain { - Union(Union), - Cosmos(Cosmos), - EthereumMainnet(Ethereum), - EthereumMinimal(Ethereum), - Scroll(Scroll), - Arbitrum(Arbitrum), - Berachain(Berachain), -} - -impl AnyChain { - pub fn downcast + Chain>( - self, - ) -> Result { - self.try_into().map_err(|c| { - any_chain!(|c| IncorrectChainTypeError { - found_chain_name: c.chain_id().to_string(), - found_chain_type: ::ChainType::EXPECTING, - expected_chain_type: T::ChainType::EXPECTING - }) - }) - } - - pub fn chain_id(&self) -> String { - let this = self; - - any_chain!(|this| this.chain_id().to_string()) - } -} - -#[derive(Debug, Clone, PartialEq, thiserror::Error)] -#[error("chain `{found_chain_name}` is of type `{found_chain_type}` but `{expected_chain_type}` was expected")] -pub struct IncorrectChainTypeError { - pub found_chain_name: String, - pub found_chain_type: &'static str, - pub expected_chain_type: &'static str, -} - -#[macro_export] -macro_rules! any_chain { - (|$c:ident| $expr:expr) => { - match $c { - AnyChain::Union($c) => { - #[allow(dead_code)] - type Hc = $crate::union::Union; - $expr - } - AnyChain::Cosmos($c) => { - #[allow(dead_code)] - type Hc = $crate::cosmos::Cosmos; - $expr - } - AnyChain::EthereumMainnet($c) => { - #[allow(dead_code)] - type Hc = $crate::ethereum::Ethereum<::unionlabs::ethereum::config::Mainnet>; - $expr - } - AnyChain::EthereumMinimal($c) => { - #[allow(dead_code)] - type Hc = $crate::ethereum::Ethereum<::unionlabs::ethereum::config::Minimal>; - $expr - } - AnyChain::Scroll($c) => { - #[allow(dead_code)] - type Hc = $crate::scroll::Scroll; - $expr - } - AnyChain::Arbitrum($c) => { - #[allow(dead_code)] - type Hc = $crate::arbitrum::Arbitrum; - $expr - } - AnyChain::Berachain($c) => { - #[allow(dead_code)] - type Hc = $crate::berachain::Berachain; - $expr - } - } - }; -} - -#[derive(Debug, thiserror::Error)] -pub enum AnyChainTryFromConfigError { - #[error("error initializing a union chain")] - Union(#[from] UnionInitError), - #[error("error initializing a cosmos chain")] - Cosmos(#[from] CosmosInitError), - #[error("error initializing an ethereum chain")] - Ethereum(#[from] EthereumInitError), - #[error("error initializing a scroll chain")] - Scroll(#[from] ScrollInitError), - #[error("error initializing an arbitrum chain")] - Arbitrum(#[from] ArbitrumInitError), - #[error("error initializing a berachain chain")] - Berachain(#[from] BerachainInitError), -} - -impl AnyChain { - pub async fn try_from_config( - config: ChainConfigType, - ) -> Result { - Ok(match config { - ChainConfigType::Union(union) => Self::Union(Union::new(union).await?), - ChainConfigType::Cosmos(cosmos) => Self::Cosmos(Cosmos::new(cosmos).await?), - ChainConfigType::Ethereum(ethereum) => { - let config = crate::ethereum::Config { - ibc_handler_address: ethereum.ibc_handler_address, - multicall_address: ethereum.multicall_address, - keyring: ethereum.keyring, - eth_rpc_api: ethereum.eth_rpc_api, - eth_beacon_rpc_api: ethereum.eth_beacon_rpc_api, - max_gas_price: ethereum.max_gas_price, - }; - match ethereum.preset_base { - PresetBaseKind::Minimal => { - Self::EthereumMinimal(Ethereum::::new(config).await?) - } - PresetBaseKind::Mainnet => { - Self::EthereumMainnet(Ethereum::::new(config).await?) - } - } - } - ChainConfigType::Scroll(scroll) => Self::Scroll(Scroll::new(scroll).await?), - ChainConfigType::Arbitrum(arbitrum) => Self::Arbitrum(Arbitrum::new(arbitrum).await?), - ChainConfigType::Berachain(berachain) => { - Self::Berachain(Berachain::new(berachain).await?) - } - }) - } -} - -pub trait LightClientType: Chain { - /// How [`Self`] tracks [`Tr`]. - const TYPE: ClientType; -} - -impl LightClientType for Wasm { - const TYPE: ClientType = ClientType::Wasm(WasmClientType::Cometbls); -} - -impl LightClientType> for Union { - const TYPE: ClientType = ClientType::Tendermint; -} - -impl LightClientType for Union { - const TYPE: ClientType = ClientType::Tendermint; -} - -impl LightClientType for Cosmos { - const TYPE: ClientType = ClientType::_11Cometbls; -} - -impl LightClientType for Cosmos { - const TYPE: ClientType = ClientType::Tendermint; -} - -impl LightClientType> for Ethereum { - const TYPE: ClientType = ClientType::Cometbls; -} - -impl LightClientType> for Scroll { - const TYPE: ClientType = ClientType::Cometbls; -} - -impl LightClientType> for Berachain { - const TYPE: ClientType = ClientType::Cometbls; -} - -impl LightClientType for Wasm { - const TYPE: ClientType = ClientType::Wasm(WasmClientType::Scroll); -} - -impl LightClientType for Wasm { - const TYPE: ClientType = ClientType::Wasm(WasmClientType::Berachain); -} - -impl LightClientType> for Arbitrum { - const TYPE: ClientType = ClientType::Cometbls; -} - -impl LightClientType for Wasm { - const TYPE: ClientType = ClientType::Wasm(WasmClientType::Arbitrum); -} - -impl LightClientType> for Wasm { - const TYPE: ClientType = ClientType::Wasm(WasmClientType::EthereumMainnet); -} - -impl LightClientType> for Wasm { - const TYPE: ClientType = ClientType::Wasm(WasmClientType::EthereumMinimal); -} +pub type BoxDynError = Box; diff --git a/lib/chain-utils/src/scroll.rs b/lib/chain-utils/src/scroll.rs index b70c58e523..08ac608895 100644 --- a/lib/chain-utils/src/scroll.rs +++ b/lib/chain-utils/src/scroll.rs @@ -1,8 +1,8 @@ -use std::{error::Error, sync::Arc}; +use std::sync::Arc; use contracts::ibc_handler::IBCHandler; use ethers::providers::{Middleware, Provider, ProviderError, Ws, WsClientError}; -use futures::{FutureExt, TryFutureExt}; +use futures::FutureExt; use scroll_api::ScrollClient; use serde::{Deserialize, Serialize}; use tracing::debug; @@ -10,20 +10,21 @@ use unionlabs::{ ethereum::config::Mainnet, google::protobuf::any::Any, hash::{H160, H256}, - ibc::{core::client::height::Height, lightclients::scroll}, - traits::{Chain, ClientIdOf, ClientState, FromStrExact}, + ibc::{ + core::client::height::Height, + lightclients::{ethereum, scroll}, + }, + id::ClientId, uint::U256, }; use crate::{ ethereum::{ - self, balance_of_signers, Ethereum, EthereumConsensusChain, EthereumIbcChain, - EthereumInitError, EthereumKeyring, EthereumSignerMiddleware, EthereumSignersConfig, - ReadWrite, Readonly, + balance_of_signers, Ethereum, EthereumConsensusChain, EthereumIbcChain, EthereumKeyring, + EthereumSignerMiddleware, EthereumSignersConfig, ReadWrite, Readonly, }, keyring::{ChainKeyring, ConcurrentKeyring, KeyringConfig, SignerBalance}, - union::Union, - wasm::Wasm, + BoxDynError, }; pub const SCROLL_REVISION_NUMBER: u64 = 0; @@ -55,7 +56,7 @@ pub struct Scroll { /// [ScrollChain.committedBatches](https://github.com/scroll-tech/scroll/blob/71f88b04f5a69196138c8cec63a75cf1f0ba2d99/contracts/src/L1/rollup/ScrollChain.sol#L156) pub rollup_committed_batches_slot: U256, - pub l1_client_id: ClientIdOf>, + pub l1_client_id: ClientId, /// GRPC url of Union, used to query the L1 state with [`Self::l1_client_id`]. pub union_grpc_url: String, } @@ -78,8 +79,8 @@ pub struct Config { pub rollup_message_queue_slot: U256, pub rollup_committed_batches_slot: U256, - pub l1_client_id: ClientIdOf>, - pub l1: ethereum::Config, + pub l1_client_id: ClientId, + pub l1: crate::ethereum::Config, pub scroll_api: String, pub union_grpc_url: String, } @@ -148,8 +149,8 @@ impl EthereumConsensusChain for Scroll { #[derive(Debug, thiserror::Error)] pub enum ScrollInitError { - #[error("unable to initialize L1")] - Ethereum(#[from] EthereumInitError), + // #[error("unable to initialize L1")] + // Ethereum(#[from] EthereumInitError), #[error("unable to connect to websocket")] Ws(#[from] WsClientError), #[error("provider error")] @@ -176,7 +177,9 @@ impl Scroll { multicall_address: config.multicall_address, provider: Arc::new(provider), scroll_api_client: ScrollClient::new(config.scroll_api), - l1: Ethereum::new(config.l1).await?, + l1: todo!(), + // l1: Ethereum::new(config.l1).await?, + #[allow(unreachable_code)] rollup_contract_address: config.rollup_contract_address, rollup_finalized_state_roots_slot: config.rollup_finalized_state_roots_slot, rollup_last_finalized_batch_index_slot: config.rollup_last_finalized_batch_index_slot, @@ -230,42 +233,13 @@ impl Scroll { } } -#[derive(Debug, Clone, PartialEq, Default)] -pub struct ScrollChainType; -impl FromStrExact for ScrollChainType { - const EXPECTING: &'static str = "scroll"; -} - -type BoxDynError = Box; - -impl Chain for Scroll { - type ChainType = ScrollChainType; - - type SelfClientState = scroll::client_state::ClientState; - type SelfConsensusState = scroll::consensus_state::ConsensusState; - - type StoredClientState = as Chain>::StoredClientState; - type StoredConsensusState = as Chain>::StoredConsensusState; - - type Header = scroll::header::Header; - - type Height = as Chain>::Height; - - type ClientId = as Chain>::ClientId; - - type IbcStateEncoding = as Chain>::IbcStateEncoding; - - type StateProof = as Chain>::StateProof; - - type ClientType = String; - - type Error = BoxDynError; - - fn chain_id(&self) -> ::ChainId { +#[allow(dead_code)] +impl Scroll { + fn chain_id(&self) -> U256 { self.chain_id } - async fn query_latest_height(&self) -> Result { + async fn query_latest_height(&self) -> Result { // the latest height of scroll is the latest height of the l1 light client on union let l1_client_state = protos::ibc::core::client::v1::query_client::QueryClient::connect( self.union_grpc_url.clone(), @@ -280,29 +254,32 @@ impl Chain for Scroll { .ok_or("client state missing???")?; // don't worry about it - let Any(l1_client_state) = - < as Chain>::StoredClientState>>::try_from( - l1_client_state, - ) - .unwrap(); + let Any(_l1_client_state) = , + >>::try_from(l1_client_state) + .unwrap(); - Ok(self.l1.make_height(l1_client_state.data.latest_slot)) - } + // Ok(self.l1.make_height(l1_client_state.data.latest_slot)) - async fn query_latest_height_as_destination(&self) -> Result { - // the height of scroll (as destination) is the beacon height of the l1 - self.l1 - .query_latest_height_as_destination() - .await - .map_err(Into::into) + todo!() } - // FIXME: must be scroll timestamp, not L1 - async fn query_latest_timestamp(&self) -> Result { - self.l1.query_latest_timestamp().map_err(Into::into).await - } + // async fn query_latest_height_as_destination(&self) -> Result { + // // the height of scroll (as destination) is the beacon height of the l1 + // self.l1 + // .query_latest_height_as_destination() + // .await + // .map_err(Into::into) + // } - async fn self_client_state(&self, height: Self::Height) -> Self::SelfClientState { + // // FIXME: must be scroll timestamp, not L1 + // async fn query_latest_timestamp(&self) -> Result { + // self.l1.query_latest_timestamp().map_err(Into::into).await + // } + + async fn self_client_state(&self, height: Height) -> scroll::client_state::ClientState { scroll::client_state::ClientState { l1_client_id: self.l1_client_id.to_string(), chain_id: self.chain_id(), @@ -321,7 +298,10 @@ impl Chain for Scroll { } } - async fn self_consensus_state(&self, height: Self::Height) -> Self::SelfConsensusState { + async fn self_consensus_state( + &self, + height: Height, + ) -> scroll::consensus_state::ConsensusState { let batch_index = self .batch_index_of_beacon_slot(height.revision_height) .await; diff --git a/lib/chain-utils/src/union.rs b/lib/chain-utils/src/union.rs index 8e55e42729..2baf18bbca 100644 --- a/lib/chain-utils/src/union.rs +++ b/lib/chain-utils/src/union.rs @@ -5,16 +5,7 @@ use ethers::prelude::k256::ecdsa; use serde::{Deserialize, Serialize}; use tendermint_rpc::{Client, WebSocketClient, WebSocketClientUrl}; use unionlabs::{ - encoding::Proto, - google::protobuf::any::Any, - hash::H256, - ibc::{ - core::{client::height::Height, commitment::merkle_root::MerkleRoot}, - lightclients::cometbls, - }, - id::ClientId, - signer::CosmosSigner, - traits::{Chain, ClientState, FromStrExact}, + hash::H256, ibc::core::client::height::Height, id::ClientId, signer::CosmosSigner, WasmClientType, }; @@ -47,7 +38,6 @@ pub struct Config { impl ChainKeyring for Union { type Address = String; - type Signer = CosmosSigner; fn keyring(&self) -> &ConcurrentKeyring { @@ -64,137 +54,6 @@ impl ChainKeyring for Union { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct UnionChainType; - -impl FromStrExact for UnionChainType { - const EXPECTING: &'static str = "union"; -} - -impl Chain for Union { - type ChainType = UnionChainType; - type SelfClientState = cometbls::client_state::ClientState; - type SelfConsensusState = cometbls::consensus_state::ConsensusState; - - type StoredClientState = Any; - type StoredConsensusState = Any; - - type Header = cometbls::header::Header; - - type Height = Height; - - type ClientId = UnionClientId; - - type ClientType = String; - - type Error = tendermint_rpc::Error; - - type IbcStateEncoding = Proto; - - type StateProof = unionlabs::union::ics23::merkle_proof::MerkleProof; - - fn chain_id(&self) -> ::ChainId { - self.chain_id.clone() - } - - async fn query_latest_height(&self) -> Result { - self.tm_client - .latest_block() - .await - .map(|response| self.make_height(response.block.header.height.value())) - } - - async fn query_latest_height_as_destination(&self) -> Result { - self.query_latest_height().await - } - - async fn query_latest_timestamp(&self) -> Result { - self.tm_client - .latest_block() - .await - .map(|response| response.block.header.time.unix_timestamp()) - } - - async fn self_client_state(&self, height: Height) -> Self::SelfClientState { - let params = protos::cosmos::staking::v1beta1::query_client::QueryClient::connect( - self.grpc_url.clone(), - ) - .await - .unwrap() - .params(protos::cosmos::staking::v1beta1::QueryParamsRequest {}) - .await - .unwrap() - .into_inner() - .params - .unwrap(); - - let commit = self - .tm_client - .commit(u32::try_from(height.revision_height).unwrap()) - .await - .unwrap(); - - let height = commit.signed_header.header.height; - - // Expected to be nanos - let unbonding_period = - u64::try_from(params.unbonding_time.clone().unwrap().seconds).unwrap() * 1_000_000_000; - - cometbls::client_state::ClientState { - chain_id: self.chain_id.clone(), - // https://github.com/cosmos/relayer/blob/23d1e5c864b35d133cad6a0ef06970a2b1e1b03f/relayer/chains/cosmos/provider.go#L177 - trusting_period: unbonding_period * 85 / 100, - unbonding_period, - // https://github.com/cosmos/relayer/blob/23d1e5c864b35d133cad6a0ef06970a2b1e1b03f/relayer/chains/cosmos/provider.go#L177 - max_clock_drift: (60 * 20) * 1_000_000_000, - frozen_height: Height { - revision_number: 0, - revision_height: 0, - }, - latest_height: Height { - revision_number: self.chain_id.split('-').last().unwrap().parse().unwrap(), - revision_height: height.value(), - }, - } - } - - async fn self_consensus_state(&self, height: Height) -> Self::SelfConsensusState { - let commit = self - .tm_client - .commit(u32::try_from(height.revision_height).unwrap()) - .await - .unwrap(); - - cometbls::consensus_state::ConsensusState { - timestamp: commit - .signed_header - .header - .time - .unix_timestamp_nanos() - .try_into() - .unwrap(), - app_hash: MerkleRoot { - hash: commit - .signed_header - .header - .app_hash - .as_bytes() - .to_vec() - .try_into() - .unwrap(), - }, - next_validators_hash: commit - .signed_header - .header - .next_validators_hash - .as_bytes() - .to_vec() - .try_into() - .unwrap(), - } - } -} - #[derive(Debug, thiserror::Error)] pub enum UnionInitError { #[error("tendermint rpc error")] @@ -202,7 +61,6 @@ pub enum UnionInitError { #[error( "unable to parse chain id: expected format `-`, found `{found}`" )] - // TODO: Once the `Id` trait in unionlabs is cleaned up to no longer use static id types, this error should just wrap `IdParseError` ChainIdParse { found: String, #[source] diff --git a/lib/chain-utils/src/wasm.rs b/lib/chain-utils/src/wasm.rs deleted file mode 100644 index a6cbd4addf..0000000000 --- a/lib/chain-utils/src/wasm.rs +++ /dev/null @@ -1,167 +0,0 @@ -use std::{marker::PhantomData, sync::Arc}; - -use frame_support_procedural::DefaultNoBound; -use futures::Future; -use tendermint_rpc::WebSocketClient; -use unionlabs::{ - encoding::Proto, - google::protobuf::any::Any, - hash::H256, - iter, - traits::{Chain, FromStrExact}, - WasmClientType, -}; - -use crate::{ - cosmos_sdk::{CosmosSdkChain, CosmosSdkChainRpcs, GasConfig}, - keyring::{ChainKeyring, ConcurrentKeyring, SignerBalance}, -}; - -#[derive(Debug, Clone)] -pub struct Wasm(pub C); - -pub trait Wraps: Chain { - fn inner(&self) -> &T; -} - -impl CosmosSdkChain for Wasm { - fn checksum_cache(&self) -> &Arc> { - self.0.checksum_cache() - } -} - -impl CosmosSdkChainRpcs for Wasm { - fn tm_chain_id(&self) -> String { - self.0.tm_chain_id() - } - - fn gas_config(&self) -> &GasConfig { - self.0.gas_config() - } - - fn grpc_url(&self) -> String { - self.0.grpc_url().clone() - } - - fn tm_client(&self) -> &WebSocketClient { - self.0.tm_client() - } -} - -impl Wraps for T { - fn inner(&self) -> &T { - self - } -} - -impl Wraps for Wasm -where - Wasm: Chain, -{ - fn inner(&self) -> &T { - &self.0 - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, DefaultNoBound)] -pub struct WasmChainType(PhantomData Hc>); - -impl FromStrExact for WasmChainType { - const EXPECTING: &'static str = { - match core::str::from_utf8( - const { - let mut buf = [0_u8; 32]; - - iter! { - for (i, b) in enumerate(b"wasm-") { - buf[i] = b; - } - } - - iter! { - for (i, b) in enumerate(Hc::ChainType::EXPECTING.as_bytes()) { - buf[5 + i] = b; - } - } - - buf - } - .split_at(5 + Hc::ChainType::EXPECTING.len()) - .0, - ) { - Ok(ok) => ok, - Err(_) => panic!("called `Result::unwrap()` on an `Err` value"), - } - }; -} - -impl ChainKeyring for Wasm { - type Address = Hc::Address; - - type Signer = Hc::Signer; - - fn keyring(&self) -> &ConcurrentKeyring { - self.0.keyring() - } - - fn balances(&self) -> impl Future>> { - self.0.balances() - } -} - -impl Chain for Wasm { - type ChainType = WasmChainType; - - type SelfClientState = Hc::SelfClientState; - type SelfConsensusState = Hc::SelfConsensusState; - type Header = Hc::Header; - - type StoredClientState = - Any>; - type StoredConsensusState = Any< - unionlabs::ibc::lightclients::wasm::consensus_state::ConsensusState, - >; - - type Height = Hc::Height; - - type ClientId = Hc::ClientId; - type ClientType = Hc::ClientType; - - type Error = Hc::Error; - - type IbcStateEncoding = Proto; - - type StateProof = Hc::StateProof; - - fn chain_id(&self) -> ::ChainId { - self.0.chain_id() - } - - fn query_latest_height(&self) -> impl Future> + '_ { - self.0.query_latest_height() - } - - fn query_latest_height_as_destination( - &self, - ) -> impl Future> + '_ { - self.0.query_latest_height_as_destination() - } - - fn query_latest_timestamp(&self) -> impl Future> + '_ { - self.0.query_latest_timestamp() - } - - fn self_client_state( - &self, - height: Self::Height, - ) -> impl Future + '_ { - self.0.self_client_state(height) - } - - fn self_consensus_state( - &self, - height: Self::Height, - ) -> impl Future + '_ { - self.0.self_consensus_state(height) - } -} diff --git a/lib/cometbft-rpc/Cargo.toml b/lib/cometbft-rpc/Cargo.toml index ce2c134bf7..e62cd653ea 100644 --- a/lib/cometbft-rpc/Cargo.toml +++ b/lib/cometbft-rpc/Cargo.toml @@ -9,17 +9,20 @@ version = "0.1.0" workspace = true [dependencies] -hex.workspace = true -jsonrpsee = { version = "0.22.3", features = ["tracing", "ws-client"] } -macros = { workspace = true } -protos.workspace = true -serde = { workspace = true, features = ["derive"] } -serde-utils = { workspace = true } -thiserror.workspace = true -tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] } -tracing.workspace = true -unionlabs = { workspace = true } +base64 = { workspace = true } +hex = { workspace = true } +jsonrpsee = { workspace = true, features = ["tracing", "ws-client", "http-client"] } +macros = { workspace = true } +protos = { workspace = true } +reconnecting-jsonrpc-ws-client = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +thiserror = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] } +unionlabs = { workspace = true } [dev-dependencies] -serde_json = "1.0.114" -tokio = { workspace = true, features = ["macros"] } +hex-literal = "0.4.1" +serde_json = "1.0.114" +tokio = { workspace = true, features = ["macros"] } diff --git a/lib/cometbft-rpc/src/lib.rs b/lib/cometbft-rpc/src/lib.rs index 0389119de1..43e5701703 100644 --- a/lib/cometbft-rpc/src/lib.rs +++ b/lib/cometbft-rpc/src/lib.rs @@ -1,43 +1,76 @@ -use std::{fmt::Debug, num::NonZeroU64, sync::Arc}; +use core::fmt; +use std::{ + fmt::Debug, + num::{NonZeroU32, NonZeroU64, NonZeroU8}, + time::Duration, +}; +use ::serde::de::DeserializeOwned; use jsonrpsee::{ - core::client::ClientT, + core::{ + async_trait, + client::{BatchResponse, ClientT}, + params::BatchRequestBuilder, + traits::ToRpcParams, + }, + http_client::{HttpClient, HttpClientBuilder}, rpc_params, - ws_client::{WsClient, WsClientBuilder}, + ws_client::{PingConfig, WsClientBuilder}, }; -use serde::{de, Deserialize, Deserializer, Serialize}; -use tracing::debug; +use tracing::{debug, debug_span, instrument, Instrument}; use unionlabs::{ - bounded::BoundedU8, - google::protobuf::timestamp::Timestamp, - hash::{H160, H256}, + bounded::{BoundedI64, BoundedU8}, + hash::H256, option_unwrap, result_unwrap, - tendermint::{ - abci::response_query::ResponseQuery, - crypto::public_key::PublicKey, - p2p::default_node_info::DefaultNodeInfo, - types::{ - block::Block, block_id::BlockId, signed_header::SignedHeader, validator::Validator, - }, - }, }; +use crate::types::{ + AbciQueryResponse, AllValidatorsResponse, BlockResponse, BroadcastTxSyncResponse, + CommitResponse, Order, StatusResponse, TxResponse, TxSearchResponse, +}; + +pub mod serde; +pub mod types; + +pub type JsonRpcError = jsonrpsee::core::client::Error; + #[derive(Debug, Clone)] pub struct Client { - client: Arc, + inner: ClientInner, } -pub type JsonRpcError = jsonrpsee::core::client::Error; - impl Client { pub async fn new(url: impl AsRef) -> Result { - Ok(Self { - client: Arc::new(WsClientBuilder::default().build(url).await?), - }) + let url = url.as_ref().to_owned(); + + let inner = match url.split_once("://") { + Some(("ws" | "wss", _)) => { + let client = reconnecting_jsonrpc_ws_client::Client::new(move || { + WsClientBuilder::default() + .enable_ws_ping(PingConfig::new()) + .build(url.clone()) + .instrument(debug_span!("cometbft_rpc_client", %url)) + }); + + // TODO: Config + client + .wait_until_connected(Duration::from_secs(5)) + .await + .map_err(|e| JsonRpcError::Custom(e.to_string()))?; + + ClientInner::Ws(client) + } + Some(("http" | "https", _)) => { + ClientInner::Http(HttpClientBuilder::default().build(url)?) + } + _ => return Err(JsonRpcError::Custom(format!("invalid url {url}"))), + }; + + Ok(Self { inner }) } pub async fn commit(&self, height: Option) -> Result { - self.client + self.inner .request("commit", (height.map(|x| x.to_string()),)) .await } @@ -45,9 +78,9 @@ impl Client { pub async fn validators( &self, height: Option, - pagination: Option, - ) -> Result { - self.client + pagination: Option, + ) -> Result { + self.inner .request( "validators", ( @@ -71,7 +104,7 @@ impl Client { let mut out = vec![]; loop { - let ValidatorsResponse { + let types::ValidatorsResponse { block_height, validators, count: _, @@ -79,7 +112,7 @@ impl Client { } = self .validators( height, - Some(ValidatorsPagination { + Some(types::ValidatorsPagination { page, per_page: Some(PER_PAGE), }), @@ -104,28 +137,36 @@ impl Client { } // would be cool to somehow have this be generic and do decoding automatically + #[instrument( + skip_all, + fields( + path = %path.as_ref(), + data = %::serde_utils::to_hex(data.as_ref()), + height = %height.map(|x| x.to_string()).as_deref().unwrap_or(""), + %prove, + ) + )] pub async fn abci_query( &self, path: impl AsRef, data: impl AsRef<[u8]>, - height: Option, + height: Option>, prove: bool, ) -> Result { - let path = path.as_ref(); - let height = height.map(|x| x.to_string()); - - debug!( - %path, - data = %::serde_utils::to_hex(data.as_ref()), - height = %height.as_deref().unwrap_or(""), - %prove, - "fetching abci query" - ); + debug!("fetching abci query"); let res: AbciQueryResponse = self - .client + .inner // the rpc needs an un-prefixed hex string - .request("abci_query", (path, hex::encode(data), height, prove)) + .request( + "abci_query", + ( + path.as_ref(), + hex::encode(data), + height.map(|x| x.to_string()), + prove, + ), + ) .await?; debug!( @@ -143,133 +184,111 @@ impl Client { Ok(res) } - // would be cool to somehow have this be generic and do decoding automatically pub async fn status(&self) -> Result { - self.client.request("status", rpc_params!()).await + self.inner.request("status", rpc_params!()).await } pub async fn block(&self, height: Option) -> Result { - self.client + self.inner .request("block", (height.map(|x| x.to_string()),)) .await } -} -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct BlockResponse { - #[serde(deserialize_with = "serde_as::<_, protos::tendermint::types::BlockId, _>")] - pub block_id: BlockId, - #[serde(deserialize_with = "serde_as::<_, protos::tendermint::types::Block, _>")] - pub block: Block, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct StatusResponse { - #[serde(deserialize_with = "serde_as::<_, protos::tendermint::p2p::DefaultNodeInfo, _>")] - pub node_info: DefaultNodeInfo, - pub sync_info: SyncInfo, - pub validator_info: ValidatorInfo, -} + pub async fn tx_search( + &self, + query: impl AsRef, + prove: bool, + page: NonZeroU32, + // REVIEW: Is this bounded in the same way as the validators pagination? + per_page: NonZeroU8, + // REVIEW: There is the enum `cosmos.tx.v1beta.OrderBy`, is that related to this? + order_by: Order, + ) -> Result { + self.inner + .request( + "tx_search", + rpc_params![ + query.as_ref(), + prove, + page.to_string(), + per_page.to_string(), + order_by + ], + ) + .await + } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct SyncInfo { - catching_up: bool, - #[serde(with = "::serde_utils::hex_allow_unprefixed")] - earliest_app_hash: H256, - #[serde(with = "::serde_utils::hex_allow_unprefixed")] - earliest_block_hash: H256, - #[serde(with = "::serde_utils::string")] - earliest_block_height: u64, - earliest_block_time: Timestamp, - #[serde(with = "::serde_utils::hex_allow_unprefixed")] - latest_app_hash: H256, - #[serde(with = "::serde_utils::hex_allow_unprefixed")] - latest_block_hash: H256, - #[serde(with = "::serde_utils::string")] - latest_block_height: u64, - latest_block_time: Timestamp, -} + // TODO: support order_by + pub async fn tx(&self, hash: H256, prove: bool) -> Result { + use base64::prelude::*; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct ValidatorInfo { - #[serde(with = "::serde_utils::hex_allow_unprefixed")] - pub address: H160, - #[serde(deserialize_with = "serde_as::<_, protos::tendermint::crypto::PublicKey, _>")] - pub pub_key: PublicKey, - // REVIEW: is this bounded the same way as Validator? - #[serde(with = "::serde_utils::string")] - pub voting_power: i64, -} + self.inner + .request("tx", rpc_params![BASE64_STANDARD.encode(hash), prove]) + .await + } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct ValidatorsResponse { - #[serde(with = "::serde_utils::string")] - pub block_height: NonZeroU64, - #[serde(deserialize_with = "serde_as_list::<_, protos::tendermint::types::Validator, _>")] - pub validators: Vec, - #[serde(with = "::serde_utils::string")] - pub count: u64, - #[serde(with = "::serde_utils::string")] - pub total: u64, -} + pub async fn broadcast_tx_sync( + &self, + tx: &[u8], + ) -> Result { + use base64::prelude::*; -#[derive(Debug, Clone, PartialEq)] -pub struct AllValidatorsResponse { - pub block_height: NonZeroU64, - pub validators: Vec, -} + self.inner + .request("broadcast_tx_sync", rpc_params![BASE64_STANDARD.encode(tx)]) + .await + } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct ValidatorsPagination { - page: NonZeroU64, - // :] - per_page: Option>, + // pub async fn block_results( + // &self, + // height: Option>, + // ) -> Result { + // self.client + // .request("block_results", rpc_params![height.map(|x| x.to_string())]) + // .await + // } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct AbciQueryResponse { - #[serde(deserialize_with = "serde_as::<_, protos::tendermint::abci::ResponseQuery, _>")] - pub response: ResponseQuery, +#[derive(Debug, Clone)] +enum ClientInner { + Http(HttpClient), + Ws(reconnecting_jsonrpc_ws_client::Client), } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct CommitResponse { - #[serde(deserialize_with = "serde_as::<_, protos::tendermint::types::SignedHeader, _>")] - pub signed_header: SignedHeader, - pub canonical: bool, -} +#[async_trait] +impl ClientT for ClientInner { + async fn notification(&self, method: &str, params: Params) -> Result<(), JsonRpcError> + where + Params: ToRpcParams + Send, + { + match self { + ClientInner::Http(client) => client.notification(method, params).await, + ClientInner::Ws(client) => client.notification(method, params).await, + } + } -pub fn serde_as<'de, D, Src, Dst>(deserializer: D) -> Result -where - D: Deserializer<'de>, - Src: Deserialize<'de>, - Src: TryInto, -{ - Src::deserialize(deserializer)? - .try_into() - .map_err(|e| de::Error::custom(format!("{e:?}"))) -} + async fn request(&self, method: &str, params: Params) -> Result + where + R: DeserializeOwned, + Params: ToRpcParams + Send, + { + match self { + ClientInner::Http(client) => client.request(method, params).await, + ClientInner::Ws(client) => client.request(method, params).await, + } + } -pub fn serde_as_list<'de, D, Src, Dst>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, - Src: Deserialize<'de>, - Src: TryInto, -{ - >::deserialize(deserializer)? - .into_iter() - .map(|x| { - x.try_into() - .map_err(|e| de::Error::custom(format!("{e:?}"))) - }) - .collect() + async fn batch_request<'a, R>( + &self, + batch: BatchRequestBuilder<'a>, + ) -> Result, JsonRpcError> + where + R: DeserializeOwned + fmt::Debug + 'a, + { + match self { + ClientInner::Http(client) => client.batch_request(batch).await, + ClientInner::Ws(client) => client.batch_request(batch).await, + } + } } // These tests are useful in testing and debugging, but should not be run in CI @@ -277,9 +296,11 @@ where // mod tests { // use std::time::Duration; +// use hex_literal::hex; + // use super::*; -// const UNION_TESTNET: &'static str = "wss://rpc.testnet.bonlulu.uno/websocket"; +// const UNION_TESTNET: &'static str = "wss://rpc.testnet-8.union.build/websocket"; // const BERACHAIN_DEVNET: &'static str = "ws://localhost:26657/websocket"; // const BERACHAIN_TESTNET: &'static str = "wss://bartio-cosmos.berachain-devnet.com/websocket"; // const OSMOSIS_TESTNET: &'static str = "wss://osmosis-rpc.publicnode.com/websocket"; @@ -308,7 +329,7 @@ where // ) // .await; -// dbg!(result); +// bg!(result); // } // #[tokio::test] @@ -372,4 +393,21 @@ where // tokio::time::sleep(Duration::from_millis(100)).await; // } // } + +// #[tokio::test] +// async fn tx() { +// let _ = tracing_subscriber::fmt().try_init(); + +// let client = Client::new(UNION_TESTNET).await.unwrap(); + +// let result = client +// .tx( +// hex!("32DAD1842DF0441870B168D0C177F8EEC156B18B32D88C3658349BE07F352CCA").into(), +// true, +// ) +// .await +// .unwrap(); + +// dbg!(result); +// } // } diff --git a/lib/cometbft-rpc/src/serde.rs b/lib/cometbft-rpc/src/serde.rs new file mode 100644 index 0000000000..dfcba1c385 --- /dev/null +++ b/lib/cometbft-rpc/src/serde.rs @@ -0,0 +1,43 @@ +use std::fmt::Debug; + +use serde::{de, Deserialize, Deserializer}; + +pub fn serde_as<'de, D, Src, Dst>(deserializer: D) -> Result +where + D: Deserializer<'de>, + Src: Deserialize<'de>, + Src: TryInto, +{ + Src::deserialize(deserializer)? + .try_into() + .map_err(|e| de::Error::custom(format!("{e:?}"))) +} + +pub fn serde_as_opt<'de, D, Src, Dst>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, + Src: Deserialize<'de>, + Src: TryInto, +{ + >::deserialize(deserializer)? + .map(|src| { + src.try_into() + .map_err(|e| de::Error::custom(format!("{e:?}"))) + }) + .transpose() +} + +pub fn serde_as_list<'de, D, Src, Dst>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, + Src: Deserialize<'de>, + Src: TryInto, +{ + >::deserialize(deserializer)? + .into_iter() + .map(|x| { + x.try_into() + .map_err(|e| de::Error::custom(format!("{e:?}"))) + }) + .collect() +} diff --git a/lib/cometbft-rpc/src/types.rs b/lib/cometbft-rpc/src/types.rs new file mode 100644 index 0000000000..3a4c0c3c35 --- /dev/null +++ b/lib/cometbft-rpc/src/types.rs @@ -0,0 +1,163 @@ +use std::num::NonZeroU64; + +use serde::{Deserialize, Serialize}; +use unionlabs::{ + bounded::BoundedU8, + google::protobuf::timestamp::Timestamp, + hash::{H160, H256}, + tendermint::{ + abci::{exec_tx_result::ExecTxResult, response_query::ResponseQuery}, + crypto::public_key::PublicKey, + p2p::default_node_info::DefaultNodeInfo, + types::{ + block::Block, block_id::BlockId, signed_header::SignedHeader, tx_proof::TxProof, + validator::Validator, + }, + }, +}; + +use crate::serde::{serde_as, serde_as_list, serde_as_opt}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields, rename_all = "snake_case")] +pub enum Order { + Asc, + Desc, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct BlockResponse { + #[serde(deserialize_with = "serde_as::<_, protos::tendermint::types::BlockId, _>")] + pub block_id: BlockId, + #[serde(deserialize_with = "serde_as::<_, protos::tendermint::types::Block, _>")] + pub block: Block, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct StatusResponse { + #[serde(deserialize_with = "serde_as::<_, protos::tendermint::p2p::DefaultNodeInfo, _>")] + pub node_info: DefaultNodeInfo, + pub sync_info: SyncInfo, + pub validator_info: ValidatorInfo, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct SyncInfo { + pub(crate) catching_up: bool, + #[serde(with = "::serde_utils::hex_allow_unprefixed_maybe_empty")] + pub(crate) earliest_app_hash: Option, + #[serde(with = "::serde_utils::hex_allow_unprefixed_maybe_empty")] + pub(crate) earliest_block_hash: Option, + #[serde(with = "::serde_utils::string")] + pub(crate) earliest_block_height: u64, + pub(crate) earliest_block_time: Timestamp, + #[serde(with = "::serde_utils::hex_allow_unprefixed")] + pub(crate) latest_app_hash: H256, + #[serde(with = "::serde_utils::hex_allow_unprefixed")] + pub(crate) latest_block_hash: H256, + #[serde(with = "::serde_utils::string")] + pub(crate) latest_block_height: u64, + pub(crate) latest_block_time: Timestamp, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ValidatorInfo { + #[serde(with = "::serde_utils::hex_allow_unprefixed")] + pub address: H160, + #[serde(deserialize_with = "serde_as::<_, protos::tendermint::crypto::PublicKey, _>")] + pub pub_key: PublicKey, + // REVIEW: is this bounded the same way as Validator? + #[serde(with = "::serde_utils::string")] + pub voting_power: i64, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct ValidatorsResponse { + #[serde(with = "::serde_utils::string")] + pub block_height: NonZeroU64, + #[serde(deserialize_with = "serde_as_list::<_, protos::tendermint::types::Validator, _>")] + pub validators: Vec, + #[serde(with = "::serde_utils::string")] + pub count: u64, + #[serde(with = "::serde_utils::string")] + pub total: u64, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct AllValidatorsResponse { + pub block_height: NonZeroU64, + pub validators: Vec, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ValidatorsPagination { + pub page: NonZeroU64, + // :] + pub per_page: Option>, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct AbciQueryResponse { + #[serde(deserialize_with = "serde_as::<_, protos::tendermint::abci::ResponseQuery, _>")] + pub response: ResponseQuery, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct CommitResponse { + #[serde(deserialize_with = "serde_as::<_, protos::tendermint::types::SignedHeader, _>")] + pub signed_header: SignedHeader, + pub canonical: bool, +} + +#[derive(macros::Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct TxResponse { + #[serde(with = "::serde_utils::hex_allow_unprefixed")] + pub hash: H256, + // review: is this really optional? + #[serde(with = "::serde_utils::string_opt")] + pub height: Option, + pub index: u32, + #[serde(deserialize_with = "serde_as::<_, protos::tendermint::abci::ExecTxResult, _>")] + pub tx_result: ExecTxResult, + #[serde(with = "::serde_utils::base64")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub tx: Vec, + #[serde( + default, + deserialize_with = "serde_as_opt::<_, protos::tendermint::types::TxProof, _>" + )] + pub proof: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct TxSearchResponse { + pub txs: Vec, + #[serde(with = "::serde_utils::string")] + pub total_count: u32, +} + +#[derive(macros::Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct BroadcastTxSyncResponse { + pub codespace: String, + + pub code: u32, + + #[serde(with = "::serde_utils::base64")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub data: Vec, + + pub log: String, + + #[serde(with = "::serde_utils::hex_allow_unprefixed")] + pub hash: H256, +} diff --git a/lib/ethereum-verifier/src/error.rs b/lib/ethereum-verifier/src/error.rs index b73022b292..a06ac3c15e 100644 --- a/lib/ethereum-verifier/src/error.rs +++ b/lib/ethereum-verifier/src/error.rs @@ -42,11 +42,38 @@ pub enum Error { #[error("expected next sync committee to be provided since `update_period > current_period`")] ExpectedNextSyncCommittee, #[error( - "irrelevant update since the order of the slots in the update data, and stored data is not correct" + "irrelevant update since the order of the slots in the update data, and stored data is not correct. \ + either the update_attested_slot (found {update_attested_slot}) must be > the trusted_finalized_slot \ + (found {trusted_finalized_slot}) or if it is not, then the update_attested_period \ + (found {update_attested_period}) must be the same as the store_period (found {stored_period}) and \ + the update_sync_committee must be set (was set: {update_sync_committee_is_set}) and the trusted \ + next_sync_committee must be unset (was set: {trusted_next_sync_committee_is_set})" )] - IrrelevantUpdate, - #[error("the order of the slots in the update data and stored data is not correct")] - InvalidSlots, + IrrelevantUpdate { + update_attested_slot: u64, + trusted_finalized_slot: u64, + update_attested_period: u64, + stored_period: u64, + update_sync_committee_is_set: bool, + trusted_next_sync_committee_is_set: bool, + }, + #[error( + "(update_signature_slot > update_attested_slot >= update_finalized_slot) must hold, \ + found: ({update_signature_slot} > {update_attested_slot} >= {update_finalized_slot})" + )] + InvalidSlots { + update_signature_slot: u64, + update_attested_slot: u64, + update_finalized_slot: u64, + }, + #[error( + "update slot {update_signature_slot} is more recent than the \ + calculated current slot {current_slot}" + )] + UpdateMoreRecentThanCurrentSlot { + current_slot: u64, + update_signature_slot: u64, + }, #[error( "signature period ({signature_period}) must be equal to `store_period` \ ({stored_period}) or `store_period + 1` when the next sync committee is stored" diff --git a/lib/ethereum-verifier/src/utils.rs b/lib/ethereum-verifier/src/utils.rs index 8b24213db5..6a2f9c7aac 100644 --- a/lib/ethereum-verifier/src/utils.rs +++ b/lib/ethereum-verifier/src/utils.rs @@ -3,11 +3,12 @@ use ssz::{types::BitVector, Ssz}; use typenum::Unsigned; use unionlabs::{ ethereum::{ + beacon::{fork_data::ForkData, signing_data::SigningData}, config::{ EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SECONDS_PER_SLOT, SLOTS_PER_EPOCH, SYNC_COMMITTEE_SIZE, }, - Domain, DomainType, ForkData, SigningData, Version, + Domain, DomainType, Version, }, hash::H256, ibc::lightclients::ethereum::fork_parameters::ForkParameters, @@ -184,7 +185,10 @@ pub fn validate_merkle_branch<'a>( #[allow(clippy::redundant_clone)] mod tests { - use unionlabs::ethereum::config::{Minimal, SEPOLIA}; + use unionlabs::ethereum::{ + beacon::signing_data::SigningData, + config::{Minimal, SEPOLIA}, + }; use super::*; diff --git a/lib/ethereum-verifier/src/verify.rs b/lib/ethereum-verifier/src/verify.rs index 903bf02ca1..be8381410f 100644 --- a/lib/ethereum-verifier/src/verify.rs +++ b/lib/ethereum-verifier/src/verify.rs @@ -94,10 +94,21 @@ pub fn validate_light_client_update( )?; ensure( - current_slot >= update.signature_slot - && update.signature_slot > update_attested_slot + current_slot >= update.signature_slot, + Error::UpdateMoreRecentThanCurrentSlot { + current_slot, + update_signature_slot: update.signature_slot, + }, + )?; + + ensure( + update.signature_slot > update_attested_slot && update_attested_slot >= update_finalized_slot, - Error::InvalidSlots, + Error::InvalidSlots { + update_signature_slot: update.signature_slot, + update_attested_slot, + update_finalized_slot, + }, )?; // Let's say N is the signature period of the header we store, we can only do updates with @@ -143,7 +154,14 @@ pub fn validate_light_client_update( || (update_attested_period == stored_period && update.next_sync_committee.is_some() && ctx.next_sync_committee().is_none()), - Error::IrrelevantUpdate, + Error::IrrelevantUpdate { + update_attested_slot, + trusted_finalized_slot: ctx.finalized_slot(), + update_attested_period, + stored_period, + update_sync_committee_is_set: update.next_sync_committee.is_some(), + trusted_next_sync_committee_is_set: ctx.next_sync_committee().is_some(), + }, )?; // Verify that the `finality_branch`, if present, confirms `finalized_header` @@ -557,10 +575,13 @@ mod tests { let mut update = correct_update.clone(); update.signature_slot = u64::MAX; - assert_eq!( + assert!(matches!( do_validate_light_client_update(&ctx, update), - Err(Error::InvalidSlots) - ); + Err(Error::UpdateMoreRecentThanCurrentSlot { + current_slot: 3577248, + update_signature_slot: u64::MAX, + }) + )); // attested slot can't be bigger than the signature slot let mut update = correct_update.clone(); @@ -569,19 +590,19 @@ mod tests { SEPOLIA.fork_parameters.deneb.epoch * (SEPOLIA.preset.SLOTS_PER_EPOCH as u64) - 1; update.finalized_header.beacon.slot = before_deneb - 100; - assert_eq!( + assert!(matches!( do_validate_light_client_update(&ctx, update), - Err(Error::InvalidSlots) - ); + Err(Error::InvalidSlots { .. }) + )); // finalized slot can't be bigger than the attested slot let mut update = correct_update; update.finalized_header.beacon.slot = before_deneb; - assert_eq!( + assert!(matches!( do_validate_light_client_update(&ctx, update), - Err(Error::InvalidSlots) - ); + Err(Error::InvalidSlots { .. }) + )); } #[test] @@ -617,16 +638,16 @@ mod tests { update.next_sync_committee = None; ctx.finalized_slot = update.attested_header.beacon.slot; - assert_eq!( + assert!(matches!( do_validate_light_client_update(&ctx, update), - Err(Error::IrrelevantUpdate) - ); + Err(Error::IrrelevantUpdate { .. }) + )); // Expected stored next sync committee to be None - assert_eq!( + assert!(matches!( do_validate_light_client_update(&ctx, correct_update), - Err(Error::IrrelevantUpdate) - ); + Err(Error::IrrelevantUpdate { .. }) + )); } #[test] diff --git a/lib/gnark-key-parser/Cargo.toml b/lib/gnark-key-parser/Cargo.toml index 3c473cab60..2d9e57ad1a 100644 --- a/lib/gnark-key-parser/Cargo.toml +++ b/lib/gnark-key-parser/Cargo.toml @@ -1,9 +1,9 @@ [package] -edition.workspace = true -license-file.workspace = true -name = "gnark-key-parser" -repository.workspace = true -version = "0.1.0" +edition = { workspace = true } +license-file = { workspace = true } +name = "gnark-key-parser" +repository = { workspace = true } +version = "0.1.0" [dependencies] arith = "0.2.3" diff --git a/lib/gnark-mimc/Cargo.toml b/lib/gnark-mimc/Cargo.toml index c0c4b1fe94..024e72534d 100644 --- a/lib/gnark-mimc/Cargo.toml +++ b/lib/gnark-mimc/Cargo.toml @@ -1,9 +1,9 @@ [package] -edition.workspace = true -license-file.workspace = true -name = "gnark-mimc" -repository.workspace = true -version = "0.1.0" +edition = { workspace = true } +license-file = { workspace = true } +name = "gnark-mimc" +repository = { workspace = true } +version = "0.1.0" [dependencies] ark-bls12-377 = { version = "0.4", default-features = false, features = ["curve"] } diff --git a/lib/ibc-vm-rs/Cargo.toml b/lib/ibc-vm-rs/Cargo.toml index a20baa82f0..2b35d51788 100644 --- a/lib/ibc-vm-rs/Cargo.toml +++ b/lib/ibc-vm-rs/Cargo.toml @@ -1,20 +1,20 @@ [package] -edition.workspace = true -license-file.workspace = true -name = "ibc-vm-rs" -repository.workspace = true -version = "0.1.0" +edition = { workspace = true } +license-file = { workspace = true } +name = "ibc-vm-rs" +repository = { workspace = true } +version = "0.1.0" [dependencies] -enumorph.workspace = true -frame-support-procedural.workspace = true -hex.workspace = true -lazy_static.workspace = true -schemars = { workspace = true, features = ["derive"], optional = true } -serde-utils.workspace = true -serde.workspace = true -thiserror.workspace = true -unionlabs.workspace = true +enumorph = { workspace = true } +frame-support-procedural = { workspace = true } +hex = { workspace = true } +lazy_static = { workspace = true } +schemars = { workspace = true, features = ["derive"], optional = true } +serde = { workspace = true } +serde-utils = { workspace = true } +thiserror = { workspace = true } +unionlabs = { workspace = true } [lints] workspace = true diff --git a/lib/ibc-vm-rs/src/lib.rs b/lib/ibc-vm-rs/src/lib.rs index c91c36d7cb..7f2da57b22 100644 --- a/lib/ibc-vm-rs/src/lib.rs +++ b/lib/ibc-vm-rs/src/lib.rs @@ -13,6 +13,7 @@ use states::{ }; use unionlabs::{ encoding::{Decode, Encode, Proto}, + events::IbcEvent, ibc::core::{ channel::{self, order::Order, packet::Packet}, client::height::Height, @@ -23,8 +24,6 @@ use unionlabs::{ id::{ChannelId, ClientId, ConnectionId, PortId}, }; -pub type IbcEvent = unionlabs::events::IbcEvent; - pub mod states; lazy_static::lazy_static! { @@ -125,24 +124,16 @@ pub trait IbcHost: Sized { fn client_state(&self, client_id: &str) -> Option>; - fn read>(&self, path: &Path) -> Option; + fn read>(&self, path: &Path) -> Option; - fn read_raw(&self, key: &Path) -> Option>; + fn read_raw(&self, key: &Path) -> Option>; - fn commit_raw( - &mut self, - key: Path, - value: Vec, - ) -> Result<(), Self::Error>; + fn commit_raw(&mut self, key: Path, value: Vec) -> Result<(), Self::Error>; // TODO(aeryz): generic over encoding - fn commit>( - &mut self, - key: Path, - value: T, - ) -> Result<(), Self::Error>; + fn commit>(&mut self, key: Path, value: T) -> Result<(), Self::Error>; - fn delete(&mut self, key: &Path) -> Result<(), Self::Error>; + fn delete(&mut self, key: &Path) -> Result<(), Self::Error>; fn current_height(&self) -> Height; diff --git a/lib/ibc-vm-rs/src/states/channel_handshake.rs b/lib/ibc-vm-rs/src/states/channel_handshake.rs index 830096cc73..369ce5601d 100644 --- a/lib/ibc-vm-rs/src/states/channel_handshake.rs +++ b/lib/ibc-vm-rs/src/states/channel_handshake.rs @@ -6,7 +6,7 @@ use unionlabs::{ channel::{self, channel::Channel, counterparty::Counterparty, order::Order}, client::height::Height, commitment::merkle_path::MerklePath, - connection, + connection::{self, connection_end::ConnectionEnd}, }, ics24::{ ChannelEndPath, ConnectionPath, NextSequenceAckPath, NextSequenceRecvPath, @@ -17,8 +17,8 @@ use unionlabs::{ }; use crate::{ - states::connection_handshake::ConnectionEnd, Either, IbcAction, IbcError, IbcEvent, IbcHost, - IbcMsg, IbcQuery, IbcResponse, IbcVmResponse, Runnable, Status, + Either, IbcAction, IbcError, IbcEvent, IbcHost, IbcMsg, IbcQuery, IbcResponse, IbcVmResponse, + Runnable, Status, }; #[derive(Deserialize, Serialize, Debug, Clone)] @@ -280,11 +280,7 @@ impl Runnable for ChannelOpenTry { port_id: port_id.clone(), channel_id: "".to_string(), }, - connection_hops: vec![connection - .counterparty - .connection_id - .validate() - .unwrap()], + connection_hops: vec![connection.counterparty.connection_id.unwrap()], version: counterparty_version.clone(), }; @@ -535,11 +531,7 @@ impl Runnable for ChannelOpenAck { port_id: port_id.clone(), channel_id: channel_id.clone().to_string(), }, - connection_hops: vec![connection - .counterparty - .connection_id - .validate() - .unwrap()], + connection_hops: vec![connection.counterparty.connection_id.unwrap()], version: counterparty_version.clone(), }; @@ -751,11 +743,7 @@ impl Runnable for ChannelOpenConfirm { port_id: port_id.clone(), channel_id: channel_id.clone().to_string(), }, - connection_hops: vec![connection - .counterparty - .connection_id - .validate() - .unwrap()], + connection_hops: vec![connection.counterparty.connection_id.unwrap()], version: channel.version, }; diff --git a/lib/ibc-vm-rs/src/states/connection_handshake.rs b/lib/ibc-vm-rs/src/states/connection_handshake.rs index 126b37e1e6..3d6afc471c 100644 --- a/lib/ibc-vm-rs/src/states/connection_handshake.rs +++ b/lib/ibc-vm-rs/src/states/connection_handshake.rs @@ -5,7 +5,9 @@ use unionlabs::{ ibc::core::{ client::height::Height, commitment::merkle_path::MerklePath, - connection::{self, version::Version}, + connection::{ + self, connection_end::ConnectionEnd, counterparty::Counterparty, version::Version, + }, }, ics24::ConnectionPath, id::ClientId, @@ -17,9 +19,6 @@ use crate::{ Status, DEFAULT_IBC_VERSION, DEFAULT_MERKLE_PREFIX, }; -pub type Counterparty = connection::counterparty::Counterparty; -pub type ConnectionEnd = connection::connection_end::ConnectionEnd; - #[derive(Deserialize, Serialize, Debug, Clone)] #[cfg_attr(feature = "schemars", derive(::schemars::JsonSchema))] pub enum ConnectionOpenInit { @@ -211,7 +210,7 @@ impl Runnable for ConnectionOpenTry { state: connection::state::State::Init, counterparty: Counterparty { client_id: client_id.clone(), - connection_id: String::new(), + connection_id: None, prefix: DEFAULT_MERKLE_PREFIX.clone(), }, delay_period, @@ -235,7 +234,7 @@ impl Runnable for ConnectionOpenTry { path: MerklePath { key_path: vec![ "ibc".to_string(), - format!("connections/{}", counterparty_connection_id), + format!("connections/{}", counterparty_connection_id.unwrap()), ], }, // TODO(aeryz): generic over the encoding @@ -279,7 +278,7 @@ impl Runnable for ConnectionOpenTry { connection_id, client_id, counterparty_client_id: counterparty.client_id, - counterparty_connection_id: counterparty.connection_id.validate().unwrap(), + counterparty_connection_id: counterparty.connection_id.unwrap(), })], IbcVmResponse::Empty, )) @@ -355,7 +354,7 @@ impl Runnable for ConnectionOpenAck { state: connection::state::State::Tryopen, counterparty: Counterparty { client_id: client_id.clone(), - connection_id: connection_id.clone(), + connection_id: Some(connection_id.clone().validate().unwrap()), prefix: DEFAULT_MERKLE_PREFIX.clone(), }, delay_period: connection.delay_period, @@ -401,7 +400,8 @@ impl Runnable for ConnectionOpenAck { return Err(IbcError::MembershipVerificationFailure.into()); } connection.state = connection::state::State::Open; - connection.counterparty.connection_id = counterparty_connection_id.clone(); + connection.counterparty.connection_id = + Some(counterparty_connection_id.clone().validate().unwrap()); let counterparty_client_id = connection.counterparty.client_id.clone(); @@ -487,13 +487,14 @@ impl Runnable for ConnectionOpenConfirm { state: connection::state::State::Open, counterparty: Counterparty { client_id: client_id.clone(), - connection_id: connection_id.clone(), + connection_id: Some(connection_id.clone().validate().unwrap()), prefix: DEFAULT_MERKLE_PREFIX.clone(), }, delay_period: connection.delay_period, }; - let counterparty_connection_id = connection.counterparty.connection_id.clone(); + let counterparty_connection_id = + connection.counterparty.connection_id.clone().unwrap(); Either::Left(( ConnectionOpenConfirm::ConnectionStateVerified { @@ -534,7 +535,8 @@ impl Runnable for ConnectionOpenConfirm { } let counterparty_client_id = connection.counterparty.client_id.clone(); - let counterparty_connection_id = connection.counterparty.connection_id.clone(); + let counterparty_connection_id = + connection.counterparty.connection_id.clone().unwrap(); connection.state = connection::state::State::Open; host.commit( @@ -551,9 +553,7 @@ impl Runnable for ConnectionOpenConfirm { connection_id: connection_id.validate().unwrap(), client_id, counterparty_client_id, - counterparty_connection_id: counterparty_connection_id - .validate() - .unwrap(), + counterparty_connection_id, }, )], IbcVmResponse::Empty, diff --git a/lib/ibc-vm-rs/src/states/packet.rs b/lib/ibc-vm-rs/src/states/packet.rs index 29aa94f837..8552c4e170 100644 --- a/lib/ibc-vm-rs/src/states/packet.rs +++ b/lib/ibc-vm-rs/src/states/packet.rs @@ -1,11 +1,11 @@ use serde::{Deserialize, Serialize}; use unionlabs::{ - events::{self}, + events, ibc::core::{ channel::{self, channel::Channel, order::Order, packet::Packet}, client::height::Height, commitment::merkle_path::MerklePath, - connection, + connection::{self, connection_end::ConnectionEnd}, }, ics24::{ AcknowledgementPath, ChannelEndPath, CommitmentPath, ConnectionPath, NextSequenceSendPath, @@ -15,7 +15,6 @@ use unionlabs::{ validated::ValidateT, }; -use super::connection_handshake::ConnectionEnd; use crate::{ Either, IbcAction, IbcError, IbcEvent, IbcHost, IbcMsg, IbcQuery, IbcResponse, IbcVmResponse, Runnable, Status, diff --git a/lib/ics23/src/ibc_api.rs b/lib/ics23/src/ibc_api.rs index cdaaf724e5..ea0fd37757 100644 --- a/lib/ics23/src/ibc_api.rs +++ b/lib/ics23/src/ibc_api.rs @@ -168,6 +168,7 @@ mod tests { ibc::core::commitment::{ merkle_path::MerklePath, merkle_proof::MerkleProof, merkle_root::MerkleRoot, }, + ics24::ConnectionPath, }; use super::{verify_membership, verify_non_membership, VerifyMembershipError, SDK_SPECS}; @@ -335,4 +336,17 @@ mod tests { Ok(()) ); } + + #[test] + fn try_proof() { + let proof= serde_json::from_str::(r#"{"proofs":[{"@type":"exist","@value":{"key":"0x636f6e6e656374696f6e732f636f6e6e656374696f6e2d32","leaf":{"hash":"sha256","length":"var_proto","prefix":"0x0002c005","prehash_key":"no_hash","prehash_value":"sha256"},"path":[{"hash":"sha256","prefix":"0x0204c00520f3c95230594f910cfcda0f08040272de9ff25ebdc362fa2984fe04372b5c56fb20","suffix":"0x0"},{"hash":"sha256","prefix":"0x0408c00520d4c306fc76462b92c3888a22f78962e742022a4fa4b272947acf199993820a0720","suffix":"0x0"},{"hash":"sha256","prefix":"0x0610c00520","suffix":"0x2002a35cfb0a1fe5aec25e1d915887411f67741f9c511b3befa22eb95bc709792d"},{"hash":"sha256","prefix":"0x0a22c0052008808333ca466e463fd6174d936b7e9ae0153af98f42fd848b7c7cb53580de2b20","suffix":"0x0"}],"value":"0x0a0930382d7761736d2d3112140a0131120f4f524445525f554e4f524445524544180122130a0a636f6d6574626c732d301a050a03696263"}},{"@type":"exist","@value":{"key":"0x696263","leaf":{"hash":"sha256","length":"var_proto","prefix":"0x00","prehash_key":"no_hash","prehash_value":"sha256"},"path":[{"hash":"sha256","prefix":"0x01","suffix":"0x2cd8b50700950546180ad979135a8708c2ea2098fff6ade31b7e40eb5dcf7c05"},{"hash":"sha256","prefix":"0x012cf3feea58fcdb48b73c2cdd1b018c90c4078f924385675a0e9457168cd47ff1","suffix":"0x0"},{"hash":"sha256","prefix":"0x01373d3c4151d1fbe9641325af4682f5c936b22ddd6f27693369920ec5db527eb5","suffix":"0x0"},{"hash":"sha256","prefix":"0x01b0b8ee671be7e2122d443854cee9939a9a8b323d535db88124e99490b975b87e","suffix":"0x0"},{"hash":"sha256","prefix":"0x01","suffix":"0x40c17eb6aef68c760f6d7eb72e33e09610e5523f7eb6e9416a2e0ea0cc9fc171"}],"value":"0xfa6e73dfa59c3977f62f4f14ec1a1c1b4b8c90e644cb274cb938b484f3310e7d"}}]}"#).unwrap(); + + verify_membership( + &proof, + &SDK_SPECS, + &MerkleRoot { hash: hex!("F7ED1D182E325EA21817DC6048C7043056F76AB044642504CE57DDC5C1B47CD3").into() }, + &[b"ibc".to_vec(), ConnectionPath { connection_id: "connection-2".parse().unwrap() }.to_string().into_bytes()], + hex!("0a0930382d7761736d2d3112140a0131120f4f524445525f554e4f524445524544180122130a0a636f6d6574626c732d301a050a03696263").into() + ).unwrap(); + } } diff --git a/lib/linea-verifier/Cargo.toml b/lib/linea-verifier/Cargo.toml index cdd13b27d1..ee722a8071 100644 --- a/lib/linea-verifier/Cargo.toml +++ b/lib/linea-verifier/Cargo.toml @@ -12,17 +12,17 @@ workspace = true test-include = ["lib/scroll-verifier/tests"] [dependencies] -ethereum-verifier = { workspace = true } -ethers-core.workspace = true -gnark-mimc = { workspace = true } -hex = { workspace = true } -hex-literal.workspace = true -linea-zktrie = { workspace = true } -rlp = { workspace = true } -scroll-codec.workspace = true -serde = { workspace = true } -serde-utils = { workspace = true } -serde_json = { workspace = true } -sha3 = { workspace = true } -thiserror = { workspace = true } -unionlabs = { workspace = true } +ethereum-verifier = { workspace = true } +ethers-core = { workspace = true } +gnark-mimc = { workspace = true } +hex = { workspace = true } +hex-literal = { workspace = true } +linea-zktrie = { workspace = true } +rlp = { workspace = true } +scroll-codec = { workspace = true } +serde = { workspace = true } +serde-utils = { workspace = true } +serde_json = { workspace = true } +sha3 = { workspace = true } +thiserror = { workspace = true } +unionlabs = { workspace = true } diff --git a/lib/linea-verifier/src/lib.rs b/lib/linea-verifier/src/lib.rs index 432a448166..fa26403269 100644 --- a/lib/linea-verifier/src/lib.rs +++ b/lib/linea-verifier/src/lib.rs @@ -24,13 +24,11 @@ pub enum Error { InvalidL2IbcContractProof(linea_zktrie::verify::Error), } -/* -1. assert rootHash(rollup) in l1StateRoot -2. assert rollup.currentL2BlockNumber = l2BlockNumber -3. assert rollup.currentL2Timestamp = l2Timestamp -4. assert rollup.stateRootHashes[l2BlockNumber] = l2StateRoot -5. assert rootHash(l2IbcContract) in l2StateRoot - */ +// 1. assert rootHash(rollup) in l1StateRoot +// 2. assert rollup.currentL2BlockNumber = l2BlockNumber +// 3. assert rollup.currentL2Timestamp = l2Timestamp +// 4. assert rollup.stateRootHashes[l2BlockNumber] = l2StateRoot +// 5. assert rootHash(l2IbcContract) in l2StateRoot pub fn verify_header( client_state: ClientState, header: Header, diff --git a/lib/linea-zktrie/Cargo.toml b/lib/linea-zktrie/Cargo.toml index fc573c97c1..2f91e1b675 100644 --- a/lib/linea-zktrie/Cargo.toml +++ b/lib/linea-zktrie/Cargo.toml @@ -1,9 +1,9 @@ [package] -edition.workspace = true -license-file.workspace = true -name = "linea-zktrie" -repository.workspace = true -version = "0.1.0" +edition = { workspace = true } +license-file = { workspace = true } +name = "linea-zktrie" +repository = { workspace = true } +version = "0.1.0" [dependencies] gnark-mimc = { workspace = true } diff --git a/lib/macros/src/lib.rs b/lib/macros/src/lib.rs index 12d688aa97..37f72ad022 100644 --- a/lib/macros/src/lib.rs +++ b/lib/macros/src/lib.rs @@ -2,16 +2,16 @@ use std::{collections::HashMap, convert}; use proc_macro::{Delimiter, Group, Punct, Spacing, TokenStream, TokenTree}; use proc_macro2::{Literal, Span}; -use quote::{format_ident, quote, ToTokens}; +use quote::{format_ident, quote, quote_spanned, ToTokens}; use syn::{ fold::Fold, parenthesized, - parse::{discouraged::Speculative, Parse, ParseStream}, + parse::{Parse, ParseStream}, parse_macro_input, parse_quote, parse_quote_spanned, punctuated::Punctuated, spanned::Spanned, Attribute, Data, DeriveInput, Expr, ExprPath, Field, Fields, GenericParam, Generics, Ident, - Item, ItemEnum, ItemStruct, LitStr, MacroDelimiter, Meta, MetaList, Path, Token, Variant, + Item, ItemEnum, ItemStruct, LitStr, MacroDelimiter, Meta, MetaList, Path, Token, Type, Variant, WhereClause, WherePredicate, }; @@ -34,9 +34,7 @@ pub fn apply(meta: TokenStream, ts: TokenStream) -> TokenStream { #[proc_macro_derive(Debug, attributes(debug))] pub fn debug(ts: TokenStream) -> TokenStream { - let di = parse_macro_input!(ts as DeriveInput); - - derive_debug(di) + derive_debug(parse_macro_input!(ts as DeriveInput)) // .inspect(|x| println!("{x}")) .map_err(|e| e.into_compile_error()) .unwrap_or_else(convert::identity) @@ -143,7 +141,7 @@ fn derive_debug( } } - DebugAsDisplay(format!(#lit, #(#exprs)*)) + DebugAsDisplay(format!(#lit, #(#exprs,)*)) }} } Some(DebugMetaFmt::Wrap(path)) => { @@ -205,7 +203,10 @@ fn derive_debug( }) } (Data::Enum(e), None) => { - let variant_debugs = e + if e.variants.is_empty() { + Ok(quote!(unreachable!())) + } else { + let variant_debugs = e .variants .iter() .map( @@ -263,14 +264,15 @@ fn derive_debug( ) .collect::, _>>()?; - Ok(quote! { - match self { - #(#variant_debugs)* - } - }) + Ok(quote! { + match self { + #(#variant_debugs)* + } + }) + } } (Data::Struct(_) | Data::Enum(_), Some(DebugMetaFmt::Format(lit, exprs))) => Ok(quote! { - write!(f, #lit, #(#exprs)*) + write!(f, #lit, #(#exprs,)*) }), (Data::Struct(_) | Data::Enum(_), Some(DebugMetaFmt::Wrap(path))) => Ok(quote! { ::core::fmt::Debug::fmt((#path)(self), f) @@ -455,14 +457,9 @@ impl DebugMeta { let fmt: LitStr = input.parse()?; - let ahead = input.fork(); - ahead.parse::>()?; - let args = if ahead.is_empty() { - input.advance_to(&ahead); - Punctuated::default() - } else { - input.advance_to(&ahead); - Punctuated::::parse_terminated(input)? + let args = match input.parse::>()? { + Some(_token) => Punctuated::::parse_terminated(input)?, + None => Punctuated::default(), }; let prev = debug_meta @@ -702,8 +699,8 @@ pub fn model(meta: TokenStream, ts: TokenStream) -> TokenStream { #debug_derive_crate::Debug, ::core::clone::Clone, ::core::cmp::PartialEq, + ::core::cmp::Eq, )] - #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #serde } } @@ -731,8 +728,8 @@ pub fn model(meta: TokenStream, ts: TokenStream) -> TokenStream { #debug_derive_crate::Debug, ::core::clone::Clone, ::core::cmp::PartialEq, + ::core::cmp::Eq, )] - #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #serde } } @@ -916,12 +913,11 @@ impl Parse for FromRawAttrs { } } +/// NOTE: Doesn't support generics. Generics this low in the stack is a dark path I do not wish to explore again #[proc_macro_attribute] pub fn ibc_path(meta: TokenStream, ts: TokenStream) -> TokenStream { let item_struct = parse_macro_input!(ts as ItemStruct); - let path = parse_macro_input!(meta as LitStr); - - let (impl_generics, ty_generics, where_clause) = item_struct.generics.split_for_impl(); + let IbcPathMeta { path, comma: _, ty } = parse_macro_input!(meta as IbcPathMeta); let segments = parse_ibc_path(path.clone()); @@ -984,7 +980,7 @@ pub fn ibc_path(meta: TokenStream, ts: TokenStream) -> TokenStream { .iter() .map(|x| match x { Segment::Static(_) => quote! {}, - Segment::Variable(variable_seg) => quote! { + Segment::Variable(variable_seg) => quote_spanned! {fields_map[variable_seg].span()=> let #variable_seg = &self.#variable_seg; }, }) @@ -992,26 +988,20 @@ pub fn ibc_path(meta: TokenStream, ts: TokenStream) -> TokenStream { let field_pat = segments.iter().filter_map(|seg| match seg { Segment::Static(_) => None, - Segment::Variable(var) => Some(var), + // use the span of the input tokens + Segment::Variable(variable_seg) => Some(fields_map.get_key_value(variable_seg).unwrap().0), }); let ident = &item_struct.ident; - let serde_ser_bound = item_struct.generics.params.to_token_stream().to_string(); - let serde_de_bound = item_struct.generics.params.to_token_stream().to_string(); - quote! { - #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ::clap::Args)] - #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] - #[serde(bound( - serialize = #serde_ser_bound, - deserialize = #serde_de_bound, - ))] + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, ::clap::Args)] + #[serde(deny_unknown_fields)] #item_struct const _: () = { #[automatically_derived] - impl #impl_generics ::core::fmt::Display for #ident #ty_generics #where_clause { + impl ::core::fmt::Display for #ident { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { #display_body @@ -1022,7 +1012,7 @@ pub fn ibc_path(meta: TokenStream, ts: TokenStream) -> TokenStream { const _: () = { #[automatically_derived] - impl #impl_generics ::core::str::FromStr for #ident #ty_generics #where_clause { + impl ::core::str::FromStr for #ident { type Err = PathParseError; fn from_str(s: &str) -> ::core::result::Result { @@ -1038,10 +1028,33 @@ pub fn ibc_path(meta: TokenStream, ts: TokenStream) -> TokenStream { } } }; + + const _: () = { + impl IbcPath for #ident { + type Value = #ty; + } + }; } .into() } +struct IbcPathMeta { + path: LitStr, + #[allow(unused)] + comma: Token![,], + ty: Type, +} + +impl Parse for IbcPathMeta { + fn parse(input: ParseStream) -> syn::Result { + Ok(Self { + path: input.parse()?, + comma: input.parse()?, + ty: input.parse()?, + }) + } +} + enum Segment { Static(String), Variable(syn::Ident), diff --git a/lib/move-bindgen-derive/Cargo.toml b/lib/move-bindgen-derive/Cargo.toml new file mode 100644 index 0000000000..be89da8a0d --- /dev/null +++ b/lib/move-bindgen-derive/Cargo.toml @@ -0,0 +1,17 @@ +[package] +edition = { workspace = true } +license-file = { workspace = true } +name = "move-bindgen-derive" +repository = { workspace = true } +version = "0.0.0" + +[lints] +workspace = true + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.78" +quote = "1.0.35" +syn = { version = "2.0.52", default-features = false, features = ["clone-impls", "parsing", "printing", "proc-macro", "derive", "fold"] } diff --git a/lib/move-bindgen-derive/src/lib.rs b/lib/move-bindgen-derive/src/lib.rs new file mode 100644 index 0000000000..5f782638e0 --- /dev/null +++ b/lib/move-bindgen-derive/src/lib.rs @@ -0,0 +1,115 @@ +use std::convert; + +use quote::quote; +use syn::{ + parse_macro_input, parse_quote, parse_quote_spanned, spanned::Spanned, Data, DeriveInput, Expr, + Field, MetaNameValue, WhereClause, WherePredicate, +}; + +#[proc_macro_derive(TypeTagged, attributes(type_tag))] +pub fn type_tagged(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { + derive_type_tagged(parse_macro_input!(ts as DeriveInput)) + // .inspect(|x| println!("{x}")) + .map_err(|e| e.into_compile_error()) + .unwrap_or_else(convert::identity) + .into() +} + +fn derive_type_tagged( + DeriveInput { + attrs, + ident, + generics, + data, + .. + }: DeriveInput, +) -> Result { + let (impl_generics, ty_generics, original_where_clause) = generics.split_for_impl(); + + let bounds = mk_where_clause(&data); + + let mut where_clause = original_where_clause + .cloned() + .unwrap_or_else(|| WhereClause { + where_token: parse_quote!(where), + predicates: Default::default(), + }); + where_clause.predicates.extend(bounds.clone()); + + let [module] = attrs + .into_iter() + .filter(|attr| attr.path().is_ident("type_tag")) + .map(|attr| { + let mnv = + syn::parse2::(attr.meta.require_list().unwrap().tokens.clone()) + .unwrap(); + + assert!(mnv.path.is_ident("module")); + match &mnv.value { + Expr::Path(expr) => expr.path.require_ident().unwrap().clone(), + _ => panic!("???"), + } + }) + .collect::>() + .try_into() + .unwrap(); + + let ident_str = ident.to_string(); + let module_str = module.to_string(); + + let body = match data { + Data::Struct(_) => { + quote! { + ::move_bindgen::move_core_types::language_storage::TypeTag::Struct( + ::std::boxed::Box::new( + ::move_bindgen::move_core_types::language_storage::StructTag { + address: ctx, + module: ::move_bindgen::move_core_types::ident_str!(#module_str).into(), + name: ::move_bindgen::move_core_types::ident_str!(#ident_str).into(), + type_args: vec![], + } + ) + ) + } + } + _ => panic!(), + }; + + // let ctxs = bounds.iter().filter_map(|wp| match wp { + // WherePredicate::Type(PredicateType { bounded_ty, .. }) => { + // Some(quote!(<#bounded_ty as ::move_bindgen::TypeTagged>::Ctx)) + // } + // _ => None, + // }); + + Ok(quote! { + const _: () = { + #[automatically_derived] + impl #impl_generics ::move_bindgen::TypeTagged for #ident #ty_generics #where_clause { + // type Ctx = (#(#ctxs,)* ::move_bindgen::move_core_types::account_address::AccountAddress); + type Ctx = ::move_bindgen::move_core_types::account_address::AccountAddress; + + fn type_tag(ctx: Self::Ctx) -> ::move_bindgen::move_core_types::language_storage::TypeTag { + #body + } + } + + #[automatically_derived] + impl #impl_generics #ident #ty_generics #original_where_clause { + pub fn with_address(self, address: ::move_bindgen::move_core_types::account_address::AccountAddress) -> (Self, ::move_bindgen::move_core_types::account_address::AccountAddress) { + (self, address) + } + } + }; + }) +} + +fn mk_where_clause(data: &Data) -> Vec { + let f = |Field { ty, .. }: &Field| parse_quote_spanned!(ty.span()=> #ty: ::move_bindgen::TypeTagged); + + match data { + Data::Struct(s) => s.fields.iter().map(f).collect(), + Data::Enum(e) => e.variants.iter().flat_map(|v| &v.fields).map(f).collect(), + Data::Union(_) => panic!(), + } +} diff --git a/lib/near/dummy-ibc-app/Cargo.toml b/lib/near/dummy-ibc-app/Cargo.toml index d6dd617c97..21276795fb 100644 --- a/lib/near/dummy-ibc-app/Cargo.toml +++ b/lib/near/dummy-ibc-app/Cargo.toml @@ -6,12 +6,12 @@ version = "0.1.0" [dependencies] borsh = { workspace = true, features = ["borsh-derive"] } -ibc-vm-rs.workspace = true +ibc-vm-rs = { workspace = true } near-contract-standards = { workspace = true } near-sdk = { workspace = true } near-sdk-contract-tools = { workspace = true } -serde.workspace = true -serde_json.workspace = true +serde = { workspace = true } +serde_json = { workspace = true } unionlabs = { workspace = true, features = ["near"] } [lib] diff --git a/lib/near/near-ibc-tests/Cargo.toml b/lib/near/near-ibc-tests/Cargo.toml index 226c0fae04..77a2c91bab 100644 --- a/lib/near/near-ibc-tests/Cargo.toml +++ b/lib/near/near-ibc-tests/Cargo.toml @@ -5,22 +5,22 @@ name = "near-ibc-tests" version = "0.1.0" [dependencies] -anyhow = "1.0" -borsh = { workspace = true, features = ["borsh-derive"] } -ibc-vm-rs.workspace = true -near-contract-standards.workspace = true -near-sdk = { workspace = true } -near-sdk-contract-tools = { workspace = true } -near-units = "0.2.0" -near-workspaces.workspace = true -serde.workspace = true -serde_json.workspace = true -tokio = { workspace = true, features = ["full"] } -unionlabs = { workspace = true, features = ["near"] } +anyhow = "1.0" +borsh = { workspace = true, features = ["borsh-derive"] } +ibc-vm-rs = { workspace = true } +near-contract-standards = { workspace = true } +near-sdk = { workspace = true } +near-sdk-contract-tools = { workspace = true } +near-units = "0.2.0" +near-workspaces = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +tokio = { workspace = true, features = ["full"] } +unionlabs = { workspace = true, features = ["near"] } # near-primitives = { git = "https://github.com/near/nearcore" } base64 = { workspace = true } -env_logger = "0.9" -hex.workspace = true +env_logger = "0.11.5" +hex = { workspace = true } near-crypto = "0.20" near-jsonrpc-client = "0.8" near-jsonrpc-primitives = "0.20" diff --git a/lib/near/near-ibc-tests/src/main.rs b/lib/near/near-ibc-tests/src/main.rs index a0c5d42d76..29ce822b35 100644 --- a/lib/near/near-ibc-tests/src/main.rs +++ b/lib/near/near-ibc-tests/src/main.rs @@ -3,7 +3,7 @@ mod utils; use std::{env, thread::sleep, time::Duration}; -use ibc_vm_rs::{states::connection_handshake, IbcEvent, DEFAULT_IBC_VERSION}; +use ibc_vm_rs::DEFAULT_IBC_VERSION; use msgs::{ChannelOpenTry, RecvPacket}; use near_primitives_core::hash::CryptoHash; use near_workspaces::{ @@ -13,10 +13,12 @@ use near_workspaces::{ Account, AccountId, Contract, Worker, }; use unionlabs::{ + events::IbcEvent, ibc::core::{ channel::{self, packet::Packet}, client::height::Height, commitment::merkle_prefix::MerklePrefix, + connection, }, near::types::HeaderUpdate, validated::ValidateT, @@ -139,9 +141,9 @@ async fn connection_open_init( ) { let open_init = ConnectionOpenInit { client_id: client_id.to_string(), - counterparty: connection_handshake::Counterparty { + counterparty: connection::counterparty::Counterparty { client_id: counterparty_client_id.to_string().validate().unwrap(), - connection_id: "".into(), + connection_id: None, prefix: MerklePrefix { key_prefix: b"ibc".into(), }, @@ -182,9 +184,9 @@ async fn connection_open_try( let open_try = ConnectionOpenTry { client_id: client_id.to_string(), - counterparty: connection_handshake::Counterparty { + counterparty: connection::counterparty::Counterparty { client_id: counterparty_client_id.to_string().validate().unwrap(), - connection_id: counterparty_connection_id.to_string(), + connection_id: Some(counterparty_connection_id.parse().unwrap()), prefix: MerklePrefix { key_prefix: b"ibc".into(), }, diff --git a/lib/near/near-ibc-tests/src/msgs.rs b/lib/near/near-ibc-tests/src/msgs.rs index 485535b9b2..a649a3e318 100644 --- a/lib/near/near-ibc-tests/src/msgs.rs +++ b/lib/near/near-ibc-tests/src/msgs.rs @@ -1,12 +1,11 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use ibc_vm_rs::states::connection_handshake; use near_primitives_core::hash::CryptoHash; use near_sdk::AccountId; use unionlabs::{ ibc::core::{ channel::{self, packet::Packet}, client::height::Height, - connection::version::Version, + connection::{self, version::Version}, }, id::{ChannelId, ConnectionId, PortId}, near::types::{self, BlockHeaderInnerLiteView}, @@ -34,7 +33,7 @@ pub struct CreateClient { #[derive(serde::Serialize)] pub struct ConnectionOpenInit { pub client_id: String, - pub counterparty: connection_handshake::Counterparty, + pub counterparty: connection::counterparty::Counterparty, pub version: Version, pub delay_period: u64, } @@ -42,7 +41,7 @@ pub struct ConnectionOpenInit { #[derive(serde::Serialize)] pub struct ConnectionOpenTry { pub client_id: String, - pub counterparty: connection_handshake::Counterparty, + pub counterparty: connection::counterparty::Counterparty, pub counterparty_versions: Vec, pub connection_end_proof: Vec, pub proof_height: Height, diff --git a/lib/near/near-ibc/Cargo.toml b/lib/near/near-ibc/Cargo.toml index 4e8f8d95ff..4e5b38fc58 100644 --- a/lib/near/near-ibc/Cargo.toml +++ b/lib/near/near-ibc/Cargo.toml @@ -12,9 +12,9 @@ near-contract-standards = { workspace = true } near-sdk = { workspace = true } near-sdk-contract-tools = { workspace = true } schemars = { workspace = true, features = ["derive"], optional = true } -serde.workspace = true -serde_json.workspace = true -thiserror.workspace = true +serde = { workspace = true } +serde_json = { workspace = true } +thiserror = { workspace = true } unionlabs = { workspace = true, features = ["near"] } [lib] diff --git a/lib/near/near-ibc/src/contract.rs b/lib/near/near-ibc/src/contract.rs index a42dba6be6..c9cb2737fe 100644 --- a/lib/near/near-ibc/src/contract.rs +++ b/lib/near/near-ibc/src/contract.rs @@ -3,7 +3,7 @@ use ibc_vm_rs::{ channel_handshake::{ChannelOpenAck, ChannelOpenConfirm, ChannelOpenInit, ChannelOpenTry}, client_state::UpdateClient, connection_handshake::{ - self, ConnectionOpenAck, ConnectionOpenConfirm, ConnectionOpenInit, ConnectionOpenTry, + ConnectionOpenAck, ConnectionOpenConfirm, ConnectionOpenInit, ConnectionOpenTry, }, packet::{Acknowledgement, RecvPacket, SendPacket}, CreateClient, @@ -50,7 +50,7 @@ impl IbcHost for Contract { .unwrap()) } - fn commit_raw(&mut self, key: Path, value: Vec) -> Result<(), Error> { + fn commit_raw(&mut self, key: Path, value: Vec) -> Result<(), Error> { self.commitments.insert(&key.to_string(), &value); Ok(()) } @@ -67,17 +67,13 @@ impl IbcHost for Contract { .get(&format!("clients/{client_id}/clientState")) } - fn read>(&self, key: &Path) -> Option { + fn read>(&self, key: &Path) -> Option { self.commitments .get(&key.to_string()) .map(|item| T::decode(&item).unwrap()) } - fn commit>( - &mut self, - key: Path, - value: T, - ) -> Result<(), Error> { + fn commit>(&mut self, key: Path, value: T) -> Result<(), Error> { self.commitments.insert(&key.to_string(), &value.encode()); Ok(()) } @@ -89,7 +85,7 @@ impl IbcHost for Contract { .unwrap()) } - fn read_raw(&self, key: &Path) -> Option> { + fn read_raw(&self, key: &Path) -> Option> { self.commitments.get(&key.to_string()) } @@ -109,7 +105,7 @@ impl IbcHost for Contract { env::sha256(&data) } - fn delete(&mut self, key: &Path) -> Result<(), Self::Error> { + fn delete(&mut self, key: &Path) -> Result<(), Self::Error> { let _ = self.commitments.remove(&key.to_string()); Ok(()) } @@ -170,7 +166,7 @@ impl Contract { pub fn connection_open_init( &mut self, client_id: ClientId, - counterparty: connection_handshake::Counterparty, + counterparty: connection::counterparty::Counterparty, version: connection::version::Version, delay_period: u64, ) -> PromiseOrValue { @@ -188,7 +184,7 @@ impl Contract { pub fn connection_open_try( &mut self, client_id: ClientId, - counterparty: connection_handshake::Counterparty, + counterparty: connection::counterparty::Counterparty, counterparty_versions: Vec, connection_end_proof: Vec, proof_height: Height, diff --git a/lib/near/near.nix b/lib/near/near.nix index 78610afafd..6e9481b737 100644 --- a/lib/near/near.nix +++ b/lib/near/near.nix @@ -2,31 +2,31 @@ perSystem = { self', lib, unstablePkgs, pkgs, system, config, rust, crane, stdenv, dbg, ... }: let - near-ibc-tests = pkgs.stdenv.mkDerivation { - name = "near-ibc-tests"; - buildInputs = [ pkgs.makeWrapper ]; - src = - (crane.buildWorkspaceMember { - crateDirFromRoot = "lib/near/near-ibc-tests"; - extraEnv = { - PROTOC = "${pkgs.protobuf}/bin/protoc"; - LIBCLANG_PATH = "${pkgs.llvmPackages_14.libclang.lib}/lib"; - }; - extraBuildInputs = [ pkgs.pkg-config pkgs.openssl pkgs.perl pkgs.gnumake ]; - extraNativeBuildInputs = [ pkgs.clang ]; - extraEnv = { }; - }).packages.near-ibc-tests; - installPhase = '' - mkdir -p $out/bin - cp -r $src/bin/near-ibc-tests $out/bin/near-ibc-tests - wrapProgram $out/bin/near-ibc-tests \ - --set NEAR_SANDBOX_BIN_PATH "${near-sandbox}/bin/neard" \ - --set IBC_WASM_FILEPATH "${self'.packages.near-ibc}/lib/near_ibc.wasm" \ - --set NEAR_LC_WASM_FILEPATH "${self'.packages.near-light-client}/lib/near_light_client.wasm" \ - --set IBC_APP_WASM_FILEPATH "${self'.packages.dummy-ibc-app}/lib/dummy_ibc_app.wasm"; - ''; - meta.mainProgram = "near-ibc-tests"; - }; + # near-ibc-tests = pkgs.stdenv.mkDerivation { + # name = "near-ibc-tests"; + # buildInputs = [ pkgs.makeWrapper ]; + # src = + # (crane.buildWorkspaceMember { + # crateDirFromRoot = "lib/near/near-ibc-tests"; + # extraEnv = { + # PROTOC = "${pkgs.protobuf}/bin/protoc"; + # LIBCLANG_PATH = "${pkgs.llvmPackages_14.libclang.lib}/lib"; + # }; + # extraBuildInputs = [ pkgs.pkg-config pkgs.openssl pkgs.perl pkgs.gnumake ]; + # extraNativeBuildInputs = [ pkgs.clang ]; + # extraEnv = { }; + # }).packages.near-ibc-tests; + # installPhase = '' + # mkdir -p $out/bin + # cp -r $src/bin/near-ibc-tests $out/bin/near-ibc-tests + # wrapProgram $out/bin/near-ibc-tests \ + # --set NEAR_SANDBOX_BIN_PATH "${near-sandbox}/bin/neard" \ + # --set IBC_WASM_FILEPATH "${self'.packages.near-ibc}/lib/near_ibc.wasm" \ + # --set NEAR_LC_WASM_FILEPATH "${self'.packages.near-light-client}/lib/near_light_client.wasm" \ + # --set IBC_APP_WASM_FILEPATH "${self'.packages.dummy-ibc-app}/lib/dummy_ibc_app.wasm"; + # ''; + # meta.mainProgram = "near-ibc-tests"; + # }; cargo-near = craneLib.buildPackage rec { pname = "cargo-near"; @@ -113,7 +113,8 @@ in { packages = near-light-client.packages // dummy-ibc-app.packages // near-ibc.packages // { - inherit near-ibc-tests near-sandbox cargo-near; + # TODO: Reenable near-ibc-tests + inherit near-sandbox cargo-near; }; checks = near-light-client.checks // near-ibc.checks; diff --git a/lib/pg-queue/Cargo.toml b/lib/pg-queue/Cargo.toml index dd8cd0c752..11fcb41a51 100644 --- a/lib/pg-queue/Cargo.toml +++ b/lib/pg-queue/Cargo.toml @@ -11,12 +11,12 @@ workspace = true test-include = [] [dependencies] -frame-support-procedural.workspace = true -prometheus = "0.13.4" -queue-msg.workspace = true -serde = { workspace = true } -serde_json = { workspace = true, features = ["unbounded_depth"] } -sqlx = { workspace = true, features = ["postgres", "migrate", "macros", "json", "runtime-tokio", "time"] } -tokio = { workspace = true, features = ["time"] } -tokio-postgres = { version = "0.7.10", features = ["with-serde_json-1"] } -tracing = { workspace = true } +frame-support-procedural = { workspace = true } +prometheus = "0.13.4" +queue-msg = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true, features = ["unbounded_depth"] } +sqlx = { workspace = true, features = ["postgres", "migrate", "macros", "json", "runtime-tokio", "time"] } +tokio = { workspace = true, features = ["time"] } +tokio-postgres = { version = "0.7.10", features = ["with-serde_json-1"] } +tracing = { workspace = true } diff --git a/lib/pg-queue/migrations/20240316012044_queue.sql b/lib/pg-queue/migrations/20240316012044_queue.sql index 860341f39c..101dbd4009 100644 --- a/lib/pg-queue/migrations/20240316012044_queue.sql +++ b/lib/pg-queue/migrations/20240316012044_queue.sql @@ -1,15 +1,7 @@ --- CREATE TYPE status AS ENUM( --- 'ready', --- 'done', --- 'optimize', --- 'failed' --- ); - CREATE TABLE queue( id BIGSERIAL PRIMARY KEY, item JSONB NOT NULL, - -- Can't have foreign key relations to hypertables, so recreate the constraints as best as possible - parents BIGINT[] DEFAULT '{}' CHECK (0 < ALL (parents)), + parents BIGINT[] DEFAULT '{}', created_at timestamptz NOT NULL DEFAULT now() ); @@ -17,16 +9,15 @@ CREATE TABLE optimize( -- TODO: Figure out how to do this properly id BIGINT PRIMARY KEY DEFAULT nextval('queue_id_seq'::regclass), item JSONB NOT NULL, - -- Can't have foreign key relations to hypertables, so recreate the constraints as best as possible - parents BIGINT[] DEFAULT '{}' CHECK (0 < ALL (parents)), + tag text NOT NULL, + parents BIGINT[] DEFAULT '{}', created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE done( id BIGINT, item JSONB NOT NULL, - -- Can't have foreign key relations to hypertables, so recreate the constraints as best as possible - parents BIGINT[] DEFAULT '{}' CHECK (0 < ALL (parents)), + parents BIGINT[] DEFAULT '{}', created_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (id, created_at) ); @@ -34,8 +25,7 @@ CREATE TABLE done( CREATE TABLE failed( id BIGINT PRIMARY KEY, item JSONB NOT NULL, - -- Can't have foreign key relations to hypertables, so recreate the constraints as best as possible - parents BIGINT[] DEFAULT '{}' CHECK (0 < ALL (parents)), + parents BIGINT[] DEFAULT '{}', message TEXT, created_at timestamptz NOT NULL DEFAULT now() ); diff --git a/lib/pg-queue/src/lib.rs b/lib/pg-queue/src/lib.rs index f2926446f1..a198c4d4e2 100644 --- a/lib/pg-queue/src/lib.rs +++ b/lib/pg-queue/src/lib.rs @@ -5,19 +5,18 @@ use std::{ use frame_support_procedural::{CloneNoBound, DebugNoBound}; use queue_msg::{ + normalize, optimize::{OptimizationResult, Pass, PurePass}, - Op, QueueMessage, + Captures, Op, QueueMessage, }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use sqlx::{postgres::PgPoolOptions, prelude::FromRow, types::Json, Either, PgPool}; -use tracing::{debug, debug_span, info_span, trace, Instrument}; +use tracing::{debug, debug_span, info_span, instrument, trace, Instrument}; use crate::metrics::{ITEM_PROCESSING_DURATION, OPTIMIZE_ITEM_COUNT, OPTIMIZE_PROCESSING_DURATION}; pub mod metrics; -// pub static MIGRATOR: Migrator = sqlx::migrate!(); // defaults to "./migrations" - /// A fifo queue backed by a postgres table. Not suitable for high-throughput, but enough for ~1k items/sec. /// /// The queue assumes the following database schema: @@ -99,10 +98,15 @@ impl queue_msg::Queue for PgQueue { ) -> Result<(), Self::Error> { trace!("enqueue"); + // TODO: Handle parent ids properly + let (_, msgs) = normalize::normalize(vec![item]) + .into_iter() + .unzip::<_, _, Vec<_>, Vec<_>>(); + let OptimizationResult { optimize_further, ready, - } = pre_enqueue_passes.run_pass_pure(vec![item]); + } = pre_enqueue_passes.run_pass_pure(msgs); let mut tx = self.client.begin().await?; @@ -124,17 +128,24 @@ impl queue_msg::Queue for PgQueue { let optimize_further_ids = sqlx::query( " - INSERT INTO optimize (item) - SELECT * FROM UNNEST($1::JSONB[]) + INSERT INTO optimize (item, tag) + SELECT * FROM UNNEST($1::JSONB[], $2::TEXT[]) RETURNING id ", ) .bind( optimize_further + .clone() .into_iter() .map(|x| Json(x.1)) .collect::>(), ) + .bind( + optimize_further + .into_iter() + .map(|x| x.2) + .collect::>(), + ) .try_map(|x| Id::from_row(&x)) .fetch_all(tx.as_mut()) .await?; @@ -148,14 +159,15 @@ impl queue_msg::Queue for PgQueue { Ok(()) } + #[instrument(skip_all)] async fn process<'a, F, Fut, R, O>( &'a self, pre_reenqueue_passes: &'a O, f: F, ) -> Result, Self::Error> where - F: (FnOnce(Op) -> Fut) + Send + 'static, - Fut: Future>, String>)> + Send + 'static, + F: (FnOnce(Op) -> Fut) + Send + Captures<'a>, + Fut: Future>, String>)> + Send + Captures<'a>, R: Send + Sync + 'static, O: PurePass, { @@ -222,60 +234,100 @@ impl queue_msg::Queue for PgQueue { tx.commit().await?; } Ok(new_msgs) => { - sqlx::query( - " - INSERT INTO - done (id, parents, item, created_at) - VALUES ($1, $2, $3::JSONB, $4 ) - ", - ) - .bind(row.id) - .bind(row.parents) - .bind(row.item) - .bind(row.created_at) - .execute(tx.as_mut()) - .await?; - - let OptimizationResult { - optimize_further, - ready, - } = pre_reenqueue_passes.run_pass_pure(new_msgs); - - let ready_ids = sqlx::query( - " - INSERT INTO queue (item) - SELECT * FROM UNNEST($1::JSONB[]) - RETURNING id - ", - ) - .bind(ready.into_iter().map(|x| Json(x.1)).collect::>()) - .try_map(|x| Id::from_row(&x)) - .fetch_all(tx.as_mut()) - .await?; - - for ready in ready_ids { - debug!(id = ready.id, "enqueued item"); - } - - let optimize_further_ids = sqlx::query( - " - INSERT INTO optimize (item) - SELECT * FROM UNNEST($1::JSONB[]) - RETURNING id - ", - ) - .bind( - optimize_further + 'block: { + sqlx::query( + " + INSERT INTO + done (id, parents, item, created_at) + VALUES ($1, $2, $3::JSONB, $4 ) + ", + ) + .bind(row.id) + .bind(row.parents) + .bind(row.item) + .bind(row.created_at) + .execute(tx.as_mut()) + .await?; + + trace!(new_msgs = new_msgs.len(), "normalizing"); + + // TODO: Handle parent ids properly + let (_, new_msgs) = normalize::normalize(new_msgs) .into_iter() - .map(|x| Json(x.1)) - .collect::>(), - ) - .try_map(|x| Id::from_row(&x)) - .fetch_all(tx.as_mut()) - .await?; - - for ready in optimize_further_ids { - debug!(id = ready.id, "enqueued item"); + .unzip::<_, _, Vec<_>, Vec<_>>(); + + trace!(new_msgs = new_msgs.len(), "normalized"); + + if new_msgs.is_empty() { + break 'block; + } + + trace!(new_msgs = new_msgs.len(), "running pre-reenqueue passes"); + + let OptimizationResult { + optimize_further, + ready, + } = pre_reenqueue_passes.run_pass_pure(new_msgs); + + trace!( + optimize_further = optimize_further.len(), + ready = ready.len(), + "ran pre-reenqueue passes" + ); + + let ready_ids = sqlx::query( + " + INSERT INTO queue (item) + SELECT * FROM UNNEST($1::JSONB[]) + RETURNING id + ", + ) + .bind(ready.into_iter().map(|x| Json(x.1)).collect::>()) + .try_map(|x| Id::from_row(&x)) + .fetch_all(tx.as_mut()) + .await?; + + for ready in ready_ids { + debug!(id = ready.id, "enqueued item"); + } + + // let parents = optimize_further + // .clone() + // .into_iter() + // .map(|(parents, msg, tag)| { + // parents.into_iter().map(|i| i as i64).collect::>() + // }) + // .collect::>(); + + // let parents = parents.iter().map(|x| x.as_slice()).collect::>(); + + let optimize_further_ids = sqlx::query( + " + INSERT INTO optimize (item, tag) + SELECT * FROM UNNEST($1::JSONB[], $2::TEXT[]) + RETURNING id + ", + ) + // .bind(&*parents) + .bind( + optimize_further + .iter() + .map(|(_parents, msg, _tag)| Json(msg)) + .collect::>(), + ) + .bind( + optimize_further + .iter() + .map(|(_parents, _msg, tag)| tag.as_str()) + .collect::>(), + ) + .try_map(|x| Id::from_row(&x)) + .fetch_all(tx.as_mut()) + .await?; + + for ready in optimize_further_ids { + debug!(id = ready.id, "enqueued item"); + } } tx.commit().await?; @@ -297,9 +349,10 @@ impl queue_msg::Queue for PgQueue { async fn optimize<'a, O: Pass>( &'a self, + tag: &'a str, optimizer: &'a O, ) -> Result<(), Either> { - trace!("optimize"); + trace!(%tag, "optimize"); // if self.lock.swap(false, Ordering::SeqCst) { // debug!("queue is locked"); @@ -318,6 +371,8 @@ impl queue_msg::Queue for PgQueue { id FROM optimize + WHERE + tag = $1 ORDER BY id ASC FOR UPDATE @@ -330,6 +385,7 @@ impl queue_msg::Queue for PgQueue { created_at "#, ) + .bind(tag) .try_map(|x| Record::from_row(&x)) .fetch_all(tx.as_mut()) .await @@ -354,6 +410,7 @@ impl queue_msg::Queue for PgQueue { OPTIMIZE_ITEM_COUNT.observe(msgs.len() as f64); let timer = OPTIMIZE_PROCESSING_DURATION.start_timer(); + let OptimizationResult { optimize_further, ready, @@ -384,21 +441,22 @@ impl queue_msg::Queue for PgQueue { .collect::>() }; - for (parent_idxs, new_msg) in optimize_further { + for (parent_idxs, new_msg, tag) in optimize_further { let parents = get_parent_ids(&parent_idxs); trace!(parent_idxs = ?&parent_idxs, parents = ?&parents); let new_row = sqlx::query( " - INSERT INTO queue (item, parents) + INSERT INTO optimize (item, parents, tag) VALUES - ($1::JSONB, $2) + ($1::JSONB, $2, $3) RETURNING id ", ) .bind(Json(new_msg)) .bind(&parents) - .try_map(|x| Id::from_row(&x)) + .bind(tag) + .try_map(|row| Id::from_row(&row)) .fetch_one(tx.as_mut()) .await .map_err(Either::Left)?; diff --git a/lib/pg-queue/src/metrics.rs b/lib/pg-queue/src/metrics.rs index 9430b4e91d..cd46d15315 100644 --- a/lib/pg-queue/src/metrics.rs +++ b/lib/pg-queue/src/metrics.rs @@ -10,6 +10,7 @@ pub static ITEM_PROCESSING_DURATION: LazyLock = LazyLock::new(|| { .unwrap() }); +// TODO: Add tag to this pub static OPTIMIZE_PROCESSING_DURATION: LazyLock = LazyLock::new(|| { register_histogram!( "pg_queue_optimize_processing_duration_seconds", @@ -18,6 +19,7 @@ pub static OPTIMIZE_PROCESSING_DURATION: LazyLock = LazyLock::new(|| .unwrap() }); +// TODO: Add tag to this pub static OPTIMIZE_ITEM_COUNT: LazyLock = LazyLock::new(|| { register_histogram!( "pg_queue_optimize_item_count", diff --git a/lib/queue-msg-macro/Cargo.toml b/lib/queue-msg-macro/Cargo.toml index 1b6a312e33..c4d175169c 100644 --- a/lib/queue-msg-macro/Cargo.toml +++ b/lib/queue-msg-macro/Cargo.toml @@ -2,6 +2,7 @@ autotests = false edition = "2021" name = "queue-msg-macro" +resolver = "2" version = "0.0.0" [package.metadata.crane] @@ -17,14 +18,14 @@ proc-macro = true name = "tests" path = "tests/all-tests.rs" -[dev-dependencies] -frame-support-procedural = { workspace = true } -macros.workspace = true -serde = { workspace = true, features = ["derive"] } -serde_json = { workspace = true, features = ["std"] } -trybuild = { version = "1.0.49", features = ["diff"] } - [dependencies] proc-macro2 = "1.0.79" quote = "1.0.35" syn = { version = "2.0.55", features = ["full", "extra-traits", "visit-mut"] } + +[dev-dependencies] +frame-support-procedural = { workspace = true } +macros = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true, features = ["std"] } +trybuild = { version = "1.0.91", features = ["diff"] } diff --git a/lib/queue-msg-macro/src/lib.rs b/lib/queue-msg-macro/src/lib.rs index 2966ad66b4..02ae5ba9ad 100644 --- a/lib/queue-msg-macro/src/lib.rs +++ b/lib/queue-msg-macro/src/lib.rs @@ -1,11 +1,14 @@ -#![feature(proc_macro_quote)] +// #![feature(proc_macro_quote)] use proc_macro::TokenStream; use proc_macro2::Ident; -use quote::quote; +use quote::{quote, quote_spanned, ToTokens}; use syn::{ - parse_macro_input, parse_quote, spanned::Spanned, Attribute, Data, Data::Struct, DataStruct, - DeriveInput, Error, Fields, GenericParam, Generics, Meta, + parse_macro_input, parse_quote, + spanned::Spanned, + Attribute, + Data::{self, Struct}, + DataStruct, DeriveInput, Error, Fields, GenericParam, Generics, Meta, Type, }; #[proc_macro_attribute] @@ -20,26 +23,36 @@ pub fn queue_msg(_: TokenStream, input: TokenStream) -> TokenStream { fn apply_item(derive_input: DeriveInput) -> Result { let derive_input = &mut derive_input.clone(); - let derives = if derive_input.generics.params.is_empty() { - quote! { - #[derive( - ::macros::Debug, - ::core::clone::Clone, - ::core::cmp::PartialEq, - ::serde::Serialize, - ::serde::Deserialize, - )] - } - } else { - quote! { - #[derive( - ::macros::Debug, - ::frame_support_procedural::CloneNoBound, - ::frame_support_procedural::PartialEqNoBound, - ::serde::Serialize, - ::serde::Deserialize, - )] - } + // let derives = if derive_input.generics.params.is_empty() { + // quote! { + // #[derive( + // ::macros::Debug, + // ::core::clone::Clone, + // ::core::cmp::PartialEq, + // ::serde::Serialize, + // ::serde::Deserialize, + // )] + // } + // } else { + // quote! { + // #[derive( + // ::macros::Debug, + // ::frame_support_procedural::CloneNoBound, + // ::frame_support_procedural::PartialEqNoBound, + // ::serde::Serialize, + // ::serde::Deserialize, + // )] + // } + // }; + + let derives = quote! { + #[derive( + ::macros::Debug, + ::core::clone::Clone, + ::core::cmp::PartialEq, + ::serde::Serialize, + ::serde::Deserialize, + )] }; match &mut derive_input.data { @@ -54,11 +67,9 @@ fn apply_item(derive_input: DeriveInput) -> Result Result Result (#(#type_params_to_cover),*)> }); } @@ -167,3 +175,140 @@ fn extract_covered_types(generics: &mut Generics) -> Option> { Some(type_params_to_cover.clone()) } } + +#[proc_macro_derive(SubsetOf, attributes(subset_of))] +pub fn subset_of(input: TokenStream) -> TokenStream { + // Parse the input tokens into a syntax tree + let input = parse_macro_input!(input as DeriveInput); + + let enm = match input.data { + syn::Data::Struct(struct_) => { + return syn::Error::new_spanned( + struct_.struct_token, + "SubsetOf can only be derived on enums", + ) + .into_compile_error() + .into() + } + syn::Data::Enum(enm) => enm, + syn::Data::Union(union) => { + return syn::Error::new_spanned( + union.union_token, + "SubsetOf can only be derived on enums", + ) + .into_compile_error() + .into() + } + }; + + let impl_generics: ( + syn::ImplGenerics<'_>, + syn::TypeGenerics<'_>, + Option<&syn::WhereClause>, + ) = input.generics.split_for_impl(); + + let impls = enm + .variants + .into_iter() + .filter(|x| { + x.attrs + .iter() + .all(|x| x.meta != parse_quote!(subset_of(ignore))) + }) + .map(|x| match x.fields { + syn::Fields::Unnamed(mut unnamed) => { + let fields_span = unnamed.span(); + if unnamed.unnamed.len() == 1 { + let field = unnamed.unnamed.pop().unwrap().into_value(); + Ok(mk_impls( + &input.ident, + &x.ident, + &FieldName::Index(syn::Index::from(0)), + &field.ty, + &impl_generics, + )) + } else { + Err(syn::Error::new( + fields_span, + "only newtype variants are supported", + )) + } + } + fields => Err(syn::Error::new( + fields.span(), + "only newtype variants are supported", + )), + }) + .fold( + (proc_macro2::TokenStream::new(), None::), + |mut acc, curr| { + match curr { + Ok(ok) => acc.0.extend(ok), + Err(err) => match &mut acc.1 { + Some(errs) => { + errs.combine(err); + } + None => acc.1 = Some(err), + }, + } + acc + }, + ); + + match impls { + (_, Some(errs)) => errs.into_compile_error().into(), + (impls, None) => impls.into(), + } +} + +fn mk_impls( + enum_ident: &Ident, + variant_name: &Ident, + field_name: &FieldName, + field_type: &Type, + (impl_generics, ty_generics, where_clause): &( + syn::ImplGenerics<'_>, + syn::TypeGenerics<'_>, + Option<&syn::WhereClause>, + ), +) -> proc_macro2::TokenStream { + quote_spanned! {field_type.span()=> + #[automatically_derived] + impl #impl_generics queue_msg::aggregation::SubsetOf<#enum_ident #ty_generics> for #field_type #where_clause { + fn try_from_super(t: #enum_ident #ty_generics) -> Result { + match t { + #enum_ident::#variant_name { #field_name: t, .. } => ::std::result::Result::Ok(t), + #[allow(unreachable_patterns)] // triggers on enums with one variant + _ => ::std::result::Result::Err(t), + } + } + + fn into_super(self) -> #enum_ident #ty_generics { + #[allow(clippy::init_numbered_fields)] + #enum_ident::#variant_name { #field_name: self } + } + } + + // #[automatically_derived] + // impl #impl_generics ::std::convert::From<#field_type> for #enum_ident #ty_generics #where_clause { + // fn from(value: #field_type) -> Self { + // #[allow(clippy::init_numbered_fields)] + // #enum_ident::#variant_name { #field_name: value } + // } + // } + } +} + +enum FieldName { + Index(syn::Index), + // Ident(&'a syn::Ident), +} + +impl ToTokens for FieldName { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + match self { + FieldName::Index(i) => i.to_tokens(tokens), + // FieldName::Ident(i) => i.to_tokens(tokens), + } + } +} diff --git a/lib/queue-msg/Cargo.toml b/lib/queue-msg/Cargo.toml index 94256fc3eb..f2c2f233df 100644 --- a/lib/queue-msg/Cargo.toml +++ b/lib/queue-msg/Cargo.toml @@ -8,13 +8,12 @@ edition = { workspace = true } workspace = true [dependencies] -arbitrary = { workspace = true, optional = true, features = ["derive"] } either = { workspace = true } frame-support-procedural = { workspace = true } frunk = { workspace = true } futures = { workspace = true, features = ["alloc", "std"] } itertools = { version = "0.12.1", default-features = false } -macros.workspace = true +macros = { workspace = true } queue-msg-macro = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } @@ -30,5 +29,3 @@ tracing-subscriber = { workspace = true, features = ["env-filter"] } [features] default = [] - -arbitrary = ["dep:arbitrary", "unionlabs/arbitrary"] diff --git a/lib/queue-msg/src/aggregation.rs b/lib/queue-msg/src/aggregation.rs index 073ad5c37f..c2d7e03af8 100644 --- a/lib/queue-msg/src/aggregation.rs +++ b/lib/queue-msg/src/aggregation.rs @@ -1,42 +1,56 @@ -use std::{collections::VecDeque, fmt::Debug, ops::ControlFlow}; +use std::{collections::VecDeque, fmt::Debug}; use frunk::{HCons, HList, HNil}; use tracing::error; use crate::{Op, QueueMessage}; -pub fn do_aggregate>( - event: A, +pub trait SubsetOf: Sized { + fn try_from_super(t: T) -> Result; + + fn into_super(self) -> T; +} + +pub fn do_callback>( + event: Cb, data: VecDeque, ) -> Op { let data = match HListTryFromIterator::try_from_iter(data) { Ok(ok) => ok, Err(_) => { + error!( + "could not aggregate data into {}", + std::any::type_name::() + ); panic!( "could not aggregate data into {}", - std::any::type_name::() + std::any::type_name::() ) } }; - A::aggregate(event, data) + Cb::call(event, data) } -pub(crate) fn pluck, U>( - mut vec: VecDeque, -) -> ControlFlow<(VecDeque, T), VecDeque> { +pub fn pluck, U>(mut vec: VecDeque) -> PluckResult { let mut new_vec = VecDeque::new(); while let Some(data) = vec.pop_front() { - match T::try_from(data) { + match T::try_from_super(data) { Ok(t) => { new_vec.extend(vec); - return ControlFlow::Break((new_vec, t)); + return PluckResult::Found(t, new_vec); } Err(value) => new_vec.push_back(value), } } - ControlFlow::Continue(new_vec) + PluckResult::NotFound(new_vec) +} + +pub enum PluckResult { + /// `(item, rest)` + Found(T, VecDeque), + NotFound(VecDeque), } // TODO: Figure out how to return the entire source list on error @@ -47,7 +61,7 @@ pub trait HListTryFromIterator: Sized { impl HListTryFromIterator for HCons where - T: TryFrom + Into, + T: SubsetOf, Tail: HListTryFromIterator, U: Debug, { @@ -55,13 +69,13 @@ where fn try_from_iter(vec: VecDeque) -> Result> { match pluck::(vec) { - ControlFlow::Continue(invalid) => { + PluckResult::NotFound(invalid) => { error!(?invalid, "type didn't match"); Err(invalid) } - ControlFlow::Break((vec, u)) => Ok(HCons { - head: u, + PluckResult::Found(t, vec) => Ok(HCons { + head: t, tail: Tail::try_from_iter(vec)?, }), } @@ -80,37 +94,37 @@ impl HListTryFromIterator for HNil { } } -pub trait UseAggregate> { - type AggregatedData: HListTryFromIterator; +pub trait DoCallback> { + /// Unordered params for this callback. If there are multiple params of the same type, their ordering is not guaranteed or deterministic. + type Params: HListTryFromIterator; - fn aggregate(this: Self, data: Self::AggregatedData) -> R; + fn call(this: Self, data: Self::Params) -> R; } -pub struct TupleAggregator; +pub struct TupleCallback; -pub trait IsAggregateData = TryFrom<::Data, Error = ::Data> - + Into<::Data>; +// pub trait IsAggregateData = TryFrom<::Data, Error = ::Data> +// + Into<::Data>; -impl UseAggregate for TupleAggregator +impl DoCallback for TupleCallback where T: QueueMessage, { - type AggregatedData = HList![]; + type Params = HList![]; - fn aggregate(_: TupleAggregator, _data: Self::AggregatedData) {} + fn call(_: TupleCallback, _data: Self::Params) {} } -impl UseAggregate for TupleAggregator +impl DoCallback for TupleCallback where T: QueueMessage, - U: IsAggregateData, - TupleAggregator: UseAggregate, - HList![U, ...>::AggregatedData]: - HListAsTuple, + U: SubsetOf, + TupleCallback: DoCallback, + HList![U, ...>::Params]: HListAsTuple, { - type AggregatedData = HList![U, ...>::AggregatedData]; + type Params = HList![U, ...>::Params]; - fn aggregate(_: TupleAggregator, data: Self::AggregatedData) -> (U, Tail) { + fn call(_: TupleCallback, data: Self::Params) -> (U, Tail) { data.into_tuple() } } @@ -137,23 +151,16 @@ impl HListAsTuple for HCons { #[cfg(test)] mod tests { - use std::sync::Arc; + use std::collections::VecDeque; use frunk::HList; - use tracing_subscriber::EnvFilter; - - use super::*; - use crate::{ - fetch, - optimize::{passes::NormalizeFinal, Pure}, - run_to_completion, - test_utils::{DataA, DataB, DataC, FetchA, FetchB, FetchC, SimpleMessage}, - InMemoryQueue, - }; + use queue_msg_macro::SubsetOf; + + use crate::{aggregation::HListTryFromIterator, test_utils::queue_msg}; #[test] fn hlist_try_from_iter() { - #[derive(Debug, PartialEq, enumorph::Enumorph)] + #[derive(Debug, PartialEq, enumorph::Enumorph, SubsetOf)] pub enum A { B(B), C(C), @@ -200,61 +207,54 @@ mod tests { ); } - #[tokio::test] - async fn tuple_aggregate() { - let _ = tracing_subscriber::fmt() - .with_env_filter(EnvFilter::from_default_env()) - .try_init(); - - let _: () = run_to_completion::< - TupleAggregator, - SimpleMessage, - (), - InMemoryQueue, - NormalizeFinal, - Pure, - >( - TupleAggregator, - Arc::new(()), - (), - [], - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await; - - let _: (DataA, ()) = run_to_completion::< - TupleAggregator, - SimpleMessage, - (DataA, ()), - InMemoryQueue, - NormalizeFinal, - Pure, - >( - TupleAggregator, - Arc::new(()), - (), - [fetch(FetchA {})], - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await; - - let _: (DataC, (DataB, (DataA, ()))) = run_to_completion::< - TupleAggregator, - SimpleMessage, - (DataC, (DataB, (DataA, ()))), - InMemoryQueue, - NormalizeFinal, - Pure, - >( - TupleAggregator, - Arc::new(()), - (), - [fetch(FetchA {}), fetch(FetchC {}), fetch(FetchB {})], - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await; - } + // #[tokio::test] + // async fn tuple_aggregate() { + // let _ = tracing_subscriber::fmt() + // .with_env_filter(EnvFilter::from_default_env()) + // .try_init(); + + // let _: () = run_to_completion::< + // TupleCallback, + // SimpleMessage, + // (), + // InMemoryQueue, + // NoopPass, + // Pure, + // >(TupleCallback, (), (), [], NoopPass, Pure(NoopPass)) + // .await; + + // let _: (DataA, ()) = run_to_completion::< + // TupleCallback, + // SimpleMessage, + // (DataA, ()), + // InMemoryQueue, + // NoopPass, + // Pure, + // >( + // TupleCallback, + // (), + // (), + // [call(FetchA {})], + // NoopPass, + // Pure(NoopPass), + // ) + // .await; + + // let _: (DataC, (DataB, (DataA, ()))) = run_to_completion::< + // TupleCallback, + // SimpleMessage, + // (DataC, (DataB, (DataA, ()))), + // InMemoryQueue, + // NoopPass, + // Pure, + // >( + // TupleCallback, + // (), + // (), + // [call(FetchA {}), call(FetchC {}), call(FetchB {})], + // NoopPass, + // Pure(NoopPass), + // ) + // .await; + // } } diff --git a/lib/queue-msg/src/lib.rs b/lib/queue-msg/src/lib.rs index 6d35a9d2fc..2a0c4111ba 100644 --- a/lib/queue-msg/src/lib.rs +++ b/lib/queue-msg/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(trait_alias, extract_if)] +#![feature(trait_alias, extract_if, min_exhaustive_patterns)] // #![warn(clippy::large_futures, clippy::large_stack_frames)] use std::{ @@ -18,21 +18,23 @@ use std::{ use either::Either; use frame_support_procedural::{CloneNoBound, DebugNoBound}; use futures::{ - stream::{self, try_unfold}, - Stream, StreamExt, TryStreamExt, + future, + stream::{self, FuturesUnordered}, + FutureExt, Stream, StreamExt, TryStreamExt, }; -pub use queue_msg_macro::queue_msg; +pub use queue_msg_macro::{queue_msg, SubsetOf}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use tokio::time::sleep; +use tokio::{pin, time::sleep}; use tracing::{debug, error, info, info_span, trace, warn, Instrument}; -use unionlabs::{never::Never, ErrorReporter, MaybeArbitrary}; +use unionlabs::{never::Never, ErrorReporter}; use crate::{ - aggregation::{HListTryFromIterator, UseAggregate}, + aggregation::{DoCallback, HListTryFromIterator}, optimize::{OptimizationResult, Pass, PurePass}, }; pub mod aggregation; +pub mod normalize; pub mod optimize; pub trait Queue: Debug + Clone + Send + Sync + Sized + 'static { @@ -60,40 +62,47 @@ pub trait Queue: Debug + Clone + Send + Sync + Sized + 'static &'a self, pre_reenqueue_passes: &'a O, f: F, - ) -> impl Future, Self::Error>> + Send + '_ + ) -> impl Future, Self::Error>> + Send + Captures<'a> where - F: (FnOnce(Op) -> Fut) + Send + 'static, - Fut: Future>, String>)> + Send + 'static, + F: (FnOnce(Op) -> Fut) + Send + Captures<'a>, + Fut: Future>, String>)> + Send + Captures<'a>, R: Send + Sync + 'static, O: PurePass; fn optimize<'a, O: Pass>( &'a self, + tag: &'a str, optimizer: &'a O, ) -> impl Future>> + Send + 'a; } -#[queue_msg] +#[derive( + ::macros::Debug, + ::frame_support_procedural::CloneNoBound, + ::frame_support_procedural::PartialEqNoBound, + ::serde::Serialize, + ::serde::Deserialize, +)] +#[serde( + tag = "@type", + content = "@value", + rename_all = "snake_case", + bound(serialize = "", deserialize = ""), + deny_unknown_fields +)] #[debug(bound())] // TODO: Merge "event" and "data", and "fetch", "effect", and "wait" // essentially what we want is "pure custom message" and "impure custom message" // all other logic can be built with aggregations pub enum Op { - /// An external event. This could be something like an IBC event, an external command, or - /// anything else that occurs outside of the state machine. Can also be thought of as an "entry - /// point". - Event(T::Event), /// Inert data that will either be used in an aggregation or bubbled up to the top and sent as /// an output. Data(T::Data), - /// Fetch some data from the outside world. This can also be thought of as a "read" operation. - Fetch(T::Fetch), - /// Send a message to the outside world. This can also be thought of as a "write" operation. - Effect(T::Effect), - /// Wait for some external condition. - Wait(T::Wait), - - Defer(Defer), + /// Execute an action. + Call(T::Call), + Defer { + until: u64, + }, /// Repeats the contained message `times` times. If `times` is `None`, will repeat infinitely. Repeat { #[serde(default, skip_serializing_if = "Option::is_none")] @@ -142,13 +151,13 @@ pub enum Op { remaining: NonZeroU8, msg: Box, }, - Aggregate { + Promise { /// Messages that are expected to resolve to [`Data`]. queue: VecDeque, /// The resolved data messages. data: VecDeque, /// The message that will utilize the aggregated data. - receiver: T::Aggregate, + receiver: T::Callback, }, /// Handle the contained message, voiding any returned `Data` messages that it returns. Void(Box), @@ -193,27 +202,21 @@ pub fn conc(ts: impl IntoIterator>) -> Op { #[inline] #[must_use = "constructing an instruction has no effect"] -pub fn defer_absolute(timestamp: u64) -> Op { - Op::Defer(Defer::Absolute(timestamp)) +pub fn defer(timestamp: u64) -> Op { + Op::Defer { until: timestamp } } #[inline] #[must_use = "constructing an instruction has no effect"] -pub fn defer_relative(seconds: u64) -> Op { - Op::Defer(Defer::Relative(seconds)) +pub fn call(t: impl Into) -> Op { + Op::Call(t.into()) } -#[inline] -#[must_use = "constructing an instruction has no effect"] -pub fn fetch(t: impl Into) -> Op { - Op::Fetch(t.into()) -} - -#[inline] -#[must_use = "constructing an instruction has no effect"] -pub fn effect(t: impl Into) -> Op { - Op::Effect(t.into()) -} +// #[inline] +// #[must_use = "constructing an instruction has no effect"] +// pub fn effect(t: impl Into) -> Op { +// Op::Effect(t.into()) +// } #[inline] #[must_use = "constructing an instruction has no effect"] @@ -221,29 +224,24 @@ pub fn data(t: impl Into) -> Op { Op::Data(t.into()) } -#[inline] -#[must_use = "constructing an instruction has no effect"] -pub fn wait(t: impl Into) -> Op { - Op::Wait(t.into()) -} - -#[inline] -#[must_use = "constructing an instruction has no effect"] -pub fn event(t: impl Into) -> Op { - Op::Event(t.into()) -} +// #[inline] +// #[must_use = "constructing an instruction has no effect"] +// pub fn wait(t: impl Into) -> Op { +// Op::Wait(t.into()) +// } #[inline] #[must_use = "constructing an instruction has no effect"] -pub fn aggregate( +pub fn promise( queue: impl IntoIterator>, + // TODO: Remove this and put data in `queue` instead data: impl IntoIterator, - receiver: impl Into, + callback: impl Into, ) -> Op { - Op::Aggregate { + Op::Promise { queue: queue.into_iter().collect(), data: data.into_iter().collect(), - receiver: receiver.into(), + receiver: callback.into(), } } @@ -265,26 +263,25 @@ pub fn noop() -> Op { Op::Noop } -pub trait OpT = Debug - + Clone - + PartialEq - + Serialize - + for<'a> Deserialize<'a> - + Send - + Sync - + Unpin - + MaybeArbitrary; +pub trait OpT = + Debug + Clone + PartialEq + Serialize + for<'a> Deserialize<'a> + Send + Sync + Unpin; pub trait QueueMessage: Sized + 'static { - type Event: HandleEvent + OpT; - type Data: HandleData + OpT; - type Fetch: HandleFetch + OpT; - type Effect: HandleEffect + OpT; - type Wait: HandleWait + OpT; + type Data: OpT; + type Call: HandleCall + OpT; + type Callback: HandleCallback + OpT; - type Aggregate: HandleAggregate + OpT; + type Context: Context; +} - type Store: Debug + Send + Sync; +pub trait Context: Send + Sync { + fn tags(&self) -> Vec<&str>; +} + +impl Context for () { + fn tags(&self) -> Vec<&str> { + vec![] + } } impl Op { @@ -292,22 +289,24 @@ impl Op { #[allow(clippy::type_complexity)] pub fn handle<'a>( self, - store: &'a T::Store, + store: &'a T::Context, depth: usize, ) -> Pin>, QueueError>> + Send + 'a>> { - debug!(depth, "handling message"); + trace!(%depth, "handling message"); let fut = async move { match self { - Self::Event(event) => event.handle(store).map(Some), - Self::Data(data) => data.handle(store).map(Some), - - Self::Fetch(fetch) => fetch.handle(store).await.map(Some), - Self::Effect(msg) => msg.handle(store).await.map(Some), - Self::Wait(wait) => wait.handle(store).await.map(Some), + Op::Data(data) => { + // TODO: Use valuable here + info!( + data = %serde_json::to_string(&data).unwrap(), + "received data outside of an aggregation" + ); + Ok(None) + } - Self::Defer(Defer::Relative(seconds)) => Ok(Some(defer_absolute(now() + seconds))), - Self::Defer(Defer::Absolute(seconds)) => { + Op::Call(fetch) => fetch.handle(store).await.map(Some), + Op::Defer { until: seconds } => { // if we haven't hit the time yet, requeue the defer msg let current_ts_seconds = now(); if current_ts_seconds < seconds { @@ -321,12 +320,12 @@ impl Op { // TODO: Make the time configurable? sleep(Duration::from_millis(10)).await; - Ok(Some(defer_absolute(seconds))) + Ok(Some(defer(seconds))) } else { Ok(None) } } - Self::Timeout { + Op::Timeout { timeout_timestamp, msg, } => { @@ -341,7 +340,7 @@ impl Op { msg.handle(store, depth + 1).await } } - Self::Seq(mut queue) => match queue.pop_front() { + Op::Seq(mut queue) => match queue.pop_front() { Some(msg) => { let msg = msg.handle(store, depth + 1).await?; @@ -353,7 +352,7 @@ impl Op { } None => Ok(None), }, - Self::Conc(mut queue) => match queue.pop_front() { + Op::Conc(mut queue) => match queue.pop_front() { Some(msg) => { let msg = msg.handle(store, depth + 1).await?; @@ -365,7 +364,7 @@ impl Op { } None => Ok(None), }, - Self::Retry { remaining, msg } => { + Op::Retry { remaining, msg } => { // TODO: Add some sort of exponential backoff functionality to this message type const RETRY_DELAY_SECONDS: u64 = 1; @@ -380,7 +379,7 @@ impl Op { ); Ok(Some(seq([ - defer_absolute(now() + RETRY_DELAY_SECONDS), + defer(now() + RETRY_DELAY_SECONDS), retry(retries_left, *msg), ]))) } @@ -391,35 +390,42 @@ impl Op { }, } } - Self::Aggregate { + Op::Promise { mut queue, mut data, receiver, } => { if let Some(msg) = queue.pop_front() { - let msg = msg.handle(store, depth + 1).await?; - - if let Some(msg) = msg { - match msg { - Self::Data(d) => { - data.push_back(d); - } - m => { - queue.push_back(m); + match msg { + Op::Data(d) => { + data.push_back(d); + } + msg => { + let msg = msg.handle(store, depth + 1).await?; + + if let Some(msg) = msg { + match msg { + Op::Data(d) => { + data.push_back(d); + } + m => { + queue.push_back(m); + } + } } } } - Ok(Some(aggregate(queue, data, receiver))) + Ok(Some(promise(queue, data, receiver))) } else { // queue is empty, handle msg - receiver.handle(data).map(Some) + receiver.handle(store, data).await.map(Some) } } - Self::Repeat { times: None, msg } => { + Op::Repeat { times: None, msg } => { Ok(Some(seq([*msg.clone(), repeat(None, *msg)]))) } - Self::Repeat { + Op::Repeat { times: Some(times), msg, } => Ok(Some(seq([*msg.clone()].into_iter().chain( @@ -463,74 +469,36 @@ impl Op { #[cfg(test)] mod tests { use super::*; - use crate::optimize::{ - passes::{ExtractData, FlattenConc, FlattenSeq}, - PurePass, - }; + use crate::normalize::{flatten_seq, normalize}; enum UnitMessage {} impl QueueMessage for UnitMessage { - type Event = (); type Data = (); - type Fetch = (); - type Effect = (); - type Wait = (); - - type Aggregate = (); - - type Store = (); - } - - impl HandleEffect for () { - async fn handle(self, _: &()) -> Result, QueueError> { - Ok(noop()) - } - } - - impl HandleEvent for () { - fn handle(self, _: &()) -> Result, QueueError> { - Ok(noop()) - } - } + type Call = (); + type Callback = (); - impl HandleData for () { - fn handle(self, _: &()) -> Result, QueueError> { - Ok(noop()) - } + type Context = (); } - impl HandleFetch for () { + impl HandleCall for () { async fn handle(self, _: &()) -> Result, QueueError> { Ok(noop()) } } - impl HandleWait for () { - async fn handle(self, _: &()) -> Result, QueueError> { + impl HandleCallback for () { + async fn handle(self, _: &(), _: VecDeque<()>) -> Result, QueueError> { Ok(noop()) } } - impl HandleAggregate for () { - fn handle(self, _: VecDeque<()>) -> Result, QueueError> { - Ok(noop()) - } - } - - #[queue_msg] - pub struct SimpleEvent {} #[queue_msg] pub struct SimpleData {} #[queue_msg] - pub struct SimpleFetch {} - #[queue_msg] - pub struct SimpleEffect {} - #[queue_msg] - pub struct SimpleWait {} - + pub struct SimpleCall {} #[queue_msg] - pub struct SimpleAggregate {} + pub struct SimpleCallback {} // macro_rules! vec_deque { // ($($tt:tt)*) => { @@ -538,74 +506,59 @@ mod tests { // }; // } - // async fn assert_steps( - // engine: &Engine, - // q: &mut InMemoryQueue, - // steps: impl IntoIterator>>, + // async fn assert_steps<'a, T: QueueMessage, Q: Queue, O: PurePass>( + // engine: &Engine<'a, T, Q, O>, + // q: &InMemoryQueue, + // steps: impl IntoIterator>>, // ) { // for (i, step) in steps.into_iter().enumerate() { - // engine.step(q).await.unwrap(); - // assert_eq!(*q.queue.lock().unwrap(), step, "step {i} incorrect"); + // engine.step().await.unwrap(); + // assert_eq!( + // q.ready + // .lock() + // .unwrap() + // .values() + // .map(|item| item.msg.clone()) + // .collect::>(), + // step, + // "step {i} incorrect" + // ); // } // } #[test] fn flatten() { let msg = seq::([ - defer_absolute(1), - seq([defer_absolute(2), seq([defer_absolute(3)])]), - seq([defer_absolute(4)]), - defer_absolute(5), + defer(1), + seq([defer(2), seq([defer(3)])]), + seq([defer(4)]), + defer(5), ]); assert_eq!( - FlattenSeq.run_pass_pure(vec![msg]).optimize_further, + flatten_seq(vec![msg]), vec![( vec![0], - seq([ - defer_absolute(1), - defer_absolute(2), - defer_absolute(3), - defer_absolute(4), - defer_absolute(5) - ]) + seq([defer(1), defer(2), defer(3), defer(4), defer(5)]) )] ); - let msg = seq::([defer_absolute(1)]); - assert_eq!( - FlattenSeq.run_pass_pure(vec![msg]).optimize_further, - vec![(vec![0], defer_absolute(1))] - ); + let msg = seq::([defer(1)]); + assert_eq!(normalize(vec![msg]), vec![(vec![0], defer(1))]); - let msg = conc::([defer_absolute(1)]); - assert_eq!( - FlattenSeq.run_pass_pure(vec![msg]).optimize_further, - vec![(vec![0], conc([defer_absolute(1)]))] - ); + let msg = conc::([defer(1)]); + assert_eq!(normalize(vec![msg]), vec![(vec![0], defer(1))]); - let msg = conc::([seq([defer_absolute(1)])]); - assert_eq!( - FlattenSeq.run_pass_pure(vec![msg]).optimize_further, - vec![(vec![0], conc([defer_absolute(1)]))] - ); + let msg = conc::([seq([defer(1)])]); + assert_eq!(normalize(vec![msg]), vec![(vec![0], defer(1))]); let msg = seq::([noop()]); - assert_eq!( - FlattenSeq.run_pass_pure(vec![msg]).optimize_further, - vec![(vec![0], noop())] - ); + assert_eq!(normalize(vec![msg]), vec![]); let msg = conc::([seq([noop()])]); - assert_eq!( - FlattenSeq.run_pass_pure(vec![msg]).optimize_further, - vec![(vec![0], conc([noop()]))] - ); + assert_eq!(normalize(vec![msg]), vec![]); let msg = conc::([conc([conc([noop()])])]); - assert_eq!( - FlattenConc.run_pass_pure(vec![msg]).optimize_further, - vec![(vec![0], noop())] - ); + assert_eq!(normalize(vec![msg]), vec![]); } #[test] @@ -614,79 +567,39 @@ mod tests { // (conc, seq) let msg = conc::([seq([conc([noop()])])]); - assert_eq!( - (FlattenConc, FlattenSeq) - .run_pass_pure(vec![msg]) - .optimize_further, - vec![(vec![0], noop())] - ); + assert_eq!(normalize(vec![msg]), vec![]); let msg = conc::([seq([conc([seq([conc([seq([conc([noop()])])])])])])]); - assert_eq!( - (FlattenConc, FlattenSeq) - .run_pass_pure(vec![msg]) - .optimize_further, - vec![(vec![0], noop())] - ); + assert_eq!(normalize(vec![msg]), vec![]); let msg = conc::([seq([conc([seq([conc([seq([conc([seq([conc([ - noop(), + data(()), ])])])])])])])])]); - assert_eq!( - (FlattenConc, FlattenSeq) - .run_pass_pure(vec![msg]) - .optimize_further, - vec![(vec![0], noop())] - ); + assert_eq!(normalize(vec![msg]), vec![(vec![0], data(()))]); - let msg = seq::([conc([seq([conc([noop()])])])]); - assert_eq!( - (FlattenConc, FlattenSeq) - .run_pass_pure(vec![msg]) - .optimize_further, - vec![(vec![0], noop())] - ); + let msg = seq::([conc([seq([conc([data(())])])])]); + assert_eq!(normalize(vec![msg]), vec![(vec![0], data(()))]); - let msg = seq::([conc([seq([conc([seq([conc([seq([conc([noop()])])])])])])])]); - assert_eq!( - (FlattenConc, FlattenSeq) - .run_pass_pure(vec![msg]) - .optimize_further, - vec![(vec![0], noop())] - ); + let msg = + seq::([conc([seq([conc([seq([conc([seq([conc([ + data(()), + ])])])])])])])]); + assert_eq!(normalize(vec![msg]), vec![(vec![0], data(()))]); let msg = seq::([conc([seq([conc([seq([conc([seq([conc([seq([ - conc([noop()]), + conc([data(())]), ])])])])])])])])]); - assert_eq!( - (FlattenConc, FlattenSeq) - .run_pass_pure(vec![msg]) - .optimize_further, - vec![(vec![0], noop())] - ); + assert_eq!(normalize(vec![msg]), vec![(vec![0], data(()))]); } #[test] fn flatten_seq_conc_fixed_point_is_noop() { // this message can't be optimized any further, flattening operations should be a noop - let msg = seq::([ - conc([defer_absolute(1), defer_absolute(2)]), - defer_absolute(3), - ]); - assert_eq!( - (FlattenConc, FlattenSeq) - .run_pass_pure(vec![msg.clone()]) - .optimize_further, - vec![(vec![0], msg.clone())] - ); - assert_eq!( - (FlattenSeq, FlattenConc) - .run_pass_pure(vec![msg.clone()]) - .optimize_further, - vec![(vec![0], msg)] - ); + let msg = seq::([conc([defer(1), defer(2)]), defer(3)]); + assert_eq!(normalize(vec![msg.clone()]), vec![(vec![0], msg.clone())]); + assert_eq!(normalize(vec![msg.clone()]), vec![(vec![0], msg)]); } #[test] @@ -698,171 +611,185 @@ mod tests { data(()), ]); assert_eq!( - ExtractData.run_pass_pure(vec![msg]).optimize_further, + normalize(vec![msg]), vec![ (vec![0], data(())), (vec![0], data(())), (vec![0], data(())), (vec![0], data(())), (vec![0], data(())), - (vec![0], seq([seq([seq([])]), seq([])])), ], ); } + #[test] + fn extract_data_seq_in_promise_queue() { + let msg = promise::([seq([call(()), data(())])], [], ()); + assert_eq!(normalize(vec![msg.clone()]), vec![(vec![0], msg)]); + } + + #[test] + fn seq_defer_call_data() { + let msg = seq([seq::([defer(1), call(())]), data(())]); + assert_eq!( + normalize(vec![msg.clone()]), + vec![(vec![0], seq([defer(1), call(()), data(())]))] + ); + } + #[test] fn extract_data_complex() { let msg = seq::([ data(()), - effect(()), - seq([fetch(()), data(()), seq([data(())])]), - effect(()), - seq([data(()), effect(())]), + call(()), + seq([call(()), data(()), seq([data(())])]), + call(()), + seq([data(()), call(())]), data(()), ]); assert_eq!( - ExtractData.run_pass_pure(vec![msg]).optimize_further, + normalize(vec![msg]), vec![ - (vec![0], data(())), - (vec![0], data(())), - (vec![0], data(())), - (vec![0], data(())), (vec![0], data(())), ( vec![0], seq([ - effect(()), - seq([fetch(()), seq([])]), - effect(()), - seq([effect(())]) + call(()), + call(()), + data(()), + data(()), + call(()), + data(()), + call(()), + data(()), ]) - ), + ) ], ); } // #[tokio::test] // async fn conc_seq_nested() { - // let engine = Engine::new(Arc::new(())); + // let q = InMemoryQueue::new(()).now_or_never().unwrap().unwrap(); - // let mut q = InMemoryQueue::new(()).now_or_never().unwrap().unwrap(); + // let engine = Engine::new(&(), &q, &NoopPass); - // let msgs = seq::([ - // conc([fetch(()), fetch(())]), - // conc([wait(()), wait(())]), + // let msgs = seq::([ + // conc([call(()), call(())]), + // conc([call(()), call(())]), // conc([ - // repeat(None, fetch(())), - // repeat(None, fetch(())), - // effect(()), - // seq([fetch(()), fetch(()), effect(())]), + // repeat(None, call(())), + // repeat(None, call(())), + // call(()), + // seq([call(()), call(()), call(())]), // ]), // ]); - // q.enqueue(msgs).await.unwrap(); - - // // assert_steps( - // // &engine, - // // &mut q, - // // [ - // // vec_deque![seq::([ - // // // conc(a, b), handles a, conc(b) == b - // // fetch(()), - // // conc([wait(()), wait(())]), - // // conc([ - // // repeat(None, fetch(())), - // // repeat(None, fetch(())), - // // effect(()), - // // seq([fetch(()), fetch(()), effect(())]), - // // ]), - // // ])], - // // vec_deque![seq::([ - // // conc([wait(()), wait(())]), - // // conc([ - // // repeat(None, fetch(())), - // // repeat(None, fetch(())), - // // effect(()), - // // seq([fetch(()), fetch(()), effect(())]), - // // ]), - // // ])], - // // vec_deque![seq::([ - // // // conc(a, b), handles a, conc(b) == b - // // wait(()), - // // conc([ - // // repeat(None, fetch(())), - // // repeat(None, fetch(())), - // // effect(()), - // // seq([fetch(()), fetch(()), effect(())]), - // // ]), - // // ])], - // // // seq(a, conc(m...)), handles a, seq(conc(m...)) == m... - // // vec_deque![ - // // repeat(None, fetch(())), - // // repeat(None, fetch(())), - // // effect(()), - // // seq([fetch(()), fetch(()), effect(())]), - // // ], - // // vec_deque![ - // // repeat(None, fetch(())), - // // effect(()), - // // seq([fetch(()), fetch(()), effect(())]), - // // // repeat(a) queues seq(a, repeat(a)) - // // seq([fetch(()), repeat(None, fetch(()))]) - // // ], - // // vec_deque![ - // // effect(()), - // // seq([fetch(()), fetch(()), effect(())]), - // // seq([fetch(()), repeat(None, fetch(()))]), - // // // repeat(a) queues seq(a, repeat(a)) - // // seq([fetch(()), repeat(None, fetch(()))]) - // // ], - // // vec_deque![ - // // seq([fetch(()), fetch(()), effect(())]), - // // seq([fetch(()), repeat(None, fetch(()))]), - // // seq([fetch(()), repeat(None, fetch(()))]), - // // noop(), - // // ], - // // vec_deque![ - // // seq([fetch(()), repeat(None, fetch(()))]), - // // seq([fetch(()), repeat(None, fetch(()))]), - // // noop(), - // // seq([fetch(()), effect(())]), - // // ], - // // vec_deque![ - // // seq([fetch(()), repeat(None, fetch(()))]), - // // noop(), - // // seq([fetch(()), effect(())]), - // // repeat(None, fetch(())), - // // ], - // // vec_deque![ - // // noop(), - // // seq([fetch(()), effect(())]), - // // repeat(None, fetch(())), - // // repeat(None, fetch(())), - // // ], - // // vec_deque![ - // // seq([fetch(()), effect(())]), - // // repeat(None, fetch(())), - // // repeat(None, fetch(())), - // // ], - // // vec_deque![repeat(None, fetch(())), repeat(None, fetch(())), effect(()),], - // // vec_deque![ - // // repeat(None, fetch(())), - // // effect(()), - // // seq([fetch(()), repeat(None, fetch(()))]), - // // ], - // // vec_deque![ - // // effect(()), - // // seq([fetch(()), repeat(None, fetch(()))]), - // // seq([fetch(()), repeat(None, fetch(()))]), - // // ], - // // vec_deque![ - // // seq([fetch(()), repeat(None, fetch(()))]), - // // seq([fetch(()), repeat(None, fetch(()))]), - // // noop(), - // // ], - // // ], - // // ) - // // .await; + // q.enqueue(msgs, &NoopPass).await.unwrap(); + + // assert_steps( + // &engine, + // &q, + // [ + // vec_deque![seq::([ + // // conc(a, b), handles a, conc(b) == b + // call(()), + // conc([call(()), call(())]), + // conc([ + // repeat(None, call(())), + // repeat(None, call(())), + // call(()), + // seq([call(()), call(()), call(())]), + // ]), + // ])], + // vec_deque![seq::([ + // conc([call(()), call(())]), + // conc([ + // repeat(None, call(())), + // repeat(None, call(())), + // call(()), + // seq([call(()), call(()), call(())]), + // ]), + // ])], + // vec_deque![seq::([ + // // conc(a, b), handles a, conc(b) == b + // call(()), + // conc([ + // repeat(None, call(())), + // repeat(None, call(())), + // call(()), + // seq([call(()), call(()), call(())]), + // ]), + // ])], + // // seq(a, conc(m...)), handles a, seq(conc(m...)) == m... + // vec_deque![ + // repeat(None, call(())), + // repeat(None, call(())), + // call(()), + // seq([call(()), call(()), call(())]), + // ], + // vec_deque![ + // repeat(None, call(())), + // call(()), + // seq([call(()), call(()), call(())]), + // // repeat(a) queues seq(a, repeat(a)) + // seq([call(()), repeat(None, call(()))]) + // ], + // vec_deque![ + // call(()), + // seq([call(()), call(()), call(())]), + // seq([call(()), repeat(None, call(()))]), + // // repeat(a) queues seq(a, repeat(a)) + // seq([call(()), repeat(None, call(()))]) + // ], + // vec_deque![ + // seq([call(()), call(()), call(())]), + // seq([call(()), repeat(None, call(()))]), + // seq([call(()), repeat(None, call(()))]), + // noop(), + // ], + // vec_deque![ + // seq([call(()), repeat(None, call(()))]), + // seq([call(()), repeat(None, call(()))]), + // noop(), + // seq([call(()), call(())]), + // ], + // vec_deque![ + // seq([call(()), repeat(None, call(()))]), + // noop(), + // seq([call(()), call(())]), + // repeat(None, call(())), + // ], + // vec_deque![ + // noop(), + // seq([call(()), call(())]), + // repeat(None, call(())), + // repeat(None, call(())), + // ], + // vec_deque![ + // seq([call(()), call(())]), + // repeat(None, call(())), + // repeat(None, call(())), + // ], + // vec_deque![repeat(None, call(())), repeat(None, call(())), call(()),], + // vec_deque![ + // repeat(None, call(())), + // call(()), + // seq([call(()), repeat(None, call(()))]), + // ], + // vec_deque![ + // call(()), + // seq([call(()), repeat(None, call(()))]), + // seq([call(()), repeat(None, call(()))]), + // ], + // vec_deque![ + // seq([call(()), repeat(None, call(()))]), + // seq([call(()), repeat(None, call(()))]), + // noop(), + // ], + // ], + // ) + // .await; // } } @@ -894,50 +821,20 @@ impl std::error::Error for QueueError { } } -pub trait HandleFetch { - fn handle(self, store: &T::Store) -> impl Future, QueueError>> + Send; +pub trait HandleCall { + fn handle(self, store: &T::Context) -> impl Future, QueueError>> + Send; } -pub trait HandleData { - fn handle(self, store: &T::Store) -> Result, QueueError>; -} - -pub trait HandleWait { - fn handle(self, store: &T::Store) -> impl Future, QueueError>> + Send; -} - -pub trait HandleEvent { - fn handle(self, store: &T::Store) -> Result, QueueError>; -} - -pub trait HandleEffect { - fn handle(self, store: &T::Store) -> impl Future, QueueError>> + Send; -} - -pub trait HandleAggregate { - fn handle(self, data: VecDeque) -> Result, QueueError>; -} - -impl HandleFetch for Never { - async fn handle(self, _: &::Store) -> Result, QueueError> { - match self {} - } -} - -impl HandleWait for Never { - async fn handle(self, _: &::Store) -> Result, QueueError> { - match self {} - } -} - -impl HandleEvent for Never { - fn handle(self, _: &::Store) -> Result, QueueError> { - match self {} - } +pub trait HandleCallback { + fn handle( + self, + ctx: &T::Context, + data: VecDeque, + ) -> impl Future, QueueError>> + Send; } -impl HandleEffect for Never { - async fn handle(self, _: &::Store) -> Result, QueueError> { +impl HandleCall for Never { + async fn handle(self, _: &::Context) -> Result, QueueError> { match self {} } } @@ -950,93 +847,89 @@ pub fn now() -> u64 { .as_secs() } -#[derive(DebugNoBound, CloneNoBound)] -pub struct Engine { - store: Arc, +pub struct Engine<'a, T: QueueMessage, Q: Queue, O: PurePass> { + store: &'a T::Context, + queue: &'a Q, + optimizer: &'a O, } pub type BoxDynError = Box; -impl Engine { - pub fn new(store: Arc) -> Self { - Self { store } - } - - pub fn run<'a, Q, O>( - &'a self, - q: &'a Q, - o: &'a O, - ) -> impl Stream> + Send + 'a - where - Q: Queue, - O: PurePass, - { - try_unfold::<_, _, _, Option>((), move |()| async move { - // trace!("stepping"); +pub trait Captures<'a> {} +impl Captures<'_> for T {} - // dbg!(&q); - - // sleep(Duration::from_secs(1)).await; +impl<'a, T: QueueMessage, Q: Queue, O: PurePass> Engine<'a, T, Q, O> { + pub fn new(store: &'a T::Context, queue: &'a Q, optimizer: &'a O) -> Self { + Self { + store, + queue, + optimizer, + } + } - self.step(q, o) - .await - .map(|step_result| step_result.map(|maybe_data| (maybe_data, ()))) + pub fn run(self) -> impl Stream> + Send + Captures<'a> { + futures::stream::try_unfold(self, |this| async move { + sleep(Duration::from_millis(10)).await; + let res = this.step().await; + res.map(move |x| x.map(|x| (x, this))) }) .flat_map(|x| stream::iter(x.transpose())) } - pub(crate) async fn step<'a, Q: Queue, O: PurePass>( - &'a self, - q: &'a Q, - o: &'a O, - ) -> Result>, BoxDynError> { - // yield back to the runtime - tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; - - let s = self.store.clone(); - - let data = q - .process::<_, _, Option, O>(o, move |msg| async move { - match msg.handle(&*s, 0).await { - // TODO: Make this an optimization pass - Ok(Some(Op::Data(d))) => { - let data_output = d.clone().handle(&s).unwrap(); - - // run to a fixed point - if data_output != data(d.clone()) { - (None, Ok(vec![data_output])) - } else { - (Some(d), Ok(vec![])) + pub(crate) fn step<'b>( + &'b self, + ) -> impl Future>, BoxDynError>> + + Captures<'a> + + Captures<'b> + + Send { + // yield back to the runtime and throttle a bit, prevents 100% cpu usage while still allowing for a fast spin-loop + sleep(Duration::from_millis(10)).then(|()| { + self.queue + .process::<_, _, Option, O>(self.optimizer, |msg| { + msg.clone().handle(self.store, 0).map(|res| match res { + // Ok(Some(Op::Data(d))) => { + // // // TODO: push data to a separate queue + // // let data_output = d.clone().handle(self.store).unwrap(); + + // // // run to a fixed point + // // if data_output != data(d.clone()) { + // // (None, Ok(vec![data_output])) + // // } else { + // (Some(d), Ok(vec![])) + // // } + // } + Ok(msg) => (None, Ok(msg.into_iter().collect())), + Err(QueueError::Fatal(fatal)) => { + let full_err = ErrorReporter(&*fatal); + error!(error = %full_err, "fatal error"); + (None, Err(full_err.to_string())) } - } - Ok(msg) => (None, Ok(msg.into_iter().collect())), - Err(QueueError::Fatal(fatal)) => { - let full_err = ErrorReporter(&*fatal); - error!(error = %full_err, "unrecoverable error"); - (None, Err(full_err.to_string())) - } - Err(QueueError::Retry(retry)) => panic!("{retry:?}"), - } - }) - .await; - - match data { - Ok(data) => Ok(Some(data.flatten())), - Err(err) => Err(err.into()), - } + Err(QueueError::Retry(retry)) => { + // TODO: Add some backoff logic here based on `full_err`? + let full_err = ErrorReporter(&*retry); + error!(error = %full_err, "retryable error"); + (None, Ok(vec![seq([defer(now() + 3), msg])])) + } + }) + }) + .map(|data| match data { + Ok(data) => Ok(Some(data.flatten())), + Err(err) => Err(err.into()), + }) + }) } } pub async fn run_to_completion< - A: UseAggregate, + Cb: DoCallback, T: QueueMessage, R, Q: Queue, PrePass: PurePass, PostPass: Pass, >( - a: A, - store: Arc, + callback: Cb, + ctx: T::Context, queue_config: Q::Config, msgs: impl IntoIterator>, pre_pass_optimizer: PrePass, @@ -1050,52 +943,74 @@ pub async fn run_to_completion< debug!("spawning optimizer"); - let opt_fut = tokio::spawn({ - let queue = queue.clone(); + let opt_futures = ctx + .tags() + .iter() + .map(|tag| { + future::Either::Left(async { + loop { + trace!("optimizing"); + + let res = queue + .optimize(tag, &post_pass_optimizer) + .await + .map_err(|e| { + e.map_either::<_, _, BoxDynError, BoxDynError>( + |x| Box::new(x), + |x| Box::new(x), + ) + .into_inner() + }); + + sleep(Duration::from_millis(100)).await; + + match res { + Ok(()) => {} + Err(err) => break Err::(err), + } + } + }) + }) + .chain([future::Either::Right(future::pending())]) + .collect::>(); - async move { - loop { - info!("optimizing"); + debug!("running"); - let res = queue.optimize(&post_pass_optimizer).await.map_err(|e| { - e.map_either::<_, _, BoxDynError, BoxDynError>(|x| Box::new(x), |x| Box::new(x)) - .into_inner() - }); + let engine_output = Engine::new(&ctx, &queue, &pre_pass_optimizer) + .run() + .take(Cb::Params::LEN) + .try_collect::>(); - sleep(Duration::from_millis(100)).await; + pin!(opt_futures); + pin!(engine_output); - match res { - Ok(()) => {} - Err(err) => break Err::<(), _>(err), - } - } + let output = match future::select(opt_futures.next(), engine_output).await { + future::Either::Left((err, _)) => { + let Some(Err(err)) = err else { + panic!("will always contain at least one future; qed;") + }; + panic!("optimizer returned error: {}", ErrorReporter(&*err)); } - }); + future::Either::Right((x, fut)) => { + drop(fut); - debug!("running"); - - let output = Engine::new(store) - .run(&queue, &pre_pass_optimizer) - .take(A::AggregatedData::LEN) - .try_collect() - .await - .unwrap(); - - opt_fut.abort(); + x.unwrap() + } + }; let data = match HListTryFromIterator::try_from_iter(output) { Ok(ok) => ok, Err(_) => { panic!( "could not aggregate data into {}", - std::any::type_name::() + std::any::type_name::() ) } }; // dbg!(queue); - A::aggregate(a, data) + Cb::call(callback, data) } #[derive(DebugNoBound, CloneNoBound)] @@ -1103,7 +1018,8 @@ pub struct InMemoryQueue { idx: Arc, ready: Arc>>>, done: Arc>>>, - optimizer_queue: Arc>>>, + #[allow(clippy::type_complexity)] + optimizer_queue: Arc>>>>, } #[derive(DebugNoBound, CloneNoBound)] @@ -1133,7 +1049,31 @@ impl Queue for InMemoryQueue { ) -> impl Future> + Send + 'a { debug!(?item, "enqueueing new item"); - let res = pre_enqueue_passes.run_pass_pure(vec![item]); + let (parent_idxs, normalized) = normalize::normalize(vec![item]) + .into_iter() + .unzip::<_, _, Vec<_>, Vec<_>>(); + + let res = { + let mut res = pre_enqueue_passes.run_pass_pure(normalized); + + for (parents, _) in &mut res.ready { + *parents = parents + .iter() + .flat_map(|p| &parent_idxs[*p]) + .copied() + .collect(); + } + + for (parents, _, _) in &mut res.optimize_further { + *parents = parents + .iter() + .flat_map(|p| &parent_idxs[*p]) + .copied() + .collect(); + } + + res + }; let mut optimizer_queue = self.optimizer_queue.lock().expect("mutex is poisoned"); let mut ready = self.ready.lock().expect("mutex is poisoned"); @@ -1160,8 +1100,8 @@ impl Queue for InMemoryQueue { f: F, ) -> Result, Self::Error> where - F: (FnOnce(Op) -> Fut) + Send + 'static, - Fut: Future>, String>)> + Send + 'static, + F: (FnOnce(Op) -> Fut) + Send + Captures<'a>, + Fut: Future>, String>)> + Send + Captures<'a>, R: Send + Sync + 'static, O: PurePass, { @@ -1189,6 +1129,10 @@ impl Queue for InMemoryQueue { let (r, res) = f(item.msg.clone()).instrument(span).await; match res { Ok(new_msgs) => { + let (_, new_msgs) = normalize::normalize(new_msgs) + .into_iter() + .unzip::<_, _, Vec<_>, Vec<_>>(); + let res = pre_reenqueue_passes.run_pass_pure(new_msgs); let mut optimizer_queue = @@ -1221,45 +1165,54 @@ impl Queue for InMemoryQueue { } } - async fn optimize<'a, O: Pass>( + #[allow(clippy::manual_async_fn)] + fn optimize<'a, O: Pass>( &'a self, + tag: &'a str, optimizer: &'a O, - ) -> Result<(), Either> { - let msgs = { - let lock = self.optimizer_queue.lock().unwrap(); - let msgs = lock.clone(); - drop(lock); - msgs - }; + ) -> impl Future>> + 'a { + async move { + let tagged_optimizer_queue = { + let mut optimizer_queue = self.optimizer_queue.lock().unwrap(); + let Some(tagged_optimizer_queue) = optimizer_queue.remove(tag) else { + warn!(%tag, "no items with tag"); + return Ok(()); + }; - let (ids, msgs): (Vec<_>, Vec<_>) = msgs.into_iter().unzip(); + drop(optimizer_queue); - let res = optimizer - .run_pass(msgs.into_iter().map(|item| item.msg).collect()) - .await - .map_err(Either::Right)?; + tagged_optimizer_queue + }; - // dbg!(&res, std::any::type_name::()); + let (ids, msgs): (Vec<_>, Vec<_>) = tagged_optimizer_queue.clone().into_iter().unzip(); - let mut ready = self.ready.lock().unwrap(); - let mut optimizer_queue = self.optimizer_queue.lock().unwrap(); - let mut done = self.done.lock().unwrap(); + let res = optimizer + .run_pass(msgs.into_iter().map(|item| item.msg).collect()) + .await + .map_err(Either::Right)?; - done.append(&mut optimizer_queue); + // dbg!(&res, std::any::type_name::()); - self.requeue( - res, - &mut optimizer_queue, - &mut ready, - |parent_idxs: Vec| { - ids.iter() - .enumerate() - .filter_map(|(idx, id)| parent_idxs.contains(&idx).then_some(*id)) - .collect::>() - }, - ); + let mut optimizer_queue = self.optimizer_queue.lock().unwrap(); + let mut ready = self.ready.lock().unwrap(); + let mut done = self.done.lock().unwrap(); - Ok(()) + done.append(&mut tagged_optimizer_queue.clone()); + + self.requeue( + res, + &mut optimizer_queue, + &mut ready, + |parent_idxs: Vec| { + ids.iter() + .enumerate() + .filter_map(|(idx, id)| parent_idxs.contains(&idx).then_some(*id)) + .collect::>() + }, + ); + + Ok(()) + } } } @@ -1267,12 +1220,12 @@ impl InMemoryQueue { fn requeue( &self, res: OptimizationResult, - optimizer_queue: &mut BTreeMap>, + optimizer_queue: &mut BTreeMap>>, ready: &mut BTreeMap>, get_parent_ids: impl Fn(Vec) -> Vec, ) { - for (parent_idxs, new_msg) in res.optimize_further { - optimizer_queue.insert( + for (parent_idxs, new_msg, tag) in res.optimize_further { + optimizer_queue.entry(tag).or_default().insert( self.idx.fetch_add(1, Ordering::SeqCst), Item { parents: get_parent_ids(parent_idxs), @@ -1299,77 +1252,58 @@ pub mod test_utils { use enumorph::Enumorph; use frunk::{hlist_pat, HList}; - use queue_msg_macro::queue_msg; + use queue_msg_macro::{queue_msg, SubsetOf}; use crate::{ - aggregation::{do_aggregate, UseAggregate}, - data, effect, noop, HandleAggregate, HandleData, HandleEffect, HandleEvent, HandleFetch, - HandleWait, Op, QueueError, QueueMessage, + aggregation::{do_callback, DoCallback}, + call, data, noop, HandleCall, HandleCallback, Op, QueueError, QueueMessage, }; + // for macros + pub mod queue_msg { + pub use crate::*; + } + pub enum SimpleMessage {} impl QueueMessage for SimpleMessage { - type Event = SimpleEvent; type Data = SimpleData; - type Fetch = SimpleFetch; - type Effect = SimpleEffect; - type Wait = SimpleWait; - - type Aggregate = SimpleAggregate; + type Call = SimpleCall; + type Callback = SimpleAggregate; - type Store = (); + type Context = (); } - impl HandleEffect for SimpleEffect { - async fn handle(self, _: &()) -> Result, QueueError> { - Ok(noop()) - } - } - - impl HandleEvent for SimpleEvent { - fn handle(self, _: &()) -> Result, QueueError> { - Ok(noop()) - } - } - - impl HandleData for SimpleData { - fn handle(self, _: &()) -> Result, QueueError> { - Ok(data(self)) - } - } - - impl HandleFetch for SimpleFetch { + impl HandleCall for SimpleCall { async fn handle(self, _: &()) -> Result, QueueError> { Ok(match self { - SimpleFetch::A(FetchA {}) => data(DataA {}), - SimpleFetch::B(FetchB {}) => data(DataB {}), - SimpleFetch::C(FetchC {}) => data(DataC {}), - SimpleFetch::D(FetchD {}) => data(DataD {}), - SimpleFetch::E(FetchE {}) => data(DataE {}), + SimpleCall::A(FetchA {}) => data(DataA {}), + SimpleCall::B(FetchB {}) => data(DataB {}), + SimpleCall::C(FetchC {}) => data(DataC {}), + SimpleCall::D(FetchD {}) => data(DataD {}), + SimpleCall::E(FetchE {}) => data(DataE {}), + SimpleCall::PrintAbc(PrintAbc { a, b, c }) => { + println!("a = {a:?}, b = {b:?}, c = {c:?}"); + noop() + } }) } } - impl HandleWait for SimpleWait { - async fn handle(self, _: &()) -> Result, QueueError> { - Ok(noop()) - } - } - - impl HandleAggregate for SimpleAggregate { - fn handle(self, data: VecDeque) -> Result, QueueError> { + impl HandleCallback for SimpleAggregate { + async fn handle( + self, + _: &(), + data: VecDeque, + ) -> Result, QueueError> { Ok(match self { - Self::AggregatePrintAbc(agg) => do_aggregate(agg, data), + Self::BuildPrintAbc(agg) => do_callback(agg, data), }) } } #[queue_msg] - pub struct SimpleEvent {} - - #[queue_msg] - #[derive(Enumorph)] + #[derive(Enumorph, SubsetOf)] pub enum SimpleData { A(DataA), B(DataB), @@ -1389,13 +1323,14 @@ pub mod test_utils { pub struct DataE {} #[queue_msg] - #[derive(Enumorph)] - pub enum SimpleFetch { + #[derive(Enumorph, SubsetOf)] + pub enum SimpleCall { A(FetchA), B(FetchB), C(FetchC), D(FetchD), E(FetchE), + PrintAbc(PrintAbc), } #[queue_msg] pub struct FetchA {} @@ -1408,12 +1343,6 @@ pub mod test_utils { #[queue_msg] pub struct FetchE {} - #[queue_msg] - #[derive(Enumorph)] - pub enum SimpleEffect { - PrintAbc(PrintAbc), - } - #[queue_msg] pub struct PrintAbc { pub a: DataA, @@ -1427,20 +1356,17 @@ pub mod test_utils { #[queue_msg] #[derive(Enumorph)] pub enum SimpleAggregate { - AggregatePrintAbc(AggregatePrintAbc), + BuildPrintAbc(BuildPrintAbc), } #[queue_msg] - pub struct AggregatePrintAbc {} + pub struct BuildPrintAbc {} - impl UseAggregate for AggregatePrintAbc { - type AggregatedData = HList![DataA, DataB, DataC]; + impl DoCallback for BuildPrintAbc { + type Params = HList![DataA, DataB, DataC]; - fn aggregate( - AggregatePrintAbc {}: Self, - hlist_pat![a, b, c]: Self::AggregatedData, - ) -> Op { - effect(PrintAbc { a, b, c }) + fn call(BuildPrintAbc {}: Self, hlist_pat![a, b, c]: Self::Params) -> Op { + call(PrintAbc { a, b, c }) } } } diff --git a/lib/queue-msg/src/normalize.rs b/lib/queue-msg/src/normalize.rs new file mode 100644 index 0000000000..25eb25a1fd --- /dev/null +++ b/lib/queue-msg/src/normalize.rs @@ -0,0 +1,483 @@ +use crate::{conc, noop, race, repeat, retry, seq, void, Op, QueueMessage}; + +/// Combination of passes over the queue to normalize the internal structure. See the documentation +/// on each pass for more information on how they work individually. +/// +/// This order is important, and it is recommended to reuse this type instead of the individual +/// passes when using them in combination with your own passes. +/// +/// # Passes +/// +/// First, any `Data` messages are extracted out of their contained structures, pulling them out +/// into individual top-level messages: +/// +/// ```patch +/// - seq(.., seq(data, noop, .., conc(effect, data, repeat(noop)), ..)) +/// + data, data, seq(.., seq(noop, .., conc(effect, repeat(noop)), ..)) +/// ``` +/// +/// Then, any `Noop` messages are removed: +/// +/// ```patch +/// - data, data, seq(.., seq(noop, .., conc(effect, repeat(noop)), ..)) +/// + data, data, seq(.., seq(.., conc(effect), ..)) +/// ``` +/// +/// Next, `Sequence`s are flattened: +/// +/// ```patch +/// - data, data, seq(.., seq(noop, .., conc(effect, repeat(noop)), ..)) +/// + data, data, seq(.., .., conc(effect), ..) +/// ``` +/// +/// Finally, `Concurrent`s are flattened: +/// +/// ```patch +/// - data, data, seq(.., .., conc(effect), ..) +/// + data, data, seq(.., .., effect, ..) +/// ``` +/// +/// `FlattenSeq` and `FlattenConc` are associative, as are `ExtractData` and `RemoveNoop`. +/// +/// Note how if the flattening occurred first, then the `conc(effect) -> effect` transformation could +/// never have occurred since the data and noop messages would still be there, resulting in an +/// incomplete normalization. +#[allow(clippy::let_and_return)] +pub fn normalize(msgs: Vec>) -> Vec<(Vec, Op)> { + // dbg!(&msgs); + + // let ids = msgs.iter().enumerate().map(|(id, _)| id).copied().collect::>(); + let (parent_idxs, msgs): (Vec<_>, Vec<_>) = extract_data(msgs).into_iter().unzip(); + + // dbg!(&msgs); + + let (parent_idxs, msgs): (Vec<_>, Vec<_>) = + combine_normalization_pass_output(parent_idxs, remove_noop(msgs)) + .into_iter() + .unzip(); + + // dbg!(&msgs); + + let (parent_idxs, msgs): (Vec<_>, Vec<_>) = + combine_normalization_pass_output(parent_idxs, flatten_seq(msgs)) + .into_iter() + .unzip(); + + // dbg!(&msgs); + + let output = combine_normalization_pass_output(parent_idxs, flatten_conc(msgs)); + + // dbg!(&output); + + output +} + +fn combine_normalization_pass_output( + previous_parents: Vec>, + mut output: Vec<(Vec, Op)>, +) -> Vec<(Vec, Op)> { + for (parents, _) in &mut output { + *parents = parents + .iter() + .flat_map(|p| &previous_parents[*p]) + .copied() + .collect(); + } + + output +} + +/// Extract all data out of the contained messages, pulling out into top-level messages. +/// +/// Both `Sequence` and `Concurrent` are descended into, as well as `Aggregate` - for `Aggregate`, +/// `Data` messages are pulled out to the top level of the internal aggregation queue. For `seq`, +// `data` messages are only pulled out if they are in the front of the queue. +// REVIEW: Should data messages be queued as ready? +pub fn extract_data(msgs: Vec>) -> Vec<(Vec, Op)> { + // fn extract_data_internal(msg: Op) -> Vec> { + fn go(msg: Op) -> Vec> { + match msg { + Op::Seq(msgs) => { + let mut msgs = msgs.into_iter().flat_map(go).collect::>(); + + let first_non_data_msg_idx = msgs + .iter() + .enumerate() + .find_map(|(idx, msg)| (!matches!(msg, Op::Data(_))).then_some(idx)) + .unwrap_or(msgs.len()); + + // dbg!(&msgs); + // dbg!(first_non_data_msg_idx); + + let non_data_msgs = msgs.split_off(first_non_data_msg_idx); + let data_msgs = msgs; + + if non_data_msgs.is_empty() { + data_msgs + } else { + data_msgs + .into_iter() + .chain([seq(non_data_msgs.into_iter().flat_map(go))]) + .collect() + } + + // if data.is_empty() { + // vec![seq(msgs)] + // } else { + // data.into_iter().chain([seq(msgs)]).collect() + // } + } + Op::Conc(msgs) => { + let (data, msgs): (Vec<_>, Vec<_>) = msgs + .into_iter() + .flat_map(go) + .partition(|msg| matches!(msg, Op::Data(_))); + + if data.is_empty() { + vec![conc(msgs)] + } else { + data.into_iter().chain([conc(msgs)]).collect() + } + } + Op::Promise { + queue, + data, + receiver, + } => vec![Op::Promise { + queue: queue.into_iter().flat_map(go).collect(), + data, + receiver, + }], + _ => vec![msg], + } + } + + // go(msg) + // } + + msgs.into_iter() + .enumerate() + .flat_map(|(i, msg)| go(msg).into_iter().map(move |msg| (vec![i], msg))) + .collect() +} + +/// Remove any `Noop` messages that don't hold any semantic weight (noop in a race cannot be optimized away, for example) +pub fn remove_noop(msgs: Vec>) -> Vec<(Vec, Op)> { + fn remove_noop_internal(msg: Op) -> Option> { + fn go(msg: Op) -> Option> { + match msg { + Op::Repeat { times, msg } => go(*msg).map(|msg| repeat(times, msg)), + Op::Timeout { + timeout_timestamp, + msg, + } => go(*msg).map(|msg| Op::Timeout { + timeout_timestamp, + msg: Box::new(msg), + }), + Op::Seq(msgs) => Some(seq(msgs.into_iter().flat_map(go))), + Op::Conc(msgs) => Some(conc(msgs.into_iter().flat_map(go))), + Op::Retry { remaining, msg } => go(*msg).map(|msg| retry(remaining, msg)), + Op::Promise { + queue, + data, + receiver, + } => Some(Op::Promise { + queue: queue.into_iter().flat_map(remove_noop_internal).collect(), + data, + receiver, + }), + Op::Void(msg) => go(*msg).map(void), + Op::Noop => None, + _ => Some(msg), + } + } + + go(msg) + } + + msgs.into_iter() + .enumerate() + .flat_map(|(i, msg)| remove_noop_internal(msg).map(|msg| (vec![i], msg))) + .collect() +} + +pub fn flatten_seq(msgs: Vec>) -> Vec<(Vec, Op)> { + fn flatten_seq_internal(msg: Op) -> Option> { + fn go(msg: Op) -> Vec> { + match msg { + Op::Seq(new_seq) => new_seq.into_iter().flat_map(go).collect(), + Op::Conc(c) => vec![conc(c.into_iter().flat_map(|msg| { + let mut msgs = go(msg); + + match msgs.len() { + 0 => None, + 1 => Some(msgs.pop().unwrap()), + _ => Some(seq(msgs)), + } + }))], + Op::Promise { + queue, + data, + receiver, + } => vec![Op::Promise { + queue: queue.into_iter().filter_map(flatten_seq_internal).collect(), + data, + receiver, + }], + Op::Race(msgs) => { + vec![Op::Race( + msgs.into_iter() + .filter_map(|msg| { + // `noop`s hold semantic weight in the context of a race + if msg == noop() { + Some(noop()) + // empty seq holds semantic weight in the context of a race + } else if msg == seq([]) { + Some(seq([])) + } else { + flatten_seq_internal(msg) + } + }) + .collect(), + )] + } + _ => [msg].into(), + } + } + + let mut msgs = go(msg); + + match msgs.len() { + 0 => None, + 1 => Some(msgs.pop().unwrap()), + _ => Some(seq(msgs)), + } + } + + msgs.into_iter() + .enumerate() + .filter_map(|(i, msg)| flatten_seq_internal(msg).map(|msg| (vec![i], msg))) + .collect() +} + +pub fn flatten_conc(msgs: Vec>) -> Vec<(Vec, Op)> { + fn flatten_conc_internal(msg: Op) -> Vec> { + fn go(msg: Op) -> Vec> { + match msg { + Op::Conc(new_conc) => new_conc.into_iter().flat_map(go).collect(), + Op::Seq(s) => vec![seq(s.into_iter().flat_map(|msg| { + let mut msgs = go(msg); + + match msgs.len() { + 0 => None, + 1 => Some(msgs.pop().unwrap()), + // wrap in conc again + // seq(conc(a.., conc(b..)), c..) == seq(conc(a.., b..), c..) + // seq(conc(a.., conc(b..)), c..) != seq(a.., b.., c..) + _ => Some(conc(msgs)), + } + }))], + Op::Promise { + queue, + data, + receiver, + } => vec![Op::Promise { + queue: queue.into_iter().flat_map(flatten_conc_internal).collect(), + data, + receiver, + }], + Op::Race(msgs) => { + vec![race(msgs.into_iter().map(|msg| { + let mut msgs = go(msg); + + match msgs.len() { + 0 => noop(), + 1 => msgs.pop().unwrap(), + _ => conc(msgs), + } + }))] + } + _ => [msg].into(), + } + } + + go(msg) + } + + msgs.into_iter() + .enumerate() + .flat_map(|(i, msg)| { + flatten_conc_internal(msg) + .into_iter() + .map(move |msg| (vec![i], msg)) + }) + .collect() +} + +// #[cfg(test)] +// mod tests { +// use super::*; +// use crate::{ +// aggregate, data, defer_relative, effect, fetch, noop, race, +// test_utils::{ +// AggregatePrintAbc, DataA, DataB, DataC, FetchA, PrintAbc, SimpleEvent, SimpleMessage, +// }, +// }; + +// #[test] +// fn normalize() { +// let msgs = vec![seq::([ +// fetch(FetchA {}), +// seq([ +// data(DataA {}), +// noop(), +// fetch(FetchA {}), +// conc([ +// effect(PrintAbc { +// a: DataA {}, +// b: DataB {}, +// c: DataC {}, +// }), +// data(DataC {}), +// repeat(None, noop()), +// ]), +// fetch(FetchA {}), +// ]), +// ])]; + +// let expected_output = vec![ +// (vec![0], data(DataA {})), +// (vec![0], data(DataC {})), +// ( +// vec![0], +// seq([ +// fetch(FetchA {}), +// fetch(FetchA {}), +// effect(PrintAbc { +// a: DataA {}, +// b: DataB {}, +// c: DataC {}, +// }), +// fetch(FetchA {}), +// ]), +// ), +// ]; + +// let optimized = Normalize::default().run_pass_pure(msgs.clone()); +// assert_eq!(optimized.optimize_further, expected_output); +// assert_eq!(optimized.ready, []); + +// let optimized = NormalizeFinal::default().run_pass_pure(msgs); +// assert_eq!(optimized.ready, expected_output); +// assert_eq!(optimized.optimize_further, []); +// } + +// #[test] +// fn seq_conc_conc() { +// let msgs = vec![seq::([ +// conc([ +// aggregate([], [], AggregatePrintAbc {}), +// aggregate([], [], AggregatePrintAbc {}), +// ]), +// conc([ +// aggregate([], [], AggregatePrintAbc {}), +// aggregate([], [], AggregatePrintAbc {}), +// ]), +// conc([ +// // repeat(None, seq([event(SimpleEvent {}), defer_relative(10)])), +// // repeat(None, seq([event(SimpleEvent {}), defer_relative(10)])), +// // this seq is the only message that should be flattened +// seq([ +// effect(PrintAbc { +// a: DataA {}, +// b: DataB {}, +// c: DataC {}, +// }), +// seq([ +// aggregate([], [], AggregatePrintAbc {}), +// aggregate([], [], AggregatePrintAbc {}), +// aggregate([], [], AggregatePrintAbc {}), +// ]), +// ]), +// ]), +// ])]; + +// let expected_output = vec![( +// vec![0], +// seq::([ +// conc([ +// aggregate([], [], AggregatePrintAbc {}), +// aggregate([], [], AggregatePrintAbc {}), +// ]), +// conc([ +// aggregate([], [], AggregatePrintAbc {}), +// aggregate([], [], AggregatePrintAbc {}), +// ]), +// conc([ +// repeat(None, seq([event(SimpleEvent {}), defer_relative(10)])), +// repeat(None, seq([event(SimpleEvent {}), defer_relative(10)])), +// seq([ +// effect(PrintAbc { +// a: DataA {}, +// b: DataB {}, +// c: DataC {}, +// }), +// aggregate([], [], AggregatePrintAbc {}), +// aggregate([], [], AggregatePrintAbc {}), +// aggregate([], [], AggregatePrintAbc {}), +// ]), +// ]), +// ]), +// )]; + +// let optimized = Normalize::default().run_pass_pure(msgs.clone()); + +// assert_eq!(optimized.optimize_further, expected_output); +// assert_eq!(optimized.ready, []); + +// let optimized = NormalizeFinal::default().run_pass_pure(msgs); +// assert_eq!(optimized.ready, expected_output); +// assert_eq!(optimized.optimize_further, []); +// } + +// #[test] +// fn race_opt() { +// let msgs = vec![race::([ +// seq([event(SimpleEvent {}), event(SimpleEvent {})]), +// conc([ +// event(SimpleEvent {}), +// conc([event(SimpleEvent {}), event(SimpleEvent {})]), +// ]), +// ])]; + +// let expected_output = vec![( +// vec![0], +// race::([ +// seq([event(SimpleEvent {}), event(SimpleEvent {})]), +// conc([ +// event(SimpleEvent {}), +// event(SimpleEvent {}), +// event(SimpleEvent {}), +// ]), +// ]), +// )]; + +// let optimized = Normalize::default().run_pass_pure(msgs.clone()); + +// assert_eq!(optimized.optimize_further, expected_output); +// assert_eq!(optimized.ready, []); +// } + +// #[test] +// fn race_opt_noop() { +// let msgs = vec![race::([seq([]), conc([])])]; + +// // an empty seq optimizes to an empty seq, but an empty conc optimizes to noop +// let expected_output = vec![(vec![0], race::([seq([]), noop()]))]; + +// let optimized = Normalize::default().run_pass_pure(msgs.clone()); + +// assert_eq!(optimized.optimize_further, expected_output); +// assert_eq!(optimized.ready, []); +// } +// } diff --git a/lib/queue-msg/src/optimize.rs b/lib/queue-msg/src/optimize.rs index fa8d2924c5..40945ad106 100644 --- a/lib/queue-msg/src/optimize.rs +++ b/lib/queue-msg/src/optimize.rs @@ -1,16 +1,15 @@ use std::{convert::Infallible, error::Error, fmt::Debug}; use either::Either; -use frame_support_procedural::{CloneNoBound, DebugNoBound}; +use frame_support_procedural::{CloneNoBound, DebugNoBound, DefaultNoBound}; use futures::Future; +use serde::{Deserialize, Serialize}; use crate::{Op, QueueMessage}; -pub mod passes; - /// An optimization pass over the queue. This is an "impure" pass, in that it can access the /// external environment and it is fallible. -pub trait Pass: Debug + Clone + Send + Sync + Sized + 'static { +pub trait Pass: Send + Sync + Sized { type Error: Error + Send + Sync + 'static; fn run_pass( @@ -31,7 +30,8 @@ pub trait PurePass: Debug + Clone + Send + Sync + Sized + 'stat /// The result of running an optimization pass. Both `optimize_further` and `ready` are lists of /// `(parents, msg)`, allowing for correlating new messages with multiple parents (i.e. combining /// messages). -#[derive(DebugNoBound, CloneNoBound)] +#[derive(DebugNoBound, CloneNoBound, DefaultNoBound, Serialize, Deserialize)] +#[serde(bound(serialize = "", deserialize = ""))] pub struct OptimizationResult { /// Messages that are considered incomplete by this optimization pass and are to be optimized /// further. @@ -39,7 +39,7 @@ pub struct OptimizationResult { /// For pure passes, it is recommended to return all messages here after being processed so /// that subsequent passes can run on them as well. In fact, all of the passes defined in /// [`passes`] work this way, with [`FinalPass`] requeueing everything under `ready`. - pub optimize_further: Vec<(Vec, Op)>, + pub optimize_further: Vec<(Vec, Op, String)>, /// Messages that are considered complete by this optimization pass. No more passes will be run /// on these messages, and they will be requeued as "ready" in the queue. pub ready: Vec<(Vec, Op)>, @@ -64,8 +64,14 @@ impl, B: Pass> Pass for (A, B) { async fn run_pass(&self, msgs: Vec>) -> Result, Self::Error> { let res_a = self.0.run_pass(msgs).await.map_err(Either::Left)?; - let (pass_a_optimize_further_parent_ids, pass_1_optimize_further): (Vec<_>, Vec<_>) = - res_a.optimize_further.into_iter().unzip(); + let (pass_a_optimize_further_parent_ids, (pass_1_optimize_further, _)): ( + Vec<_>, + (Vec<_>, Vec<_>), + ) = res_a + .optimize_further + .into_iter() + .map(|(a, b, c)| (a, (b, c))) + .unzip(); let res_b = self .1 @@ -84,8 +90,14 @@ impl, B: Pass> Pass for (A, B) { impl, B: PurePass> PurePass for (A, B) { fn run_pass_pure(&self, msgs: Vec>) -> OptimizationResult { let res_a = self.0.run_pass_pure(msgs); - let (pass_a_optimize_further_parent_ids, pass_1_optimize_further): (Vec<_>, Vec<_>) = - res_a.optimize_further.into_iter().unzip(); + let (pass_a_optimize_further_parent_ids, (pass_1_optimize_further, _)): ( + Vec<_>, + (Vec<_>, Vec<_>), + ) = res_a + .optimize_further + .into_iter() + .map(|(a, b, c)| (a, (b, c))) + .unzip(); let res_b = self.1.run_pass_pure(pass_1_optimize_further); @@ -106,7 +118,7 @@ fn combine_optimization_results( .collect(); } - for (parents, _) in &mut res_b.optimize_further { + for (parents, _, _) in &mut res_b.optimize_further { *parents = parents .iter() .flat_map(|p| &pass_a_optimize_further_parent_ids[*p]) @@ -119,3 +131,180 @@ fn combine_optimization_results( optimize_further: res_b.optimize_further, } } + +#[derive(Debug, Clone, PartialEq)] +pub struct NoopPass; + +impl PurePass for NoopPass { + fn run_pass_pure(&self, msgs: Vec>) -> OptimizationResult { + OptimizationResult { + optimize_further: vec![], + ready: msgs + .into_iter() + .enumerate() + .map(|(idx, msg)| (vec![idx], msg)) + .collect(), + } + } +} + +#[cfg(test)] +mod tests { + use crate::{ + call, conc, data, defer, noop, + normalize::normalize, + now, promise, race, repeat, seq, + test_utils::{BuildPrintAbc, DataA, DataB, DataC, FetchA, FetchB, PrintAbc, SimpleMessage}, + }; + + #[test] + fn normalize_works_in_single_pass() { + let msgs = vec![seq::([ + call(FetchA {}), + seq([ + data(DataA {}), + noop(), + call(FetchA {}), + conc([ + call(PrintAbc { + a: DataA {}, + b: DataB {}, + c: DataC {}, + }), + data(DataC {}), + repeat(None, noop()), + ]), + call(FetchA {}), + ]), + ])]; + + let expected_output = vec![( + vec![0], + seq([ + call(FetchA {}), + data(DataA {}), + call(FetchA {}), + data(DataC {}), + call(PrintAbc { + a: DataA {}, + b: DataB {}, + c: DataC {}, + }), + call(FetchA {}), + ]), + )]; + + let optimized = normalize(msgs.clone()); + assert_eq!(optimized, expected_output); + + let optimized = normalize(msgs); + assert_eq!(optimized, expected_output); + } + + #[test] + fn seq_call_data() { + let msg = seq::([call(FetchA {}), data(DataA {})]); + + // should be the same + let expected_output = vec![(vec![0_usize], msg.clone())]; + + let optimized = normalize(vec![msg]); + assert_eq!(optimized, expected_output); + } + + #[test] + fn seq_conc_conc() { + let msgs = vec![seq::([ + conc([ + promise([], [], BuildPrintAbc {}), + promise([], [], BuildPrintAbc {}), + ]), + conc([ + promise([], [], BuildPrintAbc {}), + promise([], [], BuildPrintAbc {}), + ]), + conc([ + repeat(None, seq([call(FetchA {}), defer(now() + 10)])), + repeat(None, seq([call(FetchB {}), defer(now() + 10)])), + // this seq is the only message that should be flattened + seq([ + call(PrintAbc { + a: DataA {}, + b: DataB {}, + c: DataC {}, + }), + seq([ + promise([], [], BuildPrintAbc {}), + promise([], [], BuildPrintAbc {}), + promise([], [], BuildPrintAbc {}), + ]), + ]), + ]), + ])]; + + let expected_output = vec![( + vec![0], + seq::([ + conc([ + promise([], [], BuildPrintAbc {}), + promise([], [], BuildPrintAbc {}), + ]), + conc([ + promise([], [], BuildPrintAbc {}), + promise([], [], BuildPrintAbc {}), + ]), + conc([ + repeat(None, seq([call(FetchA {}), defer(now() + 10)])), + repeat(None, seq([call(FetchB {}), defer(now() + 10)])), + seq([ + call(PrintAbc { + a: DataA {}, + b: DataB {}, + c: DataC {}, + }), + promise([], [], BuildPrintAbc {}), + promise([], [], BuildPrintAbc {}), + promise([], [], BuildPrintAbc {}), + ]), + ]), + ]), + )]; + + let optimized = normalize(msgs.clone()); + assert_eq!(optimized, expected_output); + + let optimized = normalize(msgs); + assert_eq!(optimized, expected_output); + } + + #[test] + fn race_opt() { + let msgs = vec![race::([ + seq([call(FetchA {}), call(FetchB {})]), + conc([call(FetchA {}), conc([call(FetchA {}), call(FetchA {})])]), + ])]; + + let expected_output = vec![( + vec![0], + race::([ + seq([call(FetchA {}), call(FetchB {})]), + conc([call(FetchA {}), call(FetchA {}), call(FetchA {})]), + ]), + )]; + + let optimized = normalize(msgs); + assert_eq!(optimized, expected_output); + } + + #[test] + fn race_opt_noop() { + let msgs = vec![race::([seq([]), conc([])])]; + + // an empty seq optimizes to an empty seq, but an empty conc optimizes to noop + // REVIEW: Why? + let expected_output = vec![(vec![0], race::([seq([]), noop()]))]; + + let optimized = normalize(msgs); + assert_eq!(optimized, expected_output); + } +} diff --git a/lib/queue-msg/src/optimize/passes.rs b/lib/queue-msg/src/optimize/passes.rs index 404536219d..94ee7c6a2d 100644 --- a/lib/queue-msg/src/optimize/passes.rs +++ b/lib/queue-msg/src/optimize/passes.rs @@ -3,7 +3,7 @@ use tracing::debug; use crate::{ conc, noop, optimize::{OptimizationResult, Pass, Pure, PurePass}, - race, repeat, retry, seq, Op, QueueMessage, + race, repeat, retry, seq, void, Op, QueueMessage, }; /// Combination of passes over the queue to normalize the internal structure. See the documentation @@ -49,10 +49,12 @@ use crate::{ /// never have occurred since the data and noop messages would still be there, resulting in an /// incomplete normalization. pub type Normalize = (ExtractData, (RemoveNoop, (FlattenSeq, FlattenConc))); +pub const NORMALIZE: Normalize = (ExtractData, (RemoveNoop, (FlattenSeq, FlattenConc))); /// Runs the normalization passes, and then finalizes the optimizations with [`FinalPass`]. Use this /// if you don't have any custom optimizations to run. pub type NormalizeFinal = (Normalize, FinalPass); +pub const NORMALIZE_FINAL: NormalizeFinal = (NORMALIZE, FinalPass); const _: fn() = || { fn impls_pure_pass>() {} @@ -146,6 +148,7 @@ impl PurePass for ExtractData { .into_iter() .enumerate() .flat_map(|(i, msg)| extract_data(msg).into_iter().map(move |msg| (vec![i], msg))) + .map(|(a, b)| (a, b, "NO TAG".to_owned())) .collect(), ready: vec![], } @@ -181,7 +184,7 @@ impl PurePass for RemoveNoop { data, receiver, }), - Op::Void(msg) => go(*msg), + Op::Void(msg) => go(*msg).map(void), Op::Noop => None, _ => Some(msg), } @@ -195,6 +198,7 @@ impl PurePass for RemoveNoop { .into_iter() .enumerate() .flat_map(|(i, msg)| remove_noop(msg).map(|msg| (vec![i], msg))) + .map(|(a, b)| (a, b, "NO TAG".to_owned())) .collect(), ready: vec![], } @@ -249,6 +253,7 @@ impl PurePass for FlattenSeq { .into_iter() .enumerate() .map(|(i, msg)| (vec![i], flatten_seq(msg))) + .map(|(a, b)| (a, b, "NO TAG".to_owned())) .collect(), ready: vec![], } @@ -308,176 +313,9 @@ impl PurePass for FlattenConc { .into_iter() .enumerate() .flat_map(|(i, msg)| flatten_conc(msg).into_iter().map(move |msg| (vec![i], msg))) + .map(|(a, b)| (a, b, "NO TAG".to_owned())) .collect(), ready: vec![], } } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - aggregate, data, defer_relative, effect, event, fetch, noop, race, - test_utils::{ - AggregatePrintAbc, DataA, DataB, DataC, FetchA, PrintAbc, SimpleEvent, SimpleMessage, - }, - }; - - #[test] - fn normalize() { - let msgs = vec![seq::([ - fetch(FetchA {}), - seq([ - data(DataA {}), - noop(), - fetch(FetchA {}), - conc([ - effect(PrintAbc { - a: DataA {}, - b: DataB {}, - c: DataC {}, - }), - data(DataC {}), - repeat(None, noop()), - ]), - fetch(FetchA {}), - ]), - ])]; - - let expected_output = vec![ - (vec![0], data(DataA {})), - (vec![0], data(DataC {})), - ( - vec![0], - seq([ - fetch(FetchA {}), - fetch(FetchA {}), - effect(PrintAbc { - a: DataA {}, - b: DataB {}, - c: DataC {}, - }), - fetch(FetchA {}), - ]), - ), - ]; - - let optimized = Normalize::default().run_pass_pure(msgs.clone()); - assert_eq!(optimized.optimize_further, expected_output); - assert_eq!(optimized.ready, []); - - let optimized = NormalizeFinal::default().run_pass_pure(msgs); - assert_eq!(optimized.ready, expected_output); - assert_eq!(optimized.optimize_further, []); - } - - #[test] - fn seq_conc_conc() { - let msgs = vec![seq::([ - conc([ - aggregate([], [], AggregatePrintAbc {}), - aggregate([], [], AggregatePrintAbc {}), - ]), - conc([ - aggregate([], [], AggregatePrintAbc {}), - aggregate([], [], AggregatePrintAbc {}), - ]), - conc([ - repeat(None, seq([event(SimpleEvent {}), defer_relative(10)])), - repeat(None, seq([event(SimpleEvent {}), defer_relative(10)])), - // this seq is the only message that should be flattened - seq([ - effect(PrintAbc { - a: DataA {}, - b: DataB {}, - c: DataC {}, - }), - seq([ - aggregate([], [], AggregatePrintAbc {}), - aggregate([], [], AggregatePrintAbc {}), - aggregate([], [], AggregatePrintAbc {}), - ]), - ]), - ]), - ])]; - - let expected_output = vec![( - vec![0], - seq::([ - conc([ - aggregate([], [], AggregatePrintAbc {}), - aggregate([], [], AggregatePrintAbc {}), - ]), - conc([ - aggregate([], [], AggregatePrintAbc {}), - aggregate([], [], AggregatePrintAbc {}), - ]), - conc([ - repeat(None, seq([event(SimpleEvent {}), defer_relative(10)])), - repeat(None, seq([event(SimpleEvent {}), defer_relative(10)])), - seq([ - effect(PrintAbc { - a: DataA {}, - b: DataB {}, - c: DataC {}, - }), - aggregate([], [], AggregatePrintAbc {}), - aggregate([], [], AggregatePrintAbc {}), - aggregate([], [], AggregatePrintAbc {}), - ]), - ]), - ]), - )]; - - let optimized = Normalize::default().run_pass_pure(msgs.clone()); - - assert_eq!(optimized.optimize_further, expected_output); - assert_eq!(optimized.ready, []); - - let optimized = NormalizeFinal::default().run_pass_pure(msgs); - assert_eq!(optimized.ready, expected_output); - assert_eq!(optimized.optimize_further, []); - } - - #[test] - fn race_opt() { - let msgs = vec![race::([ - seq([event(SimpleEvent {}), event(SimpleEvent {})]), - conc([ - event(SimpleEvent {}), - conc([event(SimpleEvent {}), event(SimpleEvent {})]), - ]), - ])]; - - let expected_output = vec![( - vec![0], - race::([ - seq([event(SimpleEvent {}), event(SimpleEvent {})]), - conc([ - event(SimpleEvent {}), - event(SimpleEvent {}), - event(SimpleEvent {}), - ]), - ]), - )]; - - let optimized = Normalize::default().run_pass_pure(msgs.clone()); - - assert_eq!(optimized.optimize_further, expected_output); - assert_eq!(optimized.ready, []); - } - - #[test] - fn race_opt_noop() { - let msgs = vec![race::([seq([]), conc([])])]; - - // an empty seq optimizes to an empty seq, but an empty conc optimizes to noop - let expected_output = vec![(vec![0], race::([seq([]), noop()]))]; - - let optimized = Normalize::default().run_pass_pure(msgs.clone()); - - assert_eq!(optimized.optimize_further, expected_output); - assert_eq!(optimized.ready, []); - } -} diff --git a/lib/reconnecting-jsonrpc-ws-client/Cargo.toml b/lib/reconnecting-jsonrpc-ws-client/Cargo.toml new file mode 100644 index 0000000000..b4f2ca6455 --- /dev/null +++ b/lib/reconnecting-jsonrpc-ws-client/Cargo.toml @@ -0,0 +1,19 @@ +[package] +edition = { workspace = true } +license-file = { workspace = true } +name = "reconnecting-jsonrpc-ws-client" +repository = { workspace = true } +version = "0.1.0" + +[lints] +workspace = true + +[dependencies] +arc-swap = "1.7.1" +futures = { workspace = true } +jsonrpsee = { workspace = true, features = ["tracing", "ws-client", "http-client"] } +thiserror = { workspace = true } +tokio = { workspace = true, features = ["rt"] } +tokio-util = "0.7.12" +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] } diff --git a/lib/reconnecting-jsonrpc-ws-client/src/lib.rs b/lib/reconnecting-jsonrpc-ws-client/src/lib.rs new file mode 100644 index 0000000000..d81b631f3d --- /dev/null +++ b/lib/reconnecting-jsonrpc-ws-client/src/lib.rs @@ -0,0 +1,273 @@ +use core::fmt; +use std::{fmt::Debug, future::Future, sync::Arc, time::Duration}; + +use arc_swap::ArcSwapOption; +use jsonrpsee::core::{ + async_trait, + client::{BatchResponse, ClientT}, + params::BatchRequestBuilder, + traits::ToRpcParams, + DeserializeOwned, +}; +use tokio::time::sleep; +use tokio_util::sync::CancellationToken; +use tracing::{debug, debug_span, error, instrument, trace, warn, Instrument}; + +#[derive(Debug, Clone)] +pub struct Client { + inner: Arc, +} + +#[derive(Debug)] // NOTE: Does NOT impl Clone, otherwise you have a bad time with cancellation tokens being cloned and dropped +pub struct ClientInner { + client: Arc>, + cancellation_token: CancellationToken, +} + +impl Client { + pub fn new< + B: (Fn() -> Fut) + Clone + Send + 'static, + Fut: Future> + Send + 'static, + E: Debug + Send, + >( + builder: B, + ) -> Self { + let client = Arc::new(ArcSwapOption::from(None)); + + let cancellation_token = CancellationToken::new(); + + tokio::spawn({ + let maybe_client = client.clone(); + let cancellation_token = cancellation_token.child_token(); + + async move { + cancellation_token + .run_until_cancelled(async move { + let mut total_reconnects = 0; + + loop { + // if !healthy { + // continue; + // } + + let loaded_maybe_client = maybe_client.load(); + + match loaded_maybe_client.as_deref() { + Some(client) => { + let client: &jsonrpsee::core::client::Client = client; + + tokio::select! { + _ = client.on_disconnect() => { + debug!("client disconnected"); + + maybe_client.store(None); + + let reason = tokio::time::timeout( + Duration::from_secs(1), + client.disconnect_reason() + ) + .await + .ok(); + + match reason { + Some(reason) => { + debug!("disconnect reason: {reason:?}"); + } + None => { + debug!("unable to retrieve disconnect reason"); + } + } + + // reconnect( + // &maybe_client, + // builder.clone(), + // &mut total_reconnects, + // ) + // .await; + + // healthy = true; + // healthy.store(true, Ordering::SeqCst); + } + _ = sleep(Duration::from_secs(3)) => { + trace!("still connected"); + } + } + + continue; + } + None => { + debug!("client not connected yet, attempting to connect"); + + reconnect( + &maybe_client, + builder.clone(), + &mut total_reconnects, + ) + .await; + } + } + } + }) + .instrument(debug_span!("ws client reconnect task")) + .await + } + }); + + Self { + inner: Arc::new(ClientInner { + client, + // handle: Arc::new(handle), + cancellation_token, + }), + } + } + + pub fn is_healthy(&self) -> bool { + self.inner.client.load().is_some() + // && self.healthy.load(Ordering::SeqCst) + } + + pub async fn wait_until_connected( + &self, + timeout: Duration, + ) -> Result<(), ConnectionTimeoutError> { + tokio::time::timeout(timeout, async { + loop { + if self.is_healthy() { + return; + } else { + trace!("unhealthy"); + sleep(Duration::from_millis(100)).await + } + } + }) + .await + .map_err(|_| ConnectionTimeoutError { timeout }) + } + + pub fn shutdown(&self) { + self.inner.cancellation_token.cancel(); + // self.handle.abort() + } +} + +#[derive(Debug, thiserror::Error)] +#[error("websocket connection timed out after {}.{}s", timeout.as_secs(), timeout.subsec_nanos())] +pub struct ConnectionTimeoutError { + pub timeout: Duration, +} + +// impl Drop for Client { +// fn drop(&mut self) { +// // panic!("WHO IS DROPPING ME"); +// self.inner.cancellation_token.cancel(); +// // self.handle.abort(); +// } +// } + +#[async_trait] +impl ClientT for Client { + async fn notification( + &self, + method: &str, + params: Params, + ) -> Result<(), jsonrpsee::core::client::Error> + where + Params: ToRpcParams + Send, + { + self.inner + .client + .load_full() + .as_deref() + .ok_or_else(|| { + jsonrpsee::core::client::Error::Custom(format!( + "not yet connected (request: {method})", + )) + })? + .notification(method, params) + .await + } + + async fn request( + &self, + method: &str, + params: Params, + ) -> Result + where + R: DeserializeOwned, + Params: ToRpcParams + Send, + { + self.inner + .client + .load_full() + .as_deref() + .ok_or_else(|| { + jsonrpsee::core::client::Error::Custom(format!( + "not yet connected (request: {method})", + )) + })? + .request(method, params) + .await + } + + async fn batch_request<'a, R>( + &self, + batch: BatchRequestBuilder<'a>, + ) -> Result, jsonrpsee::core::client::Error> + where + R: DeserializeOwned + fmt::Debug + 'a, + { + self.inner + .client + .load_full() + .as_deref() + .ok_or(jsonrpsee::core::client::Error::Custom( + "not yet connected (batch request)".to_owned(), + ))? + .batch_request(batch) + .await + } +} + +#[instrument(name = "reconnect", skip_all)] +async fn reconnect< + B: (Fn() -> Fut) + Send + 'static, + Fut: Future> + Send + 'static, + E: Debug + Send, +>( + maybe_client: &ArcSwapOption, + builder: B, + total_reconnects: &mut u64, +) { + let mut retry_ms = 5; + + const MAX_RETRY_MS: u64 = 8_000; + + let mut attempt = 0; + + let new_client = loop { + match builder().await { + Ok(client) => break client, + Err(error) => { + attempt += 1; + + warn!( + ?error, + %attempt, + "error while reconnecting client, \ + trying again in {retry_ms} ms" + ); + + sleep(Duration::from_millis(retry_ms)).await; + + retry_ms = std::cmp::min((retry_ms * 3) / 2, MAX_RETRY_MS); + } + } + }; + + *total_reconnects += 1; + + debug!(%total_reconnects, "client reconnected"); + + maybe_client.store(Some(Arc::new(new_client))); +} diff --git a/lib/relay-message/Cargo.toml b/lib/relay-message/Cargo.toml deleted file mode 100644 index 3c5deccb4a..0000000000 --- a/lib/relay-message/Cargo.toml +++ /dev/null @@ -1,61 +0,0 @@ -[package] -edition = { workspace = true } -license-file = { workspace = true } -name = "relay-message" -repository = { workspace = true } -version = "0.1.0" - -[lints] -workspace = true - -[dependencies] -arbitrary = { workspace = true, optional = true, features = ["derive"] } -arbitrum-verifier = { workspace = true } -beacon-api = { workspace = true } -chain-utils = { workspace = true } -contracts = { workspace = true, features = ["providers"] } -dashmap = { workspace = true } -enumorph = { workspace = true } -ethereum-verifier = { workspace = true } -ethers = { workspace = true, features = ["rustls", "ws"] } -frame-support-procedural = { workspace = true } -frunk = { workspace = true } -futures = { workspace = true } -hex = { workspace = true } -macros = { workspace = true } -num-bigint = { workspace = true } -prost = { workspace = true } -protos = { workspace = true, features = ["proto_full", "client"] } -queue-msg = { workspace = true } -scroll-codec = { workspace = true } -scroll-rpc = { workspace = true } -scroll-verifier = { workspace = true } -serde = { workspace = true, features = ["derive"] } -serde-utils = { workspace = true } -serde_json = { workspace = true } -static_assertions = { workspace = true } -tendermint = { workspace = true } -tendermint-proto = { workspace = true } -tendermint-rpc = { workspace = true, features = ["http-client", "websocket-client"] } -thiserror = { workspace = true } -tokio = { workspace = true, features = ["time"] } -tonic = { workspace = true, features = ["transport", "tls", "tls-roots", "tls-webpki-roots"] } -tracing = { workspace = true } -typenum = { workspace = true } -unionlabs = { workspace = true, features = ["ethabi"] } - -[dev-dependencies] -hex-literal = { workspace = true } -serde_json = { workspace = true } - -[features] -default = [] - -arbitrary = [ - "dep:arbitrary", - "tendermint/arbitrary", - "tendermint/std", - "unionlabs/arbitrary", - "chain-utils/arbitrary", - "queue-msg/arbitrary", -] diff --git a/lib/relay-message/fuzz_targets/serde_roundtrip.rs b/lib/relay-message/fuzz_targets/serde_roundtrip.rs deleted file mode 100644 index f48a0fdef8..0000000000 --- a/lib/relay-message/fuzz_targets/serde_roundtrip.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![no_main] - -use libfuzzer_sys::fuzz_target; -use queue_msg::Op; -use unionlabs::test_utils::*; -use voyager_message::RelayMessageTypes; - -fuzz_target!(|data: Op| { - assert_json_roundtrip(&data); -}); diff --git a/lib/relay-message/src/aggregate.rs b/lib/relay-message/src/aggregate.rs deleted file mode 100644 index 45cdba59af..0000000000 --- a/lib/relay-message/src/aggregate.rs +++ /dev/null @@ -1,2833 +0,0 @@ -use std::{collections::VecDeque, marker::PhantomData, num::NonZeroU64}; - -use frunk::{hlist_pat, HList}; -use macros::apply; -use queue_msg::{ - aggregate, - aggregation::{do_aggregate, UseAggregate}, - defer_relative, effect, fetch, noop, queue_msg, race, seq, wait, HandleAggregate, Op, - QueueError, QueueMessage, -}; -use tracing::{debug, info, instrument}; -use unionlabs::{ - events::{ - ChannelOpenAck, ChannelOpenInit, ChannelOpenTry, ConnectionOpenAck, ConnectionOpenInit, - ConnectionOpenTry, SendPacket, WriteAcknowledgement, - }, - hash::H256, - ibc::core::{ - channel::{ - self, channel::Channel, msg_acknowledgement::MsgAcknowledgement, - msg_channel_open_ack::MsgChannelOpenAck, - msg_channel_open_confirm::MsgChannelOpenConfirm, - msg_channel_open_try::MsgChannelOpenTry, msg_recv_packet::MsgRecvPacket, - msg_timeout::MsgTimeout, packet::Packet, - }, - client::{ - height::{Height, IsHeight}, - msg_create_client::MsgCreateClient, - }, - commitment::merkle_prefix::MerklePrefix, - connection::{ - self, msg_connection_open_ack::MsgConnectionOpenAck, - msg_connection_open_confirm::MsgConnectionOpenConfirm, - msg_connection_open_try::MsgConnectionOpenTry, - }, - }, - ics24::{ - AcknowledgementPath, ChannelEndPath, ClientConsensusStatePath, ClientStatePath, - CommitmentPath, ConnectionPath, NextClientSequencePath, NextConnectionSequencePath, - NextSequenceRecvPath, ReceiptPath, - }, - id::{ChannelId, ConnectionId, PortId}, - traits::{ChainIdOf, ClientIdOf, ClientState, HeightOf}, - QueryHeight, DELAY_PERIOD, -}; - -use crate::{ - any_enum, any_lc, - data::{AnyData, Data, IbcProof, IbcState, LatestHeight, SelfClientState, SelfConsensusState}, - effect::{ - AnyEffect, Effect, MsgAckPacketData, MsgChannelOpenAckData, MsgChannelOpenConfirmData, - MsgChannelOpenTryData, MsgConnectionOpenAckData, MsgConnectionOpenConfirmData, - MsgConnectionOpenTryData, MsgCreateClientData, MsgRecvPacketData, MsgTimeoutData, - }, - fetch::{AnyFetch, Fetch, FetchLatestHeight, FetchProof, FetchState, FetchUpdateHeaders}, - id, identified, - use_aggregate::IsAggregateData, - wait::{AnyWait, Wait, WaitForHeight, WaitForTimestamp, WaitForTrustedHeight}, - AnyLightClientIdentified, ChainExt, DoAggregate, Identified, RelayMessage, -}; - -#[apply(any_enum)] -/// Aggregate data, using data from [`AggregateData`] -#[any = AnyAggregate] -#[specific = LightClientSpecificAggregate] -pub enum Aggregate { - // put together the final pieces (proofs, states, etc) to build the msgs that will be sent - MsgConnectionOpenTry(AggregateMsgConnectionOpenTry), - MsgConnectionOpenAck(AggregateMsgConnectionOpenAck), - MsgConnectionOpenConfirm(AggregateMsgConnectionOpenConfirm), - - MsgChannelOpenTry(AggregateMsgChannelOpenTry), - MsgChannelOpenAck(AggregateMsgChannelOpenAck), - MsgChannelOpenConfirm(AggregateMsgChannelOpenConfirm), - - MsgRecvPacket(AggregateMsgRecvPacket), - MsgAckPacket(AggregateMsgAckPacket), - MsgTimeout(AggregateMsgTimeout), - - // construct one of the above messages after a required client update - AggregateMsgAfterUpdate(AggregateMsgAfterUpdate), - - MsgCreateClient(AggregateMsgCreateClient), - - PacketTimeout(AggregatePacketTimeout), - - // composite fetches - ReceiptPathProofFromChannelAndPort(AggregateFetchReceiptPathProofFromChannelAndPort), - ClientStateFromConnectionId(AggregateClientStateFromConnection), - ConnectionFetchFromChannelEnd(AggregateConnectionFetchFromChannelEnd), - - /// Aggregate that fetches the connection info from the channel, requeueing [`Self::AggregateMsgAfterUpdate`] - ChannelHandshakeMsgAfterUpdate(AggregateChannelHandshakeMsgAfterUpdate), - - PacketUpdateClient(AggregatePacketMsgAfterUpdate), - - WaitForConnectionOpen(AggregateWaitForConnectionOpen), - WaitForCounterpartyTrustedHeight(AggregateWaitForCounterpartyTrustedHeight), - WaitForTrustedHeight(AggregateWaitForTrustedHeight), - WaitForNextConnectionSequence(AggregateWaitForNextConnectionSequence), - WaitForNextClientSequence(AggregateWaitForNextClientSequence), - WaitForPacketReceipt(AggregateWaitForPacketReceipt), - - FetchCounterpartyStateproof(AggregateFetchCounterpartyStateProof), - - UpdateClient(AggregateUpdateClient), - UpdateClientFromHeight(AggregateUpdateClientFromHeight), - - #[serde(untagged)] - LightClientSpecific(LightClientSpecificAggregate), -} - -impl HandleAggregate for AnyLightClientIdentified { - #[instrument(skip_all, fields(chain_id = %self.chain_id()))] - fn handle( - self, - data: VecDeque<::Data>, - ) -> Result, QueueError> { - let aggregate = self; - - any_lc! { - |aggregate| Ok(aggregate.handle(data)) - } - } -} - -impl identified!(Aggregate) { - pub fn handle(self, data: VecDeque>) -> Op - where - identified!(SelfClientState): IsAggregateData, - identified!(SelfConsensusState): IsAggregateData, - - identified!(LatestHeight): IsAggregateData, - - identified!(LatestHeight): IsAggregateData, - - // state - Identified, Hc, Tr>>: IsAggregateData, - Identified, Tr, Hc>>: IsAggregateData, - - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - // proof - Identified, Hc, Tr>>: IsAggregateData, - Identified, Hc, Tr>>: - IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - Identified>: DoAggregate, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - { - let chain_id = self.chain_id; - - match self.t { - Aggregate::MsgConnectionOpenTry(init) => do_aggregate(id(chain_id, init), data), - Aggregate::MsgConnectionOpenAck(ack) => do_aggregate(id(chain_id, ack), data), - Aggregate::MsgConnectionOpenConfirm(confirm) => { - do_aggregate(id(chain_id, confirm), data) - } - Aggregate::MsgChannelOpenTry(try_) => do_aggregate(id(chain_id, try_), data), - Aggregate::MsgChannelOpenAck(ack) => do_aggregate(id(chain_id, ack), data), - Aggregate::MsgChannelOpenConfirm(confirm) => do_aggregate(id(chain_id, confirm), data), - Aggregate::UpdateClient(update_client) => { - do_aggregate(id(chain_id, update_client), data) - } - Aggregate::UpdateClientFromHeight(update_client) => { - do_aggregate(id(chain_id, update_client), data) - } - Aggregate::MsgCreateClient(create_client) => { - do_aggregate(id(chain_id, create_client), data) - } - Aggregate::AggregateMsgAfterUpdate(aggregate) => { - do_aggregate(id(chain_id, aggregate), data) - } - Aggregate::LightClientSpecific(LightClientSpecificAggregate(aggregate)) => { - > as DoAggregate>::do_aggregate( - id(chain_id, aggregate), - data, - ) - } - Aggregate::ConnectionFetchFromChannelEnd(aggregate) => { - do_aggregate(id(chain_id, aggregate), data) - } - Aggregate::ReceiptPathProofFromChannelAndPort(aggregate) => { - do_aggregate(id(chain_id, aggregate), data) - } - Aggregate::ChannelHandshakeMsgAfterUpdate(channel_handshake_update_client) => { - do_aggregate(id(chain_id, channel_handshake_update_client), data) - } - Aggregate::PacketUpdateClient(packet_update_client) => { - do_aggregate(id(chain_id, packet_update_client), data) - } - Aggregate::MsgRecvPacket(recv_packet) => do_aggregate(id(chain_id, recv_packet), data), - Aggregate::MsgAckPacket(ack_packet) => do_aggregate(id(chain_id, ack_packet), data), - Aggregate::MsgTimeout(timeout_packet) => { - do_aggregate(id(chain_id, timeout_packet), data) - } - Aggregate::PacketTimeout(timeout_packet) => { - do_aggregate(id(chain_id, timeout_packet), data) - } - Aggregate::WaitForCounterpartyTrustedHeight(agg) => { - do_aggregate(id(chain_id, agg), data) - } - Aggregate::WaitForTrustedHeight(agg) => do_aggregate(id(chain_id, agg), data), - Aggregate::FetchCounterpartyStateproof(agg) => do_aggregate(id(chain_id, agg), data), - Aggregate::ClientStateFromConnectionId(agg) => do_aggregate(id(chain_id, agg), data), - Aggregate::WaitForConnectionOpen(agg) => do_aggregate(id(chain_id, agg), data), - Aggregate::WaitForNextConnectionSequence(agg) => do_aggregate(id(chain_id, agg), data), - Aggregate::WaitForNextClientSequence(agg) => do_aggregate(id(chain_id, agg), data), - Aggregate::WaitForPacketReceipt(agg) => do_aggregate(id(chain_id, agg), data), - } - } -} - -#[queue_msg] -pub struct AggregateMsgConnectionOpenTry { - pub event_height: HeightOf, - pub event: ConnectionOpenInit, ClientIdOf>, -} - -#[queue_msg] -pub struct AggregateMsgConnectionOpenAck { - pub event_height: HeightOf, - pub event: ConnectionOpenTry, ClientIdOf>, -} - -#[queue_msg] -pub struct AggregateMsgConnectionOpenConfirm { - pub event_height: HeightOf, - pub event: ConnectionOpenAck, ClientIdOf>, -} - -#[queue_msg] -pub struct AggregateMsgChannelOpenTry { - pub event_height: HeightOf, - pub event: ChannelOpenInit, -} - -#[queue_msg] -pub struct AggregateMsgChannelOpenAck { - pub event_height: HeightOf, - pub event: ChannelOpenTry, -} - -#[queue_msg] -pub struct AggregateMsgChannelOpenConfirm { - pub event_height: HeightOf, - pub event: ChannelOpenAck, -} - -#[queue_msg] -pub struct AggregateMsgRecvPacket { - pub event_height: HeightOf, - pub event: SendPacket, -} - -#[queue_msg] -pub struct AggregateMsgAckPacket { - pub event_height: HeightOf, - pub event: WriteAcknowledgement, - // HACK: Need to pass the block hash through, figure out a better/cleaner way to do this - // TODO: Replace with the ack directly? - // TODO: Remove - pub tx_hash: H256, - pub counterparty_client_id: ClientIdOf, -} - -#[queue_msg] -pub struct AggregateMsgTimeout<#[cover] Hc: ChainExt, #[cover] Tr: ChainExt> { - // pub client_id: Hc::ClientId, - // pub counterparty_client_id: Tr::ClientId, - // pub counterparty_chain_id: ChainIdOf, - pub packet: Packet, -} - -#[queue_msg] -pub struct AggregateConnectionFetchFromChannelEnd { - pub at: HeightOf, -} - -#[queue_msg] -pub struct AggregateClientStateFromConnection { - pub at: HeightOf, -} - -#[queue_msg] -pub struct AggregateFetchReceiptPathProofFromChannelAndPort< - #[cover] Hc: ChainExt, - #[cover] Tr: ChainExt, -> { - pub port_id: PortId, - pub channel_id: ChannelId, -} - -#[queue_msg] -pub struct AggregateChannelHandshakeMsgAfterUpdate { - // Will be threaded through to the update msg - pub event_height: HeightOf, - pub channel_handshake_event: ChannelHandshakeEvent, -} - -#[queue_msg] -pub enum ChannelHandshakeEvent { - Init(ChannelOpenInit), - Try(ChannelOpenTry), - Ack(ChannelOpenAck), -} - -#[queue_msg] -pub struct AggregatePacketMsgAfterUpdate { - // Will be threaded through to the update msg - pub update_to: HeightOf, - pub event_height: HeightOf, - pub tx_hash: H256, - pub packet_event: PacketEvent, -} - -#[queue_msg] -pub enum PacketEvent { - Send(SendPacket), - WriteAck(WriteAcknowledgement), -} - -#[queue_msg] -pub struct AggregatePacketTimeout<#[cover] Hc: ChainExt, #[cover] Tr: ChainExt> { - pub packet: Packet, -} - -#[queue_msg] -pub struct AggregateWaitForPacketReceipt<#[cover] Hc: ChainExt, #[cover] Tr: ChainExt> { - pub packet: Packet, -} - -#[queue_msg] -pub struct AggregateFetchCounterpartyStateProof { - pub counterparty_client_id: ClientIdOf, - pub fetch: FetchProof, -} - -#[queue_msg] -pub struct AggregateUpdateClient { - pub client_id: ClientIdOf, -} - -#[queue_msg] -pub struct AggregateUpdateClientFromHeight { - pub from_height: HeightOf, - pub client_id: ClientIdOf, -} - -#[queue_msg] -pub struct AggregateWaitForCounterpartyTrustedHeight { - pub wait_for: HeightOf, - pub client_id: ClientIdOf, - pub counterparty_client_id: ClientIdOf, -} - -#[queue_msg] -pub struct AggregateWaitForConnectionOpen<#[cover] Hc: ChainExt, #[cover] Tr: ChainExt> { - pub connection_id: ConnectionId, -} - -#[queue_msg] -pub struct AggregateWaitForNextConnectionSequence<#[cover] Hc: ChainExt, #[cover] Tr: ChainExt> { - pub sequence: u64, -} - -#[queue_msg] -pub struct AggregateWaitForNextClientSequence<#[cover] Hc: ChainExt, #[cover] Tr: ChainExt> { - pub sequence: u64, -} - -#[queue_msg] -pub struct AggregateWaitForTrustedHeight { - pub client_id: ClientIdOf, - pub counterparty_chain_id: ChainIdOf, - pub counterparty_client_id: ClientIdOf, -} - -#[queue_msg] -pub struct AggregateMsgCreateClient { - pub config: ::Config, -} - -/// Messages that will be re-queued after an update. -#[queue_msg] -pub enum AggregateMsgAfterUpdate { - ConnectionOpenTry(AggregateMsgConnectionOpenTry), - ConnectionOpenAck(AggregateMsgConnectionOpenAck), - ConnectionOpenConfirm(AggregateMsgConnectionOpenConfirm), - - ChannelOpenTry(AggregateMsgChannelOpenTry), - ChannelOpenAck(AggregateMsgChannelOpenAck), - ChannelOpenConfirm(AggregateMsgChannelOpenConfirm), - - RecvPacket(AggregateMsgRecvPacket), - AckPacket(AggregateMsgAckPacket), - TimeoutPacket(AggregateMsgTimeout), -} - -#[queue_msg] -pub struct LightClientSpecificAggregate(pub Hc::Aggregate); - -impl UseAggregate for identified!(AggregateChannelHandshakeMsgAfterUpdate) -where - Identified>: IsAggregateData, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![Identified>]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateChannelHandshakeMsgAfterUpdate { - channel_handshake_event, - event_height, - __marker: _, - }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: self_chain_id, - t: IbcState { - path: _, - height: _, - state: connection, - }, - __marker: _, - }]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, self_chain_id); - - let event_msg = match channel_handshake_event { - ChannelHandshakeEvent::Init(init) => { - AggregateMsgAfterUpdate::ChannelOpenTry(AggregateMsgChannelOpenTry { - event_height, - event: init, - __marker: PhantomData, - }) - } - ChannelHandshakeEvent::Try(try_) => { - AggregateMsgAfterUpdate::ChannelOpenAck(AggregateMsgChannelOpenAck { - event_height, - event: try_, - __marker: PhantomData, - }) - } - ChannelHandshakeEvent::Ack(ack) => { - AggregateMsgAfterUpdate::ChannelOpenConfirm(AggregateMsgChannelOpenConfirm { - event_height, - event: ack, - __marker: PhantomData, - }) - } - }; - - aggregate( - [mk_aggregate_wait_for_update( - this_chain_id.clone(), - connection.client_id, - connection.counterparty.client_id, - event_height, - )], - [], - id(this_chain_id, event_msg), - ) - } -} - -pub fn mk_aggregate_wait_for_update( - chain_id: ChainIdOf, - client_id: ClientIdOf, - counterparty_client_id: ClientIdOf, - wait_for: HeightOf, -) -> Op -where - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - aggregate( - [fetch(id::( - chain_id.clone(), - FetchState { - at: QueryHeight::Latest, - path: ClientStatePath { - client_id: client_id.clone(), - } - .into(), - }, - ))], - [], - id( - chain_id, - AggregateWaitForCounterpartyTrustedHeight:: { - wait_for, - client_id, - counterparty_client_id, - }, - ), - ) -} - -impl UseAggregate for identified!(AggregatePacketMsgAfterUpdate) -where - Identified>: IsAggregateData, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![Identified>]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregatePacketMsgAfterUpdate { - update_to, - event_height, - tx_hash, - packet_event, - __marker: _, - }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: self_chain_id, - t: IbcState { - path: _, - height: _, - state: connection, - }, - __marker: _, - }]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, self_chain_id); - - let event = match packet_event { - PacketEvent::Send(send) => Aggregate::from(AggregateMsgAfterUpdate::RecvPacket( - AggregateMsgRecvPacket { - event_height, - event: send, - __marker: PhantomData, - }, - )), - PacketEvent::WriteAck(recv) => { - Aggregate::from(AggregateMsgAfterUpdate::AckPacket(AggregateMsgAckPacket { - event_height, - event: recv, - tx_hash, - counterparty_client_id: connection.counterparty.client_id.clone(), - })) - } - }; - - aggregate( - [aggregate( - [fetch(id::( - this_chain_id.clone().clone(), - FetchState { - at: QueryHeight::Latest, - path: ClientStatePath { - client_id: connection.client_id.clone(), - } - .into(), - }, - ))], - [], - id( - this_chain_id.clone(), - AggregateWaitForCounterpartyTrustedHeight:: { - wait_for: update_to, - client_id: connection.client_id.clone(), - counterparty_client_id: connection.counterparty.client_id.clone(), - }, - ), - )], - [], - id(this_chain_id, event), - ) - } -} - -impl UseAggregate for identified!(AggregatePacketTimeout) -where - Identified>, Hc, Tr>>: IsAggregateData, - Identified>: IsAggregateData, - - AnyLightClientIdentified: From)>, - - AnyLightClientIdentified: From)>, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified>, Hc, Tr>>, - Identified> - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregatePacketTimeout { - packet, - __marker: _, - }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: client_state_chain_id, - t: IbcState { - path: ClientStatePath { client_id }, - height: _, - state: client_state, - }, - __marker: _, - }, - Identified { - chain_id: connection_chain_id, - t: IbcState { - path: _, - height: _, - state: connection, - }, - __marker: _, - } - ]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, client_state_chain_id); - assert_eq!(this_chain_id, connection_chain_id); - assert_eq!(client_id, connection.client_id); - - let counterparty_chain_id: ChainIdOf = client_state.chain_id(); - - let aggregate_timeout = id( - counterparty_chain_id.clone(), - AggregateMsgAfterUpdate::::TimeoutPacket(AggregateMsgTimeout:: { - packet: packet.clone(), - __marker: PhantomData, - }), - ); - - race( - [ - Some(aggregate( - [fetch(id::( - counterparty_chain_id.clone(), - FetchState:: { - at: QueryHeight::Latest, - path: ReceiptPath { - port_id: packet.destination_port.clone(), - channel_id: packet.destination_channel.clone(), - sequence: packet.sequence, - } - .into(), - }, - ))], - [], - id( - counterparty_chain_id.clone(), - AggregateWaitForPacketReceipt:: { - packet: packet.clone(), - __marker: PhantomData, - }, - ), - )), - (packet.timeout_height != Height::default()).then(|| { - aggregate( - [ - wait(id( - counterparty_chain_id.clone(), - WaitForHeight:: { - height: packet.timeout_height.into(), - __marker: PhantomData, - }, - )), - // we bypass `AggregateWaitForCounterpartyTrustedHeight` here because we already have the client state - wait(id( - this_chain_id.clone(), - WaitForTrustedHeight:: { - height: packet.timeout_height.into(), - client_id: client_id.clone(), - counterparty_client_id: connection - .counterparty - .client_id - .clone(), - counterparty_chain_id: counterparty_chain_id.clone(), - }, - )), - ], - [], - aggregate_timeout.clone(), - ) - }), - (packet.timeout_timestamp != 0).then(|| { - aggregate( - [aggregate( - // `WaitForTimestamp` returns the latest height if the timestamp has been hit (note that this will be changed to return the height of the timestamp eventually, which is why we don't use `seq(wait(timestamp), fetch(latest_height))`) - [wait(id( - counterparty_chain_id.clone(), - WaitForTimestamp:: { - timestamp: i64::try_from( - // TODO: normalizes for voyager that - // expects seconds, we may just move to - // nanoseconds for everything to avoid - // any friction in the interface - // Add one second as we truncate the nanos. - (packet.timeout_timestamp / (1e9 as u64)) + 1, - ) - .unwrap(), - __marker: PhantomData, - }, - ))], - [], - id( - this_chain_id.clone(), - AggregateWaitForTrustedHeight:: { - client_id: client_id.clone(), - counterparty_client_id: connection - .counterparty - .client_id - .clone(), - counterparty_chain_id: counterparty_chain_id.clone(), - }, - ), - )], - [], - aggregate_timeout.clone(), - ) - }), - ] - .into_iter() - .flatten(), - ) - } -} - -impl UseAggregate for identified!(AggregateWaitForTrustedHeight) -where - identified!(LatestHeight): IsAggregateData, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![identified!(LatestHeight)]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateWaitForTrustedHeight { - client_id, - counterparty_chain_id, - counterparty_client_id, - }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: latest_height_chain_id, - t: LatestHeight { height, __marker }, - __marker: _, - }]: Self::AggregatedData, - ) -> Op { - assert_eq!(latest_height_chain_id, counterparty_chain_id); - - wait(id( - this_chain_id, - WaitForTrustedHeight { - height, - client_id, - counterparty_client_id, - counterparty_chain_id, - }, - )) - } -} - -impl UseAggregate for identified!(AggregateConnectionFetchFromChannelEnd) -where - Identified>: IsAggregateData, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![Identified>]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: AggregateConnectionFetchFromChannelEnd { at, __marker: _ }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: self_chain_id, - t: IbcState { - path: _, - height: _, - state: channel, - }, - __marker: _, - }]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, self_chain_id); - - fetch(id::( - this_chain_id, - FetchState { - at: QueryHeight::Specific(at), - path: ConnectionPath { - connection_id: channel.connection_hops[0].clone(), - } - .into(), - }, - )) - } -} - -impl UseAggregate for identified!(AggregateClientStateFromConnection) -where - Identified>: IsAggregateData, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![Identified>]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: AggregateClientStateFromConnection { at, __marker: _ }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: self_chain_id, - t: IbcState { - path: _, - height: _, - state: connection, - }, - __marker: _, - }]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, self_chain_id); - - fetch(id( - this_chain_id, - FetchState:: { - at: QueryHeight::Specific(at), - path: ClientStatePath { - client_id: connection.client_id, - } - .into(), - }, - )) - } -} - -impl UseAggregate for identified!(AggregateUpdateClient) -where - Identified, Hc, Tr>>: IsAggregateData, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified, Hc, Tr>> - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateUpdateClient { - client_id, - __marker: _, - }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: self_chain_id, - t: IbcState { - path: ClientStatePath { - client_id: trusted_client_state_client_id - }, - height: _trusted_client_state_fetched_at_height, - state: trusted_client_state - }, - __marker: _, - }]: Self::AggregatedData, - ) -> Op { - let counterparty_chain_id: ChainIdOf = trusted_client_state.chain_id(); - - assert_eq!(trusted_client_state_client_id, client_id); - assert_eq!(this_chain_id, self_chain_id); - - aggregate( - [fetch(id( - counterparty_chain_id, - FetchLatestHeight { - __marker: PhantomData, - }, - ))], - [], - id( - this_chain_id, - AggregateUpdateClientFromHeight { - from_height: trusted_client_state.height(), - client_id, - }, - ), - ) - } -} - -impl UseAggregate for identified!(AggregateUpdateClientFromHeight) -where - Identified, Hc, Tr>>: IsAggregateData, - identified!(LatestHeight): IsAggregateData, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![identified!(LatestHeight),]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateUpdateClientFromHeight { - client_id, - from_height, - }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: counterparty_chain_id, - t: LatestHeight { - height: counterparty_latest_height, - __marker - }, - __marker: _, - },]: Self::AggregatedData, - ) -> Op { - fetch(id::( - counterparty_chain_id, - FetchUpdateHeaders { - counterparty_client_id: client_id, - counterparty_chain_id: this_chain_id, - update_from: from_height, - update_to: counterparty_latest_height, - }, - )) - } -} - -impl UseAggregate for identified!(AggregateWaitForCounterpartyTrustedHeight) -where - Identified, Hc, Tr>>: IsAggregateData, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = - HList![Identified, Hc, Tr>>]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateWaitForCounterpartyTrustedHeight { - wait_for, - client_id, - counterparty_client_id, - }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: trusted_client_state_chain_id, - t: IbcState { - path: ClientStatePath { - client_id: trusted_client_state_client_id - }, - height: _trusted_client_state_fetched_at_height, - state: trusted_client_state - }, - __marker: _, - }]: Self::AggregatedData, - ) -> Op { - assert_eq!(trusted_client_state_client_id, client_id); - assert_eq!(trusted_client_state_chain_id, this_chain_id); - - let counterparty_chain_id: ChainIdOf = trusted_client_state.chain_id(); - - wait(id( - counterparty_chain_id, - WaitForTrustedHeight { - height: wait_for, - client_id: counterparty_client_id, - counterparty_client_id: client_id, - counterparty_chain_id: this_chain_id, - }, - )) - } -} - -impl UseAggregate for identified!(AggregateMsgAfterUpdate) -where - Identified, Hc, Tr>>: IsAggregateData, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = - HList![Identified, Hc, Tr>>]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: msg_to_aggregate, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: self_chain_id, - t: IbcState { - path: ClientStatePath { - client_id: trusted_client_state_client_id - }, - height: trusted_client_state_fetched_at_height, - state: trusted_client_state - }, - __marker: _, - }]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, self_chain_id); - - match msg_to_aggregate { - AggregateMsgAfterUpdate::ConnectionOpenTry(AggregateMsgConnectionOpenTry { - event_height, - event, - }) => { - let consensus_state_height = trusted_client_state_fetched_at_height; - - assert_eq!( - consensus_state_height.revision_number(), - event_height.revision_number(), - "consensus state height `{consensus_state_height}` and event height \ - `{event_height}` have different revision numbers", - ); - - assert!( - consensus_state_height.revision_height() >= event_height.revision_height(), - "{} < {}", - consensus_state_height.revision_height(), - event_height.revision_height() - ); - - let trusted_client_state_height = trusted_client_state.height(); - - aggregate( - [ - fetch(id::( - this_chain_id.clone(), - FetchProof { - at: trusted_client_state_fetched_at_height, - path: ClientStatePath { - client_id: event.client_id.clone(), - } - .into(), - }, - )), - fetch(id::( - this_chain_id.clone(), - FetchProof { - at: trusted_client_state_fetched_at_height, - path: ClientConsensusStatePath { - client_id: event.client_id.clone(), - height: trusted_client_state_height, - } - .into(), - }, - )), - fetch(id::( - this_chain_id.clone(), - FetchProof { - at: trusted_client_state_fetched_at_height, - path: ConnectionPath { - connection_id: event.connection_id.clone(), - } - .into(), - }, - )), - fetch(id::( - this_chain_id.clone(), - FetchState { - at: QueryHeight::Specific(trusted_client_state_fetched_at_height), - path: ConnectionPath { - connection_id: event.connection_id.clone(), - } - .into(), - }, - )), - ], - [id( - this_chain_id.clone(), - IbcState::, Hc, Tr> { - path: ClientStatePath { - client_id: trusted_client_state_client_id, - }, - height: trusted_client_state_fetched_at_height, - state: trusted_client_state, - }, - ) - .into()], - id( - this_chain_id, - AggregateMsgConnectionOpenTry:: { - event_height, - event, - }, - ), - ) - } - AggregateMsgAfterUpdate::ConnectionOpenAck(AggregateMsgConnectionOpenAck { - event_height, - event, - }) => { - let consensus_state_height = trusted_client_state_fetched_at_height; - - assert_eq!( - consensus_state_height.revision_number(), - event_height.revision_number(), - "consensus state height `{consensus_state_height}` and event height \ - `{event_height}` have different revision numbers", - ); - - assert!( - consensus_state_height.revision_height() >= event_height.revision_height(), - "{} < {}", - consensus_state_height.revision_height(), - event_height.revision_height() - ); - - let trusted_client_state_height = trusted_client_state.height(); - - aggregate( - [ - fetch(id::( - this_chain_id.clone(), - FetchProof { - at: trusted_client_state_fetched_at_height, - path: ClientStatePath { - client_id: event.client_id.clone(), - } - .into(), - }, - )), - fetch(id::( - this_chain_id.clone(), - FetchProof { - at: trusted_client_state_fetched_at_height, - path: ClientConsensusStatePath { - client_id: event.client_id.clone(), - height: trusted_client_state_height, - } - .into(), - }, - )), - fetch(id::( - this_chain_id.clone(), - FetchProof { - at: trusted_client_state_fetched_at_height, - path: ConnectionPath { - connection_id: event.connection_id.clone(), - } - .into(), - }, - )), - fetch(id::( - this_chain_id.clone(), - FetchState { - at: QueryHeight::Specific(trusted_client_state_fetched_at_height), - path: ConnectionPath { - connection_id: event.connection_id.clone(), - } - .into(), - }, - )), - ], - [id( - this_chain_id.clone(), - IbcState { - path: ClientStatePath { - client_id: trusted_client_state_client_id, - }, - height: trusted_client_state_fetched_at_height, - state: trusted_client_state, - }, - ) - .into()], - id( - this_chain_id, - AggregateMsgConnectionOpenAck:: { - event_height, - event, - }, - ), - ) - } - AggregateMsgAfterUpdate::ConnectionOpenConfirm(AggregateMsgConnectionOpenConfirm { - event_height, - event, - }) => { - let consensus_state_height = trusted_client_state_fetched_at_height; - - assert_eq!( - consensus_state_height.revision_number(), - event_height.revision_number(), - "consensus state height `{consensus_state_height}` and event height \ - `{event_height}` have different revision numbers", - ); - - assert!( - consensus_state_height.revision_height() >= event_height.revision_height(), - "{} < {}", - consensus_state_height.revision_height(), - event_height.revision_height() - ); - - aggregate( - [fetch(id::( - this_chain_id.clone(), - FetchProof { - at: trusted_client_state_fetched_at_height, - path: ConnectionPath { - connection_id: event.connection_id.clone(), - } - .into(), - }, - ))], - [id( - this_chain_id.clone(), - IbcState { - path: ClientStatePath { - client_id: trusted_client_state_client_id, - }, - height: trusted_client_state_fetched_at_height, - state: trusted_client_state, - }, - ) - .into()], - id( - this_chain_id, - AggregateMsgConnectionOpenConfirm:: { - event_height, - event, - }, - ), - ) - } - AggregateMsgAfterUpdate::ChannelOpenTry(AggregateMsgChannelOpenTry { - event_height, - event, - __marker: _, - }) => { - let consensus_state_height = trusted_client_state_fetched_at_height; - - assert_eq!( - consensus_state_height.revision_number(), - event_height.revision_number(), - "consensus state height `{consensus_state_height}` and event height \ - `{event_height}` have different revision numbers", - ); - - assert!( - consensus_state_height.revision_height() >= event_height.revision_height(), - "{} < {}", - consensus_state_height.revision_height(), - event_height.revision_height() - ); - - aggregate( - [ - aggregate( - [fetch(id::( - this_chain_id.clone(), - FetchState { - at: QueryHeight::Specific( - trusted_client_state_fetched_at_height, - ), - path: ChannelEndPath { - port_id: event.port_id.clone(), - channel_id: event.channel_id.clone(), - } - .into(), - }, - ))], - [], - id( - this_chain_id.clone(), - AggregateConnectionFetchFromChannelEnd:: { - at: trusted_client_state_fetched_at_height, - __marker: PhantomData, - }, - ), - ), - fetch(id::( - this_chain_id.clone(), - FetchProof { - at: trusted_client_state_fetched_at_height, - path: ChannelEndPath { - port_id: event.port_id.clone(), - channel_id: event.channel_id.clone(), - } - .into(), - }, - )), - fetch(id::( - this_chain_id.clone(), - FetchState { - at: QueryHeight::Specific(trusted_client_state_fetched_at_height), - path: ChannelEndPath { - port_id: event.port_id.clone(), - channel_id: event.channel_id.clone(), - } - .into(), - }, - )), - ], - [id( - this_chain_id.clone(), - IbcState { - path: ClientStatePath { - client_id: trusted_client_state_client_id, - }, - height: trusted_client_state_fetched_at_height, - state: trusted_client_state, - }, - ) - .into()], - id( - this_chain_id, - AggregateMsgChannelOpenTry:: { - event_height, - event, - __marker: PhantomData, - }, - ), - ) - } - AggregateMsgAfterUpdate::ChannelOpenAck(AggregateMsgChannelOpenAck { - event_height, - event, - __marker: _, - }) => { - let consensus_state_height = trusted_client_state_fetched_at_height; - - assert_eq!( - consensus_state_height.revision_number(), - event_height.revision_number(), - "{consensus_state_height}, {event_height}", - ); - - assert!( - consensus_state_height.revision_height() >= event_height.revision_height(), - "{} < {}", - consensus_state_height.revision_height(), - event_height.revision_height() - ); - - aggregate( - [ - fetch(id::( - this_chain_id.clone(), - FetchProof { - at: trusted_client_state_fetched_at_height, - path: ChannelEndPath { - port_id: event.port_id.clone(), - channel_id: event.channel_id.clone(), - } - .into(), - }, - )), - fetch(id::( - this_chain_id.clone(), - FetchState { - at: QueryHeight::Specific(trusted_client_state_fetched_at_height), - path: ChannelEndPath { - port_id: event.port_id.clone(), - channel_id: event.channel_id.clone(), - } - .into(), - }, - )), - ], - [id( - this_chain_id.clone(), - Data::ClientState(IbcState { - path: ClientStatePath { - client_id: trusted_client_state_client_id, - }, - height: trusted_client_state_fetched_at_height, - state: trusted_client_state, - }), - ) - .into()], - id( - this_chain_id, - AggregateMsgChannelOpenAck:: { - event_height, - event, - __marker: PhantomData, - }, - ), - ) - } - AggregateMsgAfterUpdate::ChannelOpenConfirm(AggregateMsgChannelOpenConfirm { - event_height, - event, - __marker: _, - }) => { - let consensus_state_height = trusted_client_state_fetched_at_height; - - assert_eq!( - consensus_state_height.revision_number(), - event_height.revision_number(), - "{consensus_state_height}, {event_height}", - ); - - assert!( - consensus_state_height.revision_height() >= event_height.revision_height(), - "{} < {}", - consensus_state_height.revision_height(), - event_height.revision_height() - ); - - aggregate( - [ - fetch(id::( - this_chain_id.clone(), - FetchProof { - at: trusted_client_state_fetched_at_height, - path: ChannelEndPath { - port_id: event.port_id.clone(), - channel_id: event.channel_id.clone(), - } - .into(), - }, - )), - fetch(id::( - this_chain_id.clone(), - FetchState { - at: QueryHeight::Specific(trusted_client_state_fetched_at_height), - path: ChannelEndPath { - port_id: event.port_id.clone(), - channel_id: event.channel_id.clone(), - } - .into(), - }, - )), - ], - [id( - this_chain_id.clone(), - IbcState { - path: ClientStatePath { - client_id: trusted_client_state_client_id, - }, - height: trusted_client_state_fetched_at_height, - state: trusted_client_state, - }, - ) - .into()], - id( - this_chain_id, - AggregateMsgChannelOpenConfirm:: { - event_height, - event, - __marker: PhantomData, - }, - ), - ) - } - AggregateMsgAfterUpdate::RecvPacket(AggregateMsgRecvPacket { - event_height, - event, - __marker: _, - }) => aggregate( - [fetch(id::( - this_chain_id.clone(), - FetchProof { - at: trusted_client_state_fetched_at_height, - path: CommitmentPath { - port_id: event.packet_src_port.clone(), - channel_id: event.packet_src_channel.clone(), - sequence: event.packet_sequence, - } - .into(), - }, - ))], - [id( - this_chain_id.clone(), - IbcState { - path: ClientStatePath { - client_id: trusted_client_state_client_id, - }, - height: trusted_client_state_fetched_at_height, - state: trusted_client_state, - }, - ) - .into()], - id( - this_chain_id, - AggregateMsgRecvPacket:: { - event_height, - event, - __marker: PhantomData, - }, - ), - ), - AggregateMsgAfterUpdate::AckPacket(AggregateMsgAckPacket { - event_height, - event, - tx_hash, - counterparty_client_id, - }) => aggregate( - [fetch(id::( - this_chain_id.clone(), - FetchProof { - at: trusted_client_state_fetched_at_height, - path: AcknowledgementPath { - port_id: event.packet_dst_port.clone(), - channel_id: event.packet_dst_channel.clone(), - sequence: event.packet_sequence, - } - .into(), - }, - ))], - [id( - this_chain_id.clone(), - IbcState { - path: ClientStatePath { - client_id: trusted_client_state_client_id, - }, - height: trusted_client_state_fetched_at_height, - state: trusted_client_state, - }, - ) - .into()], - id( - this_chain_id, - AggregateMsgAckPacket:: { - event_height, - event, - tx_hash, - counterparty_client_id, - }, - ), - ), - AggregateMsgAfterUpdate::TimeoutPacket(AggregateMsgTimeout { packet, __marker }) => { - aggregate( - [ - // NOTE: Use this when we support ordered packets - // aggregate( - // // fetch the packet nonexistence proof from the counterparty - // [fetch(id( - // this_chain_id.clone(), - // FetchState:: { - // at: QueryHeight::Specific(trusted_client_state_fetched_at_height), - // path: NextSequenceRecvPath { - // port_id: packet.destination_port.clone(), - // channel_id: packet.destination_channel.clone(), - // } - // .into(), - // }, - // ))], - // [], - // id( - // this_chain_id.clone(), - // AggregateFetchReceiptPathProofFromChannelAndPort:: { - // port_id: packet.destination_port.clone(), - // channel_id: packet.destination_channel.clone(), - // __marker: PhantomData, - // }, - // ), - // ) - fetch(id( - this_chain_id.clone(), - FetchProof:: { - at: trusted_client_state_fetched_at_height, - path: ReceiptPath { - port_id: packet.destination_port.clone(), - channel_id: packet.destination_channel.clone(), - sequence: packet.sequence, - } - .into(), - }, - )), - fetch(id( - this_chain_id, - FetchState:: { - at: QueryHeight::Specific(trusted_client_state_fetched_at_height), - path: ReceiptPath { - port_id: packet.destination_port.clone(), - channel_id: packet.destination_channel.clone(), - sequence: packet.sequence, - } - .into(), - }, - )), - ], - [], - id( - trusted_client_state.chain_id(), - AggregateMsgTimeout:: { packet, __marker }, - ), - ) - } - } - } -} - -impl UseAggregate for identified!(AggregateMsgConnectionOpenTry) -where - // state - Identified, Hc, Tr>>: IsAggregateData, - Identified>: IsAggregateData, - - // proof - Identified, Hc, Tr>>: IsAggregateData, - Identified, Hc, Tr>>: - IsAggregateData, - Identified>: IsAggregateData, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified, Hc, Tr>>, - Identified, Hc, Tr>>, - Identified, Hc, Tr>>, - Identified>, - Identified>, - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateMsgConnectionOpenTry { - event_height: trusted_height, - event, - }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: trusted_client_state_chain_id, - t: IbcState { - path: ClientStatePath { - client_id: _trusted_client_state_client_id - }, - height: _trusted_client_state_fetched_at_height, - state: trusted_client_state - }, - __marker: _, - }, - Identified { - chain_id: client_state_proof_chain_id, - t: IbcProof { - height: client_state_proof_height, - proof: client_state_proof, - path: _, - __marker: _, - }, - __marker: _, - }, - Identified { - chain_id: consensus_state_proof_chain_id, - t: IbcProof { - height: consensus_state_proof_height, - proof: consensus_state_proof, - path: _, - __marker: _, - }, - __marker: _, - }, - Identified { - chain_id: connection_proof_chain_id, - t: IbcProof { - height: connection_proof_height, - proof: connection_proof, - path: _, - __marker: _, - }, - __marker: _, - }, - Identified { - chain_id: connection_end_chain_id, - t: IbcState { - path: _, - height: _, - state: connection_end - }, - __marker: _, - }, - ]: Self::AggregatedData, - ) -> Op { - assert!(consensus_state_proof_height.revision_height() >= trusted_height.revision_height()); - assert!(client_state_proof_height.revision_height() >= trusted_height.revision_height()); - - let counterparty_chain_id: ChainIdOf = trusted_client_state.chain_id(); - - assert_eq!(trusted_client_state_chain_id, this_chain_id); - - assert_eq!(client_state_proof_chain_id, this_chain_id); - assert_eq!(consensus_state_proof_chain_id, this_chain_id); - assert_eq!(connection_proof_chain_id, this_chain_id); - assert_eq!(connection_end_chain_id, this_chain_id); - - let consensus_height = trusted_client_state.height(); - - effect(id::( - counterparty_chain_id, - MsgConnectionOpenTryData(MsgConnectionOpenTry { - client_id: event.counterparty_client_id, - client_state: trusted_client_state, - counterparty: connection::counterparty::Counterparty { - client_id: event.client_id, - connection_id: event.connection_id, - prefix: MerklePrefix { - key_prefix: b"ibc".to_vec(), - }, - }, - delay_period: DELAY_PERIOD, - counterparty_versions: connection_end.versions, - proof_height: connection_proof_height, - proof_init: connection_proof, - proof_client: client_state_proof, - proof_consensus: consensus_state_proof, - consensus_height, - }), - )) - } -} - -impl UseAggregate for identified!(AggregateMsgConnectionOpenAck) -where - Identified, Hc, Tr>>: IsAggregateData, - Identified, Hc, Tr>>: IsAggregateData, - Identified, Hc, Tr>>: - IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified, Hc, Tr>>, - Identified, Hc, Tr>>, - Identified, Hc, Tr>>, - Identified>, - Identified>, - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateMsgConnectionOpenAck { - event_height: trusted_height, - event, - }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: trusted_client_state_chain_id, - t: IbcState { - path: ClientStatePath { - client_id: _trusted_client_state_client_id - }, - height: _trusted_client_state_fetched_at_height, - state: trusted_client_state - }, - __marker: _ - }, - Identified { - chain_id: client_state_proof_chain_id, - t: IbcProof { - height: client_state_proof_height, - proof: client_state_proof, - path: _, - __marker: _, - }, - __marker: _, - }, - Identified { - chain_id: consensus_state_proof_chain_id, - t: IbcProof { - height: consensus_state_proof_height, - proof: consensus_state_proof, - path: _, - __marker: _, - }, - __marker: _, - }, - Identified { - chain_id: connection_proof_chain_id, - t: IbcProof { - height: connection_proof_height, - proof: connection_proof, - path: _, - __marker: _, - }, - __marker: _, - }, - Identified { - chain_id: connection_end_chain_id, - t: IbcState { - path: _, - height: _, - state: connection_end - }, - __marker: _, - }, - ]: Self::AggregatedData, - ) -> Op { - assert!(consensus_state_proof_height.revision_height() >= trusted_height.revision_height()); - assert!(client_state_proof_height.revision_height() >= trusted_height.revision_height()); - - let counterparty_chain_id: ChainIdOf = trusted_client_state.chain_id(); - - assert_eq!(trusted_client_state_chain_id, this_chain_id); - assert_eq!(client_state_proof_chain_id, this_chain_id); - assert_eq!(consensus_state_proof_chain_id, this_chain_id); - assert_eq!(connection_proof_chain_id, this_chain_id); - assert_eq!(connection_end_chain_id, this_chain_id); - - let consensus_height = trusted_client_state.height(); - - effect(id::( - counterparty_chain_id, - MsgConnectionOpenAckData(MsgConnectionOpenAck { - connection_id: event.counterparty_connection_id, - counterparty_connection_id: event.connection_id, - // TODO: Figure out a way to not panic here, likely by encoding this invariant into the type somehow - version: connection_end.versions[0].clone(), - client_state: trusted_client_state, - proof_height: connection_proof_height.into(), - proof_try: connection_proof, - proof_client: client_state_proof, - proof_consensus: consensus_state_proof, - consensus_height: consensus_height.into(), - }), - )) - } -} - -impl UseAggregate for identified!(AggregateMsgConnectionOpenConfirm) -where - Identified, Hc, Tr>>: IsAggregateData, - Identified, Hc, Tr>>: IsAggregateData, - Identified, Hc, Tr>>: - IsAggregateData, - Identified>: IsAggregateData, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified, Hc, Tr>>, - Identified>, - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateMsgConnectionOpenConfirm { - event_height: _, - event, - }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: trusted_client_state_chain_id, - t: IbcState { - path: ClientStatePath { - client_id: _trusted_client_state_client_id - }, - height: _trusted_client_state_fetched_at_height, - state: trusted_client_state - }, - __marker: _ - }, - Identified { - chain_id: connection_proof_chain_id, - t: IbcProof { - height: connection_proof_height, - proof: connection_proof, - path: _, - __marker: _, - }, - __marker: _, - }, - ]: Self::AggregatedData, - ) -> Op { - let counterparty_chain_id: ChainIdOf = trusted_client_state.chain_id(); - - assert_eq!(trusted_client_state_chain_id, this_chain_id); - assert_eq!(connection_proof_chain_id, this_chain_id); - - effect(id::( - counterparty_chain_id, - MsgConnectionOpenConfirmData { - msg: MsgConnectionOpenConfirm { - connection_id: event.counterparty_connection_id, - proof_height: connection_proof_height, - proof_ack: connection_proof, - }, - __marker: PhantomData, - }, - )) - } -} - -impl UseAggregate for identified!(AggregateMsgChannelOpenTry) -where - Identified, Hc, Tr>>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified, Hc, Tr>>, - Identified>, - Identified>, - Identified>, - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateMsgChannelOpenTry { - event_height: _, - event, - __marker: _, - }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: trusted_client_state_chain_id, - t: IbcState { - path: ClientStatePath { - client_id: _trusted_client_state_client_id - }, - height: _trusted_client_state_fetched_at_height, - state: trusted_client_state - }, - __marker: _ - }, - Identified { - chain_id: channel_proof_chain_id, - t: IbcProof { - proof: channel_proof, - height: channel_proof_height, - path: _, - __marker: _, - }, - __marker: _ - }, - Identified { - chain_id: _connection_end_chain_id, - t: IbcState { - path: _, - height: _, - state: connection, - }, - - __marker: _ - }, - Identified { - chain_id: _channel_end_chain_id, - t: IbcState { - path: _, - height: _, - state: channel, - }, - __marker: _, - }, - ]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, trusted_client_state_chain_id); - - let counterparty_chain_id: ChainIdOf = trusted_client_state.chain_id(); - - assert_eq!(channel_proof_chain_id, this_chain_id); - - effect(id::( - counterparty_chain_id, - MsgChannelOpenTryData { - msg: MsgChannelOpenTry { - port_id: channel.counterparty.port_id.clone(), - channel: Channel { - state: channel::state::State::Tryopen, - ordering: channel.ordering, - counterparty: channel::counterparty::Counterparty { - port_id: event.port_id.clone(), - channel_id: event.channel_id.clone().to_string(), - }, - connection_hops: vec![connection - .counterparty - .connection_id - .parse() - .unwrap()], - version: event.version.clone(), - }, - // NOTE: Review behaviour here - counterparty_version: event.version, - proof_init: channel_proof, - proof_height: channel_proof_height.into(), - }, - __marker: PhantomData, - }, - )) - } -} - -impl UseAggregate for identified!(AggregateMsgChannelOpenAck) -where - Identified, Hc, Tr>>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified, Hc, Tr>>, - Identified>, - Identified>, - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateMsgChannelOpenAck { - event_height: _, - event, - __marker: _, - }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: trusted_client_state_chain_id, - t: IbcState { - path: ClientStatePath { - client_id: _trusted_client_state_client_id - }, - height: _trusted_client_state_fetched_at_height, - state: trusted_client_state - }, - __marker: _ - }, - Identified { - chain_id: channel_proof_chain_id, - t: IbcProof { - height: channel_proof_height, - proof: channel_proof, - path: _, - __marker: _, - }, - __marker: _ - }, - Identified { - chain_id: channel_end_chain_id, - t: IbcState { - path: _, - height: _, - state: channel, - }, - __marker: _, - }, - ]: Self::AggregatedData, - ) -> Op { - let counterparty_chain_id: ChainIdOf = trusted_client_state.chain_id(); - - assert_eq!(trusted_client_state_chain_id, this_chain_id); - assert_eq!(channel_proof_chain_id, this_chain_id); - assert_eq!(channel_end_chain_id, this_chain_id); - - effect(id::( - counterparty_chain_id, - MsgChannelOpenAckData { - msg: MsgChannelOpenAck { - port_id: channel.counterparty.port_id.clone(), - channel_id: event.counterparty_channel_id, - counterparty_channel_id: event.channel_id, - counterparty_version: event.version, - proof_try: channel_proof, - proof_height: channel_proof_height, - }, - __marker: PhantomData, - }, - )) - } -} - -impl UseAggregate for identified!(AggregateMsgChannelOpenConfirm) -where - Identified, Hc, Tr>>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified, Hc, Tr>>, - Identified>, - Identified>, - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateMsgChannelOpenConfirm { - event_height: _, - event, - __marker: _, - }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: trusted_client_state_chain_id, - t: IbcState { - path: ClientStatePath { - client_id: _trusted_client_state_client_id - }, - height: _trusted_client_state_fetched_at_height, - state: trusted_client_state - }, - __marker: _ - }, - Identified { - chain_id: channel_proof_chain_id, - t: IbcProof { - height: channel_proof_height, - proof: channel_proof, - path: _, - __marker: _, - }, - __marker: _ - }, - Identified { - chain_id: channel_end_chain_id, - t: IbcState { - path: _, - height: _, - state: channel, - }, - __marker: _, - }, - ]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, trusted_client_state_chain_id); - assert_eq!(this_chain_id, channel_proof_chain_id); - assert_eq!(channel_end_chain_id, this_chain_id); - - let counterparty_chain_id: ChainIdOf = trusted_client_state.chain_id(); - - effect(id::( - counterparty_chain_id, - MsgChannelOpenConfirmData { - msg: MsgChannelOpenConfirm { - port_id: channel.counterparty.port_id, - channel_id: event.counterparty_channel_id, - proof_ack: channel_proof, - proof_height: channel_proof_height.into(), - }, - __marker: PhantomData, - }, - )) - } -} - -impl UseAggregate for identified!(AggregateMsgRecvPacket) -where - Identified, Hc, Tr>>: IsAggregateData, - Identified>: IsAggregateData, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified, Hc, Tr>>, - Identified>, - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateMsgRecvPacket { - event_height: _, - event, - __marker: _, - }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: trusted_client_state_chain_id, - t: IbcState { - path: ClientStatePath { - client_id: _trusted_client_state_client_id - }, - height: _trusted_client_state_fetched_at_height, - state: trusted_client_state - }, - __marker: _ - }, - Identified { - chain_id: commitment_proof_chain_id, - t: IbcProof { - height: commitment_proof_height, - proof: commitment_proof, - path: _, - __marker: _, - }, - __marker: _, - }, - ]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, trusted_client_state_chain_id); - assert_eq!(this_chain_id, commitment_proof_chain_id); - - debug!("aggregate recv_packet"); - - let counterparty_chain_id: ChainIdOf = trusted_client_state.chain_id(); - - effect(id::( - counterparty_chain_id, - MsgRecvPacketData { - msg: MsgRecvPacket { - packet: Packet { - sequence: event.packet_sequence, - source_port: event.packet_src_port, - source_channel: event.packet_src_channel, - destination_port: event.packet_dst_port, - destination_channel: event.packet_dst_channel, - data: event.packet_data_hex, - timeout_height: event.packet_timeout_height, - timeout_timestamp: event.packet_timeout_timestamp, - }, - proof_commitment: commitment_proof, - proof_height: commitment_proof_height, - }, - __marker: PhantomData, - }, - )) - } -} - -impl UseAggregate for identified!(AggregateMsgAckPacket) -where - Identified, Hc, Tr>>: IsAggregateData, - Identified>: IsAggregateData, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified, Hc, Tr>>, - Identified>, - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateMsgAckPacket { - event_height: _, - event, - tx_hash: _, - counterparty_client_id: _, - }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: trusted_client_state_chain_id, - t: IbcState { - path: ClientStatePath { - client_id: _trusted_client_state_client_id - }, - height: _trusted_client_state_fetched_at_height, - state: trusted_client_state - }, - __marker: _ - }, - Identified { - chain_id: commitment_proof_chain_id, - t: IbcProof { - proof: acknowledgement_proof, - height: acknowledgement_proof_height, - path: _, - __marker: _, - }, - __marker: _, - }, - ]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, trusted_client_state_chain_id); - assert_eq!(commitment_proof_chain_id, this_chain_id); - - debug!("aggregate ack_packet"); - - let counterparty_chain_id: ChainIdOf = trusted_client_state.chain_id(); - - effect(id::( - counterparty_chain_id, - MsgAckPacketData { - msg: MsgAcknowledgement { - proof_height: acknowledgement_proof_height, - packet: Packet { - sequence: event.packet_sequence, - source_port: event.packet_src_port, - source_channel: event.packet_src_channel, - destination_port: event.packet_dst_port, - destination_channel: event.packet_dst_channel, - data: event.packet_data_hex, - timeout_height: event.packet_timeout_height, - timeout_timestamp: event.packet_timeout_timestamp, - }, - acknowledgement: event.packet_ack_hex, - proof_acked: acknowledgement_proof, - }, - __marker: PhantomData, - }, - )) - } -} - -impl UseAggregate for identified!(AggregateMsgTimeout) -where - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified>, - Identified>, - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateMsgTimeout { - packet, - __marker: _, - }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: _, - t: IbcProof { - proof: proof_unreceived, - height: proof_unreceived_height, - // TODO: Assert these against the packet - path: proof_unreceived_path, - __marker: _, - }, - __marker: _, - }, - Identified { - chain_id: _, - t: IbcState { - state: packet_receipt, - height: packet_receipt_height, - path: packet_receipt_path, - }, - __marker: _, - }, - ]: Self::AggregatedData, - ) -> Op { - assert_eq!(proof_unreceived_path, packet_receipt_path); - assert_eq!(proof_unreceived_height, packet_receipt_height); - - if packet_receipt { - info!( - sequence = %packet.sequence, - source_port = %packet.source_port, - source_channel = %packet.source_channel, - destination_port = %packet.destination_port, - destination_channel = %packet.destination_channel, - "packet received, cancelling timeout" - ); - - noop() - } else { - seq([ - // void(wait(id( - // this_chain_id.clone(), - // WaitForTrustedHeight:: { - // client_id, - // counterparty_client_id, - // counterparty_chain_id, - // height: proof_unreceived_height, - // }, - // ))), - effect(id( - this_chain_id, - MsgTimeoutData:: { - msg: MsgTimeout { - packet, - proof_unreceived, - proof_height: proof_unreceived_height, - next_sequence_recv: proof_unreceived_path.sequence, - }, - __marker: PhantomData, - }, - )), - ]) - } - } -} - -impl UseAggregate for identified!(AggregateWaitForPacketReceipt) -where - Identified>: IsAggregateData, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified>, - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: AggregateWaitForPacketReceipt { packet, __marker }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: _, - t: IbcState { - state: packet_receipt, - height: _packet_receipt_height, - path: packet_receipt_path, - }, - __marker: _, - },]: Self::AggregatedData, - ) -> Op { - if packet_receipt { - info!( - sequence = %packet.sequence, - source_port = %packet.source_port, - source_channel = %packet.source_channel, - destination_port = %packet.destination_port, - destination_channel = %packet.destination_channel, - "packet received" - ); - - noop() - } else { - seq([ - defer_relative(1), - aggregate( - [fetch(id( - this_chain_id.clone(), - FetchState { - at: QueryHeight::Latest, - path: packet_receipt_path.into(), - }, - ))], - [], - id( - this_chain_id.clone(), - AggregateWaitForPacketReceipt { packet, __marker }, - ), - ), - ]) - } - } -} -impl UseAggregate for identified!(AggregateFetchCounterpartyStateProof) -where - Identified, Hc, Tr>>: IsAggregateData, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = - HList![Identified, Hc, Tr>>]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateFetchCounterpartyStateProof { - counterparty_client_id: _, - fetch: fetch_, - }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: trusted_client_state_chain_id, - t: IbcState { - height: _, - path: _, - state: trusted_client_state, - }, - __marker: _, - }]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, trusted_client_state_chain_id); - - let counterparty_chain_id: ChainIdOf = trusted_client_state.chain_id(); - - fetch(id::(counterparty_chain_id, fetch_.into())) - } -} - -impl UseAggregate for identified!(AggregateFetchReceiptPathProofFromChannelAndPort) -where - AnyLightClientIdentified: From)>, - Identified>: IsAggregateData, -{ - type AggregatedData = HList![ - Identified> - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateFetchReceiptPathProofFromChannelAndPort { - port_id, - channel_id, - __marker: _, - }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: next_sequence_recv_chain_id, - t: IbcState { - path: next_sequence_recv_path, - height, - state: next_sequence_recv - }, - __marker: _ - },]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, next_sequence_recv_chain_id); - - assert_eq!(next_sequence_recv_path.port_id, port_id); - assert_eq!(next_sequence_recv_path.channel_id, channel_id); - - fetch(id( - this_chain_id, - FetchProof:: { - at: height, - path: ReceiptPath { - port_id, - channel_id, - sequence: NonZeroU64::new(next_sequence_recv).unwrap(), - } - .into(), - }, - )) - } -} - -impl UseAggregate for identified!(AggregateMsgCreateClient) -where - identified!(SelfClientState): IsAggregateData, - identified!(SelfConsensusState): IsAggregateData, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - identified!(SelfClientState), - identified!(SelfConsensusState), - ]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: this, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: self_client_state_chain_id, - t: SelfClientState { - self_client_state, - __marker: _, - }, - __marker: _ - }, - Identified { - chain_id: self_consensus_state_chain_id, - t: SelfConsensusState { - self_consensus_state, - __marker: _, - }, - __marker: _, - }, - ]: Self::AggregatedData, - ) -> Op { - assert_eq!(self_client_state_chain_id, self_consensus_state_chain_id); - - effect(id::( - this_chain_id, - MsgCreateClientData { - config: this.config, - msg: MsgCreateClient { - client_state: self_client_state, - consensus_state: self_consensus_state, - }, - }, - )) - } -} - -impl UseAggregate for identified!(AggregateWaitForNextConnectionSequence) -where - Identified>: IsAggregateData, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![Identified>]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateWaitForNextConnectionSequence { - sequence, - __marker: _, - }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: next_connection_sequence_chain_id, - t: IbcState { - path: NextConnectionSequencePath {}, - height: _, - state: next_connection_sequence - }, - __marker: _ - },]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, next_connection_sequence_chain_id); - - if next_connection_sequence >= sequence { - noop() - } else { - seq([ - defer_relative(1), - aggregate( - [fetch(id( - this_chain_id.clone(), - FetchState { - at: QueryHeight::Latest, - path: NextConnectionSequencePath {}.into(), - }, - ))], - [], - id( - this_chain_id, - AggregateWaitForNextConnectionSequence { - sequence, - __marker: PhantomData, - }, - ), - ), - ]) - } - } -} - -impl UseAggregate for identified!(AggregateWaitForNextClientSequence) -where - Identified>: IsAggregateData, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![Identified>]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateWaitForNextClientSequence { - sequence, - __marker: _, - }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: next_client_sequence_chain_id, - t: IbcState { - path: NextClientSequencePath {}, - height: _, - state: next_client_sequence - }, - __marker: _ - },]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, next_client_sequence_chain_id); - - if next_client_sequence >= sequence { - noop() - } else { - seq([ - defer_relative(1), - aggregate( - [fetch(id( - this_chain_id.clone(), - FetchState { - at: QueryHeight::Latest, - path: NextClientSequencePath {}.into(), - }, - ))], - [], - id( - this_chain_id, - AggregateWaitForNextClientSequence { - sequence, - __marker: PhantomData, - }, - ), - ), - ]) - } - } -} - -impl UseAggregate for identified!(AggregateWaitForConnectionOpen) -where - Identified>: IsAggregateData, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![Identified>]; - - fn aggregate( - Identified { - chain_id: this_chain_id, - t: - AggregateWaitForConnectionOpen { - connection_id, - __marker: _, - }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: connection_state_client_id, - t: IbcState { - path: ConnectionPath { - connection_id: path_connection_id - }, - height: _, - state: connection - }, - __marker: _ - },]: Self::AggregatedData, - ) -> Op { - assert_eq!(this_chain_id, connection_state_client_id); - assert_eq!(connection_id, path_connection_id); - - if connection.state == connection::state::State::Open { - noop() - } else { - seq([ - defer_relative(1), - aggregate( - [fetch(id( - this_chain_id.clone(), - FetchState { - at: QueryHeight::Latest, - path: ConnectionPath { - connection_id: connection_id.clone(), - } - .into(), - }, - ))], - [], - id( - this_chain_id, - AggregateWaitForConnectionOpen { - connection_id, - __marker: PhantomData, - }, - ), - ), - ]) - } - } -} diff --git a/lib/relay-message/src/chain.rs b/lib/relay-message/src/chain.rs deleted file mode 100644 index 1e12492ed0..0000000000 --- a/lib/relay-message/src/chain.rs +++ /dev/null @@ -1,126 +0,0 @@ -// https://github.com/rust-lang/rust/issues/35853#issuecomment-415993963 -macro_rules! with_dollar_sign { - ($($body:tt)*) => { - macro_rules! __with_dollar_sign { $($body)* } - __with_dollar_sign!($); - } -} - -macro_rules! try_from_relayer_msg { - ( - chain = $Chain:ty, - generics = ($($generics:tt)+), - msgs = $Enum:ident( - $($Variant:ident($Ty:ty),)+ - ), - ) => { - const _: () = { - use crate::{AnyLightClientIdentified, RelayMessage, id, identified, Identified, data::{AnyData, Data, LightClientSpecificData}}; - use queue_msg::Op; - - with_dollar_sign! { - ($d:tt) => { - macro_rules! with_generics { - ( - chain = $d Chain:ty, - msgs = $d Enum:ident( - $d ($d Variant:ident($d Ty:ty),)+ - ), - ) => { - $d ( - impl <$($generics)+> TryFrom> for Identified<$d Chain, Tr, $d Ty> - where - identified!(Data<$d Chain, Tr>): TryFrom, Error = AnyLightClientIdentified> + Into> - { - type Error = Op; - fn try_from(value: Op) -> Result, Op> { - match value { - Op::Data(data) => { - let Identified { - chain_id, - t, - __marker: _, - } = data.try_into().map_err(Op::Data)?; - - match t { - Data::LightClientSpecific( - LightClientSpecificData($d Enum::$d Variant( - t, - ))) => Ok(id(chain_id, t)), - _ => Err(Op::Data(Into::>::into(crate::id(chain_id, t)))) - } - - }, - _ => Err(value), - } - } - } - - impl <$($generics)+> From> for AnyLightClientIdentified - where - AnyLightClientIdentified: From)> - { - fn from(Identified { chain_id, t, __marker: _ }: Identified<$d Chain, Tr, $d Ty>) -> AnyLightClientIdentified { - AnyLightClientIdentified::from(id( - chain_id, - Data::LightClientSpecific(LightClientSpecificData($d Enum::$d Variant( - t, - ))), - )) - } - } - - impl <$($generics)+> TryFrom> for Identified<$d Chain, Tr, $d Ty> - where - identified!(Data<$d Chain, Tr>): TryFrom, Error = AnyLightClientIdentified> + Into> - { - type Error = AnyLightClientIdentified; - - fn try_from(value: AnyLightClientIdentified) -> Result, AnyLightClientIdentified> { - let Identified { - chain_id, - t, - __marker: _, - } = value.try_into()?; - - match t { - Data::LightClientSpecific(LightClientSpecificData($d Enum::$d Variant( - t, - ))) => Ok(id(chain_id, t)), - _ => Err(Into::>::into(id(chain_id, t))) - } - } - } - )+ - - // impl From<<$d Chain as LightClient>::$d LcMsg> for $d Specific<$d Chain> { - // fn from(msg: <$d Chain as LightClient>::$d LcMsg) -> Self { - // Self(msg) - // } - // } - }; - } - } - } - - with_generics!( - chain = $Chain, - msgs = $Enum( - $($Variant($Ty),)+ - ), - ); - }; - }; -} - -// functionality common between all cosmos-sdk chains -pub mod cosmos_sdk; - -pub mod cosmos; -pub mod union; - -pub mod arbitrum; -pub mod ethereum; -pub mod scroll; - -pub mod berachain; diff --git a/lib/relay-message/src/chain/arbitrum.rs b/lib/relay-message/src/chain/arbitrum.rs deleted file mode 100644 index bfc9c7af58..0000000000 --- a/lib/relay-message/src/chain/arbitrum.rs +++ /dev/null @@ -1,596 +0,0 @@ -use std::{collections::VecDeque, marker::PhantomData}; - -use chain_utils::{ - arbitrum::Arbitrum, - ethereum::{EthereumConsensusChain, EthereumIbcChain, EthereumIbcChainExt, IbcHandlerExt}, -}; -use ethers::providers::Middleware; -use frunk::{hlist_pat, HList}; -use queue_msg::{ - aggregate, - aggregation::{do_aggregate, UseAggregate}, - data, effect, fetch, queue_msg, Op, -}; -use unionlabs::{ - encoding::{Decode, Encode, EthAbi}, - hash::H160, - ibc::{ - core::client::msg_update_client::MsgUpdateClient, - lightclients::{ - arbitrum, - ethereum::{account_proof::AccountProof, storage_proof::StorageProof}, - }, - }, - ics24::ClientStatePath, - never::Never, - traits::{Chain, ClientStateOf, HeightOf, IbcStateEncodingOf}, - uint::U256, -}; - -use crate::{ - aggregate::{Aggregate, AnyAggregate}, - chain::ethereum::{ - do_msg, fetch_get_proof, fetch_ibc_state, EthereumConfig, FetchIbcState, GetProof, - TxSubmitError, - }, - data::{AnyData, Data}, - effect::{AnyEffect, Effect, MsgUpdateClientData}, - fetch::{AnyFetch, DoFetch, Fetch, FetchUpdateHeaders}, - id, identified, - use_aggregate::IsAggregateData, - AnyLightClientIdentified, ChainExt, DoAggregate, DoFetchProof, DoFetchState, - DoFetchUpdateHeaders, DoMsg, Identified, PathOf, RelayMessage, -}; - -impl ChainExt for Arbitrum { - type Data = ArbitrumData; - type Fetch = ArbitrumFetch; - type Aggregate = ArbitrumAggregate; - - type MsgError = TxSubmitError; - - type Config = EthereumConfig; -} - -impl DoMsg for Arbitrum -where - ClientStateOf: Encode, - Tr: ChainExt< - SelfConsensusState: Encode, - SelfClientState: Encode, - Header: Encode, - StoredClientState: Encode, - StateProof: Encode, - >, - AnyLightClientIdentified: From)>, -{ - async fn msg(&self, msg: Effect) -> Result, Self::MsgError> { - do_msg( - self.chain_id(), - self.multicall_address, - &self.keyring, - msg, - false, - None, - ) - .await - } -} - -impl DoFetchProof for Arbitrum -where - AnyLightClientIdentified: From)>, -{ - fn proof(c: &Self, at: HeightOf, path: PathOf) -> Op { - fetch(id::( - c.chain_id(), - Fetch::::specific(GetProof { path, height: at }), - )) - } -} - -// REVIEW: This can probably be generic over Hc: EthereumChain, instead of being duplicated between ethereum and arbitrum -impl DoFetchState for Arbitrum -where - Tr: ChainExt> + Encode>, - - AnyLightClientIdentified: From)>, -{ - type QueryUnfinalizedTrustedClientStateError = Never; - - fn state(hc: &Self, at: HeightOf, path: PathOf) -> Op { - fetch(id::( - hc.chain_id(), - Fetch::::specific(FetchIbcState { path, height: at }), - )) - } - - async fn query_unfinalized_trusted_client_state( - hc: &Self, - client_id: Self::ClientId, - ) -> Result, Self::QueryUnfinalizedTrustedClientStateError> { - let latest_execution_height = hc.provider.get_block_number().await.unwrap().as_u64(); - - Ok(hc - .ibc_handler() - .ibc_state_read::<_, Self, Tr>(latest_execution_height, ClientStatePath { client_id }) - .await - .unwrap()) - } -} - -impl DoFetchUpdateHeaders for Arbitrum -where - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - Tr: ChainExt, -{ - fn fetch_update_headers( - c: &Self, - update_info: FetchUpdateHeaders, - ) -> Op { - aggregate( - [ - fetch(id( - c.chain_id(), - Fetch::specific(FetchL1ContractRootProof { - height: update_info.update_to, - l1_contract_address: c.l1_contract_address, - }), - )), - fetch(id( - c.chain_id(), - Fetch::specific(FetchIbcContractRootProof { - height: update_info.update_to, - ibc_contract_address: c.ibc_handler_address, - }), - )), - fetch(id( - c.chain_id(), - Fetch::specific(FetchLatestConfirmedProofs { - height: update_info.update_to, - l1_latest_confirmed_slot: c.l1_next_node_num_slot, - l1_nodes_slot: c.l1_nodes_slot, - l1_contract_address: c.l1_contract_address, - }), - )), - fetch(id( - c.chain_id(), - Fetch::specific(FetchL2Header { - height: update_info.update_to, - }), - )), - ], - [], - id( - c.chain_id(), - Aggregate::::specific(AggregateHeader { req: update_info }), - ), - ) - } -} - -impl DoFetch for ArbitrumFetch -where - AnyLightClientIdentified: From)>, - Tr: ChainExt< - SelfClientState: Decode>, - SelfConsensusState: Decode> + Encode, - >, -{ - type Error = Never; - - async fn do_fetch(arbitrum: &Arbitrum, msg: Self) -> Result, Self::Error> { - let msg = match msg { - Self::FetchGetProof(get_proof) => fetch_get_proof(arbitrum, get_proof).await, - Self::FetchIbcState(ibc_state) => fetch_ibc_state(arbitrum, ibc_state).await, - Self::FetchL1ContractRootProof(FetchL1ContractRootProof { - height, - l1_contract_address, - }) => { - let account_proof = arbitrum - .l1 - .provider() - .get_proof( - ethers::types::H160::from(l1_contract_address), - vec![], - Some(ethers::types::BlockId::Number( - arbitrum - .l1 - .execution_height_of_beacon_slot(height.revision_height) - .await - .into(), - )), - ) - .await - .unwrap(); - - Data::specific(L1ContractRootProof { - height, - proof: AccountProof { - storage_root: account_proof.storage_hash.into(), - proof: account_proof - .account_proof - .into_iter() - .map(|x| x.to_vec()) - .collect(), - }, - __marker: PhantomData, - }) - } - Self::FetchIbcContractRootProof(FetchIbcContractRootProof { - height, - ibc_contract_address, - }) => { - let arbitrum_height = arbitrum - .execution_height_of_beacon_slot(height.revision_height) - .await; - - let proof = arbitrum - .provider - .get_proof( - ethers::types::H160(ibc_contract_address.0), - vec![], - Some(ethers::types::BlockNumber::Number(arbitrum_height.into()).into()), - ) - .await - .unwrap(); - - Data::specific(IbcContractRootProof { - height, - proof: AccountProof { - storage_root: proof.storage_hash.0.into(), - proof: proof - .account_proof - .into_iter() - .map(|x| x.to_vec()) - .collect(), - }, - __marker: PhantomData, - }) - } - Self::FetchLatestConfirmedProofs(FetchLatestConfirmedProofs { - height, - l1_latest_confirmed_slot, - l1_nodes_slot, - l1_contract_address, - }) => { - let l1_height = arbitrum - .l1 - .execution_height_of_beacon_slot(height.revision_height) - .await; - - let latest_confirmed = arbitrum - .next_node_num_at_beacon_slot(height.revision_height) - .await; - - let [latest_confirmed_slot_proof, nodes_slot_proof] = arbitrum - .l1 - .provider() - .get_proof( - ethers::types::H160(l1_contract_address.0), - vec![ - l1_latest_confirmed_slot.to_be_bytes().into(), - arbitrum_verifier::nodes_confirm_data_mapping_key( - l1_nodes_slot, - latest_confirmed, - arbitrum.l1_nodes_confirm_data_offset, - ) - .to_be_bytes() - .into(), - ], - Some(ethers::types::BlockNumber::Number(l1_height.into()).into()), - ) - .await - .unwrap() - .storage_proof - .try_into() - .unwrap(); - - Data::specific(LatestConfirmedProofs { - height, - latest_confirmed, - // TODO: Extract this logic into a fn, we do it all over the place - latest_confirmed_slot_proof: StorageProof { - key: U256::from_be_bytes(latest_confirmed_slot_proof.key.0), - value: latest_confirmed_slot_proof.value.into(), - proof: latest_confirmed_slot_proof - .proof - .into_iter() - .map(|bytes| bytes.to_vec()) - .collect(), - }, - nodes_slot_proof: StorageProof { - key: U256::from_be_bytes(nodes_slot_proof.key.0), - value: nodes_slot_proof.value.into(), - proof: nodes_slot_proof - .proof - .into_iter() - .map(|bytes| bytes.to_vec()) - .collect(), - }, - __marker: PhantomData, - }) - } - Self::FetchL2Header(FetchL2Header { height }) => { - let arbitrum_height = arbitrum - .execution_height_of_beacon_slot(height.revision_height) - .await; - - let block = arbitrum - .provider - .get_block(ethers::types::BlockNumber::Number(arbitrum_height.into())) - .await - .unwrap() - .unwrap(); - - let l2_header = arbitrum::l2_header::L2Header { - parent_hash: block.parent_hash.0.into(), - sha3_uncles: block.uncles_hash.0.into(), - miner: block.author.unwrap().0.into(), - state_root: block.state_root.0.into(), - transactions_root: block.transactions_root.0.into(), - receipts_root: block.receipts_root.0.into(), - logs_bloom: Box::new(block.logs_bloom.unwrap().0.into()), - difficulty: block.difficulty.into(), - number: block.number.unwrap().as_u64().into(), - gas_limit: block.gas_limit.as_u64(), - gas_used: block.gas_used.as_u64(), - timestamp: block.timestamp.as_u64(), - extra_data: block.extra_data.try_into().unwrap(), - mix_hash: block.mix_hash.unwrap().0.into(), - nonce: block.nonce.unwrap().0.into(), - base_fee_per_gas: block.base_fee_per_gas.unwrap().into(), - }; - - Data::specific(L2Header { - height, - l2_header, - __marker: PhantomData, - }) - } - }; - - Ok(data(id::(arbitrum.chain_id(), msg))) - } -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum ArbitrumFetch { - FetchGetProof(GetProof), - FetchIbcState(FetchIbcState), - - // - arbitrum rollup contract root proof - FetchL1ContractRootProof(FetchL1ContractRootProof), - // - ibc contract root against finalized root on L2 - FetchIbcContractRootProof(FetchIbcContractRootProof), - /// Fetch the latest confirmed node and the relevant proofs. - FetchLatestConfirmedProofs(FetchLatestConfirmedProofs), - /// Fetch the Arbitrum header. - FetchL2Header(FetchL2Header), -} - -#[queue_msg] -pub struct FetchL1ContractRootProof { - // the height to update to - pub height: HeightOf, - pub l1_contract_address: H160, -} - -#[queue_msg] -pub struct FetchIbcContractRootProof { - // the height to update to - pub height: HeightOf, - pub ibc_contract_address: H160, -} - -#[queue_msg] -pub struct FetchLatestConfirmedProofs { - pub height: HeightOf, - pub l1_latest_confirmed_slot: U256, - pub l1_nodes_slot: U256, - pub l1_contract_address: H160, -} - -#[queue_msg] -pub struct FetchL2Header { - // the height to update to - pub height: HeightOf, -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum ArbitrumData { - L1ContractRootProof(L1ContractRootProof), - IbcContractRootProof(IbcContractRootProof), - LatestConfirmedProofs(LatestConfirmedProofs), - L2Header(L2Header), -} - -try_from_relayer_msg! { - chain = Arbitrum, - generics = (Tr: ChainExt), - msgs = ArbitrumData( - L1ContractRootProof(L1ContractRootProof), - IbcContractRootProof(IbcContractRootProof), - LatestConfirmedProofs(LatestConfirmedProofs), - L2Header(L2Header), - ), -} - -#[queue_msg] -pub struct L1ContractRootProof<#[cover] Tr: ChainExt> { - pub height: HeightOf, - pub proof: AccountProof, -} - -#[queue_msg] -pub struct IbcContractRootProof<#[cover] Tr: ChainExt> { - pub height: HeightOf, - pub proof: AccountProof, -} - -#[queue_msg] -pub struct LatestConfirmedProofs<#[cover] Tr: ChainExt> { - pub height: HeightOf, - pub latest_confirmed: u64, - pub latest_confirmed_slot_proof: StorageProof, - pub nodes_slot_proof: StorageProof, -} - -#[queue_msg] -pub struct L2Header<#[cover] Tr: ChainExt> { - pub height: HeightOf, - pub l2_header: arbitrum::l2_header::L2Header, -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum ArbitrumAggregate { - AggregateHeader(AggregateHeader), -} - -#[queue_msg] -pub struct AggregateHeader { - pub req: FetchUpdateHeaders, -} - -impl DoAggregate for Identified> -where - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - fn do_aggregate( - Identified { - chain_id, - t, - __marker, - }: Self, - data: VecDeque>, - ) -> Op { - match t { - ArbitrumAggregate::AggregateHeader(msg) => do_aggregate(id(chain_id, msg), data), - } - } -} - -impl UseAggregate for Identified> -where - Tr: ChainExt, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified>, - Identified>, - Identified>, - Identified>, - ]; - - fn aggregate( - Identified { - chain_id: _chain_id, - t: AggregateHeader { req }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: _l1_contract_root_proof_chain_id, - t: L1ContractRootProof { - height: _l1_contract_root_proof_height, - proof: l1_contract_root_proof, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: _ibc_contract_root_proof_chain_id, - t: IbcContractRootProof { - height: _ibc_contract_root_proof_height, - proof: ibc_contract_root_proof, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: _latest_confirmed_proofs_chain_id, - t: LatestConfirmedProofs { - height: _latest_confirmed_proofs_height, - latest_confirmed: _latest_confirmed, - latest_confirmed_slot_proof, - nodes_slot_proof, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: _l2_header_proof_chain_id, - t: L2Header { - height: _l2_header_proof_height, - l2_header, - __marker: _, - }, - __marker: _, - }, - ]: Self::AggregatedData, - ) -> Op { - // assert_eq!(rollup_contract_root_proof_chain_id, chain_id); - // assert_eq!(latest_batch_index_proof_chain_id, chain_id); - // assert_eq!(arbitrum_finalized_root_proof_chain_id, chain_id); - // assert_eq!(ibc_contract_root_proof_chain_id, chain_id); - // assert_eq!(batch_hash_proof_chain_id, chain_id); - // assert_eq!(commit_batch_transaction_input_chain_id, chain_id); - - // assert_eq!( - // rollup_contract_root_proof_height, - // latest_batch_index_proof_height - // ); - // assert_eq!( - // rollup_contract_root_proof_height, - // arbitrum_finalized_root_proof_height - // ); - // assert_eq!( - // rollup_contract_root_proof_height, - // ibc_contract_root_proof_height - // ); - // assert_eq!(rollup_contract_root_proof_height, batch_hash_proof_height); - // assert_eq!( - // rollup_contract_root_proof_height, - // commit_batch_transaction_input_height - // ); - - // assert_eq!( - // arbitrum_finalized_root_proof_batch_index, - // batch_hash_proof_batch_index - // ); - // assert_eq!( - // arbitrum_finalized_root_proof_batch_index, - // commit_batch_transaction_input_batch_index - // ); - - effect(id::( - req.counterparty_chain_id, - MsgUpdateClientData(MsgUpdateClient { - client_id: req.counterparty_client_id, - client_message: arbitrum::header::Header { - l1_height: req.update_to, - l1_account_proof: l1_contract_root_proof, - l2_ibc_account_proof: ibc_contract_root_proof, - l1_next_node_num_slot_proof: latest_confirmed_slot_proof, - l1_nodes_slot_proof: nodes_slot_proof, - l2_header, - }, - }), - )) - } -} diff --git a/lib/relay-message/src/chain/berachain.rs b/lib/relay-message/src/chain/berachain.rs deleted file mode 100644 index 4a0a3c55a0..0000000000 --- a/lib/relay-message/src/chain/berachain.rs +++ /dev/null @@ -1,607 +0,0 @@ -use std::{collections::VecDeque, marker::PhantomData}; - -use chain_utils::{ - berachain::Berachain, - ethereum::{EthereumConsensusChain, EthereumIbcChainExt, IbcHandlerExt}, -}; -use enumorph::Enumorph; -use ethers::providers::Middleware; -use frunk::{hlist_pat, HList}; -use queue_msg::{ - aggregate, - aggregation::{do_aggregate, UseAggregate}, - data, effect, fetch, queue_msg, seq, wait, Op, -}; -use unionlabs::{ - berachain::{BerachainChainSpec, LATEST_EXECUTION_PAYLOAD_HEADER_PREFIX}, - cosmos::ics23::commitment_proof::CommitmentProof, - encoding::{Decode, DecodeAs, Encode, EthAbi, Proto, Ssz}, - hash::H160, - ibc::{ - core::{ - client::{height::IsHeight, msg_update_client::MsgUpdateClient}, - commitment::merkle_proof::MerkleProof, - }, - lightclients::{ - berachain, - ethereum::{ - account_proof::AccountProof, execution_payload_header::ExecutionPayloadHeader, - }, - }, - }, - ics24::ClientStatePath, - never::Never, - traits::{Chain, HeightOf, IbcStateEncodingOf}, -}; - -use crate::{ - aggregate::{Aggregate, AnyAggregate}, - chain::{ - cosmos::mk_valset, - cosmos_sdk::{ - data::{TrustedCommit, TrustedValidators, UntrustedCommit, UntrustedValidators}, - fetch::{ - FetchTrustedCommit, FetchTrustedValidators, FetchUntrustedCommit, - FetchUntrustedValidators, - }, - }, - ethereum::{ - self, fetch_get_proof, fetch_ibc_state, EthereumConfig, FetchIbcState, GetProof, - TxSubmitError, - }, - }, - data::{AnyData, Data}, - effect::{AnyEffect, Effect, MsgUpdateClientData}, - fetch::{AnyFetch, DoFetch, Fetch, FetchUpdateHeaders}, - id, identified, - use_aggregate::IsAggregateData, - wait::{AnyWait, Wait, WaitForHeight}, - AnyLightClientIdentified, ChainExt, DoAggregate, DoFetchProof, DoFetchState, - DoFetchUpdateHeaders, DoMsg, Identified, PathOf, RelayMessage, -}; - -impl ChainExt for Berachain { - type Data = BerachainData; - type Fetch = BerachainFetch; - type Aggregate = BerachainAggregate; - - type MsgError = TxSubmitError; - - type Config = EthereumConfig; -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum BerachainData { - // Eth (nothing yet) - IbcAccountProof(IbcAccountProof), - - // Cosmos - LatestExecutionPayloadHeaderAbciProof(LatestExecutionPayloadHeaderAbciProof), - TrustedCommit(TrustedCommit), - UntrustedCommit(UntrustedCommit), - TrustedValidators(TrustedValidators), - UntrustedValidators(UntrustedValidators), -} - -#[queue_msg] -pub struct IbcAccountProof<#[cover] Tr: ChainExt> { - pub height: HeightOf, - pub proof: AccountProof, -} - -#[queue_msg] -pub struct LatestExecutionPayloadHeaderAbciProof { - header: ExecutionPayloadHeader, - proof: MerkleProof, -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum BerachainFetch { - // Eth - FetchIbcState(FetchIbcState), - FetchGetProof(GetProof), - FetchIbcAccountProof(FetchIbcAccountProof), - - // Cosmos - FetchLatestExecutionPayloadHeaderAbciProof(FetchLatestExecutionPayloadHeaderAbciProof), - FetchTrustedCommit(FetchTrustedCommit), - FetchUntrustedCommit(FetchUntrustedCommit), - FetchTrustedValidators(FetchTrustedValidators), - FetchUntrustedValidators(FetchUntrustedValidators), -} - -#[queue_msg] -pub struct FetchIbcAccountProof<#[cover] Tr> { - pub ibc_contract_address: H160, - pub height: HeightOf, -} - -#[queue_msg] -pub struct FetchLatestExecutionPayloadHeaderAbciProof<#[cover] Tr: ChainExt> { - pub height: HeightOf, -} - -#[queue_msg] -#[derive(Enumorph)] -pub enum BerachainAggregate { - AggregateHeader(AggregateHeader), -} - -#[queue_msg] -pub struct AggregateHeader { - pub req: FetchUpdateHeaders, -} - -impl UseAggregate for identified!(AggregateHeader) -where - Tr: ChainExt, - - identified!(TrustedCommit): IsAggregateData, - identified!(UntrustedCommit): IsAggregateData, - identified!(TrustedValidators): IsAggregateData, - identified!(UntrustedValidators): IsAggregateData, - Identified: IsAggregateData, - Identified>: IsAggregateData, - - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified>, - Identified, - identified!(TrustedCommit), - identified!(UntrustedCommit), - identified!(TrustedValidators), - identified!(UntrustedValidators), - ]; - - fn aggregate( - Identified { - chain_id, - t: AggregateHeader { req }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: _, - t: IbcAccountProof { - height: _, - proof: ibc_account_proof, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: _, - t: LatestExecutionPayloadHeaderAbciProof { - header: execution_header, - proof: execution_header_proof - }, - __marker: _, - }, - Identified { - chain_id: _trusted_commit_chain_id, - t: TrustedCommit { - height: _trusted_commit_height, - signed_header: trusted_signed_header, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: untrusted_commit_chain_id, - t: UntrustedCommit { - height: _untrusted_commit_height, - signed_header: untrusted_signed_header, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: _trusted_validators_chain_id, - t: TrustedValidators { - height: _trusted_validators_height, - validators: trusted_validators, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: _untrusted_validators_chain_id, - t: UntrustedValidators { - height: _untrusted_validators_height, - validators: untrusted_validators, - __marker: _ - }, - __marker: _, - } - ]: Self::AggregatedData, - ) -> Op { - assert_eq!(chain_id, untrusted_commit_chain_id); - - let trusted_valset = mk_valset( - trusted_validators, - trusted_signed_header.header.proposer_address, - ); - - let untrusted_valset = mk_valset( - untrusted_validators, - untrusted_signed_header.header.proposer_address, - ); - - effect(id::( - req.counterparty_chain_id, - MsgUpdateClientData(MsgUpdateClient { - client_id: req.counterparty_client_id.clone(), - client_message: berachain::header::Header { - cometbft_header: unionlabs::ibc::lightclients::tendermint::header::Header { - signed_header: untrusted_signed_header, - trusted_height: req.update_from, - validator_set: untrusted_valset, - trusted_validators: trusted_valset, - }, - execution_header, - execution_header_proof, - account_proof: ibc_account_proof, - }, - }), - )) - } -} - -impl DoFetch for BerachainFetch -where - Tr: ChainExt< - SelfClientState: Decode> + Encode, - SelfConsensusState: Decode>, - >, - AnyLightClientIdentified: From)>, -{ - type Error = Never; - - async fn do_fetch(c: &Berachain, fetch: Self) -> Result, Self::Error> { - Ok(match fetch { - Self::FetchIbcState(fetch) => data(id(c.chain_id(), fetch_ibc_state(c, fetch).await)), - Self::FetchGetProof(fetch) => data(id(c.chain_id(), fetch_get_proof(c, fetch).await)), - - Self::FetchIbcAccountProof(FetchIbcAccountProof { - ibc_contract_address, - height, - __marker: _, - }) => { - let account_proof = c - .provider - .get_proof( - ethers::types::H160::from(ibc_contract_address), - vec![], - Some(ethers::types::BlockId::Number( - c.execution_height_of_beacon_slot(height.revision_height) - .await - .into(), - )), - ) - .await - .unwrap(); - - data(id( - c.chain_id(), - Data::specific(IbcAccountProof { - height, - proof: AccountProof { - storage_root: account_proof.storage_hash.into(), - proof: account_proof - .account_proof - .into_iter() - .map(|x| x.to_vec()) - .collect(), - }, - __marker: PhantomData, - }), - )) - } - - Self::FetchLatestExecutionPayloadHeaderAbciProof( - FetchLatestExecutionPayloadHeaderAbciProof { height, __marker }, - ) => { - let query_result = c - .beacon_store_abci_query( - [LATEST_EXECUTION_PAYLOAD_HEADER_PREFIX], - height.revision_height, - true, - ) - .await; - - let execution_header = - ExecutionPayloadHeader::::decode_as::( - &query_result.response.value, - ) - .unwrap(); - - let proof = MerkleProof { - proofs: query_result - .response - .proof_ops - .unwrap() - .ops - .into_iter() - .map(|op| CommitmentProof::decode_as::(op.data.as_slice()).unwrap()) - .collect(), - }; - - data(id::( - c.chain_id(), - LatestExecutionPayloadHeaderAbciProof { - header: execution_header, - proof, - }, - )) - } - // TODO: Refactor cosmos & union to use the new cometbft_rpc::Client instead of tendermint_rpc, and then deduplicate these fetchers (they have been inlined from the fns in chain::cosmos_sdk) - Self::FetchTrustedCommit(FetchTrustedCommit { - height, - __marker: _, - }) => { - let commit = c - .tm_client - .commit(Some(height.revision_height().try_into().unwrap())) - .await - .unwrap(); - - data(id::( - c.chain_id(), - Data::specific(TrustedCommit { - height, - // REVIEW: Ensure `commit.canonical`? - signed_header: commit.signed_header, - __marker: PhantomData, - }), - )) - } - Self::FetchUntrustedCommit(FetchUntrustedCommit { - height, - __marker: _, - }) => { - let commit = c - .tm_client - .commit(Some(height.revision_height().try_into().unwrap())) - .await - .unwrap(); - - data(id::( - c.chain_id(), - Data::specific(UntrustedCommit { - height, - // REVIEW: Ensure `commit.canonical`? - signed_header: commit.signed_header, - __marker: PhantomData, - }), - )) - } - Self::FetchTrustedValidators(FetchTrustedValidators { - height, - __marker: _, - }) => { - let validators = c - .tm_client - .all_validators(Some(height.revision_height.try_into().unwrap())) - .await - .unwrap() - .validators; - - data(id::( - c.chain_id(), - Data::specific(TrustedValidators { - height, - validators, - __marker: PhantomData, - }), - )) - } - Self::FetchUntrustedValidators(FetchUntrustedValidators { - height, - __marker: _, - }) => { - let validators = c - .tm_client - .all_validators(Some(height.revision_height.try_into().unwrap())) - .await - .unwrap() - .validators; - - data(id::( - c.chain_id(), - Data::specific(UntrustedValidators { - height, - validators, - __marker: PhantomData, - }), - )) - } - }) - } -} - -impl DoMsg for Berachain -where - Tr: ChainExt< - SelfConsensusState: Encode, - SelfClientState: Encode, - Header: Encode, - StoredClientState: Encode, - StateProof: Encode, - >, - Self::SelfClientState: Encode, - AnyLightClientIdentified: From)>, -{ - async fn msg(&self, msg: Effect) -> Result, Self::MsgError> { - ethereum::do_msg( - self.chain_id(), - self.multicall_address, - &self.keyring, - msg, - false, - None, - ) - .await - } -} - -impl DoFetchState for Berachain -where - Tr: ChainExt> + Encode>, - AnyLightClientIdentified: From)>, -{ - type QueryUnfinalizedTrustedClientStateError = Never; - - fn state(hc: &Self, at: HeightOf, path: PathOf) -> Op { - fetch(id::( - hc.chain_id(), - Fetch::::specific(FetchIbcState { path, height: at }), - )) - } - - async fn query_unfinalized_trusted_client_state( - hc: &Self, - client_id: Self::ClientId, - ) -> Result, Self::QueryUnfinalizedTrustedClientStateError> { - let latest_execution_height = hc.provider.get_block_number().await.unwrap().as_u64(); - - Ok(hc - .ibc_handler() - .ibc_state_read::<_, Self, Tr>(latest_execution_height, ClientStatePath { client_id }) - .await - .unwrap()) - } -} - -impl DoFetchProof for Berachain -where - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - fn proof(hc: &Self, at: HeightOf, path: PathOf) -> Op { - fetch(id::( - hc.chain_id(), - Fetch::specific(GetProof:: { path, height: at }), - )) - } -} - -impl DoFetchUpdateHeaders for Berachain -where - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - fn fetch_update_headers( - c: &Self, - update_info: FetchUpdateHeaders, - ) -> Op { - seq([ - wait(id( - c.chain_id(), - WaitForHeight:: { - height: update_info.update_to, - __marker: PhantomData, - }, - )), - aggregate( - [ - fetch(id::( - c.chain_id(), - Fetch::specific(FetchIbcAccountProof { - ibc_contract_address: c.ibc_handler_address, - height: update_info.update_to, - __marker: PhantomData, - }), - )), - fetch(id::( - c.chain_id(), - Fetch::specific(FetchLatestExecutionPayloadHeaderAbciProof { - height: update_info.update_to, - __marker: PhantomData, - }), - )), - fetch(id::( - c.chain_id(), - Fetch::specific(FetchTrustedCommit { - height: update_info.update_from.increment(), - __marker: PhantomData, - }), - )), - fetch(id::( - c.chain_id(), - Fetch::specific(FetchUntrustedCommit { - height: update_info.update_to, - __marker: PhantomData, - }), - )), - fetch(id::( - c.chain_id(), - Fetch::specific(FetchTrustedValidators { - height: update_info.update_from.increment(), - __marker: PhantomData, - }), - )), - fetch(id::( - c.chain_id(), - Fetch::specific(FetchUntrustedValidators { - height: update_info.update_to, - __marker: PhantomData, - }), - )), - ], - [], - id::( - c.chain_id(), - Aggregate::specific(AggregateHeader { req: update_info }), - ), - ), - ]) - } -} - -impl DoAggregate for Identified> -where - Tr: ChainExt, - - identified!(TrustedCommit): IsAggregateData, - identified!(UntrustedCommit): IsAggregateData, - identified!(TrustedValidators): IsAggregateData, - identified!(UntrustedValidators): IsAggregateData, - Identified: IsAggregateData, - Identified>: IsAggregateData, - - Identified>: UseAggregate, - - AnyLightClientIdentified: From)>, -{ - fn do_aggregate( - Identified { - chain_id, - t: data, - __marker: _, - }: Self, - aggregate_data: VecDeque>, - ) -> Op { - match data { - BerachainAggregate::AggregateHeader(data) => { - do_aggregate(id(chain_id, data), aggregate_data) - } - } - } -} - -try_from_relayer_msg! { - chain = Berachain, - generics = (Tr: ChainExt), - msgs = BerachainData( - IbcAccountProof(IbcAccountProof), - LatestExecutionPayloadHeaderAbciProof(LatestExecutionPayloadHeaderAbciProof), - TrustedCommit(TrustedCommit), - UntrustedCommit(UntrustedCommit), - TrustedValidators(TrustedValidators), - UntrustedValidators(UntrustedValidators), - ), -} diff --git a/lib/relay-message/src/chain/cosmos.rs b/lib/relay-message/src/chain/cosmos.rs deleted file mode 100644 index 44735d7696..0000000000 --- a/lib/relay-message/src/chain/cosmos.rs +++ /dev/null @@ -1,398 +0,0 @@ -use std::{collections::VecDeque, fmt::Debug, marker::PhantomData}; - -use chain_utils::{cosmos::Cosmos, cosmos_sdk::BroadcastTxCommitError, wasm::Wraps}; -use frame_support_procedural::{CloneNoBound, PartialEqNoBound}; -use frunk::{hlist_pat, HList}; -use futures::Future; -use queue_msg::{ - aggregate, - aggregation::{do_aggregate, UseAggregate}, - effect, fetch, queue_msg, wait, Op, -}; -use unionlabs::{ - encoding::{Decode, Encode, Proto}, - google::protobuf::any::IntoAny, - hash::H160, - ibc::{ - core::{ - client::{height::IsHeight, msg_update_client::MsgUpdateClient}, - commitment::merkle_proof::MerkleProof, - }, - lightclients::tendermint, - }, - ics24::ClientStatePath, - tendermint::types::validator::Validator, - traits::Chain, - TypeUrl, -}; - -use crate::{ - aggregate::{Aggregate, AnyAggregate}, - chain::cosmos_sdk::{ - data::{TrustedCommit, TrustedValidators, UntrustedCommit, UntrustedValidators}, - do_msg, - fetch::{ - fetch_trusted_commit, fetch_trusted_validators, fetch_untrusted_commit, - fetch_untrusted_validators, FetchAbciQuery, FetchTrustedCommit, FetchTrustedValidators, - FetchUntrustedCommit, FetchUntrustedValidators, - }, - fetch_abci_query, CosmosSdkChainSealed, FetchAbciQueryError, - }, - data::{AnyData, Data, IbcState}, - effect::{AnyEffect, Effect, MsgUpdateClientData}, - fetch::{AnyFetch, DoFetch, Fetch, FetchUpdateHeaders}, - id, identified, seq, - use_aggregate::IsAggregateData, - wait::{AnyWait, Wait, WaitForHeight}, - AnyLightClientIdentified, ChainExt, DoAggregate, DoFetchUpdateHeaders, DoMsg, Identified, - RelayMessage, -}; - -impl ChainExt for Cosmos { - type Data = CosmosDataMsg; - type Fetch = CosmosFetch; - type Aggregate = CosmosAggregateMsg; - - type MsgError = BroadcastTxCommitError; - - type Config = (); -} - -impl CosmosSdkChainSealed for Cosmos {} - -impl DoMsg for Cosmos -where - Tr: ChainExt< - SelfConsensusState: Encode + TypeUrl, - SelfClientState: Encode + TypeUrl, - Header: Encode + TypeUrl, - StoredClientState: IntoAny, - StateProof: Encode, - >, - AnyLightClientIdentified: From)>, -{ - fn msg( - &self, - msg: Effect, - ) -> impl Future, BroadcastTxCommitError>> + Send + '_ { - do_msg( - self, - msg, - |(), client_state, consensus_state| { - ( - client_state.into_any().into(), - consensus_state.into_any().into(), - ) - }, - |client_message| client_message.into_any().into(), - ) - } -} - -impl DoFetchUpdateHeaders for Cosmos -where - Tr: ChainExt, - Hc: Wraps - + ChainExt = CosmosFetch, Aggregate = CosmosAggregateMsg>, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - fn fetch_update_headers(hc: &Hc, update_info: FetchUpdateHeaders) -> Op { - seq([ - wait(id( - hc.chain_id(), - WaitForHeight { - height: update_info.update_to, - __marker: PhantomData, - }, - )), - aggregate( - [ - fetch(id::( - hc.chain_id(), - Fetch::specific(FetchTrustedCommit { - height: update_info.update_from.increment(), - __marker: PhantomData, - }), - )), - fetch(id::( - hc.chain_id(), - Fetch::specific(FetchUntrustedCommit { - height: update_info.update_to, - __marker: PhantomData, - }), - )), - fetch(id::( - hc.chain_id(), - Fetch::specific(FetchTrustedValidators { - height: update_info.update_from.increment(), - __marker: PhantomData, - }), - )), - fetch(id::( - hc.chain_id(), - Fetch::specific(FetchUntrustedValidators { - height: update_info.update_to, - __marker: PhantomData, - }), - )), - ], - [], - id( - hc.chain_id(), - Aggregate::specific(AggregateHeader { req: update_info }), - ), - ), - ]) - } -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum CosmosDataMsg { - TrustedCommit(TrustedCommit), - UntrustedCommit(UntrustedCommit), - TrustedValidators(TrustedValidators), - UntrustedValidators(UntrustedValidators), -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum CosmosFetch { - FetchTrustedCommit(FetchTrustedCommit), - FetchUntrustedCommit(FetchUntrustedCommit), - FetchTrustedValidators(FetchTrustedValidators), - FetchUntrustedValidators(FetchUntrustedValidators), - AbciQuery(FetchAbciQuery), -} - -impl DoFetch for CosmosFetch -where - Hc: CosmosSdkChainSealed< - StateProof = MerkleProof, - Data = CosmosDataMsg, - Fetch = CosmosFetch, - StoredClientState: Decode, - StoredConsensusState: Decode< - Proto, - Error: Debug + Clone + PartialEq + std::error::Error, - >, - >, - Tr: ChainExt, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - - Identified, Hc, Tr>>: IsAggregateData, -{ - type Error = CosmosDoFetchError; - - async fn do_fetch(hc: &Hc, msg: Self) -> Result, Self::Error> { - Ok(match msg { - Self::FetchTrustedCommit(FetchTrustedCommit { - height, - __marker: _, - }) => fetch_trusted_commit(hc, height).await, - Self::FetchUntrustedCommit(FetchUntrustedCommit { - height, - __marker: _, - }) => fetch_untrusted_commit(hc, height).await, - Self::FetchTrustedValidators(FetchTrustedValidators { - height, - __marker: _, - }) => fetch_trusted_validators(hc, height).await, - Self::FetchUntrustedValidators(FetchUntrustedValidators { - height, - __marker: _, - }) => fetch_untrusted_validators(hc, height).await, - Self::AbciQuery(FetchAbciQuery { path, height, ty }) => { - fetch_abci_query::(hc, path, height, ty).await? - } - }) - } -} - -#[derive(macros::Debug, PartialEqNoBound, CloneNoBound, thiserror::Error)] -pub enum CosmosDoFetchError -where - Hc: Chain< - StateProof: TryFrom, - StoredClientState: Decode, - StoredConsensusState: Decode< - Proto, - Error: Debug + Clone + PartialEq + std::error::Error, - >, - >, - Tr: Chain, -{ - #[error("error fetching abci query")] - FetchAbciQuery(#[from] FetchAbciQueryError), -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum CosmosAggregateMsg { - AggregateHeader(AggregateHeader), -} - -impl DoAggregate for Identified> -where - Tr: ChainExt, - Hc: ChainExt, - - identified!(TrustedCommit): IsAggregateData, - identified!(UntrustedCommit): IsAggregateData, - identified!(TrustedValidators): IsAggregateData, - identified!(UntrustedValidators): IsAggregateData, - - Identified>: UseAggregate, - - AnyLightClientIdentified: From)>, -{ - fn do_aggregate( - Identified { - chain_id, - t: data, - __marker: _, - }: Self, - aggregate_data: VecDeque>, - ) -> Op { - match data { - CosmosAggregateMsg::AggregateHeader(data) => { - do_aggregate(id(chain_id, data), aggregate_data) - } - } - } -} - -try_from_relayer_msg! { - chain = Cosmos, - generics = (Tr: ChainExt), - msgs = CosmosDataMsg( - TrustedCommit(TrustedCommit), - UntrustedCommit(UntrustedCommit), - TrustedValidators(TrustedValidators), - UntrustedValidators(UntrustedValidators), - ), -} - -#[queue_msg] -pub struct AggregateHeader { - pub req: FetchUpdateHeaders, -} - -impl UseAggregate for Identified> -where - Hc: ChainExt

::Header>, - Tr: ChainExt, - - identified!(TrustedCommit): IsAggregateData, - identified!(UntrustedCommit): IsAggregateData, - identified!(TrustedValidators): IsAggregateData, - identified!(UntrustedValidators): IsAggregateData, - - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - identified!(TrustedCommit), - identified!(UntrustedCommit), - identified!(TrustedValidators), - identified!(UntrustedValidators), - ]; - - fn aggregate( - Identified { - chain_id, - t: AggregateHeader { req }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: _trusted_commit_chain_id, - t: TrustedCommit { - height: _trusted_commit_height, - signed_header: trusted_signed_header, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: untrusted_commit_chain_id, - t: UntrustedCommit { - height: _untrusted_commit_height, - signed_header: untrusted_signed_header, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: _trusted_validators_chain_id, - t: TrustedValidators { - height: _trusted_validators_height, - validators: trusted_validators, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: _untrusted_validators_chain_id, - t: UntrustedValidators { - height: _untrusted_validators_height, - validators: untrusted_validators, - __marker: _ - }, - __marker: _, - } - ]: Self::AggregatedData, - ) -> Op { - assert_eq!(chain_id, untrusted_commit_chain_id); - - let trusted_valset = mk_valset( - trusted_validators, - trusted_signed_header.header.proposer_address, - ); - - let untrusted_valset = mk_valset( - untrusted_validators, - untrusted_signed_header.header.proposer_address, - ); - - effect(id::( - req.counterparty_chain_id, - MsgUpdateClientData(MsgUpdateClient { - client_id: req.counterparty_client_id.clone(), - client_message: tendermint::header::Header { - signed_header: untrusted_signed_header, - trusted_height: req.update_from.into(), - validator_set: untrusted_valset, - trusted_validators: trusted_valset, - }, - }), - )) - } -} - -pub(crate) fn mk_valset( - validators: Vec, - proposer_address: H160, -) -> unionlabs::tendermint::types::validator_set::ValidatorSet { - let proposer = validators - .iter() - .find(|val| val.address == proposer_address) - .unwrap() - .clone(); - - let total_voting_power = validators - .iter() - .map(|v| v.voting_power.inner()) - .sum::(); - - unionlabs::tendermint::types::validator_set::ValidatorSet { - validators, - proposer, - total_voting_power, - } -} diff --git a/lib/relay-message/src/chain/cosmos_sdk.rs b/lib/relay-message/src/chain/cosmos_sdk.rs deleted file mode 100644 index 3f42b7af8c..0000000000 --- a/lib/relay-message/src/chain/cosmos_sdk.rs +++ /dev/null @@ -1,1408 +0,0 @@ -use std::{fmt::Debug, marker::PhantomData}; - -use chain_utils::{ - cosmos_sdk::{ - cosmos_sdk_error::{ChannelError, CosmosSdkError, SdkError}, - BroadcastTxCommitError, CosmosSdkChain, CosmosSdkChainExt, CosmosSdkChainIbcExt, - }, - keyring::ChainKeyring, -}; -use frame_support_procedural::{CloneNoBound, PartialEqNoBound}; -use futures::{stream, Future, FutureExt, StreamExt}; -use queue_msg::{data, effect, fetch, noop, seq, wait, Op}; -use tracing::{debug, error, info, info_span, warn}; -use unionlabs::{ - encoding::{Decode, DecodeAs, DecodeErrorOf, Encode, Proto}, - google::protobuf::any::{mk_any, IntoAny}, - ibc::core::client::height::IsHeight, - ics24::{ClientStatePath, Path}, - signer::CosmosSigner, - traits::{Chain, ClientStateOf, ConsensusStateOf, HeightOf}, - ErrorReporter, TypeUrl, -}; - -use crate::{ - chain::cosmos_sdk::fetch::{AbciQueryType, FetchAbciQuery}, - data::{AnyData, Data, IbcProof, IbcState}, - effect::{ - log_msg, AnyEffect, BatchMsg, Effect, MsgAckPacketData, MsgChannelOpenAckData, - MsgChannelOpenConfirmData, MsgChannelOpenInitData, MsgChannelOpenTryData, - MsgConnectionOpenAckData, MsgConnectionOpenConfirmData, MsgConnectionOpenInitData, - MsgConnectionOpenTryData, MsgCreateClientData, MsgRecvPacketData, MsgTimeoutData, - MsgUpdateClientData, - }, - fetch::{AnyFetch, Fetch}, - id, identified, - use_aggregate::IsAggregateData, - wait::{AnyWait, Wait, WaitForHeight}, - AnyLightClientIdentified, ChainExt, DoFetchProof, DoFetchState, Identified, PathOf, - RelayMessage, -}; - -pub trait CosmosSdkChainSealed: CosmosSdkChain + CosmosSdkChainIbcExt + ChainExt {} - -#[allow(clippy::manual_async_fn)] -pub fn do_msg( - hc: &Hc, - msg: Effect, - // We need to be able to customize the encoding of the client/consensus states and client messages (header) since Wasm<_> needs to wrap them in wasm.v1.*; but since the rest of the logic is exactly the same, the following two functions are used as hooks to allow for the behaviour to be otherwise reused. - mk_create_client_states: fn( - Hc::Config, - ClientStateOf, - ConsensusStateOf, - ) - -> (protos::google::protobuf::Any, protos::google::protobuf::Any), - mk_client_message: fn(Tr::Header) -> protos::google::protobuf::Any, -) -> impl Future, BroadcastTxCommitError>> + Send + '_ -where - Hc: ChainKeyring - + CosmosSdkChainSealed< - MsgError = BroadcastTxCommitError, - SelfConsensusState: Encode + TypeUrl, - SelfClientState: Encode + TypeUrl, - >, - Tr: ChainExt< - SelfConsensusState: Encode + TypeUrl, - SelfClientState: Encode + TypeUrl, - Header: Encode + TypeUrl, - StoredClientState: IntoAny, - StateProof: Encode, - >, - AnyLightClientIdentified: From)>, -{ - async move { - let res = hc - .keyring() - .with(|signer| { - let msg = msg.clone(); - - async move { - // TODO: Figure out a way to thread this value through - let memo = format!("Voyager {}", env!("CARGO_PKG_VERSION")); - - let mut msgs = - process_msgs(msg, signer, mk_create_client_states, mk_client_message); - - let simulation_results = stream::iter(msgs.clone().into_iter().enumerate()) - .then(move |(idx, (effect, msg))| async move { - let type_url = msg.type_url.clone(); - - hc.simulate_tx( - signer, - [msg], - format!("Voyager {}", env!("CARGO_PKG_VERSION")) - ) - .map(move |res| (idx, type_url, effect, res)) - .await - }) - .collect::)>>() - .await; - - // iterate backwards such that when we remove items from msgs, we don't shift the relative indices - for (idx, type_url, msg, simulation_result) in simulation_results.into_iter().rev() { - let _span = info_span!( - "simulation result", - msg = type_url, - idx, - ) - .entered(); - - match simulation_result { - Ok((_, _, gas_info)) => { - info!( - gas_wanted = %gas_info.gas_wanted, - gas_used = %gas_info.gas_used, - "individual message simulation successful", - ); - - log_msg(msg); - } - Err(error) => { - if error.message().contains("account sequence mismatch") { - warn!("account sequence mismatch on individual message simulation, treating this message as successful"); - log_msg(msg); - } else { - error!( - %error, - "individual message simulation failed" - ); - - log_msg(msg); - - msgs.remove(idx); - } - } - } - } - - if msgs.is_empty() { - info!( - "no messages remaining to submit after filtering out failed transactions" - ); - return Ok(()); - } - - let batch_size = msgs.len(); - let msg_names = msgs.iter().map(move |x| x.1.type_url.clone()).collect::>(); - - match hc.broadcast_tx_commit( - signer, - msgs.iter().map(move |x| x.1.clone()).collect::>(), - memo - ).await { - Ok((tx_hash, gas_used)) => { - info!( - %tx_hash, - %gas_used, - batch.size = %batch_size, - "submitted cosmos transaction" - ); - - for msg in msg_names { - info!(%tx_hash, %msg, "cosmos tx"); - } - - Ok(()) - } - Err(err) => match err { - BroadcastTxCommitError::Tx(CosmosSdkError::ChannelError( - ChannelError::ErrRedundantTx, - )) => { - info!("packet messages are redundant"); - Ok(()) - } - BroadcastTxCommitError::Tx(CosmosSdkError::SdkError( - SdkError::ErrOutOfGas - )) => { - error!("out of gas"); - Err(BroadcastTxCommitError::OutOfGas) - } - BroadcastTxCommitError::Tx(CosmosSdkError::SdkError( - SdkError::ErrWrongSequence - )) => { - warn!("account sequence mismatch on tx submission, message will be requeued and retried"); - Err(BroadcastTxCommitError::AccountSequenceMismatch(None)) - } - BroadcastTxCommitError::SimulateTx(err) if err.message().contains("account sequence mismatch") => { - warn!("account sequence mismatch on simulation, message will be requeued and retried"); - Err(BroadcastTxCommitError::AccountSequenceMismatch(Some(err))) - } - err => Err(err), - }, - } - } - }) - .await; - - match res { - Some(Err(BroadcastTxCommitError::AccountSequenceMismatch(_))) => { - Ok(effect(id(hc.chain_id(), msg))) - } - Some(Err(BroadcastTxCommitError::OutOfGas)) => Ok(effect(id(hc.chain_id(), msg))), - Some(Err(BroadcastTxCommitError::SimulateTx(err))) => { - error!( - error = %ErrorReporter(err), - "transaction simulation failed, message will be requeued and retried" - ); - - Ok(effect(id(hc.chain_id(), msg))) - } - Some(Err(BroadcastTxCommitError::QueryLatestHeight(err))) => { - error!(error = %ErrorReporter(err), "error querying latest height"); - - Ok(effect(id(hc.chain_id(), msg))) - } - Some(res) => res.map(|()| noop()), - // None => Ok(seq([defer_relative(1), effect(id(hc.chain_id(), msg))])), - None => Ok(effect(id(hc.chain_id(), msg))), - } - } -} - -fn process_msgs( - effect: Effect, - signer: &CosmosSigner, - mk_create_client_states: fn( - Hc::Config, - ClientStateOf, - ConsensusStateOf, - ) - -> (protos::google::protobuf::Any, protos::google::protobuf::Any), - mk_client_message: fn(Tr::Header) -> protos::google::protobuf::Any, -) -> Vec<(Effect, protos::google::protobuf::Any)> -where - Hc: CosmosSdkChainSealed< - MsgError = BroadcastTxCommitError, - SelfConsensusState: Encode + TypeUrl, - SelfClientState: Encode + TypeUrl, - >, - Tr: ChainExt< - SelfConsensusState: Encode + TypeUrl, - SelfClientState: Encode + TypeUrl, - Header: Encode + TypeUrl, - StoredClientState: IntoAny, - StateProof: Encode, - >, -{ - match effect.clone() { - Effect::ConnectionOpenInit(MsgConnectionOpenInitData(data)) => { - vec![( - effect, - mk_any(&protos::ibc::core::connection::v1::MsgConnectionOpenInit { - client_id: data.client_id.to_string(), - counterparty: Some(data.counterparty.into()), - version: Some(data.version.into()), - signer: signer.to_string(), - delay_period: data.delay_period, - }), - )] - } - Effect::ConnectionOpenTry(MsgConnectionOpenTryData(data)) => { - vec![( - effect, - mk_any(&protos::ibc::core::connection::v1::MsgConnectionOpenTry { - client_id: data.client_id.to_string(), - client_state: Some(data.client_state.into_any().into()), - counterparty: Some(data.counterparty.into()), - delay_period: data.delay_period, - counterparty_versions: data - .counterparty_versions - .into_iter() - .map(Into::into) - .collect(), - proof_height: Some(data.proof_height.into_height().into()), - proof_init: data.proof_init.encode(), - proof_client: data.proof_client.encode(), - proof_consensus: data.proof_consensus.encode(), - consensus_height: Some(data.consensus_height.into_height().into()), - signer: signer.to_string(), - host_consensus_state_proof: vec![], - ..Default::default() - }), - )] - } - Effect::ConnectionOpenAck(MsgConnectionOpenAckData(data)) => { - vec![( - effect, - mk_any(&protos::ibc::core::connection::v1::MsgConnectionOpenAck { - client_state: Some(data.client_state.into_any().into()), - proof_height: Some(data.proof_height.into_height().into()), - proof_client: data.proof_client.encode(), - proof_consensus: data.proof_consensus.encode(), - consensus_height: Some(data.consensus_height.into_height().into()), - signer: signer.to_string(), - host_consensus_state_proof: vec![], - connection_id: data.connection_id.to_string(), - counterparty_connection_id: data.counterparty_connection_id.to_string(), - version: Some(data.version.into()), - proof_try: data.proof_try.encode(), - }), - )] - } - Effect::ConnectionOpenConfirm(MsgConnectionOpenConfirmData { msg, __marker }) => { - vec![( - effect, - mk_any( - &protos::ibc::core::connection::v1::MsgConnectionOpenConfirm { - connection_id: msg.connection_id.to_string(), - proof_ack: msg.proof_ack.encode(), - proof_height: Some(msg.proof_height.into_height().into()), - signer: signer.to_string(), - }, - ), - )] - } - Effect::ChannelOpenInit(MsgChannelOpenInitData { msg, __marker }) => { - vec![( - effect, - mk_any(&protos::ibc::core::channel::v1::MsgChannelOpenInit { - port_id: msg.port_id.to_string(), - channel: Some(msg.channel.into()), - signer: signer.to_string(), - }), - )] - } - Effect::ChannelOpenTry(MsgChannelOpenTryData { msg, __marker }) => { - vec![( - effect, - mk_any(&protos::ibc::core::channel::v1::MsgChannelOpenTry { - port_id: msg.port_id.to_string(), - channel: Some(msg.channel.into()), - counterparty_version: msg.counterparty_version, - proof_init: msg.proof_init.encode(), - proof_height: Some(msg.proof_height.into()), - signer: signer.to_string(), - ..Default::default() - }), - )] - } - Effect::ChannelOpenAck(MsgChannelOpenAckData { msg, __marker }) => { - vec![( - effect, - mk_any(&protos::ibc::core::channel::v1::MsgChannelOpenAck { - port_id: msg.port_id.to_string(), - channel_id: msg.channel_id.to_string(), - counterparty_version: msg.counterparty_version, - counterparty_channel_id: msg.counterparty_channel_id.to_string(), - proof_try: msg.proof_try.encode(), - proof_height: Some(msg.proof_height.into_height().into()), - signer: signer.to_string(), - }), - )] - } - Effect::ChannelOpenConfirm(MsgChannelOpenConfirmData { msg, __marker }) => { - vec![( - effect, - mk_any(&protos::ibc::core::channel::v1::MsgChannelOpenConfirm { - port_id: msg.port_id.to_string(), - channel_id: msg.channel_id.to_string(), - proof_height: Some(msg.proof_height.into_height().into()), - signer: signer.to_string(), - proof_ack: msg.proof_ack.encode(), - }), - )] - } - Effect::RecvPacket(MsgRecvPacketData { msg, __marker }) => { - vec![( - effect, - mk_any(&protos::ibc::core::channel::v1::MsgRecvPacket { - packet: Some(msg.packet.into()), - proof_height: Some(msg.proof_height.into_height().into()), - signer: signer.to_string(), - proof_commitment: msg.proof_commitment.encode(), - }), - )] - } - Effect::AckPacket(MsgAckPacketData { msg, __marker }) => { - vec![( - effect, - mk_any(&protos::ibc::core::channel::v1::MsgAcknowledgement { - packet: Some(msg.packet.into()), - acknowledgement: msg.acknowledgement, - proof_acked: msg.proof_acked.encode(), - proof_height: Some(msg.proof_height.into_height().into()), - signer: signer.to_string(), - }), - )] - } - Effect::TimeoutPacket(MsgTimeoutData { msg, __marker }) => { - vec![( - effect, - mk_any(&protos::ibc::core::channel::v1::MsgTimeout { - packet: Some(msg.packet.into()), - proof_unreceived: msg.proof_unreceived.encode(), - proof_height: Some(msg.proof_height.into_height().into()), - next_sequence_recv: msg.next_sequence_recv.get(), - signer: signer.to_string(), - }), - )] - } - Effect::CreateClient(MsgCreateClientData { msg, config }) => { - let (client_state, consensus_state) = - mk_create_client_states(config, msg.client_state, msg.consensus_state); - - vec![( - effect, - mk_any(&protos::ibc::core::client::v1::MsgCreateClient { - client_state: Some(client_state), - consensus_state: Some(consensus_state), - signer: signer.to_string(), - }), - )] - } - Effect::UpdateClient(MsgUpdateClientData(msg)) => { - vec![( - effect, - mk_any(&protos::ibc::core::client::v1::MsgUpdateClient { - signer: signer.to_string(), - client_id: msg.client_id.to_string(), - client_message: Some(mk_client_message(msg.client_message)), - }), - )] - } - Effect::Batch(BatchMsg(msgs)) => msgs - .into_iter() - .flat_map(|msg| process_msgs(msg, signer, mk_create_client_states, mk_client_message)) - .collect(), - } -} - -impl DoFetchState for Hc -where - Hc: CosmosSdkChainSealed - + ChainExt< - StateProof: TryFrom, - StoredClientState: Decode< - Proto, - Error: Debug + Clone + PartialEq + std::error::Error, - >, - StoredConsensusState: Decode< - Proto, - Error: Debug + Clone + PartialEq + std::error::Error, - >, - Fetch: From>, - >, - - Tr: ChainExt, SelfConsensusState: Decode>, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - // required by fetch_abci_query, can be removed once that's been been removed - AnyLightClientIdentified: From)>, - - Identified, Hc, Tr>>: IsAggregateData, -{ - type QueryUnfinalizedTrustedClientStateError = FetchAbciQueryError; - - fn state(hc: &Hc, at: HeightOf, path: PathOf) -> Op { - seq([ - wait(id( - hc.chain_id(), - WaitForHeight { - // height: at.increment(), - height: at, - __marker: PhantomData, - }, - )), - fetch(id::( - hc.chain_id(), - Fetch::specific(FetchAbciQuery { - path, - height: at, - ty: AbciQueryType::State, - }), - )), - ]) - } - - async fn query_unfinalized_trusted_client_state( - hc: &Hc, - client_id: Hc::ClientId, - ) -> Result, Self::QueryUnfinalizedTrustedClientStateError> { - let height = hc.query_latest_height().await.unwrap(); - - let Op::Data(relayer_msg) = fetch_abci_query::( - hc, - ClientStatePath { client_id }.into(), - height, - AbciQueryType::State, - ) - .await? - else { - panic!() - }; - - Ok( - Identified::, Hc, Tr>>::try_from( - relayer_msg, - ) - .unwrap() - .t - .state, - ) - } -} - -impl DoFetchProof for Hc -where - Hc: ChainExt: From>> + CosmosSdkChainSealed, - Tr: ChainExt, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - fn proof(hc: &Hc, at: HeightOf, path: PathOf) -> Op { - seq([ - wait(id( - hc.chain_id(), - WaitForHeight { - height: at, - __marker: PhantomData, - }, - )), - fetch(id::( - hc.chain_id(), - Fetch::specific(FetchAbciQuery:: { - path, - height: at, - ty: AbciQueryType::Proof, - }), - )), - ]) - } -} - -pub async fn fetch_abci_query( - c: &Hc, - path: Path, - height: HeightOf, - ty: AbciQueryType, -) -> Result, FetchAbciQueryError> -where - Hc: CosmosSdkChainSealed< - StateProof: TryFrom, - StoredClientState: Decode, - StoredConsensusState: Decode< - Proto, - Error: Debug + Clone + PartialEq + std::error::Error, - >, - >, - Tr: ChainExt, - AnyLightClientIdentified: From)>, - Identified, Hc, Tr>>: IsAggregateData, -{ - const IBC_STORE_PATH: &str = "store/ibc/key"; - - let path_string = path.to_string(); - - debug!( - grpc_url = %c.grpc_url(), - path = %IBC_STORE_PATH, - data = %path_string, - %height, - "fetching abci query" - ); - - let mut client = - protos::cosmos::base::tendermint::v1beta1::service_client::ServiceClient::connect( - c.grpc_url().clone(), - ) - .await - .unwrap(); - - let query_result = client - .abci_query( - protos::cosmos::base::tendermint::v1beta1::AbciQueryRequest { - data: path_string.into_bytes(), - path: IBC_STORE_PATH.to_string(), - height: i64::try_from(height.revision_height()).unwrap() - 1_i64, - prove: matches!(ty, AbciQueryType::Proof), - }, - ) - .await - .unwrap() - .into_inner(); - - debug!( - code = %query_result.code, - log = %query_result.log, - info = %query_result.info, - index = %query_result.index, - key = %::serde_utils::to_hex(&query_result.key), - value = %::serde_utils::to_hex(&query_result.value), - // proof_ops = %query_result.proof_ops, - height = %query_result.height, - codespace = %query_result.codespace, - "fetched abci query" - ); - - Ok(match ty { - AbciQueryType::State => match path { - Path::ClientState(path) => data(id::( - c.chain_id(), - IbcState::, Hc, Tr> { - height, - state: Hc::StoredClientState::::decode_as::(&query_result.value) - .map_err(FetchAbciQueryError::ClientStateDecode)?, - path, - }, - )), - Path::ClientConsensusState(path) => data(id::( - c.chain_id(), - IbcState { - height, - state: Hc::StoredConsensusState::::decode(&query_result.value) - .map_err(FetchAbciQueryError::ConsensusStateDecode)?, - - path, - }, - )), - Path::Connection(path) => data(id::( - c.chain_id(), - IbcState { - height, - state: Decode::::decode(&query_result.value) - .unwrap(), - path, - }, - )), - Path::ChannelEnd(path) => data(id::( - c.chain_id(), - IbcState { - height, - state: Decode::::decode(&query_result.value) - .unwrap(), - path, - }, - )), - Path::Commitment(path) => data(id::( - c.chain_id(), - IbcState { - height, - state: query_result.value.try_into().unwrap(), - path, - }, - )), - Path::Acknowledgement(path) => data(id::( - c.chain_id(), - IbcState { - height, - state: query_result.value.try_into().unwrap(), - path, - }, - )), - Path::Receipt(path) => data(id::( - c.chain_id(), - IbcState { - height, - state: match query_result.value[..] { - [] => false, - [1] => true, - ref invalid => panic!("not a bool??? {invalid:?}"), - }, - path, - }, - )), - Path::NextSequenceSend(path) => data(id::( - c.chain_id(), - IbcState { - height, - state: u64::from_be_bytes(query_result.value.try_into().unwrap()), - path, - }, - )), - Path::NextSequenceRecv(path) => data(id::( - c.chain_id(), - IbcState { - height, - state: u64::from_be_bytes(query_result.value.try_into().unwrap()), - path, - }, - )), - Path::NextSequenceAck(path) => data(id::( - c.chain_id(), - IbcState { - height, - state: u64::from_be_bytes(query_result.value.try_into().unwrap()), - path, - }, - )), - Path::NextConnectionSequence(path) => data(id::( - c.chain_id(), - IbcState { - height, - state: u64::from_be_bytes(query_result.value.try_into().unwrap()), - path, - }, - )), - Path::NextClientSequence(path) => data(id::( - c.chain_id(), - IbcState { - height, - state: u64::from_be_bytes(query_result.value.try_into().unwrap()), - path, - }, - )), - }, - AbciQueryType::Proof => { - let proof = Hc::StateProof::try_from(protos::ibc::core::commitment::v1::MerkleProof { - proofs: query_result - .proof_ops - .unwrap() - .ops - .into_iter() - .map(|op| { - ::decode( - op.data.as_slice(), - ) - .unwrap() - }) - .collect::>(), - }) - .unwrap(); - - match path { - Path::ClientState(path) => data(id::( - c.chain_id(), - IbcProof::<_, Hc, Tr> { - proof, - height, - path, - __marker: PhantomData, - }, - )), - Path::ClientConsensusState(path) => data(id::( - c.chain_id(), - IbcProof::<_, Hc, Tr> { - proof, - height, - path, - __marker: PhantomData, - }, - )), - Path::Connection(path) => data(id::( - c.chain_id(), - IbcProof::<_, Hc, Tr> { - proof, - height, - path, - __marker: PhantomData, - }, - )), - Path::ChannelEnd(path) => data(id::( - c.chain_id(), - IbcProof::<_, Hc, Tr> { - proof, - height, - path, - __marker: PhantomData, - }, - )), - Path::Commitment(path) => data(id::( - c.chain_id(), - IbcProof::<_, Hc, Tr> { - proof, - height, - path, - __marker: PhantomData, - }, - )), - Path::Acknowledgement(path) => data(id::( - c.chain_id(), - IbcProof::<_, Hc, Tr> { - proof, - height, - path, - __marker: PhantomData, - }, - )), - Path::Receipt(path) => data(id::( - c.chain_id(), - IbcProof { - proof, - height, - path, - __marker: PhantomData, - }, - )), - Path::NextSequenceSend(path) => data(id::( - c.chain_id(), - IbcProof { - proof, - height, - path, - __marker: PhantomData, - }, - )), - Path::NextSequenceRecv(path) => data(id::( - c.chain_id(), - IbcProof { - proof, - height, - path, - __marker: PhantomData, - }, - )), - Path::NextSequenceAck(path) => data(id::( - c.chain_id(), - IbcProof { - proof, - height, - path, - __marker: PhantomData, - }, - )), - Path::NextConnectionSequence(path) => data(id::( - c.chain_id(), - IbcProof { - proof, - height, - path, - __marker: PhantomData, - }, - )), - Path::NextClientSequence(path) => data(id::( - c.chain_id(), - IbcProof { - proof, - height, - path, - __marker: PhantomData, - }, - )), - } - } - }) -} - -#[derive(macros::Debug, PartialEqNoBound, CloneNoBound, thiserror::Error)] -pub enum FetchAbciQueryError -where - Hc: Chain< - StateProof: TryFrom, - StoredClientState: Decode, - StoredConsensusState: Decode< - Proto, - Error: Debug + Clone + PartialEq + std::error::Error, - >, - >, - Tr: Chain, -{ - #[error("unable to decode client state")] - ClientStateDecode(#[source] DecodeErrorOf>), - #[error("unable to decode consensus state")] - ConsensusStateDecode(#[source] DecodeErrorOf>), -} - -pub mod fetch { - use std::marker::PhantomData; - - use chain_utils::cosmos_sdk::CosmosSdkChainRpcs; - use frame_support_procedural::{CloneNoBound, DebugNoBound, PartialEqNoBound}; - use queue_msg::{data, queue_msg, Op}; - use serde::{Deserialize, Serialize}; - use tendermint_rpc::Client; - use unionlabs::{ibc::core::client::height::IsHeight, traits::HeightOf}; - - use crate::{ - chain::cosmos_sdk::{ - data::{TrustedCommit, TrustedValidators, UntrustedCommit, UntrustedValidators}, - tendermint_helpers::{ - tendermint_commit_to_signed_header, tendermint_validator_info_to_validator, - }, - }, - data::{AnyData, Data}, - id, identified, AnyLightClientIdentified, ChainExt, PathOf, RelayMessage, - }; - - #[queue_msg] - pub struct FetchAbciQuery { - pub path: PathOf, - pub height: HeightOf, - pub ty: AbciQueryType, - } - - #[derive(DebugNoBound, CloneNoBound, PartialEqNoBound, Serialize, Deserialize)] - #[serde( - bound(serialize = "", deserialize = ""), - deny_unknown_fields, - rename_all = "snake_case" - )] - #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] - pub enum AbciQueryType { - State, - Proof, - } - - #[queue_msg] - pub struct FetchTrustedCommit { - pub height: Hc::Height, - } - - #[queue_msg] - pub struct FetchUntrustedCommit { - pub height: Hc::Height, - } - - #[queue_msg] - pub struct FetchTrustedValidators { - pub height: Hc::Height, - } - - #[queue_msg] - pub struct FetchUntrustedValidators { - pub height: Hc::Height, - } - - pub async fn fetch_trusted_commit(hc: &Hc, height: Hc::Height) -> Op - where - Hc: CosmosSdkChainRpcs + ChainExt: From>>, - Tr: ChainExt, - AnyLightClientIdentified: From)>, - { - let commit = hc - .tm_client() - .commit( - TryInto::<::tendermint::block::Height>::try_into(height.revision_height()).unwrap(), - ) - .await - .unwrap(); - - let signed_header = tendermint_commit_to_signed_header(commit); - - data(id::( - hc.chain_id(), - Data::specific(TrustedCommit { - height, - // REVIEW: Ensure `commit.canonical`? - signed_header, - __marker: PhantomData, - }), - )) - } - - pub async fn fetch_untrusted_commit(hc: &Hc, height: Hc::Height) -> Op - where - Hc: CosmosSdkChainRpcs + ChainExt: From>>, - Tr: ChainExt, - AnyLightClientIdentified: From)>, - { - let commit = hc - .tm_client() - .commit( - TryInto::<::tendermint::block::Height>::try_into(height.revision_height()).unwrap(), - ) - .await - .unwrap(); - - let signed_header = tendermint_commit_to_signed_header(commit); - - data(id::( - hc.chain_id(), - Data::specific(UntrustedCommit { - height, - // REVIEW: Ensure `commit.canonical`? - signed_header, - __marker: PhantomData, - }), - )) - } - - pub async fn fetch_trusted_validators(hc: &Hc, height: Hc::Height) -> Op - where - Hc: CosmosSdkChainRpcs + ChainExt: From>>, - Tr: ChainExt, - AnyLightClientIdentified: From)>, - { - let validators = hc - .tm_client() - .validators( - TryInto::<::tendermint::block::Height>::try_into(height.revision_height()).unwrap(), - tendermint_rpc::Paging::All, - ) - .await - .unwrap() - .validators - .into_iter() - .map(tendermint_validator_info_to_validator) - .collect(); - - data(id::( - hc.chain_id(), - Data::specific(TrustedValidators { - height, - validators, - __marker: PhantomData, - }), - )) - } - - pub async fn fetch_untrusted_validators(hc: &Hc, height: Hc::Height) -> Op - where - Hc: CosmosSdkChainRpcs + ChainExt: From>>, - Tr: ChainExt, - AnyLightClientIdentified: From)>, - { - let validators = hc - .tm_client() - .validators( - TryInto::<::tendermint::block::Height>::try_into(height.revision_height()).unwrap(), - tendermint_rpc::Paging::All, - ) - .await - .unwrap() - .validators - .into_iter() - .map(tendermint_validator_info_to_validator) - .collect(); - - data(id::( - hc.chain_id(), - Data::specific(UntrustedValidators { - height, - validators, - __marker: PhantomData, - }), - )) - } -} - -pub mod data { - use queue_msg::queue_msg; - use unionlabs::tendermint::types::{signed_header::SignedHeader, validator::Validator}; - - use crate::ChainExt; - - #[queue_msg] - pub struct UntrustedCommit { - pub height: Hc::Height, - pub signed_header: SignedHeader, - } - - #[queue_msg] - pub struct TrustedCommit { - pub height: Hc::Height, - pub signed_header: SignedHeader, - } - - #[queue_msg] - pub struct TrustedValidators { - pub height: Hc::Height, - pub validators: Vec, - } - - #[queue_msg] - pub struct UntrustedValidators { - pub height: Hc::Height, - pub validators: Vec, - } -} - -pub mod tendermint_helpers { - use unionlabs::{ - bounded::BoundedI64, - google::protobuf::timestamp::Timestamp, - hash::H256, - tendermint::{ - crypto::public_key::PublicKey, - types::{ - block_id::BlockId, commit::Commit, commit_sig::CommitSig, - part_set_header::PartSetHeader, signed_header::SignedHeader, validator::Validator, - }, - }, - }; - - pub fn tendermint_commit_to_signed_header( - commit: tendermint_rpc::endpoint::commit::Response, - ) -> SignedHeader { - let header_timestamp = - tendermint_proto::google::protobuf::Timestamp::from(commit.signed_header.header.time); - - SignedHeader { - header: unionlabs::tendermint::types::header::Header { - version: unionlabs::tendermint::version::consensus::Consensus { - block: commit.signed_header.header.version.block, - app: commit.signed_header.header.version.app, - }, - chain_id: commit.signed_header.header.chain_id.into(), - height: tendermint_height_to_bounded_i64(commit.signed_header.header.height), - time: Timestamp { - seconds: header_timestamp.seconds.try_into().unwrap(), - nanos: header_timestamp.nanos.try_into().unwrap(), - }, - last_block_id: BlockId { - hash: Some(tendermint_hash_to_h256( - commit.signed_header.header.last_block_id.unwrap().hash, - )), - part_set_header: PartSetHeader { - total: commit - .signed_header - .header - .last_block_id - .unwrap() - .part_set_header - .total, - hash: Some(tendermint_hash_to_h256( - commit - .signed_header - .header - .last_block_id - .unwrap() - .part_set_header - .hash, - )), - }, - }, - last_commit_hash: tendermint_hash_to_h256( - commit.signed_header.header.last_commit_hash.unwrap(), - ), - data_hash: tendermint_hash_to_h256(commit.signed_header.header.data_hash.unwrap()), - validators_hash: tendermint_hash_to_h256( - commit.signed_header.header.validators_hash, - ), - next_validators_hash: tendermint_hash_to_h256( - commit.signed_header.header.next_validators_hash, - ), - consensus_hash: tendermint_hash_to_h256(commit.signed_header.header.consensus_hash), - app_hash: commit - .signed_header - .header - .app_hash - .as_bytes() - .try_into() - .unwrap(), - last_results_hash: tendermint_hash_to_h256( - commit.signed_header.header.last_results_hash.unwrap(), - ), - evidence_hash: tendermint_hash_to_h256( - commit.signed_header.header.evidence_hash.unwrap(), - ), - proposer_address: commit - .signed_header - .header - .proposer_address - .as_bytes() - .try_into() - .expect("value is a [u8; 20] internally, this should not fail; qed;"), - }, - commit: Commit { - height: tendermint_height_to_bounded_i64(commit.signed_header.commit.height), - round: i32::from(commit.signed_header.commit.round) - .try_into() - .unwrap(), - block_id: BlockId { - hash: Some(tendermint_hash_to_h256( - commit.signed_header.commit.block_id.hash, - )), - part_set_header: PartSetHeader { - total: commit.signed_header.commit.block_id.part_set_header.total, - hash: Some(tendermint_hash_to_h256( - commit.signed_header.commit.block_id.part_set_header.hash, - )), - }, - }, - signatures: commit - .signed_header - .commit - .signatures - .into_iter() - .map(tendermint_commit_sig_to_commit_sig) - .collect(), - }, - } - } - - fn tendermint_commit_sig_to_commit_sig(sig: tendermint::block::CommitSig) -> CommitSig { - match sig { - ::tendermint::block::CommitSig::BlockIdFlagAbsent => CommitSig::Absent, - ::tendermint::block::CommitSig::BlockIdFlagCommit { - validator_address, - timestamp, - signature, - } => CommitSig::Commit { - validator_address: Vec::from(validator_address).try_into().unwrap(), - timestamp: { - let ts = tendermint_proto::google::protobuf::Timestamp::from(timestamp); - - Timestamp { - seconds: ts.seconds.try_into().unwrap(), - nanos: ts.nanos.try_into().unwrap(), - } - }, - signature: signature.unwrap().into_bytes(), - }, - ::tendermint::block::CommitSig::BlockIdFlagNil { - validator_address, - timestamp, - signature, - } => CommitSig::Nil { - validator_address: Vec::from(validator_address).try_into().unwrap(), - timestamp: { - let ts = tendermint_proto::google::protobuf::Timestamp::from(timestamp); - - Timestamp { - seconds: ts.seconds.try_into().unwrap(), - nanos: ts.nanos.try_into().unwrap(), - } - }, - signature: signature.unwrap().into_bytes(), - }, - } - } - - pub fn tendermint_validator_info_to_validator(val: ::tendermint::validator::Info) -> Validator { - Validator { - address: val - .address - .as_bytes() - .try_into() - .expect("value is 20 bytes internally; should not fail; qed"), - pub_key: match val.pub_key { - ::tendermint::PublicKey::Ed25519(key) => PublicKey::Ed25519(key.as_bytes().into()), - ::tendermint::PublicKey::Bn254(key) => PublicKey::Bn254(key.to_vec()), - _ => todo!(), - }, - voting_power: BoundedI64::new(val.power.value().try_into().unwrap()).unwrap(), - proposer_priority: val.proposer_priority.value(), - } - } - - fn tendermint_hash_to_h256(hash: tendermint::Hash) -> H256 { - match hash { - tendermint::Hash::Sha256(hash) => hash.into(), - tendermint::Hash::None => panic!("empty hash???"), - } - } - - pub fn tendermint_height_to_bounded_i64( - height: ::tendermint::block::Height, - ) -> BoundedI64<0, { i64::MAX }> { - i64::from(height).try_into().unwrap() - } -} - -pub mod wasm { - use chain_utils::{ - cosmos::Cosmos, - cosmos_sdk::{BroadcastTxCommitError, CosmosSdkChain}, - keyring::ChainKeyring, - union::Union, - wasm::Wasm, - }; - use queue_msg::Op; - use serde::{Deserialize, Serialize}; - use unionlabs::{ - encoding::{Encode, Proto}, - google::protobuf::any::{Any, IntoAny}, - hash::H256, - ibc::lightclients::wasm, - signer::CosmosSigner, - traits::ClientState, - TypeUrl, - }; - - use crate::{ - chain::{ - cosmos::{CosmosAggregateMsg, CosmosDataMsg, CosmosFetch}, - cosmos_sdk::{ - data::{TrustedCommit, TrustedValidators, UntrustedCommit, UntrustedValidators}, - do_msg, CosmosSdkChainSealed, - }, - union::{ProveResponse, UnionAggregateMsg, UnionDataMsg, UnionFetch}, - }, - effect::{AnyEffect, Effect}, - fetch::FetchUpdateHeaders, - identified, AnyLightClientIdentified, ChainExt, DoFetchUpdateHeaders, DoMsg, RelayMessage, - }; - - impl ChainExt for Wasm { - type Data = UnionDataMsg, Tr>; - type Fetch = UnionFetch, Tr>; - type Aggregate = UnionAggregateMsg, Tr>; - - type MsgError = BroadcastTxCommitError; - - type Config = WasmConfig; - } - - try_from_relayer_msg! { - chain = Wasm, - generics = (Tr: ChainExt), - msgs = UnionDataMsg( - UntrustedCommit(UntrustedCommit, Tr>), - TrustedValidators(TrustedValidators, Tr>), - UntrustedValidators(UntrustedValidators, Tr>), - ProveResponse(ProveResponse, Tr>), - ), - } - - impl ChainExt for Wasm { - type Data = CosmosDataMsg, Tr>; - type Fetch = CosmosFetch, Tr>; - type Aggregate = CosmosAggregateMsg, Tr>; - - type MsgError = BroadcastTxCommitError; - - type Config = WasmConfig; - } - - try_from_relayer_msg! { - chain = Wasm, - generics = (Tr: ChainExt), - msgs = CosmosDataMsg( - TrustedCommit(TrustedCommit, Tr>), - UntrustedCommit(UntrustedCommit, Tr>), - TrustedValidators(TrustedValidators, Tr>), - UntrustedValidators(UntrustedValidators, Tr>), - ), - } - - impl CosmosSdkChainSealed for Wasm - where - Wasm: ChainExt, - Hc: CosmosSdkChainSealed, - { - } - - #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] - #[serde(deny_unknown_fields)] - #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] - pub struct WasmConfig { - pub checksum: H256, - // pub inner: T, - } - - impl DoFetchUpdateHeaders for Wasm - where - Wasm: ChainExt, - Hc: ChainExt + CosmosSdkChain + DoFetchUpdateHeaders, - Tr: ChainExt, - { - fn fetch_update_headers( - hc: &Self, - update_info: FetchUpdateHeaders, - ) -> Op { - Hc::fetch_update_headers( - hc, - FetchUpdateHeaders { - counterparty_chain_id: update_info.counterparty_chain_id, - counterparty_client_id: update_info.counterparty_client_id, - update_from: update_info.update_from, - update_to: update_info.update_to, - }, - ) - } - } - - impl DoMsg, Tr> for Wasm - where - Wasm: ChainKeyring - + ChainExt< - SelfConsensusState: Encode + TypeUrl, - SelfClientState: Encode + TypeUrl, - MsgError = BroadcastTxCommitError, - Config = WasmConfig, - Error = tendermint_rpc::Error, - >, - Hc: ChainKeyring - + CosmosSdkChainSealed, - Tr: ChainExt< - StoredClientState>: IntoAny, - StateProof: Encode, - SelfConsensusState: Encode + TypeUrl, - SelfClientState: Encode + TypeUrl, - Header: Encode + TypeUrl, - >, - AnyLightClientIdentified: From, Tr>)>, - { - async fn msg( - &self, - effect: Effect, Tr>, - ) -> Result, Self::MsgError> { - do_msg( - self, - effect, - |config, client_state, consensus_state| { - ( - Any(wasm::client_state::ClientState { - latest_height: client_state.height().into(), - data: client_state, - checksum: config.checksum, - }) - .into(), - Any(wasm::consensus_state::ConsensusState { - data: consensus_state, - }) - .into(), - ) - }, - |client_message| { - Any(wasm::client_message::ClientMessage { - data: client_message, - }) - .into() - }, - ) - .await - } - } -} diff --git a/lib/relay-message/src/chain/ethereum.rs b/lib/relay-message/src/chain/ethereum.rs deleted file mode 100644 index 8dc61d7c5d..0000000000 --- a/lib/relay-message/src/chain/ethereum.rs +++ /dev/null @@ -1,1655 +0,0 @@ -use std::{collections::VecDeque, fmt::Debug, marker::PhantomData, ops::Div, sync::Arc}; - -use chain_utils::ethereum::{ - Ethereum, EthereumChain, EthereumConsensusChain, EthereumIbcChain, EthereumKeyring, - EthereumSignerMiddleware, IbcHandlerErrors, IbcHandlerExt, ETHEREUM_REVISION_NUMBER, -}; -use contracts::{ - ibc_handler::{ - self, AcknowledgePacketCall, ChannelOpenAckCall, ChannelOpenConfirmCall, - ChannelOpenInitCall, ChannelOpenTryCall, ConnectionOpenAckCall, ConnectionOpenConfirmCall, - ConnectionOpenInitCall, ConnectionOpenTryCall, CreateClientCall, IBCHandler, - RecvPacketCall, TimeoutPacketCall, UpdateClientCall, - }, - multicall::{Call3, Multicall, MulticallResultFilter}, -}; -use ethereum_verifier::utils::validate_signature_supermajority; -use ethers::{ - self, - abi::{AbiDecode, AbiEncode}, - contract::{ContractError, EthCall, FunctionCall}, - middleware::{nonce_manager::NonceManagerError, signer::SignerMiddlewareError}, - providers::{Middleware, ProviderError}, - types::{Bytes, TransactionReceipt}, - utils::keccak256, -}; -use frunk::{hlist_pat, HList}; -use queue_msg::{ - aggregate, - aggregation::{do_aggregate, UseAggregate}, - data, defer_relative, effect, fetch, noop, queue_msg, void, wait, Op, -}; -use serde::{Deserialize, Serialize}; -use tracing::{debug, error, error_span, info, info_span, warn, Instrument}; -use typenum::Unsigned; -use unionlabs::{ - encoding::{Decode, Encode, EncodeAs, EthAbi}, - ethereum::{ - beacon::{GenesisData, LightClientBootstrap, LightClientFinalityUpdate}, - config::ChainSpec, - IBC_HANDLER_COMMITMENTS_SLOT, - }, - hash::{H160, H256}, - ibc::{ - core::client::{ - height::{Height, IsHeight}, - msg_update_client::MsgUpdateClient, - }, - lightclients::ethereum::{ - self, - account_proof::AccountProof, - account_update::AccountUpdate, - light_client_update, - trusted_sync_committee::{ActiveSyncCommittee, TrustedSyncCommittee}, - }, - }, - ics24::{ClientStatePath, NextSequenceAckPath, NextSequenceSendPath, Path}, - never::Never, - traits::{ - Chain, ChainIdOf, ClientIdOf, ClientState, ClientStateOf, HeightOf, IbcStateEncodingOf, - }, - uint::U256, - ErrorReporter, MaybeRecoverableError, -}; - -use crate::{ - aggregate::{Aggregate, AnyAggregate}, - data::{AnyData, Data, IbcProof, IbcState}, - effect::{ - log_msg, AnyEffect, BatchMsg, Effect, MsgConnectionOpenAckData, MsgConnectionOpenInitData, - MsgConnectionOpenTryData, MsgUpdateClientData, - }, - fetch::{AnyFetch, DoFetch, Fetch, FetchUpdateHeaders}, - id, identified, seq, - use_aggregate::IsAggregateData, - wait::{AnyWait, Wait, WaitForTimestamp}, - AnyLightClientIdentified, ChainExt, DoAggregate, DoFetchProof, DoFetchState, - DoFetchUpdateHeaders, DoMsg, Identified, PathOf, RelayMessage, -}; - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct EthereumConfig { - // TODO: Make this an enum perhaps? - pub client_type: String, -} - -impl ChainExt for Ethereum { - type Data = EthereumDataMsg; - type Fetch = EthereumFetchMsg; - type Aggregate = EthereumAggregateMsg; - - type MsgError = TxSubmitError; - - type Config = EthereumConfig; -} - -impl DoMsg for Ethereum -where - C: ChainSpec, - Tr: ChainExt< - SelfConsensusState: Encode, - SelfClientState: Encode, - Header: Encode, - StoredClientState>: Encode, - StateProof: Encode, - >, - - ClientStateOf>: Encode, - AnyLightClientIdentified: From)>, -{ - async fn msg(&self, msg: Effect) -> Result, Self::MsgError> { - do_msg( - self.chain_id(), - self.multicall_address, - &self.keyring, - msg, - false, - self.max_gas_price, - ) - .await - } -} - -// TODO: Refactor this to use `Hc: ChainKeyring` -pub async fn do_msg( - chain_id: ChainIdOf, - multicall_address: H160, - ibc_handlers: &EthereumKeyring, - msg: Effect, - legacy: bool, - max_gas_price: Option, -) -> Result, TxSubmitError> -where - Hc: ChainExt> - + EthereumIbcChain, - Tr: ChainExt< - SelfConsensusState: Encode, - SelfClientState: Encode, - Header: Encode, - StoredClientState: Encode, - StateProof: Encode, - >, - AnyLightClientIdentified: From)>, -{ - do_msg_fixed_gas( - chain_id, - multicall_address, - ibc_handlers, - msg, - legacy, - None, - max_gas_price, - ) - .await -} - -// TODO: Refactor this to use `Hc: ChainKeyring` -pub async fn do_msg_fixed_gas( - chain_id: ChainIdOf, - multicall_address: H160, - ibc_handlers: &EthereumKeyring, - msg: Effect, - legacy: bool, - fixed_gas: Option, - max_gas_price: Option, -) -> Result, TxSubmitError> -where - Hc: ChainExt> - + EthereumIbcChain, - Tr: ChainExt< - SelfConsensusState: Encode, - SelfClientState: Encode, - Header: Encode, - StoredClientState: Encode, - StateProof: Encode, - >, - AnyLightClientIdentified: From)>, -{ - let res = ibc_handlers - .with({ - let chain_id = chain_id.clone(); - let msg = msg.clone(); - - move |ibc_handler: &IBCHandler<_>| -> _ { - async move { - if let Some(max_gas_price) = max_gas_price { - let gas_price = U256::from(ibc_handler - .client() - .provider() - .get_gas_price() - .await - .expect("unable to fetch gas price")); - - if gas_price > max_gas_price { - warn!(%max_gas_price, %gas_price, "gas price is too high"); - return Err(TxSubmitError::GasPriceTooHigh { - max: max_gas_price, - price: gas_price - }) - } - } - - let multicall = Multicall::new(multicall_address, ibc_handler.client()); - - let msgs = process_msgs( - msg, - ibc_handler, - chain_id, - ibc_handler.client().address().into(), - ); - - let msg_names = msgs - .iter() - .map(|x| (x.0.clone(), x.1.function.name.clone())) - .collect::>(); - - let call = multicall.multicall( - msgs.into_iter() - .map(|(_, x): (_, FunctionCall<_, _, _>)| Call3 { - target: ibc_handler.address(), - allow_failure: true, - call_data: x.calldata().expect("is a contract call"), - }) - .collect(), - ); - - let call = if legacy { call.legacy() } else { call }; - - let msg_name = call.function.name.clone(); - - info!("submitting evm tx"); - - match call.estimate_gas().await { - Ok(estimated_gas) => { - debug!( - %estimated_gas, - "gas estimation" - ); - - // TODO: config - match call.gas(fixed_gas.map(Into::into).unwrap_or(estimated_gas + (estimated_gas / 10))).send().await { - Ok(ok) => { - let tx_hash = ok.tx_hash(); - async move { - let tx_rcp: TransactionReceipt = ok.await?.ok_or(TxSubmitError::NoTxReceipt)?; - - let result = ::decode_log( - ðers::abi::RawLog::from( - tx_rcp - .logs - .last() - .expect("multicall event should be last log") - .clone(), - ), - ) - .expect("unable to decode multicall result log"); - - info!( - gas_used = %tx_rcp.gas_used.unwrap_or_default(), - batch.size = msg_names.len(), - "submitted batched evm messages" - ); - - for (idx, (result, (effect, msg_name))) in result.0.into_iter().zip(msg_names).enumerate() { - if result.success { - info_span!( - "evm tx", - msg = msg_name, - %idx, - ) - .in_scope(|| log_msg(effect)); - } else if let Ok(known_revert) = - IbcHandlerErrors::decode(&*result.return_data.clone()) - { - error_span!( - "evm message failed", - msg = %msg_name, - %idx, - revert = ?known_revert, - well_known = true, - ) - .in_scope(|| log_msg(effect)); - } else if result.return_data.is_empty() { - error_span!( - "evm message failed", - msg = %msg_name, - %idx, - revert = %serde_utils::to_hex(result.return_data), - well_known = false, - ) - .in_scope(|| log_msg(effect)); - - return Err(TxSubmitError::EmptyRevert) - } else { - error_span!( - "evm message failed", - msg = %msg_name, - %idx, - revert = %serde_utils::to_hex(result.return_data), - well_known = false, - ) - .in_scope(|| log_msg(effect)); - } - } - - Ok(()) - } - .instrument(info_span!( - "evm tx", - tx_hash = %H256::from(tx_hash), - )).await - } - // Err(ContractError::Revert(revert)) => { - // error!(?revert, "evm transaction failed"); - // let err = ::decode( - // revert.clone(), - // ) - // .map_err(|_| TxSubmitError::InvalidRevert(revert.clone()))?; - // error!( - // msg = %msg_name, - // ?revert, - // ?err, - // "evm transaction failed" - // ); - - // Ok(()) - // } - Err(ContractError::ProviderError { - e: ProviderError::JsonRpcClientError(e), - }) - | Err(ContractError::MiddlewareError { - e: - SignerMiddlewareError::MiddlewareError(NonceManagerError::MiddlewareError( - ProviderError::JsonRpcClientError(e), - )), - }) if e.as_error_response().is_some_and(|e| { - e.message - .contains("insufficient funds for gas * price + value") - }) => - { - error!("out of gas"); - Err(TxSubmitError::OutOfGas) - } - err => { - panic!("evm transaction non-recoverable failure: {err:?}") - } - } - } - Err(err) => { - let _span = error_span!( - "tx error", - msg = %msg_name, - err = %ErrorReporter(&err) - ); - - match err { - ContractError::Revert(revert) => { - error!(?revert, "evm gas estimation failed"); - - match ::decode( - &revert, - ) { - Ok(known_err) => { - // REVIEW: Are any of these recoverable? - // match known_err { - // IbcHandlerErrors::PacketErrors(_) => todo!(), - // IbcHandlerErrors::ConnectionErrors(_) => todo!(), - // IbcHandlerErrors::ChannelErrors(_) => todo!(), - // IbcHandlerErrors::ClientErrors(_) => todo!(), - // IbcHandlerErrors::CometblsClientErrors(_) => todo!(), - // } - - error!(?revert, ?known_err, "evm estimation failed"); - } - Err(_) => { - error!( - "evm estimation failed with unknown revert code" - ); - } - } - - Ok(()) - } - _ => { - error!("evm tx recoverable error"); - panic!(); - } - } - } - } - } - } - }) - .await; - - match res { - Some(Ok(())) => Ok(noop()), - Some(Err(TxSubmitError::GasPriceTooHigh { .. })) => { - Ok(seq([defer_relative(6), effect(id(chain_id, msg))])) - } - Some(Err(TxSubmitError::OutOfGas)) => { - Ok(seq([defer_relative(12), effect(id(chain_id, msg))])) - } - Some(Err(TxSubmitError::EmptyRevert)) => { - Ok(seq([defer_relative(12), effect(id(chain_id, msg))])) - } - Some(Err(err)) => Err(err), - None => Ok(effect(id(chain_id, msg))), - } -} - -fn process_msgs( - effect: Effect, - ibc_handler: &IBCHandler, - chain_id: ChainIdOf, - relayer: H160, -) -> Vec<(Effect, FunctionCall, M, ()>)> -where - Hc: ChainExt>, - Tr: ChainExt< - SelfConsensusState: Encode, - SelfClientState: Encode, - Header: Encode, - StoredClientState: Encode, - StateProof: Encode, - >, - M: Middleware, -{ - match effect.clone() { - Effect::ConnectionOpenInit(MsgConnectionOpenInitData(data)) => vec![( - effect, - mk_function_call( - ibc_handler, - ConnectionOpenInitCall(contracts::ibc_handler::MsgConnectionOpenInit { - client_id: data.client_id.to_string(), - version: data.version.into(), - counterparty: data.counterparty.into(), - delay_period: data.delay_period, - relayer: relayer.into(), - }), - ), - )], - Effect::ConnectionOpenTry(MsgConnectionOpenTryData(data)) => vec![( - effect, - mk_function_call( - ibc_handler, - ConnectionOpenTryCall(contracts::ibc_handler::MsgConnectionOpenTry { - counterparty: data.counterparty.into(), - delay_period: data.delay_period, - client_id: data.client_id.to_string(), - // needs to be encoded how the counterparty is encoding it - client_state_bytes: Encode::::encode(data.client_state) - .into(), - counterparty_versions: data - .counterparty_versions - .into_iter() - .map(Into::into) - .collect(), - proof_init: data.proof_init.encode().into(), - proof_client: data.proof_client.encode().into(), - proof_consensus: data.proof_consensus.encode().into(), - proof_height: data.proof_height.into_height().into(), - consensus_height: data.consensus_height.into_height().into(), - relayer: relayer.into(), - }), - ), - )], - Effect::ConnectionOpenAck(MsgConnectionOpenAckData(data)) => vec![( - effect, - mk_function_call( - ibc_handler, - ConnectionOpenAckCall(contracts::ibc_handler::MsgConnectionOpenAck { - connection_id: data.connection_id.to_string(), - counterparty_connection_id: data.counterparty_connection_id.to_string(), - version: data.version.into(), - // needs to be encoded how the counterparty is encoding it - client_state_bytes: Encode::::encode(data.client_state) - .into(), - proof_height: data.proof_height.into(), - proof_try: data.proof_try.encode().into(), - proof_client: data.proof_client.encode().into(), - proof_consensus: data.proof_consensus.encode().into(), - consensus_height: data.consensus_height.into(), - relayer: relayer.into(), - }), - ), - )], - Effect::ConnectionOpenConfirm(data) => vec![( - effect, - mk_function_call( - ibc_handler, - ConnectionOpenConfirmCall(contracts::ibc_handler::MsgConnectionOpenConfirm { - connection_id: data.msg.connection_id.to_string(), - proof_ack: data.msg.proof_ack.encode().into(), - proof_height: data.msg.proof_height.into_height().into(), - relayer: relayer.into(), - }), - ), - )], - Effect::ChannelOpenInit(data) => vec![( - effect, - mk_function_call( - ibc_handler, - ChannelOpenInitCall(contracts::ibc_handler::MsgChannelOpenInit { - port_id: data.msg.port_id.to_string(), - channel: data.msg.channel.into(), - relayer: relayer.into(), - }), - ), - )], - Effect::ChannelOpenTry(data) => vec![( - effect, - mk_function_call( - ibc_handler, - ChannelOpenTryCall(contracts::ibc_handler::MsgChannelOpenTry { - port_id: data.msg.port_id.to_string(), - channel: data.msg.channel.into(), - counterparty_version: data.msg.counterparty_version, - proof_init: data.msg.proof_init.encode().into(), - proof_height: data.msg.proof_height.into(), - relayer: relayer.into(), - }), - ), - )], - Effect::ChannelOpenAck(data) => vec![( - effect, - mk_function_call( - ibc_handler, - ChannelOpenAckCall(contracts::ibc_handler::MsgChannelOpenAck { - port_id: data.msg.port_id.to_string(), - channel_id: data.msg.channel_id.to_string(), - counterparty_version: data.msg.counterparty_version, - counterparty_channel_id: data.msg.counterparty_channel_id.to_string(), - proof_try: data.msg.proof_try.encode().into(), - proof_height: data.msg.proof_height.into_height().into(), - relayer: relayer.into(), - }), - ), - )], - Effect::ChannelOpenConfirm(data) => vec![( - effect, - mk_function_call( - ibc_handler, - ChannelOpenConfirmCall(contracts::ibc_handler::MsgChannelOpenConfirm { - port_id: data.msg.port_id.to_string(), - channel_id: data.msg.channel_id.to_string(), - proof_ack: data.msg.proof_ack.encode().into(), - proof_height: data.msg.proof_height.into_height().into(), - relayer: relayer.into(), - }), - ), - )], - Effect::RecvPacket(data) => vec![( - effect, - mk_function_call( - ibc_handler, - RecvPacketCall(contracts::ibc_handler::MsgPacketRecv { - packet: data.msg.packet.into(), - proof: data.msg.proof_commitment.encode().into(), - proof_height: data.msg.proof_height.into_height().into(), - relayer: relayer.into(), - }), - ), - )], - Effect::AckPacket(data) => vec![( - effect, - mk_function_call( - ibc_handler, - AcknowledgePacketCall(contracts::ibc_handler::MsgPacketAcknowledgement { - packet: data.msg.packet.into(), - acknowledgement: data.msg.acknowledgement.into(), - proof: data.msg.proof_acked.encode().into(), - proof_height: data.msg.proof_height.into_height().into(), - relayer: relayer.into(), - }), - ), - )], - Effect::TimeoutPacket(data) => vec![( - effect, - mk_function_call( - ibc_handler, - TimeoutPacketCall(contracts::ibc_handler::MsgPacketTimeout { - packet: data.msg.packet.into(), - proof: data.msg.proof_unreceived.encode().into(), - proof_height: data.msg.proof_height.into_height().into(), - next_sequence_recv: data.msg.next_sequence_recv.get(), - relayer: relayer.into(), - }), - ), - )], - Effect::CreateClient(data) => { - vec![( - effect, - mk_function_call( - ibc_handler, - CreateClientCall(contracts::shared_types::MsgCreateClient { - client_type: data.config.client_type, - client_state_bytes: data.msg.client_state.encode_as::().into(), - consensus_state_bytes: data - .msg - .consensus_state - .encode_as::() - .into(), - relayer: relayer.into(), - }), - ), - )] - } - Effect::UpdateClient(MsgUpdateClientData(data)) => vec![( - effect, - mk_function_call( - ibc_handler, - UpdateClientCall(ibc_handler::MsgUpdateClient { - client_id: data.client_id.to_string(), - client_message: data.client_message.clone().encode_as::().into(), - relayer: relayer.into(), - }), - ), - )], - Effect::Batch(BatchMsg(msgs)) => msgs - .into_iter() - .flat_map(|msg| process_msgs(msg, ibc_handler, chain_id.clone(), relayer)) - .collect(), - } -} - -impl DoFetchProof for Ethereum -where - AnyLightClientIdentified: From, Tr>)>, -{ - fn proof(c: &Self, at: HeightOf, path: PathOf, Tr>) -> Op { - fetch(id::( - c.chain_id(), - Fetch::specific(GetProof { path, height: at }), - )) - } -} - -impl DoFetchState for Ethereum -where - C: ChainSpec, - Tr: ChainExt>> + Encode>, - - AnyLightClientIdentified: From, Tr>)>, -{ - type QueryUnfinalizedTrustedClientStateError = Never; - - fn state(hc: &Self, at: HeightOf, path: PathOf) -> Op { - fetch(id::( - hc.chain_id(), - Fetch::::specific(FetchIbcState { path, height: at }), - )) - } - - async fn query_unfinalized_trusted_client_state( - hc: &Self, - client_id: Self::ClientId, - ) -> Result, Self::QueryUnfinalizedTrustedClientStateError> { - let latest_execution_height = hc.provider.get_block_number().await.unwrap().as_u64(); - - Ok(hc - .ibc_handler() - .ibc_state_read::<_, Self, Tr>(latest_execution_height, ClientStatePath { client_id }) - .await - .unwrap()) - } -} - -impl DoFetchUpdateHeaders for Ethereum -where - C: ChainSpec, - Tr: ChainExt, - AnyLightClientIdentified: From, Tr>)>, - AnyLightClientIdentified: From, Tr>)>, -{ - fn fetch_update_headers( - c: &Self, - update_info: FetchUpdateHeaders, - ) -> Op { - aggregate( - [fetch(id::, Tr, _>( - c.chain_id, - Fetch::specific(FetchFinalityUpdate {}), - ))], - [], - id( - c.chain_id, - Aggregate::specific(MakeCreateUpdatesData { req: update_info }), - ), - ) - } -} - -impl DoFetch> for EthereumFetchMsg -where - C: ChainSpec, - Tr: ChainExt< - SelfClientState: Decode< as Chain>::IbcStateEncoding> + Encode, - SelfConsensusState: Decode< as Chain>::IbcStateEncoding>, - >, - AnyLightClientIdentified: From, Tr>)>, - AnyLightClientIdentified: From, Tr>)>, -{ - type Error = Never; - - async fn do_fetch(ethereum: &Ethereum, msg: Self) -> Result, Self::Error> { - let msg: EthereumFetchMsg = msg; - let msg = match msg { - Self::FetchFinalityUpdate(FetchFinalityUpdate {}) => { - let finality_update = ethereum - .beacon_api_client - .finality_update() - .await - .unwrap() - .data; - - if !validate_signature_supermajority::( - &finality_update.sync_aggregate.sync_committee_bits, - ) { - info!( - signature_slot = finality_update.signature_slot, - "signature supermajority not hit" - ); - - seq([ - defer_relative(1), - fetch(id( - ethereum.chain_id(), - Fetch::specific(FetchFinalityUpdate {}), - )), - ]) - } else { - data(id::, Tr, _>( - ethereum.chain_id, - Data::specific(FinalityUpdate { - finality_update, - __marker: PhantomData, - }), - )) - } - } - Self::FetchLightClientUpdates(FetchLightClientUpdates { - trusted_period, - target_period, - }) => data(id::, Tr, _>( - ethereum.chain_id, - Data::specific(LightClientUpdates { - light_client_updates: ethereum - .beacon_api_client - .light_client_updates(trusted_period + 1, target_period - trusted_period) - .await - .unwrap() - .0 - .into_iter() - .map(|x| x.data) - .collect(), - __marker: PhantomData, - }), - )), - Self::FetchLightClientUpdate(FetchLightClientUpdate { period }) => { - data(id::, Tr, _>( - ethereum.chain_id, - Data::specific(LightClientUpdate { - update: ethereum - .beacon_api_client - .light_client_updates(period, 1) - .await - .unwrap() - .0 - .into_iter() - .map(|x| x.data) - .collect::>>() - .pop() - .unwrap(), - __marker: PhantomData, - }), - )) - } - Self::FetchBootstrap(FetchBootstrap { slot }) => data(id::, Tr, _>( - ethereum.chain_id, - Data::specific(BootstrapData { - slot, - bootstrap: ethereum - .beacon_api_client - .bootstrap_for_slot(slot) - .await - .unwrap() - .data, - __marker: PhantomData, - }), - )), - Self::FetchAccountUpdate(FetchAccountUpdate { slot }) => { - let execution_height = ethereum - .beacon_api_client - .execution_height(beacon_api::client::BlockId::Slot(slot)) - .await - .unwrap(); - - let account_update = ethereum - .provider - .get_proof( - ethers::types::H160::from(ethereum.ibc_handler_address), - vec![], - // NOTE: Proofs are from the execution layer, so we use execution height, not beacon slot. - Some(execution_height.into()), - ) - .await - .unwrap(); - - data(id::, Tr, _>( - ethereum.chain_id, - Data::specific(AccountUpdateData { - slot, - update: AccountUpdate { - account_proof: AccountProof { - storage_root: account_update.storage_hash.into(), - proof: account_update - .account_proof - .into_iter() - .map(|x| x.to_vec()) - .collect(), - }, - }, - __marker: PhantomData, - }), - )) - } - Self::FetchBeaconGenesis(_) => data(id::, Tr, _>( - ethereum.chain_id, - Data::specific(BeaconGenesisData { - genesis: ethereum.beacon_api_client.genesis().await.unwrap().data, - __marker: PhantomData, - }), - )), - Self::FetchGetProof(get_proof) => data(id::, Tr, _>( - ethereum.chain_id, - fetch_get_proof(ethereum, get_proof).await, - )), - Self::FetchIbcState(ibc_state) => data(id::, Tr, _>( - ethereum.chain_id, - fetch_ibc_state(ethereum, ibc_state).await, - )), - }; - - Ok(msg) - } -} - -pub async fn fetch_get_proof(c: &Hc, get_proof: GetProof) -> Data -where - Hc: ChainExt + EthereumChain + EthereumConsensusChain, - Tr: ChainExt, -{ - let path = get_proof.path.to_string(); - - // TODO: Use unionlabs::slot here - // or ibc_commitment_key? - let location = keccak256( - keccak256(path.as_bytes()) - .into_iter() - .chain(AbiEncode::encode(IBC_HANDLER_COMMITMENTS_SLOT)) - .collect::>(), - ); - - let execution_height = c - .execution_height_of_beacon_slot(get_proof.height.revision_height()) - .await; - - let proof = c - .get_proof( - c.ibc_handler_address(), - U256::from_be_bytes(location), - execution_height, - ) - .await; - - match get_proof.path { - Path::ClientState(path) => Data::from(IbcProof::<_, Hc, Tr> { - proof, - height: get_proof.height, - path, - __marker: PhantomData, - }), - Path::ClientConsensusState(path) => Data::from(IbcProof::<_, Hc, Tr> { - proof, - height: get_proof.height, - path, - __marker: PhantomData, - }), - Path::Connection(path) => Data::from(IbcProof::<_, Hc, Tr> { - proof, - height: get_proof.height, - path, - __marker: PhantomData, - }), - Path::ChannelEnd(path) => Data::from(IbcProof::<_, Hc, Tr> { - proof, - height: get_proof.height, - path, - __marker: PhantomData, - }), - Path::Commitment(path) => Data::from(IbcProof::<_, Hc, Tr> { - proof, - height: get_proof.height, - path, - __marker: PhantomData, - }), - Path::Acknowledgement(path) => Data::from(IbcProof::<_, Hc, Tr> { - proof, - height: get_proof.height, - path, - __marker: PhantomData, - }), - Path::Receipt(path) => Data::from(IbcProof::<_, Hc, Tr> { - proof, - height: get_proof.height, - path, - __marker: PhantomData, - }), - Path::NextSequenceSend(path) => Data::from(IbcProof::<_, Hc, Tr> { - proof, - height: get_proof.height, - path, - __marker: PhantomData, - }), - Path::NextSequenceRecv(path) => Data::from(IbcProof::<_, Hc, Tr> { - proof, - height: get_proof.height, - path, - __marker: PhantomData, - }), - Path::NextSequenceAck(path) => Data::from(IbcProof::<_, Hc, Tr> { - proof, - height: get_proof.height, - path, - __marker: PhantomData, - }), - Path::NextConnectionSequence(path) => Data::from(IbcProof::<_, Hc, Tr> { - proof, - height: get_proof.height, - path, - __marker: PhantomData, - }), - Path::NextClientSequence(path) => Data::from(IbcProof::<_, Hc, Tr> { - proof, - height: get_proof.height, - path, - __marker: PhantomData, - }), - } -} - -pub async fn fetch_ibc_state( - c: &Hc, - FetchIbcState { path, height }: FetchIbcState, -) -> Data -where - Hc: ChainExt< - StoredClientState: Decode, - StoredConsensusState: Decode, - > + EthereumIbcChain - + EthereumChain - + EthereumConsensusChain, - Tr: ChainExt, -{ - let execution_height = c - .execution_height_of_beacon_slot(height.revision_height()) - .await; - - match path { - Path::ClientState(path) => Data::from(IbcState { - state: c - .ibc_handler() - .ibc_state_read::<_, Hc, Tr>(execution_height, path.clone()) - .await - .unwrap(), - height, - path, - }), - Path::ClientConsensusState(path) => Data::from(IbcState { - state: c - .ibc_handler() - .ibc_state_read::<_, Hc, Tr>(execution_height, path.clone()) - .await - .unwrap(), - height, - path, - }), - Path::Connection(path) => Data::from(IbcState { - state: c - .ibc_handler() - .ibc_state_read::<_, Hc, Tr>(execution_height, path.clone()) - .await - .unwrap(), - height, - path, - }), - Path::ChannelEnd(path) => Data::from(IbcState { - state: c - .ibc_handler() - .ibc_state_read::<_, Hc, Tr>(execution_height, path.clone()) - .await - .unwrap(), - height, - path, - }), - Path::Commitment(path) => Data::from(IbcState { - state: c - .ibc_handler() - .ibc_state_read::<_, Hc, Tr>(execution_height, path.clone()) - .await - .unwrap(), - height, - path, - }), - Path::Acknowledgement(path) => Data::from(IbcState { - state: c - .ibc_handler() - .ibc_state_read::<_, Hc, Tr>(execution_height, path.clone()) - .await - .unwrap(), - height, - path, - }), - Path::Receipt(path) => Data::from(IbcState { - state: c - .ibc_handler() - .ibc_state_read::<_, Hc, Tr>(execution_height, path.clone()) - .await - .unwrap(), - height, - path, - }), - Path::NextSequenceSend(path) => { - let path_str = path.to_string(); - - let location = keccak256( - keccak256(path_str.as_bytes()) - .into_iter() - .chain(AbiEncode::encode(IBC_HANDLER_COMMITMENTS_SLOT)) - .collect::>(), - ); - - let state = c - .provider() - .get_storage_at( - ethers::types::H160::from(c.ibc_handler_address()), - location.into(), - Some(execution_height.into()), - ) - .await - .unwrap(); - - Data::from(IbcState:: { - state: AbiDecode::decode(state.0).unwrap(), - height, - path, - }) - } - Path::NextSequenceRecv(path) => Data::from(IbcState { - state: c - .ibc_handler() - .ibc_state_read::<_, Hc, Tr>(execution_height, path.clone()) - .await - .unwrap(), - height, - path, - }), - // REVIEW: Can we use ibc_handler().ibc_state_read() here? - Path::NextSequenceAck(path) => { - let path_str = path.to_string(); - - let location = keccak256( - keccak256(path_str.as_bytes()) - .into_iter() - .chain(AbiEncode::encode(IBC_HANDLER_COMMITMENTS_SLOT)) - .collect::>(), - ); - - let state = c - .provider() - .get_storage_at( - ethers::types::H160::from(c.ibc_handler_address()), - location.into(), - Some(execution_height.into()), - ) - .await - .unwrap(); - - Data::from(IbcState:: { - state: AbiDecode::decode(state.0).unwrap(), - height, - path, - }) - } - Path::NextConnectionSequence(path) => Data::from(IbcState { - state: c - .ibc_handler() - .ibc_state_read::<_, Hc, Tr>(execution_height, path.clone()) - .await - .unwrap(), - height, - path, - }), - Path::NextClientSequence(path) => Data::from(IbcState { - state: c - .ibc_handler() - .ibc_state_read::<_, Hc, Tr>(execution_height, path.clone()) - .await - .unwrap(), - height, - path, - }), - } -} - -#[queue_msg] -pub struct CreateUpdateData { - pub req: FetchUpdateHeaders, Tr>, - pub currently_trusted_slot: u64, - pub light_client_update: light_client_update::LightClientUpdate, - pub is_next: bool, -} - -#[queue_msg] -pub struct MakeCreateUpdatesData { - pub req: FetchUpdateHeaders, Tr>, -} - -#[queue_msg] -pub struct MakeCreateUpdatesFromLightClientUpdatesData { - pub req: FetchUpdateHeaders, Tr>, - pub trusted_height: Height, - pub finality_update: LightClientFinalityUpdate, -} - -#[queue_msg] -pub struct FetchLightClientUpdate { - pub period: u64, -} - -#[queue_msg] -pub struct FetchFinalityUpdate {} - -#[queue_msg] -pub struct FetchLightClientUpdates { - pub trusted_period: u64, - pub target_period: u64, -} - -#[queue_msg] -pub struct FetchBootstrap { - pub slot: u64, -} - -#[queue_msg] -pub struct FetchAccountUpdate { - pub slot: u64, -} - -#[queue_msg] -pub struct FetchBeaconGenesis {} - -#[queue_msg] -pub struct BootstrapData { - pub slot: u64, - pub bootstrap: LightClientBootstrap, -} - -#[queue_msg] -pub struct AccountUpdateData<#[cover] C: ChainSpec, #[cover] Tr: ChainExt> { - pub slot: u64, - pub update: AccountUpdate, -} - -#[queue_msg] -pub struct BeaconGenesisData<#[cover] C: ChainSpec, #[cover] Tr: ChainExt> { - pub genesis: GenesisData, -} - -try_from_relayer_msg! { - chain = Ethereum, - generics = (C: ChainSpec, Tr: ChainExt), - msgs = EthereumDataMsg( - FinalityUpdate(FinalityUpdate), - LightClientUpdates(LightClientUpdates), - LightClientUpdate(LightClientUpdate), - Bootstrap(BootstrapData), - AccountUpdate(AccountUpdateData), - BeaconGenesis(BeaconGenesisData), - ), -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum EthereumFetchMsg { - FetchFinalityUpdate(FetchFinalityUpdate), - FetchLightClientUpdates(FetchLightClientUpdates), - FetchLightClientUpdate(FetchLightClientUpdate), - FetchBootstrap(FetchBootstrap), - FetchAccountUpdate(FetchAccountUpdate), - FetchBeaconGenesis(FetchBeaconGenesis), - FetchGetProof(GetProof, Tr>), - FetchIbcState(FetchIbcState, Tr>), -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum EthereumDataMsg { - FinalityUpdate(FinalityUpdate), - LightClientUpdates(LightClientUpdates), - LightClientUpdate(LightClientUpdate), - Bootstrap(BootstrapData), - AccountUpdate(AccountUpdateData), - BeaconGenesis(BeaconGenesisData), -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum EthereumAggregateMsg { - CreateUpdate(CreateUpdateData), - MakeCreateUpdates(MakeCreateUpdatesData), - MakeCreateUpdatesFromLightClientUpdates(MakeCreateUpdatesFromLightClientUpdatesData), -} - -#[queue_msg] -pub struct FinalityUpdate { - pub finality_update: LightClientFinalityUpdate, -} - -#[queue_msg] -pub struct LightClientUpdates { - pub light_client_updates: Vec>, -} - -#[queue_msg] -pub struct LightClientUpdate { - pub update: light_client_update::LightClientUpdate, -} - -impl DoAggregate for Identified, Tr, EthereumAggregateMsg> -where - C: ChainSpec, - Tr: ChainExt>, - - Identified, Tr, AccountUpdateData>: IsAggregateData, - Identified, Tr, BootstrapData>: IsAggregateData, - Identified, Tr, BeaconGenesisData>: IsAggregateData, - Identified, Tr, FinalityUpdate>: IsAggregateData, - Identified, Tr, LightClientUpdates>: IsAggregateData, - Identified, Tr, LightClientUpdate>: IsAggregateData, - - AnyLightClientIdentified: From, Tr>)>, - AnyLightClientIdentified: From>)>, - AnyLightClientIdentified: From>)>, - - AnyLightClientIdentified: From, Tr>)>, - AnyLightClientIdentified: From, Tr>)>, -{ - fn do_aggregate( - Identified { - chain_id, - t: data, - __marker: _, - }: Self, - aggregated_data: VecDeque>, - ) -> Op { - match data { - EthereumAggregateMsg::CreateUpdate(msg) => { - do_aggregate(id(chain_id, msg), aggregated_data) - } - EthereumAggregateMsg::MakeCreateUpdates(msg) => { - do_aggregate(id(chain_id, msg), aggregated_data) - } - EthereumAggregateMsg::MakeCreateUpdatesFromLightClientUpdates(msg) => { - do_aggregate(id(chain_id, msg), aggregated_data) - } - } - } -} - -fn make_create_update( - req: FetchUpdateHeaders, Tr>, - chain_id: < as Chain>::SelfClientState as ClientState>::ChainId, - currently_trusted_slot: u64, - light_client_update: light_client_update::LightClientUpdate, - is_next: bool, -) -> Op -where - C: ChainSpec, - Tr: ChainExt, - AnyLightClientIdentified: From, Tr>)>, - AnyLightClientIdentified: From, Tr>)>, -{ - // When we fetch the update at this height, the `next_sync_committee` will - // be the current sync committee of the period that we want to update to. - let previous_period = u64::max( - 1, - light_client_update.attested_header.beacon.slot - / (C::SLOTS_PER_EPOCH::U64 * C::EPOCHS_PER_SYNC_COMMITTEE_PERIOD::U64), - ) - 1; - - aggregate( - [ - fetch(id::, Tr, _>( - chain_id, - Fetch::specific(FetchLightClientUpdate { - period: previous_period, - }), - )), - fetch(id::, Tr, _>( - chain_id, - Fetch::specific(FetchAccountUpdate { - slot: light_client_update.attested_header.beacon.slot, - }), - )), - fetch(id::, Tr, _>( - chain_id, - Fetch::specific(FetchBeaconGenesis {}), - )), - ], - [], - id( - chain_id, - Aggregate::specific(CreateUpdateData { - req, - currently_trusted_slot, - light_client_update, - is_next, - }), - ), - ) -} - -// REVIEW: Does this function exist anywhere else? -fn sync_committee_period, C: ChainSpec>(height: H) -> u64 { - height.into().div(C::PERIOD::U64) -} - -#[derive(Debug, thiserror::Error)] -pub enum TxSubmitError { - #[error(transparent)] - Contract(#[from] ContractError), - #[error(transparent)] - Provider(#[from] ProviderError), - #[error("no tx receipt from tx")] - NoTxReceipt, - #[error("invalid revert code: {0}")] - InvalidRevert(Bytes), - #[error("out of gas")] - OutOfGas, - #[error("0x revert")] - EmptyRevert, - #[error("gas price is too high: max {max}, price {price}")] - GasPriceTooHigh { max: U256, price: U256 }, -} - -impl MaybeRecoverableError for TxSubmitError { - fn is_recoverable(&self) -> bool { - // TODO: Figure out if any failures are unrecoverable - true - } -} - -pub fn mk_function_call( - ibc_handler: &IBCHandler, - data: Call, -) -> ethers::contract::FunctionCall, M, ()> { - ibc_handler - .method_hash(::selector(), data) - .expect("method selector is generated; qed;") -} - -pub trait EthereumChainExt = - ChainExt + chain_utils::ethereum::EthereumIbcChainExt + chain_utils::ethereum::EthereumChain; - -#[queue_msg] -pub struct GetProof { - pub path: Path, HeightOf>, - pub height: HeightOf, -} - -#[queue_msg] -pub struct FetchIbcState { - pub path: Path, HeightOf>, - pub height: HeightOf, -} - -impl UseAggregate for Identified, Tr, CreateUpdateData> -where - C: ChainSpec, - Tr: ChainExt, - - Identified, Tr, AccountUpdateData>: IsAggregateData, - Identified, Tr, LightClientUpdate>: IsAggregateData, - Identified, Tr, BeaconGenesisData>: IsAggregateData, - - AnyLightClientIdentified: From>)>, - AnyLightClientIdentified: From>)>, -{ - type AggregatedData = HList![ - Identified, Tr, LightClientUpdate>, - Identified, Tr, AccountUpdateData>, - Identified, Tr, BeaconGenesisData> - ]; - - fn aggregate( - Identified { - chain_id, - t: - CreateUpdateData { - req, - currently_trusted_slot, - light_client_update, - is_next, - }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: light_client_update_chain_id, - t: LightClientUpdate { - update: light_client_update::LightClientUpdate { - next_sync_committee, - .. - }, - __marker: _, - }, - __marker: _, - }, - Identified { - chain_id: account_update_chain_id, - t: AccountUpdateData { - slot: _account_update_data_beacon_slot, - // ibc_handler_address, - update: account_update, - __marker, - }, - __marker: _, - }, - Identified { - chain_id: beacon_api_chain_id, - t: BeaconGenesisData { - genesis, - __marker: _, - }, - __marker: _, - } - ]: Self::AggregatedData, - ) -> Op { - assert_eq!(light_client_update_chain_id, account_update_chain_id); - assert_eq!(chain_id, account_update_chain_id); - assert_eq!(chain_id, beacon_api_chain_id); - - let header = ethereum::header::Header { - consensus_update: light_client_update, - trusted_sync_committee: TrustedSyncCommittee { - trusted_height: Height { - revision_number: ETHEREUM_REVISION_NUMBER, - revision_height: currently_trusted_slot, - }, - sync_committee: if is_next { - ActiveSyncCommittee::Next(next_sync_committee.unwrap()) - } else { - ActiveSyncCommittee::Current(next_sync_committee.unwrap()) - }, - }, - account_update, - }; - - seq([ - void(wait(id( - req.counterparty_chain_id.clone(), - WaitForTimestamp { - timestamp: (genesis.genesis_time - + (header.consensus_update.signature_slot * C::SECONDS_PER_SLOT::U64)) - .try_into() - .unwrap(), - __marker: PhantomData, - }, - ))), - effect(id::, _>( - req.counterparty_chain_id, - MsgUpdateClientData(MsgUpdateClient { - client_id: req.counterparty_client_id, - client_message: header, - }), - )), - ]) - } -} - -impl UseAggregate for Identified, Tr, MakeCreateUpdatesData> -where - C: ChainSpec, - Tr: ChainExt, - - Identified, Tr, FinalityUpdate>: IsAggregateData, - - AnyLightClientIdentified: From, Tr>)>, - AnyLightClientIdentified: From, Tr>)>, -{ - type AggregatedData = HList![Identified, Tr, FinalityUpdate>]; - - fn aggregate( - Identified { - chain_id, - t: MakeCreateUpdatesData { req }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: bootstrap_chain_id, - t: FinalityUpdate { - finality_update, - __marker: _ - }, - __marker: _, - },]: Self::AggregatedData, - ) -> Op { - assert_eq!(chain_id, bootstrap_chain_id); - - let target_period = - sync_committee_period::<_, C>(finality_update.attested_header.beacon.slot); - - let trusted_period = sync_committee_period::<_, C>(req.update_from.revision_height); - - assert!( - trusted_period <= target_period, - "trusted period {trusted_period} is behind target period {target_period}, something is wrong!", - ); - - // Eth chain is more than 1 signature period ahead of us. We need to do sync committee - // updates until we reach the `target_period - 1`. - aggregate( - [fetch(id::, Tr, _>( - chain_id, - Fetch::specific(FetchLightClientUpdates { - trusted_period, - target_period, - }), - ))], - [], - id( - chain_id, - Aggregate::specific(MakeCreateUpdatesFromLightClientUpdatesData { - req: req.clone(), - trusted_height: req.update_from, - finality_update, - }), - ), - ) - } -} - -impl UseAggregate - for Identified, Tr, MakeCreateUpdatesFromLightClientUpdatesData> -where - C: ChainSpec, - Tr: ChainExt>, - - Identified, Tr, LightClientUpdates>: IsAggregateData, - - AnyLightClientIdentified: From>)>, - AnyLightClientIdentified: From>)>, - AnyLightClientIdentified: From, Tr>)>, - AnyLightClientIdentified: From, Tr>)>, - AnyLightClientIdentified: From, Tr>)>, - // Identified, Tr, LightClientUpdates>: - // TryFrom>, -{ - type AggregatedData = HList![Identified, Tr, LightClientUpdates>]; - - fn aggregate( - Identified { - chain_id, - t: - MakeCreateUpdatesFromLightClientUpdatesData { - req, - trusted_height, - finality_update, - }, - __marker, - }: Self, - hlist_pat![Identified { - chain_id: light_client_updates_chain_id, - t: LightClientUpdates { - light_client_updates, - __marker: _, - }, - __marker: _, - },]: Self::AggregatedData, - ) -> Op { - assert_eq!(chain_id, light_client_updates_chain_id); - - let target_period = sync_committee_period::<_, C>(finality_update.signature_slot); - - let trusted_period = sync_committee_period::<_, C>(req.update_from.revision_height); - - let (updates, last_update_block_number) = light_client_updates.into_iter().fold( - (VecDeque::new(), trusted_height.revision_height), - |(mut vec, mut trusted_slot), update| { - let old_trusted_slot = trusted_slot; - - // REVIEW: Assert that this is greater (i.e. increasing)? - trusted_slot = update.attested_header.beacon.slot; - - vec.push_back(make_create_update::( - req.clone(), - chain_id, - old_trusted_slot, - update, - true, - )); - - (vec, trusted_slot) - }, - ); - - let lc_updates = if trusted_period < target_period { - updates - } else { - [].into() - }; - - let does_not_have_finality_update = - last_update_block_number >= req.update_to.revision_height; - - debug!(last_update_block_number, req.update_to.revision_height); - - let finality_update_msg = if does_not_have_finality_update { - // do nothing - None - } else { - // do finality update - Some(make_create_update( - req.clone(), - chain_id, - last_update_block_number, - light_client_update::LightClientUpdate { - attested_header: finality_update.attested_header, - next_sync_committee: None, - next_sync_committee_branch: None, - finalized_header: finality_update.finalized_header, - finality_branch: finality_update.finality_branch, - sync_aggregate: finality_update.sync_aggregate, - signature_slot: finality_update.signature_slot, - }, - false, - )) - }; - - seq(lc_updates.into_iter().chain(finality_update_msg)) - } -} diff --git a/lib/relay-message/src/chain/scroll.rs b/lib/relay-message/src/chain/scroll.rs deleted file mode 100644 index f98909ae89..0000000000 --- a/lib/relay-message/src/chain/scroll.rs +++ /dev/null @@ -1,782 +0,0 @@ -use std::{collections::VecDeque, marker::PhantomData}; - -use chain_utils::{ - ethereum::{EthereumConsensusChain, EthereumIbcChain, EthereumIbcChainExt, IbcHandlerExt}, - scroll::Scroll, -}; -use ethers::{abi::AbiDecode, providers::Middleware}; -use frunk::{hlist_pat, HList}; -use queue_msg::{ - aggregate, - aggregation::{do_aggregate, UseAggregate}, - data, effect, fetch, queue_msg, Op, -}; -use scroll_codec::{FinalizeBundle, FinalizeBundleWithProof}; -use unionlabs::{ - encoding::{Decode, Encode, EthAbi}, - hash::{H160, H256}, - ibc::{ - core::client::msg_update_client::MsgUpdateClient, - lightclients::{ - ethereum::{account_proof::AccountProof, storage_proof::StorageProof}, - scroll, - }, - }, - ics24::ClientStatePath, - never::Never, - traits::{Chain, ClientStateOf, HeightOf, IbcStateEncodingOf}, - uint::U256, -}; - -use super::ethereum::do_msg_fixed_gas; -use crate::{ - aggregate::{Aggregate, AnyAggregate}, - chain::ethereum::{ - fetch_get_proof, fetch_ibc_state, EthereumConfig, FetchIbcState, GetProof, TxSubmitError, - }, - data::{AnyData, Data}, - effect::{AnyEffect, Effect, MsgUpdateClientData}, - fetch::{AnyFetch, DoFetch, Fetch, FetchUpdateHeaders}, - id, identified, - use_aggregate::IsAggregateData, - AnyLightClientIdentified, ChainExt, DoAggregate, DoFetchProof, DoFetchState, - DoFetchUpdateHeaders, DoMsg, Identified, PathOf, RelayMessage, -}; - -impl ChainExt for Scroll { - type Data = ScrollData; - type Fetch = ScrollFetch; - type Aggregate = ScrollAggregate; - - type MsgError = TxSubmitError; - - type Config = EthereumConfig; -} - -impl DoMsg for Scroll -where - ClientStateOf: Encode, - Tr: ChainExt< - SelfConsensusState: Encode, - SelfClientState: Encode, - Header: Encode, - StoredClientState: Encode, - StateProof: Encode, - >, - AnyLightClientIdentified: From)>, -{ - async fn msg(&self, msg: Effect) -> Result, Self::MsgError> { - do_msg_fixed_gas( - self.chain_id(), - self.multicall_address, - &self.keyring, - msg, - false, - Some(5_000_000.into()), - None, - ) - .await - } -} - -impl DoFetchProof for Scroll -where - AnyLightClientIdentified: From)>, -{ - fn proof(c: &Self, at: HeightOf, path: PathOf) -> Op { - fetch(id::( - c.chain_id(), - Fetch::::specific(GetProof { path, height: at }), - )) - } -} - -// REVIEW: This can probably be generic over Hc: EthereumChain, instead of being duplicated between ethereum and scroll -impl DoFetchState for Scroll -where - Tr: ChainExt> + Encode>, - - AnyLightClientIdentified: From)>, -{ - type QueryUnfinalizedTrustedClientStateError = Never; - - fn state(hc: &Self, at: HeightOf, path: PathOf) -> Op { - fetch(id::( - hc.chain_id(), - Fetch::::specific(FetchIbcState { path, height: at }), - )) - } - - async fn query_unfinalized_trusted_client_state( - hc: &Self, - client_id: Self::ClientId, - ) -> Result, Self::QueryUnfinalizedTrustedClientStateError> { - let latest_execution_height = hc.provider.get_block_number().await.unwrap().as_u64(); - - Ok(hc - .ibc_handler() - .ibc_state_read::<_, Self, Tr>(latest_execution_height, ClientStatePath { client_id }) - .await - .unwrap()) - } -} - -impl DoFetchUpdateHeaders for Scroll -where - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - Tr: ChainExt, -{ - fn fetch_update_headers( - c: &Self, - update_info: FetchUpdateHeaders, - ) -> Op { - // - scroll rollup contract root proof - // - scroll latest batch index proof against rollup contract - // - scroll finalized root at batch index against rollup contract - // - ibc contract root against finalized root on L2 - // - commitBatch calldata and popped messages to verify timestamp - - aggregate( - [ - fetch(id( - c.chain_id(), - Fetch::specific(FetchRollupContractRootProof { - height: update_info.update_to, - rollup_contract_address: c.rollup_contract_address, - }), - )), - fetch(id( - c.chain_id(), - Fetch::specific(FetchLatestBatchIndexProof { - height: update_info.update_to, - latest_batch_index_slot: c.rollup_last_finalized_batch_index_slot, - rollup_contract_address: c.rollup_contract_address, - }), - )), - fetch(id( - c.chain_id(), - Fetch::specific(FetchScrollFinalizedRootProof { - height: update_info.update_to, - finalized_root_slot: c.rollup_finalized_state_roots_slot, - rollup_contract_address: c.rollup_contract_address, - }), - )), - fetch(id( - c.chain_id(), - Fetch::specific(FetchIbcContractRootProof { - height: update_info.update_to, - ibc_contract_address: c.ibc_handler_address, - }), - )), - fetch(id( - c.chain_id(), - Fetch::specific(FetchBatchHashProof { - height: update_info.update_to, - committed_batches_slot: c.rollup_committed_batches_slot, - rollup_contract_address: c.rollup_contract_address, - }), - )), - fetch(id( - c.chain_id(), - Fetch::specific(FetchFinalizeBatchTransactionInput { - height: update_info.update_to, - rollup_contract_address: c.rollup_contract_address, - }), - )), - ], - [], - id( - c.chain_id(), - Aggregate::::specific(AggregateHeader { req: update_info }), - ), - ) - } -} - -impl DoFetch for ScrollFetch -where - AnyLightClientIdentified: From)>, - Tr: ChainExt< - SelfClientState: Decode>, - SelfConsensusState: Decode> + Encode, - >, -{ - type Error = Never; - - async fn do_fetch(scroll: &Scroll, msg: Self) -> Result, Self::Error> { - let msg = match msg { - Self::FetchGetProof(get_proof) => fetch_get_proof(scroll, get_proof).await, - Self::FetchIbcState(ibc_state) => fetch_ibc_state(scroll, ibc_state).await, - Self::FetchRollupContractRootProof(FetchRollupContractRootProof { - height, - rollup_contract_address, - }) => { - let account_proof = scroll - .l1 - .provider() - .get_proof( - ethers::types::H160::from(rollup_contract_address), - vec![], - Some(ethers::types::BlockId::Number( - scroll - .l1 - .execution_height_of_beacon_slot(height.revision_height) - .await - .into(), - )), - ) - .await - .unwrap(); - - Data::specific(RollupContractRootProof { - height, - proof: AccountProof { - storage_root: account_proof.storage_hash.into(), - proof: account_proof - .account_proof - .into_iter() - .map(|x| x.to_vec()) - .collect(), - }, - __marker: PhantomData, - }) - } - Self::FetchLatestBatchIndexProof(FetchLatestBatchIndexProof { - height, - latest_batch_index_slot, - rollup_contract_address, - }) => { - let latest_batch_index_proof = scroll - .l1 - .provider - .get_proof( - ethers::types::H160::from(rollup_contract_address), - vec![H256(latest_batch_index_slot.to_be_bytes()).into()], - Some(ethers::types::BlockId::Number( - scroll - .l1 - .execution_height_of_beacon_slot(height.revision_height) - .await - .into(), - )), - ) - .await - .unwrap(); - - let proof = match <[_; 1]>::try_from(latest_batch_index_proof.storage_proof) { - Ok([proof]) => proof, - Err(invalid) => { - panic!("received invalid response from eth_getProof, expected length of 1 but got `{invalid:#?}`"); - } - }; - - Data::specific(LatestBatchIndexProof { - height, - proof: StorageProof { - key: U256::from_be_bytes(proof.key.to_fixed_bytes()), - value: proof.value.into(), - proof: proof - .proof - .into_iter() - .map(|bytes| bytes.to_vec()) - .collect(), - }, - __marker: PhantomData, - }) - } - Self::FetchScrollFinalizedRootProof(FetchScrollFinalizedRootProof { - height, - finalized_root_slot, - rollup_contract_address, - }) => { - let batch_index = scroll - .batch_index_of_beacon_slot(height.revision_height) - .await; - - let batch_hash_proof = scroll - .l1 - .provider - .get_proof( - ethers::types::H160::from(rollup_contract_address), - vec![H256( - scroll_verifier::mapping_index_to_slot_key( - finalized_root_slot, - batch_index.into(), - ) - .to_be_bytes(), - ) - .into()], - Some(ethers::types::BlockId::Number( - scroll - .l1 - .execution_height_of_beacon_slot(height.revision_height) - .await - .into(), - )), - ) - .await - .unwrap(); - - let proof = match <[_; 1]>::try_from(batch_hash_proof.storage_proof) { - Ok([proof]) => proof, - Err(invalid) => { - panic!("received invalid response from eth_getProof, expected length of 1 but got `{invalid:#?}`"); - } - }; - - Data::specific(ScrollFinalizedRootProof { - height, - batch_index, - proof: StorageProof { - key: U256::from_be_bytes(proof.key.to_fixed_bytes()), - value: proof.value.into(), - proof: proof - .proof - .into_iter() - .map(|bytes| bytes.to_vec()) - .collect(), - }, - __marker: PhantomData, - }) - } - Self::FetchIbcContractRootProof(FetchIbcContractRootProof { - height, - ibc_contract_address, - }) => { - let batch_index = scroll - .batch_index_of_beacon_slot(height.revision_height) - .await; - - let batch = scroll.scroll_api_client.batch(batch_index).await; - - let proof = scroll - .scroll_rpc - .get_proof( - ibc_contract_address, - [], - scroll_rpc::BlockId::Number(batch.batch.end_block_number), - ) - .await - .unwrap(); - - Data::specific(IbcContractRootProof { - height, - proof: AccountProof { - storage_root: proof.storage_hash, - proof: proof - .account_proof - .into_iter() - .map(|x| x.to_vec()) - .collect(), - }, - __marker: PhantomData, - }) - } - Self::FetchBatchHashProof(FetchBatchHashProof { - height, - committed_batches_slot, - rollup_contract_address, - }) => { - let batch_index = scroll - .batch_index_of_beacon_slot(height.revision_height) - .await; - - let batch_hash_proof = scroll - .l1 - .provider - .get_proof( - ethers::types::H160::from(rollup_contract_address), - vec![H256( - scroll_verifier::mapping_index_to_slot_key( - committed_batches_slot, - batch_index.into(), - ) - .to_be_bytes(), - ) - .into()], - Some(ethers::types::BlockId::Number( - scroll - .l1 - .execution_height_of_beacon_slot(height.revision_height) - .await - .into(), - )), - ) - .await - .unwrap(); - - let proof = match <[_; 1]>::try_from(batch_hash_proof.storage_proof) { - Ok([proof]) => proof, - Err(invalid) => { - panic!("received invalid response from eth_getProof, expected length of 1 but got `{invalid:#?}`"); - } - }; - - Data::specific(BatchHashProof { - height, - batch_index, - proof: StorageProof { - key: U256::from_be_bytes(proof.key.to_fixed_bytes()), - value: proof.value.into(), - proof: proof - .proof - .into_iter() - .map(|bytes| bytes.to_vec()) - .collect(), - }, - __marker: PhantomData, - }) - } - ScrollFetch::FetchFinalizeBatchTransactionInput( - FetchFinalizeBatchTransactionInput { - height, - // TODO: This needs to be passed to `scroll_codec::fetch_l1_message_hashes` - rollup_contract_address: _, - }, - ) => { - let batch_index = scroll - .batch_index_of_beacon_slot(height.revision_height) - .await; - - let batch = scroll.scroll_api_client.batch(batch_index).await; - - let finalize_batch_tx = scroll - .l1 - .provider - .get_transaction( - batch - .batch - .finalize_tx_hash - .expect("batch must be finalized"), - ) - .await - .unwrap() - .unwrap(); - - let calldata = finalize_batch_tx.input.to_vec(); - - let batch_header = ::decode(&calldata) - .map(|call| call.batch_header) - .or_else(|_| { - ::decode(&calldata) - .map(|call| call.batch_header) - }) - .unwrap() - .to_vec(); - - Data::specific(FinalizeBatchTransactionInput { - height, - batch_index, - batch_header, - __marker: PhantomData, - }) - } - }; - - Ok(data(id::(scroll.chain_id, msg))) - } -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum ScrollFetch { - FetchGetProof(GetProof), - FetchIbcState(FetchIbcState), - - // - scroll rollup contract root proof - FetchRollupContractRootProof(FetchRollupContractRootProof), - // - scroll latest batch index proof against rollup contract - FetchLatestBatchIndexProof(FetchLatestBatchIndexProof), - // - scroll finalized root at batch index against rollup contract - FetchScrollFinalizedRootProof(FetchScrollFinalizedRootProof), - // - ibc contract root against finalized root on L2 - FetchIbcContractRootProof(FetchIbcContractRootProof), - FetchBatchHashProof(FetchBatchHashProof), - FetchFinalizeBatchTransactionInput(FetchFinalizeBatchTransactionInput), -} - -#[queue_msg] -pub struct FetchRollupContractRootProof { - // the height to update to - pub height: HeightOf, - pub rollup_contract_address: H160, -} - -#[queue_msg] -pub struct FetchLatestBatchIndexProof { - // the height to update to - pub height: HeightOf, - pub latest_batch_index_slot: U256, - pub rollup_contract_address: H160, -} - -#[queue_msg] -pub struct FetchBatchHashProof { - pub height: HeightOf, - pub committed_batches_slot: U256, - pub rollup_contract_address: H160, -} - -#[queue_msg] -pub struct FetchScrollFinalizedRootProof { - // the height to update to - pub height: HeightOf, - pub finalized_root_slot: U256, - pub rollup_contract_address: H160, -} - -#[queue_msg] -pub struct FetchFinalizeBatchTransactionInput { - // the height to update to - pub height: HeightOf, - pub rollup_contract_address: H160, -} - -#[queue_msg] -pub struct FetchIbcContractRootProof { - // the height to update to - pub height: HeightOf, - pub ibc_contract_address: H160, -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum ScrollData { - RollupContractRootProof(RollupContractRootProof), - LatestBatchIndexProof(LatestBatchIndexProof), - ScrollFinalizedRootProof(ScrollFinalizedRootProof), - IbcContractRootProof(IbcContractRootProof), - BatchHashProof(BatchHashProof), - FinalizeBatchTransactionInput(FinalizeBatchTransactionInput), -} - -try_from_relayer_msg! { - chain = Scroll, - generics = (Tr: ChainExt), - msgs = ScrollData( - RollupContractRootProof(RollupContractRootProof), - LatestBatchIndexProof(LatestBatchIndexProof), - ScrollFinalizedRootProof(ScrollFinalizedRootProof), - IbcContractRootProof(IbcContractRootProof), - BatchHashProof(BatchHashProof), - FinalizeBatchTransactionInput(FinalizeBatchTransactionInput), - ), -} - -#[queue_msg] -pub struct RollupContractRootProof<#[cover] Tr: ChainExt> { - pub height: HeightOf, - pub proof: AccountProof, -} - -#[queue_msg] -pub struct LatestBatchIndexProof<#[cover] Tr: ChainExt> { - pub height: HeightOf, - pub proof: StorageProof, -} - -#[queue_msg] -pub struct BatchHashProof<#[cover] Tr: ChainExt> { - pub height: HeightOf, - pub batch_index: u64, - pub proof: StorageProof, -} - -#[queue_msg] -pub struct ScrollFinalizedRootProof<#[cover] Tr: ChainExt> { - pub height: HeightOf, - pub batch_index: u64, - pub proof: StorageProof, -} - -#[queue_msg] -pub struct IbcContractRootProof<#[cover] Tr: ChainExt> { - pub height: HeightOf, - pub proof: AccountProof, -} - -#[queue_msg] -pub struct FinalizeBatchTransactionInput<#[cover] Tr: ChainExt> { - pub height: HeightOf, - pub batch_index: u64, - #[serde(with = "::serde_utils::hex_string")] - #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] - pub batch_header: Vec, -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum ScrollAggregate { - AggregateHeader(AggregateHeader), -} - -#[queue_msg] -pub struct AggregateHeader { - pub req: FetchUpdateHeaders, -} - -impl DoAggregate for Identified> -where - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - fn do_aggregate( - Identified { - chain_id, - t, - __marker, - }: Self, - data: VecDeque>, - ) -> Op { - match t { - ScrollAggregate::AggregateHeader(msg) => do_aggregate(id(chain_id, msg), data), - } - } -} - -impl UseAggregate for Identified> -where - Tr: ChainExt, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - Identified>, - Identified>, - Identified>, - Identified>, - Identified>, - Identified>, - ]; - - fn aggregate( - Identified { - chain_id, - t: AggregateHeader { req }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: rollup_contract_root_proof_chain_id, - t: RollupContractRootProof { - height: rollup_contract_root_proof_height, - proof: rollup_contract_root_proof, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: latest_batch_index_proof_chain_id, - t: LatestBatchIndexProof { - height: latest_batch_index_proof_height, - proof: latest_batch_index_proof, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: scroll_finalized_root_proof_chain_id, - t: ScrollFinalizedRootProof { - height: scroll_finalized_root_proof_height, - batch_index: scroll_finalized_root_proof_batch_index, - proof: scroll_finalized_root_proof, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: ibc_contract_root_proof_chain_id, - t: IbcContractRootProof { - height: ibc_contract_root_proof_height, - proof: ibc_contract_account_proof, - __marker: _ - }, - __marker: _, - }, - Identified { - chain_id: batch_hash_proof_chain_id, - t: BatchHashProof { - height: batch_hash_proof_height, - batch_index: batch_hash_proof_batch_index, - proof: batch_hash_proof, - __marker: _, - }, - __marker: _, - }, - Identified { - chain_id: finalize_batch_transaction_input_chain_id, - t: FinalizeBatchTransactionInput { - height: finalize_batch_transaction_input_height, - batch_index: finalize_batch_transaction_input_batch_index, - batch_header, - __marker, - }, - __marker: _, - } - ]: Self::AggregatedData, - ) -> Op { - assert_eq!(rollup_contract_root_proof_chain_id, chain_id); - assert_eq!(latest_batch_index_proof_chain_id, chain_id); - assert_eq!(scroll_finalized_root_proof_chain_id, chain_id); - assert_eq!(ibc_contract_root_proof_chain_id, chain_id); - assert_eq!(batch_hash_proof_chain_id, chain_id); - assert_eq!(finalize_batch_transaction_input_chain_id, chain_id); - - assert_eq!( - rollup_contract_root_proof_height, - latest_batch_index_proof_height - ); - assert_eq!( - rollup_contract_root_proof_height, - scroll_finalized_root_proof_height - ); - assert_eq!( - rollup_contract_root_proof_height, - ibc_contract_root_proof_height - ); - assert_eq!(rollup_contract_root_proof_height, batch_hash_proof_height); - assert_eq!( - rollup_contract_root_proof_height, - finalize_batch_transaction_input_height - ); - - assert_eq!( - scroll_finalized_root_proof_batch_index, - batch_hash_proof_batch_index - ); - assert_eq!( - scroll_finalized_root_proof_batch_index, - finalize_batch_transaction_input_batch_index - ); - - effect(id::( - req.counterparty_chain_id, - MsgUpdateClientData(MsgUpdateClient { - client_id: req.counterparty_client_id, - client_message: scroll::header::Header { - l1_height: req.update_to, - l1_account_proof: rollup_contract_root_proof, - l2_state_root_proof: scroll_finalized_root_proof, - last_batch_index_proof: latest_batch_index_proof, - l2_ibc_account_proof: ibc_contract_account_proof, - batch_hash_proof, - batch_header, - }, - }), - )) - } -} diff --git a/lib/relay-message/src/chain/union.rs b/lib/relay-message/src/chain/union.rs deleted file mode 100644 index d69eb4ed0c..0000000000 --- a/lib/relay-message/src/chain/union.rs +++ /dev/null @@ -1,640 +0,0 @@ -use std::{ - collections::{HashMap, VecDeque}, - fmt::Debug, - marker::PhantomData, -}; - -use chain_utils::{ - cosmos_sdk::{BroadcastTxCommitError, CosmosSdkChain}, - union::Union, - wasm::Wraps, -}; -use frame_support_procedural::{CloneNoBound, PartialEqNoBound}; -use frunk::{hlist_pat, HList}; -use num_bigint::BigUint; -use protos::union::galois::api::v3::union_prover_api_client; -use queue_msg::{ - aggregate, - aggregation::{do_aggregate, UseAggregate}, - data, defer_relative, effect, fetch, queue_msg, wait, Op, -}; -use tracing::{debug, error, info, instrument, trace}; -use unionlabs::{ - bounded::BoundedI64, - cometbls::types::canonical_vote::CanonicalVote, - encoding::{Decode, Encode, Proto}, - google::protobuf::any::IntoAny, - ibc::{ - core::client::{height::IsHeight, msg_update_client::MsgUpdateClient}, - lightclients::cometbls, - }, - ics24::ClientStatePath, - tendermint::{ - crypto::public_key::PublicKey, - types::{ - canonical_block_header::CanonicalPartSetHeader, canonical_block_id::CanonicalBlockId, - commit_sig::CommitSig, signed_header::SignedHeader, signed_msg_type::SignedMsgType, - simple_validator::SimpleValidator, - }, - }, - traits::Chain, - union::galois::{ - poll_request::PollRequest, - poll_response::{PollResponse, ProveRequestDone, ProveRequestFailed}, - prove_request::ProveRequest, - prove_response, - validator_set_commit::ValidatorSetCommit, - }, - TypeUrl, -}; - -use crate::{ - aggregate::{Aggregate, AnyAggregate}, - chain::cosmos_sdk::{ - data::{TrustedValidators, UntrustedCommit, UntrustedValidators}, - do_msg, - fetch::{ - fetch_trusted_validators, fetch_untrusted_commit, fetch_untrusted_validators, - FetchAbciQuery, FetchTrustedValidators, FetchUntrustedCommit, FetchUntrustedValidators, - }, - fetch_abci_query, CosmosSdkChainSealed, FetchAbciQueryError, - }, - data::{AnyData, Data, IbcState}, - effect::{AnyEffect, Effect, MsgUpdateClientData}, - fetch::{AnyFetch, DoFetch, Fetch, FetchUpdateHeaders}, - id, identified, seq, - use_aggregate::IsAggregateData, - wait::{AnyWait, Wait, WaitForHeight}, - AnyLightClientIdentified, ChainExt, DoAggregate, DoFetchUpdateHeaders, DoMsg, Identified, - RelayMessage, -}; - -impl ChainExt for Union { - type Data = UnionDataMsg; - type Fetch = UnionFetch; - type Aggregate = UnionAggregateMsg; - - type MsgError = BroadcastTxCommitError; - - type Config = (); -} - -impl CosmosSdkChainSealed for Union {} - -impl DoMsg for Union -where - Tr: ChainExt< - SelfConsensusState: Encode + TypeUrl, - SelfClientState: Encode + TypeUrl, - Header: Encode + TypeUrl, - StoredClientState: IntoAny, - StateProof: Encode, - >, - AnyLightClientIdentified: From)>, -{ - async fn msg( - &self, - msg: Effect, - ) -> Result, BroadcastTxCommitError> { - do_msg( - self, - msg, - |(), client_state, consensus_state| { - ( - client_state.into_any().into(), - consensus_state.into_any().into(), - ) - }, - |client_message| client_message.into_any().into(), - ) - .await - } -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum UnionDataMsg { - UntrustedCommit(UntrustedCommit), - TrustedValidators(TrustedValidators), - UntrustedValidators(UntrustedValidators), - ProveResponse(ProveResponse), -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum UnionFetch { - FetchUntrustedCommit(FetchUntrustedCommit), - FetchTrustedValidators(FetchTrustedValidators), - FetchUntrustedValidators(FetchUntrustedValidators), - FetchProveRequest(FetchProveRequest), - AbciQuery(FetchAbciQuery), -} - -impl DoFetch for UnionFetch -where - Hc: Wraps - + CosmosSdkChainSealed< - StateProof = unionlabs::union::ics23::merkle_proof::MerkleProof, - StoredClientState: Decode< - Proto, - Error: Debug + Clone + PartialEq + std::error::Error, - >, - StoredConsensusState: Decode< - Proto, - Error: Debug + Clone + PartialEq + std::error::Error, - >, - Data = UnionDataMsg, - Fetch = UnionFetch, - >, - Tr: ChainExt, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - - Identified, Hc, Tr>>: IsAggregateData, -{ - type Error = UnionDoFetchError; - - async fn do_fetch(hc: &Hc, msg: Self) -> Result, Self::Error> { - Ok(match msg { - Self::FetchUntrustedCommit(FetchUntrustedCommit { - height, - __marker: _, - }) => fetch_untrusted_commit(hc, height).await, - Self::FetchTrustedValidators(FetchTrustedValidators { - height, - __marker: _, - }) => fetch_trusted_validators(hc, height).await, - Self::FetchUntrustedValidators(FetchUntrustedValidators { - height, - __marker: _, - }) => fetch_untrusted_validators(hc, height).await, - Self::FetchProveRequest(FetchProveRequest { request }) => { - fetch_prove_request::(hc, request).await - } - Self::AbciQuery(FetchAbciQuery { path, height, ty }) => { - fetch_abci_query::(hc, path, height, ty).await? - } - }) - } -} - -#[derive(macros::Debug, PartialEqNoBound, CloneNoBound, thiserror::Error)] -pub enum UnionDoFetchError -where - Hc: Chain< - StateProof: TryFrom, - StoredClientState: Decode, - StoredConsensusState: Decode< - Proto, - Error: Debug + Clone + PartialEq + std::error::Error, - >, - >, - Tr: Chain, -{ - #[error("error fetching abci query")] - FetchAbciQuery(#[from] FetchAbciQueryError), -} - -#[instrument( - skip_all, - fields(height = %request.vote.height) -)] -async fn fetch_prove_request(hc: &Hc, request: ProveRequest) -> Op -where - Hc: Wraps - + CosmosSdkChain - + ChainExt = UnionDataMsg, Fetch = UnionFetch>, - Tr: ChainExt, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - debug!("submitting prove request"); - - let prover_endpoint = - &hc.inner().prover_endpoints[usize::try_from(request.untrusted_header.height.inner()) - .expect("never going to happen bro") - % hc.inner().prover_endpoints.len()]; - - let response = union_prover_api_client::UnionProverApiClient::connect(prover_endpoint.clone()) - .await - .unwrap() - .poll(protos::union::galois::api::v3::PollRequest::from( - PollRequest { - request: request.clone(), - }, - )) - .await - .map(|x| x.into_inner().try_into().unwrap()); - - debug!("submitted prove request"); - - let retry = || { - debug!("proof pending"); - - seq([ - // REVIEW: How long should we wait between polls? - defer_relative(1), - fetch(id::( - hc.chain_id(), - Fetch::specific(FetchProveRequest { request }), - )), - ]) - }; - match response { - Ok(PollResponse::Pending) => retry(), - Err(status) if status.message() == "busy_building" => retry(), - Err(err) => panic!("prove request failed: {:?}", err), - Ok(PollResponse::Failed(ProveRequestFailed { message })) => { - error!(%message, "prove request failed"); - panic!() - } - Ok(PollResponse::Done(ProveRequestDone { response })) => { - info!(prover = %prover_endpoint, "proof generated"); - - data(id::( - hc.chain_id(), - Data::specific(ProveResponse { - prove_response: response, - __marker: PhantomData, - }), - )) - } - } -} - -impl DoFetchUpdateHeaders for Union -where - Tr: ChainExt, - Hc: ChainExt = UnionFetch, Aggregate = UnionAggregateMsg> - + Wraps, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - fn fetch_update_headers(hc: &Hc, update_info: FetchUpdateHeaders) -> Op { - seq([ - wait(id( - hc.chain_id(), - WaitForHeight { - height: update_info.update_to, - __marker: PhantomData, - }, - )), - aggregate( - [ - fetch(id::( - hc.chain_id(), - Fetch::specific(FetchUntrustedCommit { - height: update_info.update_to, - __marker: PhantomData, - }), - )), - fetch(id::( - hc.chain_id(), - Fetch::specific(FetchUntrustedValidators { - height: update_info.update_to, - __marker: PhantomData, - }), - )), - fetch(id::( - hc.chain_id(), - Fetch::specific(FetchTrustedValidators { - height: update_info.update_from.increment(), - __marker: PhantomData, - }), - )), - ], - [], - id( - hc.chain_id(), - Aggregate::specific(AggregateProveRequest { req: update_info }), - ), - ), - ]) - } -} - -#[queue_msg] -#[derive(enumorph::Enumorph)] -pub enum UnionAggregateMsg { - AggregateProveRequest(AggregateProveRequest), - AggregateHeader(AggregateHeader), -} - -impl DoAggregate for Identified> -where - Tr: ChainExt, - Hc: ChainExt, - - identified!(UntrustedCommit): IsAggregateData, - identified!(TrustedValidators): IsAggregateData, - identified!(UntrustedValidators): IsAggregateData, - - Identified>: IsAggregateData, - - identified!(AggregateProveRequest): UseAggregate, - identified!(AggregateHeader): UseAggregate, - - AnyLightClientIdentified: From)>, -{ - fn do_aggregate( - Identified { - chain_id, - t: data, - __marker: _, - }: Self, - aggregate_data: VecDeque>, - ) -> Op { - match data { - UnionAggregateMsg::AggregateProveRequest(data) => { - do_aggregate(id(chain_id, data), aggregate_data) - } - UnionAggregateMsg::AggregateHeader(data) => { - do_aggregate(id(chain_id, data), aggregate_data) - } - } - } -} - -try_from_relayer_msg! { - chain = Union, - generics = (Tr: ChainExt), - msgs = UnionDataMsg( - UntrustedCommit(UntrustedCommit), - TrustedValidators(TrustedValidators), - UntrustedValidators(UntrustedValidators), - ProveResponse(ProveResponse), - ), -} - -#[queue_msg] -pub struct ProveResponse<#[cover] Hc: ChainExt, #[cover] Tr: ChainExt> { - pub prove_response: prove_response::ProveResponse, -} - -#[queue_msg] -pub struct FetchProveRequest { - pub request: ProveRequest, -} - -#[queue_msg] -pub struct AggregateHeader { - pub signed_header: SignedHeader, - pub req: FetchUpdateHeaders, -} - -#[queue_msg] -pub struct AggregateProveRequest { - pub req: FetchUpdateHeaders, -} - -impl UseAggregate for Identified> -where - Hc: ChainExt = UnionFetch, Aggregate = UnionAggregateMsg>, - Tr: ChainExt, - - identified!(UntrustedCommit): IsAggregateData, - identified!(TrustedValidators): IsAggregateData, - identified!(UntrustedValidators): IsAggregateData, - - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![ - identified!(UntrustedCommit), - identified!(TrustedValidators), - identified!(UntrustedValidators), - ]; - - fn aggregate( - Identified { - chain_id, - t: AggregateProveRequest { req }, - __marker: _, - }: Self, - hlist_pat![ - Identified { - chain_id: untrusted_commit_chain_id, - t: UntrustedCommit { - height: untrusted_commit_height, - signed_header, - __marker: _, - }, - __marker: _, - }, - Identified { - chain_id: trusted_validators_chain_id, - t: TrustedValidators { - height: trusted_validators_height, - validators: trusted_validators, - __marker: _, - }, - __marker: _, - }, - Identified { - chain_id: untrusted_validators_chain_id, - t: UntrustedValidators { - height: untrusted_validators_height, - validators: untrusted_validators, - __marker: _, - }, - __marker: _, - }, - ]: Self::AggregatedData, - ) -> Op { - assert_eq!(untrusted_commit_chain_id, untrusted_validators_chain_id); - assert_eq!(chain_id, trusted_validators_chain_id); - assert_eq!(chain_id, untrusted_validators_chain_id); - - assert_eq!(req.update_from, trusted_validators_height.decrement()); - assert_eq!(untrusted_commit_height, untrusted_validators_height); - - let make_validators_commit = - |mut validators: Vec| { - // Validators must be sorted to match the root, by token then address - validators.sort_by(|a, b| { - // TODO: Double check how these comparisons are supposed to work - #[allow(clippy::collapsible_else_if)] - if a.voting_power == b.voting_power { - if a.address < b.address { - std::cmp::Ordering::Less - } else { - std::cmp::Ordering::Greater - } - } else { - if a.voting_power > b.voting_power { - std::cmp::Ordering::Less - } else { - std::cmp::Ordering::Greater - } - } - }); - - // The bitmap is a public input of the circuit, it must fit in Fr (scalar field) bn254 - let mut bitmap = BigUint::default(); - // REVIEW: This will over-allocate for the trusted validators; should be benchmarked - let mut signatures = Vec::>::with_capacity(validators.len()); - - let validators_map = validators - .iter() - .enumerate() - .map(|(i, v)| (v.address, i)) - .collect::>(); - - // For each validator signature, we search for the actual validator - // in the set and set it's signed bit to 1. We then push the - // signature only if the validator signed. It's possible that we - // don't find a validator for a given signature as the validator set - // may have drifted (trusted validator set). - for sig in signed_header.commit.signatures.iter() { - match sig { - CommitSig::Absent => { - debug!("validator did not sign"); - } - CommitSig::Commit { - validator_address, - timestamp: _, - signature, - } => { - if let Some(validator_index) = validators_map.get(validator_address) { - bitmap.set_bit(*validator_index as u64, true); - signatures.push(signature.clone()); - trace!( - %validator_address, - %validator_index, - "validator signed" - ); - } else { - trace!( - %validator_address, - "validator set drifted, could not find validator signature" - ); - } - } - CommitSig::Nil { - validator_address, .. - } => { - trace!( - %validator_address, - "validator commit is nil" - ); - } - } - } - - let simple_validators = validators - .iter() - .map(|v| { - let PublicKey::Bn254(ref key) = v.pub_key else { - panic!("must be bn254") - }; - SimpleValidator { - pub_key: PublicKey::Bn254(key.to_vec()), - voting_power: v.voting_power.into(), - } - }) - .collect::>(); - - ValidatorSetCommit { - validators: simple_validators, - signatures, - bitmap: bitmap.to_bytes_be(), - } - }; - - let trusted_validators_commit = make_validators_commit(trusted_validators); - let untrusted_validators_commit = make_validators_commit(untrusted_validators); - - aggregate( - [fetch(id::( - chain_id.clone(), - Fetch::specific(FetchProveRequest { - request: ProveRequest { - vote: CanonicalVote { - // REVIEW: Should this be hardcoded to precommit? - ty: SignedMsgType::Precommit, - height: signed_header.commit.height, - round: BoundedI64::new(signed_header.commit.round.inner().into()) - .expect("0..=i32::MAX can be converted to 0..=i64::MAX safely"), - block_id: CanonicalBlockId { - hash: signed_header.commit.block_id.hash.unwrap_or_default(), - part_set_header: CanonicalPartSetHeader { - total: signed_header.commit.block_id.part_set_header.total, - hash: signed_header - .commit - .block_id - .part_set_header - .hash - .unwrap_or_default(), - }, - }, - chain_id: signed_header.header.chain_id.clone(), - }, - untrusted_header: signed_header.header.clone(), - trusted_commit: trusted_validators_commit, - untrusted_commit: untrusted_validators_commit, - }, - }), - ))], - [], - id( - chain_id, - Aggregate::specific(AggregateHeader { signed_header, req }), - ), - ) - } -} - -impl UseAggregate for Identified> -where - Hc: ChainExt
::Header>, - Tr: ChainExt, - - Identified>: IsAggregateData, - - AnyLightClientIdentified: From)>, -{ - type AggregatedData = HList![Identified>]; - - fn aggregate( - Identified { - chain_id, - t: - AggregateHeader { - mut signed_header, - req, - }, - __marker: _, - }: Self, - hlist_pat![Identified { - chain_id: untrusted_commit_chain_id, - t: ProveResponse { - prove_response: response, - __marker: _ - }, - __marker: _, - }]: Self::AggregatedData, - ) -> Op { - assert_eq!(chain_id, untrusted_commit_chain_id); - - // TODO: maybe introduce a new commit for union signed header as we don't need the signatures but the ZKP only - // Keeping this signatures significantly increase the size of the structure and the associated gas cost in EVM (calldata). - signed_header.commit.signatures.clear(); - - effect(id::( - req.counterparty_chain_id, - MsgUpdateClientData(MsgUpdateClient { - client_id: req.counterparty_client_id.clone(), - client_message: cometbls::header::Header { - signed_header: signed_header.into(), - trusted_height: req.update_from.into(), - zero_knowledge_proof: response.proof.evm_proof, - }, - }), - )) - } -} diff --git a/lib/relay-message/src/data.rs b/lib/relay-message/src/data.rs deleted file mode 100644 index 1420faa0c7..0000000000 --- a/lib/relay-message/src/data.rs +++ /dev/null @@ -1,111 +0,0 @@ -use macros::apply; -use queue_msg::{data, queue_msg, HandleData, Op, QueueError, QueueMessage}; -use tracing::instrument; -use unionlabs::{ - ics24::{ - AcknowledgementPath, ChannelEndPath, ClientConsensusStatePath, ClientStatePath, - CommitmentPath, ConnectionPath, IbcPath, NextClientSequencePath, - NextConnectionSequencePath, NextSequenceAckPath, NextSequenceRecvPath, - NextSequenceSendPath, ReceiptPath, - }, - traits::{ClientStateOf, ConsensusStateOf, HeaderOf, HeightOf}, -}; - -use crate::{any_enum, AnyLightClientIdentified, ChainExt, RelayMessage}; - -#[apply(any_enum)] -/// Data that will likely be used in an [`Op::Aggregate`]. -#[any = AnyData] -#[specific = LightClientSpecificData] -pub enum Data { - SelfClientState(SelfClientState), - SelfConsensusState(SelfConsensusState), - - LatestHeight(LatestHeight), - UnfinalizedClientState(UnfinalizedTrustedClientState), - - // state - ClientState(IbcState, Hc, Tr>), - ClientConsensusState(IbcState, Hc, Tr>), - Connection(IbcState), - ChannelEnd(IbcState), - Commitment(IbcState), - Acknowledgement(IbcState), - Receipt(IbcState), - NextSequenceSend(IbcState), - NextSequenceRecv(IbcState), - NextSequenceAck(IbcState), - NextConnectionSequence(IbcState), - NextClientSequence(IbcState), - - // proof - ClientStateProof(IbcProof, Hc, Tr>), - ClientConsensusStateProof(IbcProof, Hc, Tr>), - ConnectionProof(IbcProof), - ChannelEndProof(IbcProof), - CommitmentProof(IbcProof), - AcknowledgementProof(IbcProof), - ReceiptProof(IbcProof), - NextSequenceSendProof(IbcProof), - NextSequenceRecvProof(IbcProof), - NextSequenceAckProof(IbcProof), - NextConnectionSequenceProof(IbcProof), - NextClientSequenceProof(IbcProof), - - #[serde(untagged)] - LightClientSpecific(LightClientSpecificData), -} - -// Passthrough since we don't want to handle any top-level data, just bubble it up to the top level. -impl HandleData for AnyLightClientIdentified { - #[instrument(skip_all, fields(chain_id = %self.chain_id()))] - fn handle( - self, - _: &::Store, - ) -> Result, QueueError> { - Ok(data(self)) - } -} - -#[queue_msg] -pub struct SelfClientState { - pub self_client_state: ClientStateOf, -} - -#[queue_msg] -pub struct SelfConsensusState { - pub self_consensus_state: ConsensusStateOf, -} - -#[queue_msg] -pub struct LatestHeight { - pub height: HeightOf, -} - -#[queue_msg] -pub struct UnfinalizedTrustedClientState { - pub height: HeightOf, - pub client_state: Hc::StoredClientState, -} - -#[queue_msg] -pub struct Header { - pub header: HeaderOf, -} - -#[queue_msg] -pub struct IbcState, Hc: ChainExt, Tr: ChainExt> { - pub path: P, - pub height: HeightOf, - pub state: P::Value, -} - -#[queue_msg] -pub struct IbcProof, Hc: ChainExt, #[cover] Tr: ChainExt> { - pub path: P, - pub height: HeightOf, - pub proof: Hc::StateProof, -} - -#[queue_msg] -pub struct LightClientSpecificData(pub Hc::Data); diff --git a/lib/relay-message/src/effect.rs b/lib/relay-message/src/effect.rs deleted file mode 100644 index accd621514..0000000000 --- a/lib/relay-message/src/effect.rs +++ /dev/null @@ -1,332 +0,0 @@ -use chain_utils::GetChain; -use futures::Future; -use macros::apply; -use queue_msg::{queue_msg, HandleEffect, Op, QueueError, QueueMessage}; -use tracing::{error, info, instrument}; -use unionlabs::{ - ibc::core::{ - channel::{ - msg_acknowledgement::MsgAcknowledgement, msg_channel_open_ack::MsgChannelOpenAck, - msg_channel_open_confirm::MsgChannelOpenConfirm, - msg_channel_open_init::MsgChannelOpenInit, msg_channel_open_try::MsgChannelOpenTry, - msg_recv_packet::MsgRecvPacket, msg_timeout::MsgTimeout, - }, - client::{msg_create_client::MsgCreateClient, msg_update_client::MsgUpdateClient}, - connection::{ - msg_connection_open_ack::MsgConnectionOpenAck, - msg_connection_open_confirm::MsgConnectionOpenConfirm, - msg_connection_open_init::MsgConnectionOpenInit, - msg_connection_open_try::MsgConnectionOpenTry, - }, - }, - id::ConnectionId, - traits::{ - ClientIdOf, ClientState, ClientStateOf, ConsensusState, ConsensusStateOf, Header, HeaderOf, - HeightOf, - }, - MaybeRecoverableError, -}; - -use crate::{any_enum, any_lc, AnyLightClientIdentified, ChainExt, DoMsg, RelayMessage}; - -#[apply(any_enum)] -#[any = AnyEffect] -pub enum Effect { - ConnectionOpenInit(MsgConnectionOpenInitData), - ConnectionOpenTry(MsgConnectionOpenTryData), - ConnectionOpenAck(MsgConnectionOpenAckData), - ConnectionOpenConfirm(MsgConnectionOpenConfirmData), - - ChannelOpenInit(MsgChannelOpenInitData), - ChannelOpenTry(MsgChannelOpenTryData), - ChannelOpenAck(MsgChannelOpenAckData), - ChannelOpenConfirm(MsgChannelOpenConfirmData), - - RecvPacket(MsgRecvPacketData), - AckPacket(MsgAckPacketData), - TimeoutPacket(MsgTimeoutData), - - CreateClient(MsgCreateClientData), - UpdateClient(MsgUpdateClientData), - - Batch(BatchMsg), -} - -impl HandleEffect for AnyLightClientIdentified { - #[instrument(skip_all, fields(chain_id = %self.chain_id()))] - #[allow(clippy::manual_async_fn)] - fn handle( - self, - store: &::Store, - ) -> impl Future, QueueError>> + Send { - async move { - let msg = self; - - any_lc! { - |msg| { - store - .with_chain(&msg.chain_id, move |c| async move { msg.t.handle(&c).await }) - .map_err(|e| QueueError::Fatal(Box::new(e)))? - .await - .map_err(|e: ::MsgError| { - if e.is_recoverable() { - QueueError::Retry(Box::new(e)) - } else { - QueueError::Fatal(Box::new(e)) - } - }) - } - } - } - } -} - -impl Effect -where - Hc: ChainExt + DoMsg, - Tr: ChainExt, -{ - pub fn handle( - self, - c: &Hc, - ) -> impl Future, Hc::MsgError>> + Send + '_ { - >::msg(c, self) - } -} - -#[queue_msg] -pub struct MsgConnectionOpenInitData( - pub MsgConnectionOpenInit, ClientIdOf>, -); - -#[queue_msg] -pub struct MsgConnectionOpenTryData( - pub MsgConnectionOpenTry< - Tr::StoredClientState, - ClientIdOf, - ClientIdOf, - ConnectionId, - Tr::Height, - Hc::Height, - Tr::StateProof, - Tr::StateProof, - Tr::StateProof, - >, -); - -#[queue_msg] -pub struct MsgConnectionOpenAckData( - pub MsgConnectionOpenAck< - Tr::StoredClientState, - Tr::StateProof, - Tr::StateProof, - Tr::StateProof, - >, -); - -#[queue_msg] -pub struct MsgConnectionOpenConfirmData<#[cover] Hc: ChainExt, Tr: ChainExt> { - pub msg: MsgConnectionOpenConfirm, Tr::StateProof>, -} - -#[queue_msg] -pub struct MsgChannelOpenInitData<#[cover] Hc: ChainExt, #[cover] Tr: ChainExt> { - pub msg: MsgChannelOpenInit, -} - -#[queue_msg] -pub struct MsgChannelOpenTryData<#[cover] Hc: ChainExt, Tr: ChainExt> { - pub msg: MsgChannelOpenTry, -} - -#[queue_msg] -pub struct MsgChannelOpenAckData<#[cover] Hc: ChainExt, Tr: ChainExt> { - pub msg: MsgChannelOpenAck, -} - -#[queue_msg] -pub struct MsgChannelOpenConfirmData<#[cover] Hc: ChainExt, Tr: ChainExt> { - pub msg: MsgChannelOpenConfirm, -} - -#[queue_msg] -pub struct MsgRecvPacketData<#[cover] Hc: ChainExt, Tr: ChainExt> { - pub msg: MsgRecvPacket, -} - -#[queue_msg] -pub struct MsgAckPacketData<#[cover] Hc: ChainExt, Tr: ChainExt> { - pub msg: MsgAcknowledgement, -} - -#[queue_msg] -pub struct MsgTimeoutData<#[cover] Hc: ChainExt, Tr: ChainExt> { - pub msg: MsgTimeout, -} - -#[queue_msg] -pub struct MsgCreateClientData { - pub config: Hc::Config, - pub msg: MsgCreateClient, ConsensusStateOf>, -} - -#[queue_msg] -pub struct MsgUpdateClientData( - pub MsgUpdateClient, HeaderOf>, -); - -#[queue_msg] -#[debug(bound())] // break cyclic debug bounds -pub struct BatchMsg(pub Vec>); - -pub fn log_msg(effect: Effect) { - match effect.clone() { - Effect::ConnectionOpenInit(MsgConnectionOpenInitData(data)) => { - info!( - client_id = %data.client_id, - counterparty.client_id = %data.counterparty.client_id, - counterparty.connection_id = %data.counterparty.connection_id, - counterparty.prefix.key_prefix = %::serde_utils::to_hex(data.counterparty.prefix.key_prefix), - version.identifier = %data.version.identifier, - version.features = %data.version.features.into_iter().map(|x| x.to_string()).collect::>().join(","), - delay_period = %data.delay_period, - ) - } - Effect::ConnectionOpenTry(MsgConnectionOpenTryData(data)) => { - info!( - client_id = %data.client_id.to_string(), - client_state.height = %data.client_state.height(), - counterparty.client_id = %data.counterparty.client_id, - counterparty.connection_id = %data.counterparty.connection_id, - counterparty.prefix.key_prefix = %::serde_utils::to_hex(data.counterparty.prefix.key_prefix), - delay_period = %data.delay_period, - // counterparty_versions = %data - // .counterparty_versions - // .into_iter() - // .map(Into::into) - // .collect(), - proof_height = %data.proof_height, - consensus_height = %data.consensus_height, - ) - } - Effect::ConnectionOpenAck(MsgConnectionOpenAckData(data)) => { - info!( - client_state.height = %data.client_state.height(), - proof_height = %data.proof_height, - consensus_height = %data.consensus_height, - connection_id = %data.connection_id, - counterparty_connection_id = %data.counterparty_connection_id, - version.identifier = %data.version.identifier, - version.features = %data.version.features.into_iter().map(|x| x.to_string()).collect::>().join(","), - ) - } - Effect::ConnectionOpenConfirm(MsgConnectionOpenConfirmData { msg, __marker }) => { - info!( - connection_id = %msg.connection_id, - proof_height = %msg.proof_height, - ) - } - Effect::ChannelOpenInit(MsgChannelOpenInitData { msg, __marker }) => { - info!( - port_id = %msg.port_id, - - channel.state = %msg.channel.state, - channel.ordering = %msg.channel.ordering, - channel.counterparty.port_id = %msg.channel.counterparty.port_id, - channel.counterparty.channel_id = %msg.channel.counterparty.channel_id, - channel.connection_hops = %msg.channel.connection_hops.into_iter().map(|x| x.to_string()).collect::>().join(","), - channel.version = %msg.channel.version, - ) - } - Effect::ChannelOpenTry(MsgChannelOpenTryData { msg, __marker }) => { - info!( - port_id = %msg.port_id.to_string(), - - channel.state = %msg.channel.state, - channel.ordering = %msg.channel.ordering, - channel.counterparty.port_id = %msg.channel.counterparty.port_id, - channel.counterparty.channel_id = %msg.channel.counterparty.channel_id, - channel.connection_hops = %msg.channel.connection_hops.into_iter().map(|x| x.to_string()).collect::>().join(","), - channel.version = %msg.channel.version, - - counterparty_version = %msg.counterparty_version, - proof_height = %msg.proof_height, - ) - } - Effect::ChannelOpenAck(MsgChannelOpenAckData { msg, __marker }) => { - info!( - port_id = %msg.port_id, - channel_id = %msg.channel_id, - counterparty_version = %msg.counterparty_version, - counterparty_channel_id = %msg.counterparty_channel_id, - proof_height = %msg.proof_height, - ) - } - Effect::ChannelOpenConfirm(MsgChannelOpenConfirmData { msg, __marker }) => { - info!( - port_id = %msg.port_id, - channel_id = %msg.channel_id, - proof_height = %msg.proof_height, - ) - } - Effect::RecvPacket(MsgRecvPacketData { msg, __marker }) => { - info!( - sequence = %msg.packet.sequence, - source_port = %msg.packet.source_port, - source_channel = %msg.packet.source_channel, - destination_port = %msg.packet.destination_port, - destination_channel = %msg.packet.destination_channel, - data = %::serde_utils::to_hex(msg.packet.data), - timeout_height = %msg.packet.timeout_height, - timeout_timestamp = %msg.packet.timeout_timestamp, - - proof_height = %msg.proof_height, - ) - } - Effect::AckPacket(MsgAckPacketData { msg, __marker }) => { - info!( - sequence = %msg.packet.sequence, - source_port = %msg.packet.source_port, - source_channel = %msg.packet.source_channel, - destination_port = %msg.packet.destination_port, - destination_channel = %msg.packet.destination_channel, - data = %::serde_utils::to_hex(msg.packet.data), - timeout_height = %msg.packet.timeout_height, - timeout_timestamp = %msg.packet.timeout_timestamp, - - data = %::serde_utils::to_hex(msg.acknowledgement), - proof_height = %msg.proof_height, - ) - } - Effect::TimeoutPacket(MsgTimeoutData { msg, __marker }) => { - info!( - sequence = %msg.packet.sequence, - source_port = %msg.packet.source_port, - source_channel = %msg.packet.source_channel, - destination_port = %msg.packet.destination_port, - destination_channel = %msg.packet.destination_channel, - data = %::serde_utils::to_hex(msg.packet.data), - timeout_height = %msg.packet.timeout_height, - timeout_timestamp = %msg.packet.timeout_timestamp, - - proof_height = %msg.proof_height, - next_sequence_recv = %msg.next_sequence_recv.get(), - ) - } - Effect::CreateClient(MsgCreateClientData { msg, config }) => { - info!( - config_json = %::serde_json::to_string(&config).expect("serialization is infallible"), - client_state.height = %msg.client_state.height(), - client_state.chain_id = %msg.client_state.chain_id(), - consensus_state.timestamp = %msg.consensus_state.timestamp(), - ) - } - Effect::UpdateClient(MsgUpdateClientData(msg)) => { - info!( - client_id = %msg.client_id.to_string(), - header.trusted_height = %msg.client_message.trusted_height(), - ) - } - Effect::Batch(BatchMsg(_msgs)) => error!("attempted to log a batch tx???"), - } -} diff --git a/lib/relay-message/src/event.rs b/lib/relay-message/src/event.rs deleted file mode 100644 index 30010cd276..0000000000 --- a/lib/relay-message/src/event.rs +++ /dev/null @@ -1,617 +0,0 @@ -use std::marker::PhantomData; - -use chain_utils::GetChain; -use macros::apply; -use queue_msg::{ - aggregate, conc, fetch, noop, queue_msg, wait, HandleEvent, Op, QueueError, QueueMessage, -}; -use tracing::{info, instrument}; -use unionlabs::{ - events::UpdateClient, - hash::H256, - ibc::core::channel::packet::Packet, - ics24::{ChannelEndPath, ClientStatePath, ConnectionPath}, - traits::{ClientIdOf, ClientTypeOf, HeightOf}, - QueryHeight, -}; - -use crate::{ - aggregate::{ - mk_aggregate_wait_for_update, Aggregate, AggregateChannelHandshakeMsgAfterUpdate, - AggregateClientStateFromConnection, AggregateConnectionFetchFromChannelEnd, - AggregateMsgAfterUpdate, AggregateMsgConnectionOpenAck, AggregateMsgConnectionOpenConfirm, - AggregateMsgConnectionOpenTry, AggregatePacketMsgAfterUpdate, AggregatePacketTimeout, - AggregateUpdateClient, AnyAggregate, ChannelHandshakeEvent, PacketEvent, - }, - any_enum, any_lc, - fetch::{AnyFetch, Fetch, FetchState}, - id, identified, seq, - wait::{AnyWait, Wait, WaitForHeight}, - AnyLightClientIdentified, ChainExt, RelayMessage, -}; - -#[apply(any_enum)] -#[any = AnyEvent] -pub enum Event { - Ibc(IbcEvent), - Command(Command), -} - -impl HandleEvent for AnyLightClientIdentified { - #[instrument(skip_all, fields(chain_id = %self.chain_id()))] - fn handle( - self, - store: &::Store, - ) -> Result, QueueError> { - let wait = self; - - any_lc! { - |wait| { - store - .with_chain(&wait.chain_id, move |c| wait.t.handle(c)) - .map_err(|e| QueueError::Fatal(Box::new(e))) - } - } - } -} - -impl Event { - pub fn handle(self, hc: Hc) -> Op - where - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - { - match self { - Event::Ibc(ibc_event) => { - let event_name = ibc_event.event.name(); - - match ibc_event.event { - unionlabs::events::IbcEvent::CreateClient(e) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - client_id = %e.client_id, - client_type = %e.client_type, - consensus_height = %e.consensus_height - ); - - noop() - } - unionlabs::events::IbcEvent::UpdateClient(UpdateClient { - client_id, - client_type, - consensus_heights, - }) => { - let consensus_heights = consensus_heights - .iter() - .map(|x| x.to_string()) - .collect::>() - .join(","); - - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - %client_id, - %client_type, - %consensus_heights - ); - - noop() - } - - unionlabs::events::IbcEvent::ClientMisbehaviour(_) => unimplemented!(), - unionlabs::events::IbcEvent::SubmitEvidence(_) => unimplemented!(), - - unionlabs::events::IbcEvent::ConnectionOpenInit(init) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - connection_id = %init.connection_id, - client_id = %init.client_id, - counterparty_client_id = %init.counterparty_client_id - ); - - seq([ - wait(id( - hc.chain_id(), - WaitForHeight { - height: ibc_event.height, - __marker: PhantomData, - }, - )), - aggregate( - [mk_aggregate_wait_for_update( - hc.chain_id(), - init.client_id.clone(), - init.counterparty_client_id.clone(), - ibc_event.height, - )], - [], - id( - hc.chain_id(), - AggregateMsgAfterUpdate::ConnectionOpenTry( - AggregateMsgConnectionOpenTry { - event_height: ibc_event.height, - event: init, - }, - ), - ), - ), - ]) - } - unionlabs::events::IbcEvent::ConnectionOpenTry(try_) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - connection_id = %try_.connection_id, - counterparty_connection_id = %try_.counterparty_connection_id, - client_id = %try_.client_id, - counterparty_client_id = %try_.counterparty_client_id - ); - - aggregate( - [mk_aggregate_wait_for_update( - hc.chain_id(), - try_.client_id.clone(), - try_.counterparty_client_id.clone(), - ibc_event.height, - )], - [], - id( - hc.chain_id(), - AggregateMsgAfterUpdate::ConnectionOpenAck( - AggregateMsgConnectionOpenAck { - event_height: ibc_event.height, - event: try_, - }, - ), - ), - ) - } - unionlabs::events::IbcEvent::ConnectionOpenAck(ack) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - connection_id = %ack.connection_id, - counterparty_connection_id = %ack.counterparty_connection_id, - client_id = %ack.client_id, - counterparty_client_id = %ack.counterparty_client_id - ); - - aggregate( - [mk_aggregate_wait_for_update( - hc.chain_id(), - ack.client_id.clone(), - ack.counterparty_client_id.clone(), - ibc_event.height, - )], - [], - id( - hc.chain_id(), - AggregateMsgAfterUpdate::ConnectionOpenConfirm( - AggregateMsgConnectionOpenConfirm { - event_height: ibc_event.height, - event: ack, - }, - ), - ), - ) - } - unionlabs::events::IbcEvent::ConnectionOpenConfirm(confirm) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - connection_id = %confirm.connection_id, - counterparty_connection_id = %confirm.counterparty_connection_id, - client_id = %confirm.client_id, - counterparty_client_id = %confirm.counterparty_client_id - ); - - noop() - } - - unionlabs::events::IbcEvent::ChannelOpenInit(init) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - port_id = %init.port_id, - channel_id = %init.channel_id, - counterparty_port_id = %init.counterparty_port_id, - connection_id = %init.connection_id, - version = %init.version, - ); - - aggregate( - [aggregate( - [fetch(id::( - hc.chain_id(), - FetchState { - at: QueryHeight::Specific(ibc_event.height), - path: ChannelEndPath { - port_id: init.port_id.clone(), - channel_id: init.channel_id.clone(), - } - .into(), - }, - ))], - [], - id( - hc.chain_id(), - AggregateConnectionFetchFromChannelEnd { - at: ibc_event.height, - __marker: PhantomData, - }, - ), - )], - [], - id( - hc.chain_id(), - AggregateChannelHandshakeMsgAfterUpdate { - event_height: ibc_event.height, - channel_handshake_event: ChannelHandshakeEvent::Init(init), - __marker: PhantomData, - }, - ), - ) - } - unionlabs::events::IbcEvent::ChannelOpenTry(try_) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - port_id = %try_.port_id, - channel_id = %try_.channel_id, - counterparty_port_id = %try_.counterparty_port_id, - counterparty_channel_id = %try_.counterparty_channel_id, - connection_id = %try_.connection_id, - version = %try_.version, - ); - - aggregate( - [aggregate( - [fetch(id::( - hc.chain_id(), - FetchState { - at: QueryHeight::Specific(ibc_event.height), - path: ChannelEndPath { - port_id: try_.port_id.clone(), - channel_id: try_.channel_id.clone(), - } - .into(), - }, - ))], - [], - id( - hc.chain_id(), - AggregateConnectionFetchFromChannelEnd { - at: ibc_event.height, - __marker: PhantomData, - }, - ), - )], - [], - id( - hc.chain_id(), - AggregateChannelHandshakeMsgAfterUpdate { - event_height: ibc_event.height, - channel_handshake_event: ChannelHandshakeEvent::Try(try_), - __marker: PhantomData, - }, - ), - ) - } - unionlabs::events::IbcEvent::ChannelOpenAck(ack) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - port_id = %ack.port_id, - channel_id = %ack.channel_id, - counterparty_port_id = %ack.counterparty_port_id, - counterparty_channel_id = %ack.counterparty_channel_id, - connection_id = %ack.connection_id, - ); - - aggregate( - [aggregate( - [fetch(id::( - hc.chain_id(), - FetchState { - at: QueryHeight::Specific(ibc_event.height), - path: ChannelEndPath { - port_id: ack.port_id.clone(), - channel_id: ack.channel_id.clone(), - } - .into(), - }, - ))], - [], - id( - hc.chain_id(), - AggregateConnectionFetchFromChannelEnd { - at: ibc_event.height, - __marker: PhantomData, - }, - ), - )], - [], - id( - hc.chain_id(), - AggregateChannelHandshakeMsgAfterUpdate { - event_height: ibc_event.height, - channel_handshake_event: ChannelHandshakeEvent::Ack(ack), - __marker: PhantomData, - }, - ), - ) - } - unionlabs::events::IbcEvent::ChannelOpenConfirm(confirm) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - port_id = %confirm.port_id, - channel_id = %confirm.channel_id, - counterparty_port_id = %confirm.counterparty_port_id, - counterparty_channel_id = %confirm.counterparty_channel_id, - connection_id = %confirm.connection_id, - ); - - noop() - } - unionlabs::events::IbcEvent::SendPacket(send) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - timeout_height = %send.packet_timeout_height, - timeout_timestamp = %send.packet_timeout_timestamp, - sequence = %send.packet_sequence, - src_port = %send.packet_src_port, - src_channel = %send.packet_src_channel, - dst_port = %send.packet_dst_port, - dst_channel = %send.packet_dst_channel, - channel_ordering = %send.packet_channel_ordering, - connection_id = %send.connection_id, - ); - - // in parallel, run height timeout, timestamp timeout, and send packet - conc([ - aggregate( - [ - fetch(id( - hc.chain_id(), - FetchState:: { - at: QueryHeight::Specific(ibc_event.height), - path: ConnectionPath { - connection_id: send.connection_id.clone(), - } - .into(), - }, - )), - aggregate( - [fetch(id( - hc.chain_id(), - FetchState:: { - at: QueryHeight::Specific(ibc_event.height), - path: ConnectionPath { - connection_id: send.connection_id.clone(), - } - .into(), - }, - ))], - [], - id( - hc.chain_id(), - AggregateClientStateFromConnection:: { - at: ibc_event.height, - __marker: PhantomData, - }, - ), - ), - ], - [], - id( - hc.chain_id(), - AggregatePacketTimeout { - packet: Packet { - sequence: send.packet_sequence, - source_port: send.packet_src_port.clone(), - source_channel: send.packet_src_channel.clone(), - destination_port: send.packet_dst_port.clone(), - destination_channel: send.packet_dst_channel.clone(), - data: send.packet_data_hex.clone(), - timeout_height: send.packet_timeout_height, - timeout_timestamp: send.packet_timeout_timestamp, - }, - __marker: PhantomData, - }, - ), - ), - aggregate( - [fetch(id::( - hc.chain_id(), - FetchState { - at: QueryHeight::Specific(ibc_event.height), - path: ConnectionPath { - connection_id: send.connection_id.clone(), - } - .into(), - }, - ))], - [], - id( - hc.chain_id(), - AggregatePacketMsgAfterUpdate { - update_to: ibc_event.height, - event_height: ibc_event.height, - tx_hash: ibc_event.tx_hash, - packet_event: PacketEvent::Send(send), - __marker: PhantomData, - }, - ), - ), - ]) - } - unionlabs::events::IbcEvent::RecvPacket(recv) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - timeout_height = %recv.packet_timeout_height, - timeout_timestamp = %recv.packet_timeout_timestamp, - sequence = %recv.packet_sequence, - src_port = %recv.packet_src_port, - src_channel = %recv.packet_src_channel, - dst_port = %recv.packet_dst_port, - dst_channel = %recv.packet_dst_channel, - channel_ordering = %recv.packet_channel_ordering, - connection_id = %recv.connection_id, - ); - - noop() - } - unionlabs::events::IbcEvent::AcknowledgePacket(ack) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - timeout_height = %ack.packet_timeout_height, - timeout_timestamp = %ack.packet_timeout_timestamp, - sequence = %ack.packet_sequence, - src_port = %ack.packet_src_port, - src_channel = %ack.packet_src_channel, - dst_port = %ack.packet_dst_port, - dst_channel = %ack.packet_dst_channel, - channel_ordering = %ack.packet_channel_ordering, - connection_id = %ack.connection_id, - ); - - noop() - } - unionlabs::events::IbcEvent::TimeoutPacket(timeout) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - timeout_height = %timeout.packet_timeout_height, - timeout_timestamp = %timeout.packet_timeout_timestamp, - sequence = %timeout.packet_sequence, - src_port = %timeout.packet_src_port, - src_channel = %timeout.packet_src_channel, - dst_port = %timeout.packet_dst_port, - dst_channel = %timeout.packet_dst_channel, - channel_ordering = %timeout.packet_channel_ordering, - connection_id = %timeout.connection_id, - ); - - noop() - } - unionlabs::events::IbcEvent::WriteAcknowledgement(write_ack) => { - info!( - event = %event_name, - height = %ibc_event.height, - tx_hash = %ibc_event.tx_hash, - - timeout_height = %write_ack.packet_timeout_height, - timeout_timestamp = %write_ack.packet_timeout_timestamp, - sequence = %write_ack.packet_sequence, - src_port = %write_ack.packet_src_port, - src_channel = %write_ack.packet_src_channel, - dst_port = %write_ack.packet_dst_port, - dst_channel = %write_ack.packet_dst_channel, - ack = %::serde_utils::to_hex(&write_ack.packet_ack_hex), - connection_id = %write_ack.connection_id, - ); - - aggregate( - [fetch(id::( - hc.chain_id(), - FetchState { - at: QueryHeight::Specific(ibc_event.height), - path: ConnectionPath { - connection_id: write_ack.connection_id.clone(), - } - .into(), - }, - ))], - [], - id( - hc.chain_id(), - AggregatePacketMsgAfterUpdate { - update_to: ibc_event.height, - event_height: ibc_event.height, - tx_hash: ibc_event.tx_hash, - packet_event: PacketEvent::WriteAck(write_ack), - __marker: PhantomData, - }, - ), - ) - } - } - } - Event::Command(command) => match command { - Command::UpdateClient { - client_id, - __marker: _, - } => aggregate( - [fetch(id::( - hc.chain_id(), - FetchState { - at: QueryHeight::Latest, - path: ClientStatePath { - client_id: client_id.clone(), - } - .into(), - }, - ))], - [], - id( - hc.chain_id(), - AggregateUpdateClient { - client_id, - __marker: PhantomData, - }, - ), - ), - }, - } - } -} - -#[queue_msg] -pub struct IbcEvent { - pub tx_hash: H256, - pub height: HeightOf, - pub event: unionlabs::events::IbcEvent, ClientTypeOf, ClientIdOf>, -} - -#[queue_msg] -pub enum Command { - UpdateClient { - client_id: ClientIdOf, - #[serde(skip)] - __marker: PhantomData Tr>, - }, -} diff --git a/lib/relay-message/src/fetch.rs b/lib/relay-message/src/fetch.rs deleted file mode 100644 index 2f81186e3c..0000000000 --- a/lib/relay-message/src/fetch.rs +++ /dev/null @@ -1,251 +0,0 @@ -use std::{fmt::Debug, marker::PhantomData}; - -use chain_utils::GetChain; -use futures::Future; -use macros::apply; -use queue_msg::{data, fetch, queue_msg, HandleFetch, Op, QueueError, QueueMessage}; -use tracing::instrument; -use unionlabs::{ - ics24, - never::Never, - traits::{ChainIdOf, ClientIdOf, HeightOf}, - QueryHeight, -}; - -use crate::{ - any_enum, any_lc, - data::{AnyData, Data, LatestHeight, SelfClientState, SelfConsensusState}, - id, identified, AnyLightClientIdentified, ChainExt, DoFetchProof, DoFetchState, - DoFetchUpdateHeaders, RelayMessage, -}; - -#[apply(any_enum)] -/// Fetch some data that will likely be used in a [`QueueMsg::Aggregate`]. -#[any = AnyFetch] -#[specific = LightClientSpecificFetch] -pub enum Fetch { - State(FetchState), - Proof(FetchProof), - - LatestHeight(FetchLatestHeight), - - UnfinalizedTrustedClientState(FetchUnfinalizedTrustedClientState), - - SelfClientState(FetchSelfClientState), - SelfConsensusState(FetchSelfConsensusState), - - UpdateHeaders(FetchUpdateHeaders), - - #[serde(untagged)] - LightClientSpecific(LightClientSpecificFetch), -} - -impl HandleFetch for AnyLightClientIdentified { - #[instrument(skip_all, fields(chain_id = %self.chain_id()))] - async fn handle( - self, - store: &::Store, - ) -> Result, QueueError> { - let fetch = self; - - any_lc! { - |fetch| { - Ok(store - .with_chain(&fetch.chain_id, move |c| async move { fetch.t.handle(c).await }) - .map_err(|e| QueueError::Fatal(Box::new(e)))? - .await - .map_err(|e| QueueError::Fatal(Box::new(e)))?) - } - } - } -} - -pub trait DoFetch: Sized + Debug + Clone + PartialEq { - type Error: Debug + Clone + PartialEq + std::error::Error + Send + Sync; - - fn do_fetch(c: &Hc, _: Self) -> impl Future, Self::Error>>; -} - -impl DoFetch for Never { - type Error = Never; - - async fn do_fetch(_: &Hc, this: Self) -> Result, Never> { - match this {} - } -} - -#[queue_msg] -pub struct FetchSelfClientState { - pub at: QueryHeight>, -} - -#[queue_msg] -pub struct FetchSelfConsensusState { - pub at: QueryHeight>, -} - -#[queue_msg] -pub struct FetchProof { - pub at: HeightOf, - pub path: ics24::Path, -} - -#[queue_msg] -pub struct FetchState { - pub at: QueryHeight>, - pub path: ics24::Path, -} - -#[queue_msg] -pub struct FetchUpdateHeaders { - pub counterparty_chain_id: ChainIdOf, - // id of the counterparty client that will be updated with the fetched headers - pub counterparty_client_id: ClientIdOf, - pub update_from: HeightOf, - pub update_to: HeightOf, -} - -#[queue_msg] -pub struct FetchLatestHeight<#[cover] Hc: ChainExt, #[cover] Tr: ChainExt> {} - -#[queue_msg] -pub struct FetchUnfinalizedTrustedClientState { - client_id: Hc::ClientId, -} - -#[queue_msg] -pub struct LightClientSpecificFetch(pub Hc::Fetch); - -impl Fetch -where - Hc: ChainExt: DoFetch> - + DoFetchState - + DoFetchProof - + DoFetchUpdateHeaders, - - Tr: ChainExt, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, -{ - pub async fn handle(self, c: Hc) -> Result, FetchError> { - match self { - Fetch::Proof(msg) => Ok(Hc::proof(&c, msg.at, msg.path)), - Fetch::State(msg) => match msg.at { - QueryHeight::Latest => Ok(fetch(id( - c.chain_id(), - FetchState { - at: QueryHeight::Specific(c.query_latest_height().await.unwrap()), - path: msg.path, - }, - ))), - QueryHeight::Specific(at) => Ok(Hc::state(&c, at, msg.path)), - }, - Fetch::LatestHeight(FetchLatestHeight { __marker: _ }) => Ok(data(id( - c.chain_id(), - LatestHeight { - height: c.query_latest_height().await.unwrap(), - __marker: PhantomData, - }, - ))), - Fetch::UnfinalizedTrustedClientState(FetchUnfinalizedTrustedClientState { - client_id, - __marker: _, - }) => { - let _client_state = Hc::query_unfinalized_trusted_client_state(&c, client_id).await; - - // data(id( - // c.chain_id(), - // UnfinalizedTrustedClientState { - // height, - // client_state, - // }, - // )) - todo!() - } - Fetch::SelfClientState(FetchSelfClientState { - at: height, - __marker: _, - }) => { - // TODO: Split this into a separate query and aggregate - let height = match height { - QueryHeight::Latest => c.query_latest_height().await.unwrap(), - QueryHeight::Specific(h) => h, - }; - - Ok(data(id::( - c.chain_id(), - SelfClientState { - self_client_state: c.self_client_state(height).await, - __marker: PhantomData, - }, - ))) - } - Fetch::SelfConsensusState(FetchSelfConsensusState { - at: height, - __marker: _, - }) => { - // TODO: Split this into a separate query and aggregate - let height = match height { - QueryHeight::Latest => c.query_latest_height().await.unwrap(), - QueryHeight::Specific(h) => h, - }; - - Ok(data(id::( - c.chain_id(), - SelfConsensusState { - self_consensus_state: c.self_consensus_state(height).await, - __marker: PhantomData, - }, - ))) - } - Fetch::UpdateHeaders(fetch_update_headers) => { - Ok(Hc::fetch_update_headers(&c, fetch_update_headers)) - } - Fetch::LightClientSpecific(LightClientSpecificFetch(fetch)) => { - Hc::Fetch::do_fetch(&c, fetch) - .await - .map_err(|err| FetchError::LightClientSpecific(Box::new(err))) - } - } - } -} - -/// NOTE: The following is the ideal implementation of this error type: -/// -/// ``` -/// #[derive(macros::Debug, PartialEqNoBound, CloneNoBound, thiserror::Error)] -/// pub enum FetchError -/// where -/// Hc::Fetch: DoFetch, -/// { -/// LightClientSpecific( as DoFetch>::Error), -/// } - -/// pub enum AnyFetchError {} -/// impl crate::AnyLightClient for AnyFetchError { -/// type Inner = FetchError; -/// } -/// ``` -/// -/// However, due to limitations in rust's type system, this isn't possible - we need to add an extra constraint on `Self::Inner`, which can't be expressed without non lifetime binders: https://github.com/rust-lang/rust/issues/108185. As such, we have to type-erase here via box dyn error. -#[derive(macros::Debug, thiserror::Error)] -pub enum FetchError { - #[error(transparent)] - LightClientSpecific(Box), -} - -#[cfg(test)] -mod tests { - use chain_utils::{cosmos::Cosmos, union::Union, wasm::Wasm}; - use static_assertions::assert_impl_all; - - use crate::{ - chain::union::UnionFetch, - fetch::{DoFetch, FetchError}, - DoFetchState, - }; - - assert_impl_all!(Union: DoFetchState>); - assert_impl_all!(UnionFetch>: DoFetch); - assert_impl_all!(FetchError: std::error::Error); -} diff --git a/lib/relay-message/src/lib.rs b/lib/relay-message/src/lib.rs deleted file mode 100644 index f880dafc1b..0000000000 --- a/lib/relay-message/src/lib.rs +++ /dev/null @@ -1,675 +0,0 @@ -#![feature(trait_alias)] -#![allow(clippy::type_complexity, async_fn_in_trait)] - -use std::{collections::VecDeque, fmt::Debug, future::Future, marker::PhantomData}; - -use chain_utils::{ - arbitrum::Arbitrum, berachain::Berachain, cosmos::Cosmos, ethereum::Ethereum, scroll::Scroll, - union::Union, wasm::Wasm, Chains, -}; -use frame_support_procedural::{CloneNoBound, DebugNoBound, PartialEqNoBound}; -use queue_msg::{seq, Op, OpT, QueueMessage}; -use serde::{Deserialize, Serialize}; -use unionlabs::{ - ethereum::config::{Mainnet, Minimal}, - ics24, - never::Never, - traits::{Chain, ChainIdOf, ClientIdOf, HeightOf}, - MaybeArbitrary, MaybeRecoverableError, -}; - -use crate::{ - aggregate::AnyAggregate, - data::AnyData, - effect::{AnyEffect, Effect}, - event::AnyEvent, - fetch::{AnyFetch, FetchUpdateHeaders}, - wait::AnyWait, -}; - -pub mod use_aggregate; - -pub mod aggregate; -pub mod data; -pub mod effect; -pub mod event; -pub mod fetch; -pub mod wait; - -pub mod chain; - -pub trait ChainExt: Chain { - type Data: OpT; - type Fetch: OpT; - type Aggregate: OpT; - - /// Error type for [`Self::msg`]. - type MsgError: Debug + MaybeRecoverableError; - - /// The config required to create a light client on this chain. - type Config: Debug - + Clone - + PartialEq - + Serialize - + for<'de> Deserialize<'de> - + MaybeArbitrary - + Send - + Sync; -} - -pub enum RelayMessage {} - -impl QueueMessage for RelayMessage { - type Event = AnyLightClientIdentified; - type Data = AnyLightClientIdentified; - type Fetch = AnyLightClientIdentified; - type Effect = AnyLightClientIdentified; - type Wait = AnyLightClientIdentified; - type Aggregate = AnyLightClientIdentified; - - type Store = Chains; -} - -impl TryFrom> for AnyLightClientIdentified { - type Error = Op; - - fn try_from(value: Op) -> Result { - match value { - Op::Data(data) => Ok(data), - _ => Err(value), - } - } -} - -macro_rules! any_enum { - ( - $(#[doc = $outer_doc:literal])* - #[any = $Any:ident] - $(#[specific = $Specific:ident])? - pub enum $Enum:ident { - $( - $(#[doc = $doc:literal])* - $(#[serde($untagged:ident)])* - $Variant:ident( - $(#[$variant_inner_meta:meta])* - $VariantInner:ty - ), - )+ - } - ) => { - #[::queue_msg::queue_msg] - #[derive(::enumorph::Enumorph)] - $(#[doc = $outer_doc])* - pub enum $Enum { - $( - $(#[doc = $doc])* - $(#[serde($untagged)])* - $Variant( - $(#[$variant_inner_meta])* - $VariantInner - ), - )+ - } - - pub enum $Any {} - impl crate::AnyLightClient for $Any { - type Inner = $Enum; - } - - const _: () = { - use crate::{AnyLightClientIdentified, Identified}; - - $( - impl From> - for AnyLightClientIdentified<$Any> - where - $VariantInner: Into<$Enum>, - AnyLightClientIdentified<$Any>: From>>, - { - fn from( - Identified { - chain_id, - t, - __marker: _, - }: Identified, - ) -> Self { - Self::from(crate::id( - chain_id, - <$Enum>::from(t), - )) - } - } - - impl - TryFrom> for Identified - where - Identified>: TryFrom, Error = AnyLightClientIdentified<$Any>> - + Into>, - { - type Error = AnyLightClientIdentified<$Any>; - - fn try_from(value: AnyLightClientIdentified<$Any>) -> Result { - let Identified { - chain_id, - t, - __marker: _, - } = >>::try_from(value)?; - - Ok(crate::id( - chain_id.clone(), - <$VariantInner>::try_from(t).map_err(|x: $Enum| { - Into::>::into(crate::id(chain_id, x)) - })?, - )) - } - } - )+ - - $( - impl $Enum { - pub fn specific(t: impl Into>) -> $Enum { - $Specific(t.into()).into() - } - } - )? - }; - }; -} -pub(crate) use any_enum; - -pub type PathOf = ics24::Path, HeightOf>; - -pub trait AnyLightClient { - type Inner: Debug + Clone + PartialEq; - // + Serialize - // + for<'de> Deserialize<'de> - // + MaybeArbitrary; -} - -pub type InnerOf = ::Inner; - -macro_rules! lc { - // A on B - ($Tr:ty => $Hc:ty) => { - Identified<$Hc, $Tr, InnerOf> - }; -} - -#[derive( - DebugNoBound, CloneNoBound, PartialEqNoBound, Serialize, Deserialize, enumorph::Enumorph, -)] -#[cfg_attr( - feature = "arbitrary", - derive(arbitrary::Arbitrary), - arbitrary(bound = "") -)] -#[serde( - from = "AnyLightClientIdentifiedSerde", - into = "AnyLightClientIdentifiedSerde", - bound( - serialize = "AnyLightClientIdentifiedSerde: Serialize", - deserialize = "AnyLightClientIdentifiedSerde: Deserialize<'de>" - ) -)] -#[allow(clippy::large_enum_variant)] -pub enum AnyLightClientIdentified { - /// The 08-wasm client tracking the state of Ethereum. - EthereumMainnetOnUnion(lc!(Ethereum => Wasm)), - /// The solidity client on Ethereum tracking the state of Wasm. - UnionOnEthereumMainnet(lc!(Wasm => Ethereum)), - - /// The 08-wasm client tracking the state of Ethereum. - EthereumMinimalOnUnion(lc!(Ethereum => Wasm)), - /// The solidity client on Ethereum tracking the state of Wasm. - UnionOnEthereumMinimal(lc!(Wasm => Ethereum)), - - /// The 08-wasm client tracking the state of Scroll. - ScrollOnUnion(lc!(Scroll => Wasm)), - /// The solidity client on Scroll tracking the state of Wasm. - UnionOnScroll(lc!(Wasm => Scroll)), - - /// The 08-wasm client tracking the state of Arbitrum. - ArbitrumOnUnion(lc!(Arbitrum => Wasm)), - /// The solidity client on Arbitrum tracking the state of Wasm. - UnionOnArbitrum(lc!(Wasm => Arbitrum)), - - /// The 08-wasm client tracking the state of Berachain. - BerachainOnUnion(lc!(Berachain => Wasm)), - /// The solidity client on Berachain tracking the state of Wasm. - UnionOnBerachain(lc!(Wasm => Berachain)), - - /// The native tendermint client on Union tracking the state of Wasm. - WasmCosmosOnUnion(lc!(Wasm => Union)), - /// The 08-wasm client on Cosmos tracking the state of Union. - UnionOnWasmCosmos(lc!(Union => Wasm)), - - /// The native tendermint client on Union tracking the state of Cosmos. - CosmosOnUnion(lc!(Cosmos => Union)), - /// The native cometbls client on Cosmos tracking the state of Union. - UnionOnCosmos(lc!(Union => Cosmos)), - - /// The 08-wasm client tracking the state of Cosmos. - CosmosOnCosmos(lc!(Cosmos => Cosmos)), -} - -impl AnyLightClientIdentified { - fn chain_id(&self) -> String { - let i = self; - - any_lc! { - |i| i.chain_id.to_string() - } - } -} - -#[derive(Serialize, Deserialize, enumorph::Enumorph)] -#[serde( - bound( - serialize = " - Inner, Ethereum, lc!(Ethereum => Wasm)>: Serialize, - Inner, Wasm, lc!(Wasm => Ethereum)>: Serialize, - Inner, Ethereum, lc!(Ethereum => Wasm)>: Serialize, - - Inner, Wasm, lc!(Wasm => Ethereum)>: Serialize, - - Inner, Scroll, lc!(Scroll => Wasm)>: Serialize, - Inner, lc!(Wasm => Scroll)>: Serialize, - - Inner, Arbitrum, lc!(Arbitrum => Wasm)>: Serialize, - Inner, lc!(Wasm => Arbitrum)>: Serialize, - - Inner, Berachain, lc!(Berachain => Wasm)>: Serialize, - Inner, lc!(Wasm => Berachain)>: Serialize, - Inner, lc!(Wasm => Union)>: Serialize, - Inner, Union, lc!(Union => Wasm)>: Serialize, - - Inner Union)>: Serialize, - Inner Cosmos)>: Serialize, - - Inner Cosmos)>: Serialize, - ", - deserialize = " - Inner, Ethereum, lc!(Ethereum => Wasm)>: Deserialize<'de>, - Inner, Wasm, lc!(Wasm => Ethereum)>: Deserialize<'de>, - Inner, Ethereum, lc!(Ethereum => Wasm)>: Deserialize<'de>, - - Inner, Wasm, lc!(Wasm => Ethereum)>: Deserialize<'de>, - - Inner, Scroll, lc!(Scroll => Wasm)>: Deserialize<'de>, - Inner, lc!(Wasm => Scroll)>: Deserialize<'de>, - - Inner, Arbitrum, lc!(Arbitrum => Wasm)>: Deserialize<'de>, - Inner, lc!(Wasm => Arbitrum)>: Deserialize<'de>, - - Inner, Berachain, lc!(Berachain => Wasm)>: Deserialize<'de>, - Inner, lc!(Wasm => Berachain)>: Deserialize<'de>, - Inner, lc!(Wasm => Union)>: Deserialize<'de>, - Inner, Union, lc!(Union => Wasm)>: Deserialize<'de>, - - Inner Union)>: Deserialize<'de>, - Inner Cosmos)>: Deserialize<'de>, - - Inner Cosmos)>: Deserialize<'de>, - " - ), - untagged, - deny_unknown_fields -)] -#[allow(clippy::large_enum_variant)] -enum AnyLightClientIdentifiedSerde { - EthereumMainnetOnUnion( - Inner, Ethereum, lc!(Ethereum => Wasm)>, - ), - UnionOnEthereumMainnet( - Inner, Wasm, lc!(Wasm => Ethereum)>, - ), - - EthereumMinimalOnUnion( - Inner, Ethereum, lc!(Ethereum => Wasm)>, - ), - UnionOnEthereumMinimal( - Inner, Wasm, lc!(Wasm => Ethereum)>, - ), - - ScrollOnUnion(Inner, Scroll, lc!(Scroll => Wasm)>), - UnionOnScroll(Inner, lc!(Wasm => Scroll)>), - - ArbitrumOnUnion(Inner, Arbitrum, lc!(Arbitrum => Wasm)>), - UnionOnArbitrum(Inner, lc!(Wasm => Arbitrum)>), - - BerachainOnUnion(Inner, Berachain, lc!(Berachain => Wasm)>), - UnionOnBerachain(Inner, lc!(Wasm => Berachain)>), - WasmCosmosOnUnion(Inner, lc!(Wasm => Union)>), - UnionOnWasmCosmos(Inner, Union, lc!(Union => Wasm)>), - - CosmosOnUnion(Inner Union)>), - UnionOnCosmos(Inner Cosmos)>), - - CosmosOnCosmos(Inner Cosmos)>), -} - -impl From> for AnyLightClientIdentifiedSerde { - fn from(value: AnyLightClientIdentified) -> Self { - any_lc! { - |value| Inner::new(value).into() - } - } -} - -impl From> for AnyLightClientIdentified { - fn from(value: AnyLightClientIdentifiedSerde) -> Self { - match value { - AnyLightClientIdentifiedSerde::EthereumMainnetOnUnion(t) => { - Self::EthereumMainnetOnUnion(t.inner) - } - AnyLightClientIdentifiedSerde::UnionOnEthereumMainnet(t) => { - Self::UnionOnEthereumMainnet(t.inner) - } - - AnyLightClientIdentifiedSerde::EthereumMinimalOnUnion(t) => { - Self::EthereumMinimalOnUnion(t.inner) - } - AnyLightClientIdentifiedSerde::UnionOnEthereumMinimal(t) => { - Self::UnionOnEthereumMinimal(t.inner) - } - - AnyLightClientIdentifiedSerde::ScrollOnUnion(t) => Self::ScrollOnUnion(t.inner), - AnyLightClientIdentifiedSerde::UnionOnScroll(t) => Self::UnionOnScroll(t.inner), - - AnyLightClientIdentifiedSerde::ArbitrumOnUnion(t) => Self::ArbitrumOnUnion(t.inner), - AnyLightClientIdentifiedSerde::UnionOnArbitrum(t) => Self::UnionOnArbitrum(t.inner), - - AnyLightClientIdentifiedSerde::BerachainOnUnion(t) => Self::BerachainOnUnion(t.inner), - AnyLightClientIdentifiedSerde::UnionOnBerachain(t) => Self::UnionOnBerachain(t.inner), - AnyLightClientIdentifiedSerde::WasmCosmosOnUnion(t) => Self::WasmCosmosOnUnion(t.inner), - AnyLightClientIdentifiedSerde::UnionOnWasmCosmos(t) => Self::UnionOnWasmCosmos(t.inner), - - AnyLightClientIdentifiedSerde::CosmosOnCosmos(t) => Self::CosmosOnCosmos(t.inner), - AnyLightClientIdentifiedSerde::CosmosOnUnion(t) => Self::CosmosOnUnion(t.inner), - - AnyLightClientIdentifiedSerde::UnionOnCosmos(t) => Self::UnionOnCosmos(t.inner), - } - } -} - -#[macro_export] -macro_rules! identified { - ($Ty:ident<$Hc:ty, $Tr:ty>) => { - $crate::Identified<$Hc, $Tr, $Ty<$Hc, $Tr>> - }; -} - -#[derive(DebugNoBound, thiserror::Error)] -pub enum LcError { - #[error(transparent)] - Msg(Hc::MsgError), - __Marker(PhantomData Tr>), -} - -#[derive(macros::Debug, Serialize, Deserialize)] -#[serde( - bound( - serialize = "T: ::serde::Serialize", - deserialize = "T: for<'d> Deserialize<'d>" - ), - deny_unknown_fields -)] -// TODO: `T: AnyLightClient` -// prerequisites: derive macro for AnyLightClient -#[cfg_attr( - feature = "arbitrary", - derive(arbitrary::Arbitrary), - arbitrary(bound = "T: arbitrary::Arbitrary<'arbitrary>") -)] -pub struct Identified { - pub chain_id: ChainIdOf, - pub t: T, - #[serde(skip)] - #[debug(skip)] - #[cfg_attr(feature = "arbitrary", arbitrary(default))] - pub __marker: PhantomData Tr>, -} - -impl PartialEq for Identified { - fn eq(&self, other: &Self) -> bool { - self.chain_id == other.chain_id && self.t == other.t - } -} - -impl Clone for Identified { - fn clone(&self) -> Self { - Self { - chain_id: self.chain_id.clone(), - t: self.t.clone(), - __marker: PhantomData, - } - } -} - -pub fn id(chain_id: ChainIdOf, t: T) -> Identified { - Identified { - chain_id, - t, - __marker: PhantomData, - } -} - -pub trait DoAggregate: Sized + Debug + Clone + PartialEq { - fn do_aggregate(_: Self, _: VecDeque>) -> Op; -} - -impl DoAggregate for Identified { - fn do_aggregate(s: Self, _: VecDeque>) -> Op { - match s.t {} - } -} - -pub trait DoFetchState: ChainExt { - type QueryUnfinalizedTrustedClientStateError: Debug - + Clone - + PartialEq - + std::error::Error - + Send - + Sync; - - fn state(hc: &Hc, at: Hc::Height, path: PathOf) -> Op; - - // SEE: - fn query_unfinalized_trusted_client_state( - hc: &Hc, - client_id: Hc::ClientId, - ) -> impl Future< - Output = Result, Self::QueryUnfinalizedTrustedClientStateError>, - > + '_; -} - -pub trait DoFetchProof: ChainExt { - fn proof(hc: &Hc, at: HeightOf, path: PathOf) -> Op; -} - -pub trait DoFetchUpdateHeaders: ChainExt { - fn fetch_update_headers(hc: &Hc, update_info: FetchUpdateHeaders) -> Op; -} - -pub trait DoMsg: ChainExt { - fn msg( - &self, - msg: Effect, - ) -> impl Future, Self::MsgError>> + Send + '_; -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde( - bound(serialize = "T: Serialize", deserialize = "T: for<'d> Deserialize<'d>"), - deny_unknown_fields -)] -struct Inner { - #[serde(rename = "@host_chain", with = "::unionlabs::traits::from_str_exact")] - host_chain: Hc::ChainType, - #[serde(rename = "@tracking", with = "::unionlabs::traits::from_str_exact")] - tracking: Tr::ChainType, - #[serde(rename = "@value")] - inner: T, -} - -impl Inner { - fn new(s: T) -> Inner { - Self { - host_chain: Hc::ChainType::default(), - tracking: Tr::ChainType::default(), - inner: s, - } - } -} - -macro_rules! any_lc { - (|$msg:ident| $expr:expr) => { - match $msg { - AnyLightClientIdentified::EthereumMainnetOnUnion($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::wasm::Wasm; - #[allow(dead_code)] - type Tr = chain_utils::ethereum::Ethereum; - - $expr - } - AnyLightClientIdentified::UnionOnEthereumMainnet($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::ethereum::Ethereum; - #[allow(dead_code)] - type Tr = chain_utils::wasm::Wasm; - - $expr - } - - AnyLightClientIdentified::EthereumMinimalOnUnion($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::wasm::Wasm; - #[allow(dead_code)] - type Tr = chain_utils::ethereum::Ethereum; - - $expr - } - AnyLightClientIdentified::UnionOnEthereumMinimal($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::ethereum::Ethereum; - #[allow(dead_code)] - type Tr = chain_utils::wasm::Wasm; - - $expr - } - - AnyLightClientIdentified::ScrollOnUnion($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::wasm::Wasm; - #[allow(dead_code)] - type Tr = chain_utils::scroll::Scroll; - - $expr - } - AnyLightClientIdentified::UnionOnScroll($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::scroll::Scroll; - #[allow(dead_code)] - type Tr = chain_utils::wasm::Wasm; - - $expr - } - - AnyLightClientIdentified::ArbitrumOnUnion($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::wasm::Wasm; - #[allow(dead_code)] - type Tr = chain_utils::arbitrum::Arbitrum; - - $expr - } - AnyLightClientIdentified::UnionOnArbitrum($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::arbitrum::Arbitrum; - #[allow(dead_code)] - type Tr = chain_utils::wasm::Wasm; - - $expr - } - - AnyLightClientIdentified::BerachainOnUnion($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::wasm::Wasm; - #[allow(dead_code)] - type Tr = chain_utils::berachain::Berachain; - - $expr - } - AnyLightClientIdentified::UnionOnBerachain($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::berachain::Berachain; - #[allow(dead_code)] - type Tr = chain_utils::wasm::Wasm; - - $expr - } - AnyLightClientIdentified::WasmCosmosOnUnion($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::union::Union; - #[allow(dead_code)] - type Tr = chain_utils::wasm::Wasm; - - $expr - } - AnyLightClientIdentified::UnionOnWasmCosmos($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::wasm::Wasm; - #[allow(dead_code)] - type Tr = chain_utils::union::Union; - - $expr - } - - AnyLightClientIdentified::CosmosOnUnion($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::union::Union; - #[allow(dead_code)] - type Tr = chain_utils::cosmos::Cosmos; - - $expr - } - AnyLightClientIdentified::UnionOnCosmos($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::cosmos::Cosmos; - #[allow(dead_code)] - type Tr = chain_utils::union::Union; - - $expr - } - - AnyLightClientIdentified::CosmosOnCosmos($msg) => { - #[allow(dead_code)] - type Hc = chain_utils::cosmos::Cosmos; - #[allow(dead_code)] - type Tr = chain_utils::cosmos::Cosmos; - - $expr - } - } - }; -} -pub(crate) use any_lc; - -mod sanity_checks { - use chain_utils::{cosmos::Cosmos, ethereum::Ethereum, union::Union, wasm::Wasm}; - use queue_msg::aggregation::UseAggregate; - use static_assertions::assert_impl_all; - use unionlabs::ethereum::config::Mainnet; - - use crate::{ - aggregate::AggregateMsgConnectionOpenTry, chain::union::UnionFetch, fetch::DoFetch, - DoFetchState, RelayMessage, - }; - - assert_impl_all!(Wasm: DoFetchState, Union>); - - assert_impl_all!(identified!(AggregateMsgConnectionOpenTry, Union>): UseAggregate); - - assert_impl_all!(UnionFetch, Ethereum>: DoFetch>); -} diff --git a/lib/relay-message/src/use_aggregate.rs b/lib/relay-message/src/use_aggregate.rs deleted file mode 100644 index c30a001c8e..0000000000 --- a/lib/relay-message/src/use_aggregate.rs +++ /dev/null @@ -1,4 +0,0 @@ -use crate::{data::AnyData, AnyLightClientIdentified}; - -pub trait IsAggregateData = TryFrom, Error = AnyLightClientIdentified> - + Into>; diff --git a/lib/relay-message/src/wait.rs b/lib/relay-message/src/wait.rs deleted file mode 100644 index 2ea8a100e6..0000000000 --- a/lib/relay-message/src/wait.rs +++ /dev/null @@ -1,212 +0,0 @@ -use std::marker::PhantomData; - -use chain_utils::{ChainNotFoundError, GetChain}; -use macros::apply; -use queue_msg::{ - data, defer_absolute, fetch, noop, now, queue_msg, seq, wait, HandleWait, Op, QueueError, - QueueMessage, -}; -use tracing::{debug, instrument}; -use unionlabs::{ - ibc::core::client::height::{Height, IsHeight}, - ics24::ClientStatePath, - traits::{ChainIdOf, ClientState, HeightOf}, - QueryHeight, -}; - -use crate::{ - any_enum, any_lc, - data::{AnyData, Data, LatestHeight}, - fetch::{AnyFetch, Fetch, FetchState}, - id, identified, AnyLightClientIdentified, ChainExt, DoFetchState, RelayMessage, -}; - -#[apply(any_enum)] -#[any = AnyWait] -pub enum Wait { - Height(WaitForHeight), - HeightRelative(WaitForHeightRelative), - Timestamp(WaitForTimestamp), - TrustedHeight(WaitForTrustedHeight), -} - -impl HandleWait for AnyLightClientIdentified { - #[instrument(skip_all, fields(chain_id = %self.chain_id()))] - async fn handle( - self, - store: &::Store, - ) -> Result, QueueError> { - let wait = self; - - any_lc! { - |wait| { - Ok(store - .with_chain(&wait.chain_id, move |c| async move { wait.t.handle(&c).await }) - .map_err(|e: ChainNotFoundError| QueueError::Fatal(Box::new(e)))? - .await - .map_err(|e| QueueError::Fatal(Box::new(e)))? - ) - } - } - } -} - -impl Wait -where - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - AnyLightClientIdentified: From)>, - Hc: ChainExt + DoFetchState, - Tr: ChainExt, -{ - pub async fn handle(self, c: &Hc) -> Result, WaitError> { - match self { - Wait::Height(WaitForHeight { height, __marker }) => { - let chain_height = c.query_latest_height().await.unwrap(); - if chain_height >= height { - Ok(noop()) - } else { - Ok(seq([ - // REVIEW: Defer until `now + chain.block_time()`? Would require a new method on chain - defer_absolute(now() + 1), - wait(id::( - c.chain_id(), - WaitForHeight { height, __marker }, - )), - ])) - } - } - // REVIEW: Perhaps remove, unused - Wait::HeightRelative(WaitForHeightRelative { - height, - __marker: _, - }) => { - let chain_height = c.query_latest_height().await.unwrap(); - - Ok(wait(id::( - c.chain_id(), - WaitForHeight { - height: Height { - revision_number: chain_height.revision_number(), - revision_height: chain_height.revision_height() + height, - } - .into(), - __marker: PhantomData, - }, - ))) - } - Wait::Timestamp(WaitForTimestamp { - timestamp, - __marker, - }) => { - let chain_ts = c.query_latest_timestamp().await.unwrap(); - - if chain_ts >= timestamp { - // TODO: Figure out a way to fetch a height at a specific timestamp - Ok(data(id( - c.chain_id(), - LatestHeight:: { - height: c.query_latest_height().await.unwrap(), - __marker: PhantomData, - }, - ))) - } else { - Ok(seq([ - // REVIEW: Defer until `now + chain.block_time()`? Would require a new method on chain - defer_absolute(now() + 1), - wait(id::( - c.chain_id(), - WaitForTimestamp { - timestamp, - __marker, - } - .into(), - )), - ])) - } - } - Wait::TrustedHeight(WaitForTrustedHeight { - client_id, - counterparty_client_id, - counterparty_chain_id, - height, - }) => { - let trusted_client_state = - Hc::query_unfinalized_trusted_client_state(c, client_id.clone()) - .await - .map_err(|err| { - WaitError::FetchUnfinalizedTrustedClientState(Box::new(err)) - })?; - - if trusted_client_state.height().revision_height() >= height.revision_height() { - debug!( - "client height reached ({} >= {})", - trusted_client_state.height(), - height - ); - - // the height has been reached, fetch the counterparty client state on `Tr` at the trusted height - Ok(fetch(id( - counterparty_chain_id, - FetchState:: { - at: QueryHeight::Specific(trusted_client_state.height()), - path: ClientStatePath { - client_id: counterparty_client_id.clone(), - } - .into(), - }, - ))) - } else { - Ok(seq([ - // REVIEW: Defer until `now + counterparty_chain.block_time()`? Would require a new method on chain - defer_absolute(now() + 1), - wait(id( - c.chain_id(), - WaitForTrustedHeight { - client_id, - height, - counterparty_client_id, - counterparty_chain_id, - }, - )), - ])) - } - } - } - } -} - -/// See docs on `FetchError` for more information about the design of this type. -#[derive(macros::Debug, thiserror::Error)] -pub enum WaitError { - #[error("error fetching unfinalized trusted client state")] - FetchUnfinalizedTrustedClientState( - #[source] Box, - ), -} - -#[queue_msg] -pub struct WaitForHeight { - pub height: HeightOf, -} - -#[queue_msg] -pub struct WaitForHeightRelative<#[cover] Hc: ChainExt, #[cover] Tr: ChainExt> { - pub height: u64, -} - -#[queue_msg] -pub struct WaitForTimestamp<#[cover] Hc: ChainExt, #[cover] Tr: ChainExt> { - pub timestamp: i64, -} - -/// Wait for the client `.client_id` on `Hc` to trust a height >= `.height`, returning the counterparty's client state at that height when it's reached. -#[queue_msg] -pub struct WaitForTrustedHeight { - /// The id of the client on `Hc` who's [`ClientState::height()`] we're waiting to be >= `.height`. - pub client_id: Hc::ClientId, - /// The id of the counterparty client on `Tr`, who's state will be fetched at [`ClientState::height()`] when `.client_id` on `Hc` trusts a height >= `.height`. - pub counterparty_client_id: Tr::ClientId, - pub counterparty_chain_id: ChainIdOf, - pub height: Tr::Height, -} diff --git a/lib/scroll-codec/src/batch_header.rs b/lib/scroll-codec/src/batch_header.rs index 2893b4c29a..3d4776ea21 100644 --- a/lib/scroll-codec/src/batch_header.rs +++ b/lib/scroll-codec/src/batch_header.rs @@ -58,7 +58,6 @@ impl BatchHeaderV3 { /// # Errors /// /// Fails if the length of the stream doesn't match the expected length. - /// pub fn decode(bz: impl AsRef<[u8]>) -> Result { let bz = bz.as_ref(); diff --git a/lib/scroll-codec/src/lib.rs b/lib/scroll-codec/src/lib.rs index 17fb1217cd..3b4f05df51 100644 --- a/lib/scroll-codec/src/lib.rs +++ b/lib/scroll-codec/src/lib.rs @@ -65,7 +65,6 @@ pub enum HashBatchError { /// # Errors /// /// Fails if the batch header can't be decoded. -/// pub fn hash_batch(batch_header: Vec) -> Result { let batch_header = BatchHeaderV3::decode(batch_header)?; Ok(batch_header.compute_batch_hash()) diff --git a/lib/scroll-rpc/Cargo.toml b/lib/scroll-rpc/Cargo.toml index d2b10c09c4..741f4df351 100644 --- a/lib/scroll-rpc/Cargo.toml +++ b/lib/scroll-rpc/Cargo.toml @@ -6,7 +6,7 @@ repository = { workspace = true } version = "0.1.0" [dependencies] -jsonrpsee = { version = "0.22.3", features = ["tracing", "ws-client"] } +jsonrpsee = { workspace = true, features = ["tracing", "ws-client"] } macros = { workspace = true } serde = { workspace = true, features = ["derive"] } serde-utils = { workspace = true } diff --git a/lib/scroll-verifier/Cargo.toml b/lib/scroll-verifier/Cargo.toml index 7facea0bf4..90e1f7ebcc 100644 --- a/lib/scroll-verifier/Cargo.toml +++ b/lib/scroll-verifier/Cargo.toml @@ -12,16 +12,16 @@ workspace = true test-include = ["lib/scroll-verifier/tests"] [dependencies] -ethereum-verifier = { workspace = true } -ethers-core.workspace = true -hex = { workspace = true } -hex-literal.workspace = true -rlp = { workspace = true } -scroll-codec.workspace = true -serde = { workspace = true } -serde-utils = { workspace = true } -serde_json = { workspace = true } -sha3 = { workspace = true } -thiserror = { workspace = true } -unionlabs = { workspace = true } -zktrie = { workspace = true } +ethereum-verifier = { workspace = true } +ethers-core = { workspace = true } +hex = { workspace = true } +hex-literal = { workspace = true } +rlp = { workspace = true } +scroll-codec = { workspace = true } +serde = { workspace = true } +serde-utils = { workspace = true } +serde_json = { workspace = true } +sha3 = { workspace = true } +thiserror = { workspace = true } +unionlabs = { workspace = true } +zktrie = { workspace = true } diff --git a/lib/scroll-verifier/src/lib.rs b/lib/scroll-verifier/src/lib.rs index 2bc661b55e..7406afce3c 100644 --- a/lib/scroll-verifier/src/lib.rs +++ b/lib/scroll-verifier/src/lib.rs @@ -29,13 +29,11 @@ pub enum Error { HashBatch(#[from] HashBatchError), } -/* - 1. rollupContractOnL1 ∈ L1Stateroot - 2. lastBatchIndex ≡ rollupContractOnL1.lastBatchIndex - 3. L2stateRoot ≡ rollupContractOnL1.finalized[lastBatchIndex] - 4. batchHash ≡ rollupContractOnL1.batchHashes[lastBatchIndex] - 5. ibcContractOnL2 ∈ L2StateRoot -*/ +// 1. rollupContractOnL1 ∈ L1Stateroot +// 2. lastBatchIndex ≡ rollupContractOnL1.lastBatchIndex +// 3. L2stateRoot ≡ rollupContractOnL1.finalized[lastBatchIndex] +// 4. batchHash ≡ rollupContractOnL1.batchHashes[lastBatchIndex] +// 5. ibcContractOnL2 ∈ L2StateRoot pub fn verify_header( client_state: ClientState, header: Header, diff --git a/lib/serde-utils/src/lib.rs b/lib/serde-utils/src/lib.rs index 93a4c996fc..67966428e1 100644 --- a/lib/serde-utils/src/lib.rs +++ b/lib/serde-utils/src/lib.rs @@ -12,6 +12,7 @@ use alloc::{ use core::fmt::Debug; use hex::FromHexError; +use serde::{Deserialize, Serialize}; pub const HEX_ENCODING_PREFIX: &str = "0x"; @@ -357,6 +358,41 @@ pub mod hex_allow_unprefixed { } } +pub mod hex_allow_unprefixed_maybe_empty { + use alloc::{format, string::String, vec::Vec}; + use core::fmt::Debug; + + use serde::{de, Deserialize, Deserializer, Serializer}; + + pub fn serialize>(data: &Option, serializer: S) -> Result + where + S: Serializer, + { + match data { + Some(data) => crate::hex_string::serialize(data, serializer), + None => serializer.serialize_str(""), + } + } + + pub fn deserialize<'de, D, T>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + T: TryFrom, Error: Debug + 'static>, + { + let s = String::deserialize(deserializer)?; + let s = s.strip_prefix("0x").unwrap_or(&s); + + if s.is_empty() { + return Ok(None); + } + + let bz = hex::decode(s).map_err(de::Error::custom)?; + bz.try_into() + .map(Some) + .map_err(|y: >>::Error| de::Error::custom(format!("{y:?}"))) + } +} + pub mod hex_string_list { use alloc::{format, string::String, vec::Vec}; use core::fmt::Debug; @@ -389,6 +425,7 @@ pub mod hex_string_list { } } +// TODO: Check if human readable pub mod string { use alloc::string::String; use core::{fmt::Display, str::FromStr}; @@ -417,6 +454,41 @@ pub mod string { } } +pub mod string_list { + use alloc::{format, string::String, vec::Vec}; + use core::{fmt::Debug, str::FromStr}; + + use serde::{de, Deserialize, Deserializer, Serializer}; + + use crate::alloc::string::ToString; + + pub fn serialize(list: &C, serializer: S) -> Result + where + S: Serializer, + T: core::fmt::Display, + for<'a> &'a C: IntoIterator, + { + serializer.collect_seq(list.into_iter().map(|t| t.to_string())) + } + + pub fn deserialize<'de, D, T, C>(deserializer: D) -> Result + where + D: Deserializer<'de>, + T: FromStr, + C: TryFrom, Error: Debug>, + { + Vec::::deserialize(deserializer)? + .into_iter() + .map(|s| { + s.parse() + .map_err(|err| de::Error::custom(format!("{err:?}"))) + }) + .collect::, D::Error>>()? + .try_into() + .map_err(|err| de::Error::custom(format!("failed to collect list: {err:#?}"))) + } +} + pub mod map_numeric_keys_as_string { use alloc::{ collections::BTreeMap, @@ -680,6 +752,19 @@ pub mod fmt { } } +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)] +#[serde(bound( + serialize = "T: AsRef<[u8]>", + deserialize = "T: TryFrom, Error: Debug + 'static>", +))] +pub struct Hex(#[serde(with = "crate::hex_string")] pub T); + +impl> core::fmt::Display for Hex { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(&to_hex(&self.0)) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/lib/ssz-derive/src/lib.rs b/lib/ssz-derive/src/lib.rs index aefa2d1000..9b35e85ac8 100644 --- a/lib/ssz-derive/src/lib.rs +++ b/lib/ssz-derive/src/lib.rs @@ -5,12 +5,8 @@ //! //! The following struct/enum attributes are available: //! -//! - `#[ssz(tag)]`: encodes and decodes an `enum` with 0 fields per variant //! - `#[ssz(union)]`: encodes and decodes an `enum` with a one-byte variant selector. -//! - `#[ssz(transparent)]`: allows encoding an `enum` by serializing only the -//! value whilst ignoring outermost the `enum`. -//! - `#[ssz(transparent)]`: encodes and decodes a `struct` with exactly one -//! non-skipped field as if the outermost `struct` does not exist. +//! - `#[ssz(transparent)]`: encodes and decodes a `struct` with exactly one field as if the outermost `struct` does not exist. //! //! The following field attributes are available: //! @@ -24,7 +20,6 @@ //! //! /// Represented as an SSZ "list" wrapped in an SSZ "container". //! #[derive(Debug, PartialEq, Ssz)] -//! #[ssz(struct_behaviour = "container")] // "container" is the default behaviour //! struct TypicalStruct { //! foo: List //! } @@ -102,7 +97,7 @@ //! //! /// Represented as an SSZ "union". //! #[derive(Debug, PartialEq, Ssz)] -//! #[ssz(enum_behaviour = "union")] +//! #[ssz(union)] //! enum UnionEnum { //! Foo(u8), //! Bar(List), @@ -119,7 +114,7 @@ //! //! /// Represented as only the value in the enum variant. //! #[derive(Debug, PartialEq, Encode)] -//! #[ssz(enum_behaviour = "transparent")] +//! #[ssz(transparent)] //! enum TransparentEnum { //! Foo(u8), //! Bar(List), @@ -133,23 +128,6 @@ //! TransparentEnum::Bar(vec![42, 42].try_into().unwrap()).as_ssz_bytes(), //! vec![42, 42] //! ); -//! -//! /// Represented as an SSZ "uint8" -//! #[derive(Debug, PartialEq, Ssz)] -//! #[ssz(enum_behaviour = "tag")] -//! enum TagEnum { -//! Foo, -//! Bar, -//! } -//! assert_eq!( -//! TagEnum::Foo.as_ssz_bytes(), -//! vec![0] -//! ); -//! assert_eq!( -//! TagEnum::from_ssz_bytes(&[1]).unwrap(), -//! TagEnum::Bar, -//! ); -//! ``` use syn::{parse_macro_input, DeriveInput}; diff --git a/lib/ssz/Cargo.toml b/lib/ssz/Cargo.toml index e599f56d30..0ee48443d1 100644 --- a/lib/ssz/Cargo.toml +++ b/lib/ssz/Cargo.toml @@ -9,24 +9,22 @@ version = "0.5.3" name = "ssz" [dependencies] -arbitrary = { workspace = true, features = ["derive"], optional = true } -derivative = "2.1.1" -itertools = "0.10.3" -lazy_static = { workspace = true } -serde = { workspace = true, features = ["derive"] } -serde-utils.workspace = true -sha2.workspace = true -smallvec = { version = "1.6.1", features = ["const_generics"] } -ssz-derive = { workspace = true } -thiserror.workspace = true -typenum = { workspace = true, features = ["const-generics"] } +derivative = "2.1.1" +itertools = "0.10.3" +lazy_static = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +sha2 = { workspace = true } +smallvec = { version = "1.6.1", features = ["const_generics"] } +ssz-derive = { workspace = true } +thiserror = { workspace = true } +typenum = { workspace = true, features = ["const-generics"] } [dev-dependencies] -hex-literal.workspace = true -serde_json = { workspace = true } -serde_yaml = "0.9.34" -snap = "1.1.1" -unionlabs.workspace = true +hex-literal = { workspace = true } +serde_json = { workspace = true } +serde_yaml = "0.9.34" +snap = "1.1.1" +unionlabs = { workspace = true } [features] -arbitrary = ["dep:arbitrary"] diff --git a/lib/ssz/src/decode.rs b/lib/ssz/src/decode.rs index 4ef1ea4b4b..e0161e6e0b 100644 --- a/lib/ssz/src/decode.rs +++ b/lib/ssz/src/decode.rs @@ -41,24 +41,24 @@ pub enum DecodeError { /// An offset points “backwards” into the fixed-bytes portion of the message, essentially /// double-decoding bytes that will also be decoded as fixed-length. /// - /// https://notes.ethereum.org/ruKvDXl6QOW3gnqVYb8ezA?view#1-Offset-into-fixed-portion + /// #[error("tried to read offset {0} into fixed-size portion")] OffsetIntoFixedPortion(usize), /// The first offset does not point to the byte that follows the fixed byte portion, /// essentially skipping a variable-length byte. /// - /// https://notes.ethereum.org/ruKvDXl6QOW3gnqVYb8ezA?view#2-Skip-first-variable-byte + /// #[error("first offset {0} does not point to the byte that follows the fixed-size portion")] OffsetSkipsVariableBytes(usize), /// An offset points to bytes prior to the previous offset. Depending on how you look at it, /// this either double-decodes bytes or makes the first offset a negative-length. /// - /// https://notes.ethereum.org/ruKvDXl6QOW3gnqVYb8ezA?view#3-Offsets-are-decreasing + /// #[error("offset {0} points to bytes prior to the previous offset")] OffsetsAreDecreasing(usize), /// An offset references byte indices that do not exist in the source bytes. /// - /// https://notes.ethereum.org/ruKvDXl6QOW3gnqVYb8ezA?view#4-Offsets-are-out-of-bounds + /// #[error("offset {0} points beyond the end of the source data")] OffsetOutOfBounds(usize), /// A variable-length list does not have a fixed portion that is cleanly divisible by @@ -93,7 +93,7 @@ pub enum DecodeError { /// /// The checks here are derived from this document: /// -/// https://notes.ethereum.org/ruKvDXl6QOW3gnqVYb8ezA?view +/// pub(crate) fn sanitize_offset( offset: usize, previous_offset: Option, @@ -265,7 +265,6 @@ impl<'a> SszDecoderBuilder<'a> { /// /// assert_eq!(foo, decoded_foo); /// } -/// /// ``` pub struct SszDecoder<'a> { items: SmallVec8<&'a [u8]>, diff --git a/lib/ssz/src/lib.rs b/lib/ssz/src/lib.rs index a52b4eca95..4e9ebcd400 100644 --- a/lib/ssz/src/lib.rs +++ b/lib/ssz/src/lib.rs @@ -29,7 +29,6 @@ //! //! assert_eq!(foo, decoded_foo); //! } -//! //! ``` pub mod decode; diff --git a/lib/ssz/src/tree_hash.rs b/lib/ssz/src/tree_hash.rs index da692f880f..c63bedd13b 100644 --- a/lib/ssz/src/tree_hash.rs +++ b/lib/ssz/src/tree_hash.rs @@ -108,7 +108,7 @@ pub fn mix_in_type(root: &Hash256, type_index: usize) -> Hash256 { /// serialization) return hash(root + selector). /// ``` /// -/// https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.3/ssz/simple-serialize.md#union +/// #[must_use] pub fn mix_in_selector(root: &Hash256, selector: u8) -> Option { if selector > MAX_UNION_SELECTOR { diff --git a/lib/ssz/src/tree_hash/merkle_hasher.rs b/lib/ssz/src/tree_hash/merkle_hasher.rs index 0108e65119..df7db5c5de 100644 --- a/lib/ssz/src/tree_hash/merkle_hasher.rs +++ b/lib/ssz/src/tree_hash/merkle_hasher.rs @@ -121,7 +121,6 @@ impl HalfNode { /// / \ / \ /// L L L L /// ``` -/// pub struct MerkleHasher { /// Stores the nodes that are half-complete and awaiting a right node. /// diff --git a/lib/ssz/src/types/bitfield.rs b/lib/ssz/src/types/bitfield.rs index 2eccc9f400..280193d55e 100644 --- a/lib/ssz/src/types/bitfield.rs +++ b/lib/ssz/src/types/bitfield.rs @@ -90,7 +90,6 @@ pub type BitVector = Bitfield>; /// assert_eq!(bitvector.len(), 8); // `BitVector` length is fixed at the type-level. /// assert!(bitvector.set(7, true).is_ok()); // Setting inside the capacity is permitted. /// assert!(bitvector.set(9, true).is_err()); // Setting outside the capacity is not. -/// /// ``` /// /// ## Note @@ -569,28 +568,6 @@ impl<'de, N: Unsigned + Clone> Deserialize<'de> for Bitfield> { } } -#[cfg(feature = "arbitrary")] -impl arbitrary::Arbitrary<'_> for Bitfield> { - fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result { - let size = N::USIZE; - let mut vec = smallvec![0u8; size]; - u.fill_buffer(&mut vec)?; - Ok(Self::from_bytes(vec).map_err(|_| arbitrary::Error::IncorrectFormat)?) - } -} - -#[cfg(feature = "arbitrary")] -impl arbitrary::Arbitrary<'_> for Bitfield> { - fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result { - let max_size = N::USIZE; - let rand = usize::arbitrary(u)?; - let size = std::cmp::min(rand, max_size); - let mut vec = smallvec![0u8; size]; - u.fill_buffer(&mut vec)?; - Ok(Self::from_bytes(vec).map_err(|_| arbitrary::Error::IncorrectFormat)?) - } -} - #[cfg(test)] mod bitvector { use super::*; diff --git a/lib/ssz/src/types/list.rs b/lib/ssz/src/types/list.rs index 017736874c..1fa1478bc5 100644 --- a/lib/ssz/src/types/list.rs +++ b/lib/ssz/src/types/list.rs @@ -299,22 +299,6 @@ impl TryFromIter for List { } } -#[cfg(feature = "arbitrary")] -impl<'a, T: arbitrary::Arbitrary<'a>, N: 'static + Unsigned + NonZero> arbitrary::Arbitrary<'a> - for List -{ - fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - let max_size = N::USIZE; - let rand = usize::arbitrary(u)?; - let size = std::cmp::min(rand, max_size); - let mut vec: Vec = Vec::with_capacity(size); - for _ in 0..size { - vec.push(::arbitrary(u)?); - } - Ok(Self::new(vec).map_err(|_| arbitrary::Error::IncorrectFormat)?) - } -} - #[cfg(test)] mod test { use typenum::*; diff --git a/lib/ssz/src/types/vector.rs b/lib/ssz/src/types/vector.rs index 69557a73fe..a9e47a716e 100644 --- a/lib/ssz/src/types/vector.rs +++ b/lib/ssz/src/types/vector.rs @@ -44,6 +44,7 @@ use crate::{ #[derivative( Clone(bound = "T: ::core::clone::Clone"), PartialEq(bound = "T: ::core::cmp::PartialEq"), + Eq(bound = "T: ::core::cmp::Eq"), Hash(bound = "T: ::core::hash::Hash") )] #[serde(transparent)] @@ -278,20 +279,6 @@ impl TryFromIter for Vector { } } -#[cfg(feature = "arbitrary")] -impl<'a, T: arbitrary::Arbitrary<'a>, N: 'static + Unsigned + NonZero> arbitrary::Arbitrary<'a> - for Vector -{ - fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - let size = N::USIZE; - let mut vec: Vec = Vec::with_capacity(size); - for _ in 0..size { - vec.push(::arbitrary(u)?); - } - Ok(Self::new(vec).map_err(|_| arbitrary::Error::IncorrectFormat)?) - } -} - #[cfg(test)] mod test { use typenum::*; diff --git a/lib/ssz/src/union_selector.rs b/lib/ssz/src/union_selector.rs index fdb5035c6e..b70d8573e9 100644 --- a/lib/ssz/src/union_selector.rs +++ b/lib/ssz/src/union_selector.rs @@ -2,7 +2,7 @@ use crate::{DecodeError, MAX_UNION_SELECTOR}; /// Provides the one-byte "selector" from the SSZ union specification: /// -/// https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.3/ssz/simple-serialize.md#union +/// #[derive(Copy, Clone)] pub struct UnionSelector(u8); diff --git a/lib/ssz/tests-generator/Cargo.toml b/lib/ssz/tests-generator/Cargo.toml index fcfaec6723..885e2089ea 100644 --- a/lib/ssz/tests-generator/Cargo.toml +++ b/lib/ssz/tests-generator/Cargo.toml @@ -1,21 +1,21 @@ [package] -edition.workspace = true -license-file.workspace = true -name = "ssz-tests-generator" -publish = false -repository.workspace = true -version = "0.1.0" +edition = { workspace = true } +license-file = { workspace = true } +name = "ssz-tests-generator" +publish = false +repository = { workspace = true } +version = "0.1.0" [lints] workspace = true [dependencies] -hex.workspace = true -serde = { workspace = true, features = ["derive"] } -serde-utils = { workspace = true } -serde_json = { workspace = true } -serde_yaml = "0.9.34" -snap = "1.1.1" -ssz.workspace = true -typenum.workspace = true -unionlabs.workspace = true +hex = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +serde_json = { workspace = true } +serde_yaml = "0.9.34" +snap = "1.1.1" +ssz = { workspace = true } +typenum = { workspace = true } +unionlabs = { workspace = true } diff --git a/lib/ssz/tests/derive.rs b/lib/ssz/tests/derive.rs index 7e214a3218..97780ecdcb 100644 --- a/lib/ssz/tests/derive.rs +++ b/lib/ssz/tests/derive.rs @@ -14,14 +14,6 @@ fn assert_encode_decode(item: &T, bytes: &[u8]) { assert_eq!(T::from_ssz_bytes(bytes).unwrap(), *item); } -// #[derive(PartialEq, Debug, Ssz)] -// #[ssz(tag)] -// enum TagEnum { -// A, -// B, -// C, -// } - #[derive(PartialEq, Debug, Ssz)] #[ssz(union)] enum TwoFixedUnion { @@ -58,18 +50,6 @@ struct VariableB { b: u8, } -// #[derive(PartialEq, Debug, Ssz)] -// #[ssz(transparent)] -// enum TwoVariableTrans { -// A(VariableA), -// B(VariableB), -// } - -// #[derive(PartialEq, Debug, Ssz)] -// struct TwoVariableTransStruct { -// a: TwoVariableTrans, -// } - #[derive(PartialEq, Debug, Ssz)] #[ssz(union)] enum TwoVariableUnion { @@ -82,30 +62,6 @@ struct TwoVariableUnionStruct { a: TwoVariableUnion, } -// #[test] -// fn two_variable_trans() { -// let trans_a = TwoVariableTrans::A(VariableA { -// a: 1, -// b: vec![2, 3].try_into().unwrap(), -// }); -// let trans_b = TwoVariableTrans::B(VariableB { -// a: vec![1, 2].try_into().unwrap(), -// b: 3, -// }); - -// assert_encode(&trans_a, &[1, 5, 0, 0, 0, 2, 3]); -// assert_encode(&trans_b, &[5, 0, 0, 0, 3, 1, 2]); - -// assert_encode( -// &TwoVariableTransStruct { a: trans_a }, -// &[4, 0, 0, 0, 1, 5, 0, 0, 0, 2, 3], -// ); -// assert_encode( -// &TwoVariableTransStruct { a: trans_b }, -// &[4, 0, 0, 0, 5, 0, 0, 0, 3, 1, 2], -// ); -// } - #[test] fn two_variable_union() { let union_a = TwoVariableUnion::A(VariableA { @@ -130,13 +86,6 @@ fn two_variable_union() { ); } -// #[test] -// fn tag_enum() { -// assert_encode_decode(&TagEnum::A, &[0]); -// assert_encode_decode(&TagEnum::B, &[1]); -// assert_encode_decode(&TagEnum::C, &[2]); -// } - #[derive(PartialEq, Debug, Ssz)] #[ssz(union)] enum TwoListUnion { diff --git a/lib/unionlabs/Cargo.toml b/lib/unionlabs/Cargo.toml index 1a9884feaf..2901f59b23 100644 --- a/lib/unionlabs/Cargo.toml +++ b/lib/unionlabs/Cargo.toml @@ -12,7 +12,6 @@ test-include = [] workspace = true [dependencies] -arbitrary = { workspace = true, optional = true, features = ["derive"] } bip32 = { workspace = true, features = ["secp256k1"] } bitvec = { workspace = true } chrono = { workspace = true, features = ["alloc"] } @@ -43,7 +42,7 @@ serde = { workspace = true, features = ["derive"] } serde-utils = { workspace = true } serde_json = { workspace = true } sha2 = { workspace = true } -sha3.workspace = true +sha3 = { workspace = true } ssz = { workspace = true } static_assertions = { workspace = true } subtle-encoding = { workspace = true, features = ["bech32-preview"] } @@ -74,8 +73,7 @@ grpc = ["protos/client"] near = ["borsh", "near-sdk", "near-primitives-core"] std = ["ethers-core/std"] -arbitrary = ["dep:arbitrary", "primitive-types/arbitrary"] -fuzzing = ["arbitrary"] +fuzzing = [] test_utils = [] schemars = ["dep:schemars"] diff --git a/lib/unionlabs/src/aptos.rs b/lib/unionlabs/src/aptos.rs index 1c5b50181d..f17ea681ba 100644 --- a/lib/unionlabs/src/aptos.rs +++ b/lib/unionlabs/src/aptos.rs @@ -1,9 +1,7 @@ pub mod account; -pub mod bit_vec; pub mod block_info; pub mod epoch_change; pub mod epoch_state; -pub mod hash_value; pub mod ledger_info; pub mod public_key; pub mod signature; @@ -12,3 +10,5 @@ pub mod state_proof; pub mod transaction_info; pub mod transaction_proof; pub mod validator_verifier; + +pub mod object; diff --git a/lib/unionlabs/src/aptos/account.rs b/lib/unionlabs/src/aptos/account.rs index 9b774c69b2..5d7f9e6d65 100644 --- a/lib/unionlabs/src/aptos/account.rs +++ b/lib/unionlabs/src/aptos/account.rs @@ -1,72 +1,55 @@ -use core::str::FromStr; +//! Yoinked from +/// +/// We only use the strict parsing and display functionality, and wrap our `H256` type instead of `[u8; 32]`. +use core::{fmt, str::FromStr}; -use hex::FromHex; use serde::{de::Error as _, Deserialize, Serialize}; -#[derive(thiserror::Error, Debug)] -pub enum AccountAddressParseError { - #[error("AccountAddress data should be exactly 32 bytes long")] - IncorrectNumberOfBytes, +use crate::hash::H256; - #[error("Hex characters are invalid: {0}")] - InvalidHexChars(String), +#[derive(macros::Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[debug("AccountAddress({})", self)] +pub struct AccountAddress(pub H256); - #[error("Hex string is too short, must be 1 to 64 chars long, excluding the leading 0x")] - TooShort, +impl AccountAddress { + /// Returns whether the address is a "special" address. Addresses are considered + /// special if the first 63 characters of the hex string are zero. In other words, + /// an address is special if the first 31 bytes are zero and the last byte is + /// smaller than than `0b10000` (16). In other words, special is defined as an address + /// that matches the following regex: `^0x0{63}[0-9a-f]$`. In short form this means + /// the addresses in the range from `0x0` to `0xf` (inclusive) are special. + /// + /// For more details see the v1 address standard defined as part of AIP-40: + /// + #[must_use] + pub fn is_special(&self) -> bool { + (self.0).0[..H256::BYTES_LEN - 1].iter().all(|x| *x == 0) + && is_special_byte((self.0).0[H256::BYTES_LEN - 1]) + } +} + +const fn is_special_byte(b: u8) -> bool { + b < 0b10000 +} - #[error("Hex string is too long, must be 1 to 64 chars long, excluding the leading 0x")] - TooLong, +#[derive(thiserror::Error, Debug)] +pub enum AccountAddressParseError { + #[error("hex string must start with a leading 0x")] + Leading0XRequired, - #[error("Hex string must start with a leading 0x")] - LeadingZeroXRequired, + #[error(transparent)] + HexDecode(#[from] hex::FromHexError), #[error( - "The given hex string is not a special address, it must be represented as 0x + 64 chars" + "the given hex string is not a special address, it must be represented as 0x + 64 chars" )] LongFormRequiredUnlessSpecial, - #[error("The given hex string is a special address not in LONG form, it must be 0x0 to 0xf without padding zeroes")] + #[error("the given hex string is a special address not in long form, it must be 0x0 to 0xf without padding zeroes")] InvalidPaddingZeroes, -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct AccountAddress(pub [u8; Self::LENGTH]); - -impl AccountAddress { - pub const LENGTH: usize = 32; - - #[must_use] - pub const fn new(address: [u8; Self::LENGTH]) -> Self { - Self(address) - } - - /// NOTE: Where possible use `from_str_strict` or `from_str` instead. - pub fn from_hex>(hex: T) -> Result { - <[u8; Self::LENGTH]>::from_hex(hex) - .map_err(|e| AccountAddressParseError::InvalidHexChars(format!("{e:#}"))) - .map(Self) - } - - /// NOTE: Where possible use `from_str_strict` or `from_str` instead. - pub fn from_hex_literal(literal: &str) -> Result { - if !literal.starts_with("0x") { - return Err(AccountAddressParseError::LeadingZeroXRequired); - } - - let hex_len = literal.len() - 2; - // If the string is too short, pad it - if hex_len < Self::LENGTH * 2 { - let mut hex_str = String::with_capacity(Self::LENGTH * 2); - for _ in 0..Self::LENGTH * 2 - hex_len { - hex_str.push('0'); - } - hex_str.push_str(&literal[2..]); - AccountAddress::from_hex(hex_str) - } else { - AccountAddress::from_hex(&literal[2..]) - } - } + #[error("invalid address length: {0}")] + InvalidLength(usize), } impl Serialize for AccountAddress { @@ -97,10 +80,10 @@ impl<'de> Deserialize<'de> for AccountAddress { // as the original type. #[derive(::serde::Deserialize)] #[serde(rename = "AccountAddress")] - struct Value([u8; AccountAddress::LENGTH]); + struct Value([u8; H256::BYTES_LEN]); let value = Value::deserialize(deserializer)?; - Ok(AccountAddress::new(value.0)) + Ok(AccountAddress(H256(value.0))) } } } @@ -108,36 +91,70 @@ impl<'de> Deserialize<'de> for AccountAddress { impl FromStr for AccountAddress { type Err = AccountAddressParseError; - /// NOTE: This function has relaxed parsing behavior. For strict behavior, please use - /// the `from_str_strict` function. Where possible use `from_str_strict` rather than - /// this function. + /// NOTE: This function has strict parsing behavior. For relaxed behavior, please use + /// the `from_str` function. Where possible, prefer to use `from_str_strict`. /// - /// Create an instance of `AccountAddress` by parsing a hex string representation. + /// Create an instance of [`AccountAddress`] by parsing a hex string representation. /// - /// This function allows all formats defined by AIP-40. In short this means the - /// following formats are accepted: + /// This function allows only the strictest formats defined by AIP-40. In short this + /// means only the following formats are accepted: /// - /// - LONG, with or without leading 0x - /// - SHORT, with or without leading 0x + /// - LONG + /// - SHORT for special addresses /// /// Where: /// - /// - LONG is 64 hex characters. - /// - SHORT is 1 to 63 hex characters inclusive. + /// - LONG is defined as 0x + 64 hex characters. + /// - SHORT for special addresses is 0x0 to 0xf inclusive. + /// + /// This means the following are not accepted: + /// + /// - SHORT for non-special addresses. + /// - Any address without a leading 0x. /// /// Learn more about the different address formats by reading AIP-40: /// . fn from_str(s: &str) -> Result { - if s.starts_with("0x") { - if s.len() == 2 { - return Err(AccountAddressParseError::TooShort); + // Assert the string starts with 0x. + if !s.starts_with("0x") { + return Err(AccountAddressParseError::Leading0XRequired); + } + + let address = hex::decode(&s[2..])?; + + // Check if the address is in LONG form. If it is not, this is only allowed for + // special addresses, in which case we check it is in proper SHORT form. + match address.len() { + H256::BYTES_LEN => Ok(Self(H256(address.try_into().unwrap()))), + 1 => { + let b = address[0]; + + if is_special_byte(b) { + return Err(AccountAddressParseError::LongFormRequiredUnlessSpecial); + } + + // 0x + one hex char is the only valid SHORT form for special addresses. + if s.len() != 3 { + return Err(AccountAddressParseError::InvalidPaddingZeroes); + } + + let mut address = [0; H256::BYTES_LEN]; + + address[H256::BYTES_LEN - 1] = b; + + Ok(Self(H256(address))) } - AccountAddress::from_hex_literal(s) + len => Err(AccountAddressParseError::InvalidLength(len)), + } + } +} + +impl fmt::Display for AccountAddress { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.is_special() { + f.write_fmt(format_args!("0x{:x}", self.0 .0[H256::BYTES_LEN - 1])) } else { - if s.is_empty() { - return Err(AccountAddressParseError::TooShort); - } - AccountAddress::from_hex_literal(&format!("0x{s}")) + self.0.fmt(f) } } } diff --git a/lib/unionlabs/src/aptos/bit_vec.rs b/lib/unionlabs/src/aptos/bit_vec.rs index e490a851e3..5d23f85797 100644 --- a/lib/unionlabs/src/aptos/bit_vec.rs +++ b/lib/unionlabs/src/aptos/bit_vec.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; -#[derive(Clone, Default, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub struct BitVec { - #[serde(with = "serde_bytes")] - pub inner: Vec, -} +// #[derive(Clone, Default, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +// pub struct BitVec { +// #[serde(with = "serde_bytes")] +// pub inner: Vec, +// } diff --git a/lib/unionlabs/src/aptos/block_info.rs b/lib/unionlabs/src/aptos/block_info.rs index 7d9e46c88b..0b72a003b8 100644 --- a/lib/unionlabs/src/aptos/block_info.rs +++ b/lib/unionlabs/src/aptos/block_info.rs @@ -1,10 +1,7 @@ use macros::model; -use super::{ - epoch_state::{EpochState, TryFromEpochStateError}, - hash_value::HashValue, -}; -use crate::errors::{ExpectedLength, InvalidLength}; +use super::epoch_state::{EpochState, TryFromEpochStateError}; +use crate::{errors::InvalidLength, hash::H256}; /// The round of a block is a consensus-internal counter, which starts with 0 and increases /// monotonically. @@ -35,9 +32,9 @@ pub struct BlockInfo { /// The consensus protocol is executed in rounds, which monotonically increase per epoch. pub round: Round, /// The identifier (hash) of the block. - pub id: HashValue, + pub id: H256, /// The accumulator root hash after executing this block. - pub executed_state_id: HashValue, + pub executed_state_id: H256, /// The version of the latest transaction after executing this block. pub version: Version, /// The timestamp this block was proposed by a proposer. @@ -79,20 +76,9 @@ impl TryFrom for Bloc Ok(Self { epoch: value.epoch, round: value.round, - id: HashValue::new(value.id.as_slice().try_into().map_err(|_| { - TryFromBlockInfoError::Id(InvalidLength { - expected: ExpectedLength::Exact(HashValue::LENGTH), - found: value.id.len(), - }) - })?), - executed_state_id: HashValue::new( - value.executed_state_id.as_slice().try_into().map_err(|_| { - TryFromBlockInfoError::ExecutedStateId(InvalidLength { - expected: ExpectedLength::Exact(HashValue::LENGTH), - found: value.executed_state_id.len(), - }) - })?, - ), + id: H256::try_from(value.id).map_err(TryFromBlockInfoError::Id)?, + executed_state_id: H256::try_from(value.executed_state_id) + .map_err(TryFromBlockInfoError::ExecutedStateId)?, version: value.version, timestamp_usecs: value.timestamp_usecs, next_epoch_state: value.next_epoch_state.map(TryInto::try_into).transpose()?, diff --git a/lib/unionlabs/src/aptos/hash_value.rs b/lib/unionlabs/src/aptos/hash_value.rs deleted file mode 100644 index 2c8150931d..0000000000 --- a/lib/unionlabs/src/aptos/hash_value.rs +++ /dev/null @@ -1,230 +0,0 @@ -use core::fmt; - -use hex::FromHex; -use serde::{de, ser, Deserialize, Serialize}; - -use crate::errors::{ExpectedLength, InvalidLength}; - -impl AsRef<[u8; HashValue::LENGTH]> for HashValue { - fn as_ref(&self) -> &[u8; HashValue::LENGTH] { - &self.0 - } -} - -impl core::ops::Deref for HashValue { - type Target = [u8; Self::LENGTH]; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl core::ops::Index for HashValue { - type Output = u8; - - fn index(&self, s: usize) -> &u8 { - self.0.index(s) - } -} - -impl fmt::Display for HashValueParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "unable to parse HashValue") - } -} - -impl fmt::LowerHex for HashValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if f.alternate() { - write!(f, "0x")?; - } - for byte in &self.0 { - write!(f, "{byte:02x}")?; - } - Ok(()) - } -} - -/// Will print shortened (4 bytes) hash -impl fmt::Display for HashValue { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for byte in self.0.iter().take(4) { - write!(f, "{byte:02x}")?; - } - Ok(()) - } -} - -impl fmt::Debug for HashValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "HashValue(")?; - ::fmt(self, f)?; - write!(f, ")")?; - Ok(()) - } -} - -impl core::error::Error for HashValueParseError {} - -/// Parse error when attempting to construct a `HashValue` -#[derive(Clone, Copy, Debug)] -pub struct HashValueParseError; - -#[derive(Eq, PartialEq, Clone, Copy)] -pub struct HashValue(pub [u8; HashValue::LENGTH]); - -impl HashValue { - /// The length of the hash in bytes. - pub const LENGTH: usize = 32; - /// The length of the hash in bits. - pub const LENGTH_IN_BITS: usize = Self::LENGTH * 8; - - /// Create a new [`HashValue`] from a byte array. - #[must_use] - pub fn new(hash: [u8; HashValue::LENGTH]) -> Self { - HashValue(hash) - } - - /// Parse a given hex string to a hash value. - pub fn from_hex>(hex: T) -> Result { - <[u8; Self::LENGTH]>::from_hex(hex) - .map_err(|_| HashValueParseError) - .map(Self::new) - } - - /// Full hex representation of a given hash value. - #[must_use] - pub fn to_hex(&self) -> String { - format!("{self:x}") - } - - #[must_use] - pub fn iter_bits(&self) -> HashValueBitIterator<'_> { - HashValueBitIterator::new(self) - } - - /// Returns the length of common prefix of `self` and `other` in bits. - #[must_use] - pub fn common_prefix_bits_len(&self, other: HashValue) -> usize { - self.iter_bits() - .zip(other.iter_bits()) - .take_while(|(x, y)| x == y) - .count() - } -} - -impl From for Vec { - fn from(value: HashValue) -> Self { - value.0.as_slice().to_vec() - } -} - -impl Default for HashValue { - fn default() -> Self { - HashValue::new([0; HashValue::LENGTH]) - } -} - -impl ser::Serialize for HashValue { - fn serialize(&self, serializer: S) -> Result - where - S: ser::Serializer, - { - if serializer.is_human_readable() { - serializer.serialize_str(&self.to_hex()) - } else { - // In order to preserve the Serde data model and help analysis tools, - // make sure to wrap our value in a container with the same name - // as the original type. - #[derive(Serialize)] - #[serde(rename = "HashValue")] - struct Value<'a> { - hash: &'a [u8; HashValue::LENGTH], - } - Value { hash: &self.0 }.serialize(serializer) - } - } -} - -impl<'de> de::Deserialize<'de> for HashValue { - fn deserialize(deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - if deserializer.is_human_readable() { - let encoded_hash = ::deserialize(deserializer)?; - HashValue::from_hex(encoded_hash.as_str()) - .map_err(::custom) - } else { - // See comment in serialize. - #[derive(Deserialize)] - #[serde(rename = "HashValue")] - struct Value { - hash: [u8; HashValue::LENGTH], - } - - let value = Value::deserialize(deserializer) - .map_err(::custom)?; - Ok(Self::new(value.hash)) - } - } -} - -/// An iterator over `HashValue` that generates one bit for each iteration. -pub struct HashValueBitIterator<'a> { - /// The reference to the bytes that represent the `HashValue`. - hash_bytes: &'a [u8], - pos: core::ops::Range, - // invariant hash_bytes.len() == HashValue::LENGTH; - // invariant pos.end == hash_bytes.len() * 8; -} - -impl<'a> HashValueBitIterator<'a> { - /// Constructs a new `HashValueBitIterator` using given `HashValue`. - fn new(hash_value: &'a HashValue) -> Self { - HashValueBitIterator { - hash_bytes: hash_value.as_ref(), - pos: (0..HashValue::LENGTH_IN_BITS), - } - } - - /// Returns the `index`-th bit in the bytes. - fn get_bit(&self, index: usize) -> bool { - // debug_assert_eq!(self.hash_bytes.len(), HashValue::LENGTH); // invariant - // debug_assert_lt!(index, HashValue::LENGTH_IN_BITS); // assumed precondition - let pos = index / 8; - let bit = 7 - index % 8; - (self.hash_bytes[pos] >> bit) & 1 != 0 - } -} - -impl<'a> core::iter::Iterator for HashValueBitIterator<'a> { - type Item = bool; - - fn next(&mut self) -> Option { - self.pos.next().map(|x| self.get_bit(x)) - } - - fn size_hint(&self) -> (usize, Option) { - self.pos.size_hint() - } -} - -impl<'a> core::iter::DoubleEndedIterator for HashValueBitIterator<'a> { - fn next_back(&mut self) -> Option { - self.pos.next_back().map(|x| self.get_bit(x)) - } -} - -impl TryFrom> for HashValue { - type Error = InvalidLength; - - fn try_from(value: Vec) -> Result { - Ok(HashValue::new(value.as_slice().try_into().map_err( - |_| InvalidLength { - expected: ExpectedLength::Exact(HashValue::LENGTH), - found: value.len(), - }, - )?)) - } -} diff --git a/lib/unionlabs/src/aptos/ledger_info.rs b/lib/unionlabs/src/aptos/ledger_info.rs index a77f8067a0..dc922b8d2a 100644 --- a/lib/unionlabs/src/aptos/ledger_info.rs +++ b/lib/unionlabs/src/aptos/ledger_info.rs @@ -2,10 +2,12 @@ use macros::model; use super::{ block_info::{BlockInfo, TryFromBlockInfoError}, - hash_value::HashValue, signature::{AggregateSignature, TryFromAggregateSignatureError}, }; -use crate::errors::{required, ExpectedLength, InvalidLength, MissingField}; +use crate::{ + errors::{required, InvalidLength, MissingField}, + hash::H256, +}; /// Wrapper to support future upgrades, this is the data being persisted. #[model(proto( @@ -40,7 +42,7 @@ pub struct LedgerInfo { /// Hash of consensus specific data that is opaque to all parts of the system other than /// consensus. - pub consensus_data_hash: HashValue, + pub consensus_data_hash: H256, } impl From @@ -107,18 +109,8 @@ impl TryFrom for Led ) -> Result { Ok(Self { commit_info: required!(value.commit_info)?.try_into()?, - consensus_data_hash: HashValue::new( - value - .consensus_data_hash - .as_slice() - .try_into() - .map_err(|_| { - TryFromLedgerInfo::ConsensusDataHash(InvalidLength { - expected: ExpectedLength::Exact(HashValue::LENGTH), - found: value.consensus_data_hash.len(), - }) - })?, - ), + consensus_data_hash: H256::try_from(value.consensus_data_hash) + .map_err(TryFromLedgerInfo::ConsensusDataHash)?, }) } } diff --git a/lib/unionlabs/src/aptos/object.rs b/lib/unionlabs/src/aptos/object.rs new file mode 100644 index 0000000000..461921f303 --- /dev/null +++ b/lib/unionlabs/src/aptos/object.rs @@ -0,0 +1,40 @@ +use sha3::Digest; + +use crate::hash::H256; + +/// +pub const OBJECT_FROM_SEED_ADDRESS_SCHEME: u8 = 254; + +/// +#[must_use] +pub fn create_object_address(address: H256, seed: &[u8]) -> H256 { + sha3::Sha3_256::new() + .chain_update(address) + .chain_update(seed) + .chain_update([OBJECT_FROM_SEED_ADDRESS_SCHEME]) + .finalize() + .into() +} + +#[cfg(test)] +mod tests { + use hex_literal::hex; + + use crate::{aptos::object::create_object_address, hash::H256}; + + #[test] + fn ibc_store_address() { + let address = H256::from(hex!( + "dc08d8da6e3de03f62fdab618dc36f2e4e9cd70b03722c1d46df767370602771" + )); + + let hash = create_object_address(address, b"Vault Seed Example"); + + assert_eq!( + H256::from(hex!( + "14117a3adabf98fc2affa2f1583c201d348a6cb5791d94286987fffa49bb8bcb" + )), + hash + ); + } +} diff --git a/lib/unionlabs/src/aptos/signature.rs b/lib/unionlabs/src/aptos/signature.rs index 9944420973..7d3b08005d 100644 --- a/lib/unionlabs/src/aptos/signature.rs +++ b/lib/unionlabs/src/aptos/signature.rs @@ -1,72 +1,6 @@ use macros::model; -use super::bit_vec::BitVec; - -#[model( - no_serde, - proto( - raw(protos::union::ibc::lightclients::movement::v1::Signature), - into, - from - ) -)] -/// Either (1) a BLS signature share from an individual signer, (2) a BLS multi-signature or (3) a -/// BLS aggregate signature -pub struct Signature { - pub sig: Vec, -} - -impl From for protos::union::ibc::lightclients::movement::v1::Signature { - fn from(value: Signature) -> Self { - Self { sig: value.sig } - } -} - -impl From for Signature { - fn from(value: protos::union::ibc::lightclients::movement::v1::Signature) -> Self { - Self { sig: value.sig } - } -} - -impl serde::Serialize for Signature { - fn serialize(&self, serializer: S) -> core::result::Result - where - S: ::serde::Serializer, - { - if serializer.is_human_readable() { - let s = format!("0x{}", hex::encode(&self.sig)); - serializer.serialize_str(&s[..]) - } else { - // See comment in deserialize_key. - serializer - .serialize_newtype_struct("Signature", serde_bytes::Bytes::new(self.sig.as_slice())) - } - } -} - -impl<'de> serde::Deserialize<'de> for Signature { - fn deserialize(deserializer: D) -> core::result::Result - where - D: ::serde::Deserializer<'de>, - { - if deserializer.is_human_readable() { - let encoded_key = ::deserialize(deserializer)?; - let encoded_key = encoded_key.trim_start_matches("0x"); - Ok(Signature { - sig: hex::decode(encoded_key).map_err(::custom)?, - }) - } else { - #[derive(::serde::Deserialize, Debug)] - #[serde(rename = "Signature")] - struct Value<'a>(&'a [u8]); - - let value = Value::deserialize(deserializer)?; - Ok(Signature { - sig: value.0.to_vec(), - }) - } - } -} +use crate::{bls::BlsSignature, errors::InvalidLength}; #[model(proto( raw(protos::union::ibc::lightclients::movement::v1::AggregateSignature), @@ -74,8 +8,8 @@ impl<'de> serde::Deserialize<'de> for Signature { from ))] pub struct AggregateSignature { - validator_bitmask: BitVec, - sig: Option, + validator_bitmask: Vec, + sig: BlsSignature, } impl From @@ -83,14 +17,17 @@ impl From { fn from(value: AggregateSignature) -> Self { Self { - validator_bitmask: value.validator_bitmask.inner, - sig: value.sig.map(Into::into), + validator_bitmask: value.validator_bitmask, + sig: value.sig.into(), } } } #[derive(Debug, Clone, PartialEq, thiserror::Error)] -pub enum TryFromAggregateSignatureError {} +pub enum TryFromAggregateSignatureError { + #[error("invalid sig")] + Sig(#[from] InvalidLength), +} impl TryFrom for AggregateSignature @@ -101,10 +38,8 @@ impl TryFrom value: protos::union::ibc::lightclients::movement::v1::AggregateSignature, ) -> Result { Ok(Self { - validator_bitmask: BitVec { - inner: value.validator_bitmask, - }, - sig: value.sig.map(Into::into), + validator_bitmask: value.validator_bitmask, + sig: value.sig.try_into()?, }) } } diff --git a/lib/unionlabs/src/aptos/sparse_merkle_proof.rs b/lib/unionlabs/src/aptos/sparse_merkle_proof.rs index 39d16001b7..cbc4a9f3a8 100644 --- a/lib/unionlabs/src/aptos/sparse_merkle_proof.rs +++ b/lib/unionlabs/src/aptos/sparse_merkle_proof.rs @@ -1,8 +1,7 @@ use macros::model; use serde::{Deserialize, Serialize}; -use super::hash_value::HashValue; -use crate::errors::InvalidLength; +use crate::{errors::InvalidLength, hash::H256}; /// A proof that can be used to authenticate an element in a Sparse Merkle Tree given trusted root /// hash. For example, `TransactionInfoToAccountProof` can be constructed on top of this structure. @@ -25,13 +24,13 @@ pub struct SparseMerkleProof { /// All siblings in this proof, including the default ones. Siblings are ordered from the root /// level to the bottom level. - pub siblings: Vec, + pub siblings: Vec, } #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct SparseMerkleLeafNode { - pub key: HashValue, - pub value_hash: HashValue, + pub key: H256, + pub value_hash: H256, } impl From for protos::union::ibc::lightclients::movement::v1::SparseMerkleProof { diff --git a/lib/unionlabs/src/aptos/transaction_info.rs b/lib/unionlabs/src/aptos/transaction_info.rs index 1967dafecc..4e4c6ab03b 100644 --- a/lib/unionlabs/src/aptos/transaction_info.rs +++ b/lib/unionlabs/src/aptos/transaction_info.rs @@ -1,8 +1,6 @@ use macros::model; -use serde::{Deserialize, Serialize}; -use super::hash_value::HashValue; -use crate::errors::InvalidLength; +use crate::{errors::InvalidLength, hash::H256}; /// `TransactionInfo` is the object we store in the transaction accumulator. It consists of the /// transaction as well as the execution result of this transaction. @@ -15,7 +13,7 @@ pub enum TransactionInfo { V0(TransactionInfoV0), } -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[model] pub struct TransactionInfoV0 { /// The amount of gas used. pub gas_used: u64, @@ -26,26 +24,26 @@ pub struct TransactionInfoV0 { pub status: ExecutionStatus, /// The hash of this transaction. - pub transaction_hash: HashValue, + pub transaction_hash: H256, /// The root hash of Merkle Accumulator storing all events emitted during this transaction. - pub event_root_hash: HashValue, + pub event_root_hash: H256, /// The hash value summarizing all changes caused to the world state by this transaction. /// i.e. hash of the output write set. - pub state_change_hash: HashValue, + pub state_change_hash: H256, /// The root hash of the Sparse Merkle Tree describing the world state at the end of this /// transaction. Depending on the protocol configuration, this can be generated periodical /// only, like per block. - pub state_checkpoint_hash: Option, + pub state_checkpoint_hash: Option, /// Potentially summarizes all evicted items from state. Always `None` for now. - pub state_cemetery_hash: Option, + pub state_cemetery_hash: Option, } // impl TransactionInfoV0 { -// pub fn hash(&self) -> HashValue { +// pub fn hash(&self) -> H256 { // let mut state = Sha3_256::new(); // state.update( // Sha3_256::new() @@ -53,11 +51,11 @@ pub struct TransactionInfoV0 { // .finalize(), // ); // bcs::serialize_into(&mut state, &self).expect("expected to be able to serialize"); -// HashValue(state.finalize().into()) +// H256(state.finalize().into()) // } // } -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] +#[model] pub enum ExecutionStatus { Success, } diff --git a/lib/unionlabs/src/aptos/transaction_proof.rs b/lib/unionlabs/src/aptos/transaction_proof.rs index 176f42ebb4..06e3569c50 100644 --- a/lib/unionlabs/src/aptos/transaction_proof.rs +++ b/lib/unionlabs/src/aptos/transaction_proof.rs @@ -1,11 +1,10 @@ use macros::model; -use serde::{Deserialize, Serialize}; -use super::{ - hash_value::HashValue, - transaction_info::{TransactionInfo, TryFromTransactionInfoError}, +use crate::{ + aptos::transaction_info::{TransactionInfo, TryFromTransactionInfoError}, + errors::{required, InvalidLength, MissingField}, + hash::H256, }; -use crate::errors::{required, InvalidLength, MissingField}; /// `TransactionInfo` and a `TransactionAccumulatorProof` connecting it to the ledger root. #[model(proto( @@ -22,9 +21,9 @@ pub struct TransactionInfoWithProof { pub transaction_info: TransactionInfo, } -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[model] pub struct TransactionAccumulatorProof { - pub siblings: Vec, + pub siblings: Vec, } impl From diff --git a/lib/unionlabs/src/aptos/validator_verifier.rs b/lib/unionlabs/src/aptos/validator_verifier.rs index 5c0c69b6d7..0cae190dae 100644 --- a/lib/unionlabs/src/aptos/validator_verifier.rs +++ b/lib/unionlabs/src/aptos/validator_verifier.rs @@ -3,7 +3,7 @@ use macros::model; use super::public_key::PublicKey; use crate::{ aptos::account::AccountAddress, - errors::{required, ExpectedLength, InvalidLength, MissingField}, + errors::{required, InvalidLength, MissingField}, }; /// Supports validation of signatures for known authors with individual voting powers. This struct @@ -42,7 +42,7 @@ impl From for protos::union::ibc::lightclients::movement::v1: #[derive(Debug, Clone, PartialEq, thiserror::Error)] pub enum TryFromValidatorVerifierError { #[error("invalid validator infos: {0}")] - ValidatorInfos(#[from] TryFromValidatorConsensusInfo), + ValidatorInfos(#[from] TryFromValidatorConsensusInfoError), } impl TryFrom @@ -68,7 +68,7 @@ impl From { fn from(value: ValidatorConsensusInfo) -> Self { Self { - address: value.address.0.to_vec(), + address: value.address.0 .0.to_vec(), public_key: Some(value.public_key.into()), voting_power: value.voting_power, } @@ -76,7 +76,7 @@ impl From } #[derive(Debug, Clone, PartialEq, thiserror::Error)] -pub enum TryFromValidatorConsensusInfo { +pub enum TryFromValidatorConsensusInfoError { #[error(transparent)] MissingField(#[from] MissingField), #[error("invalid address")] @@ -86,18 +86,19 @@ pub enum TryFromValidatorConsensusInfo { impl TryFrom for ValidatorConsensusInfo { - type Error = TryFromValidatorConsensusInfo; + type Error = TryFromValidatorConsensusInfoError; fn try_from( value: protos::union::ibc::lightclients::movement::v1::ValidatorConsensusInfo, ) -> Result { Ok(Self { - address: AccountAddress::new(value.address.as_slice().try_into().map_err(|_| { - TryFromValidatorConsensusInfo::Address(InvalidLength { - expected: ExpectedLength::Exact(AccountAddress::LENGTH), - found: value.address.len(), - }) - })?), + address: AccountAddress( + value + .address + .as_slice() + .try_into() + .map_err(TryFromValidatorConsensusInfoError::Address)?, + ), public_key: required!(value.public_key)?.into(), voting_power: value.voting_power, }) diff --git a/lib/unionlabs/src/berachain.rs b/lib/unionlabs/src/berachain.rs index 1c086c8b2a..439ccd0c8c 100644 --- a/lib/unionlabs/src/berachain.rs +++ b/lib/unionlabs/src/berachain.rs @@ -8,12 +8,12 @@ const BERACHAIN_CHAIN_SPEC: Preset = Preset { ..MAINNET }; -// TODO: Link to berachain/beacon-kit +/// pub const LATEST_EXECUTION_PAYLOAD_HEADER_PREFIX: u8 = 17; +/// pub const LATEST_BEACON_BLOCK_HEADER_PREFIX: u8 = 0x0b; -#[derive(Debug, Clone, PartialEq, Default)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct BerachainChainSpec; impl FromStrExact for BerachainChainSpec { diff --git a/lib/unionlabs/src/bounded.rs b/lib/unionlabs/src/bounded.rs index 53401408f9..53a8de3542 100644 --- a/lib/unionlabs/src/bounded.rs +++ b/lib/unionlabs/src/bounded.rs @@ -12,6 +12,11 @@ macro_rules! bounded_int { pub const fn inner(self) -> $ty { self.0 } + + #[must_use] + pub fn add(&self, other: &$ty) -> Self { + Self::new(self.inner() + other).expect("arithmetic overflow") + } } impl core::fmt::Debug for $Struct { @@ -62,7 +67,7 @@ macro_rules! bounded_int { impl $Struct { pub const fn new(n: $ty) -> Result> { - const {MIN < MAX}; + const { assert!(MIN < MAX) }; if n >= MIN && n <= MAX { Ok(Self(n)) @@ -76,17 +81,6 @@ macro_rules! bounded_int { } } - #[cfg(feature = "arbitrary")] - impl<'a, const MIN: $ty, const MAX: $ty> arbitrary::Arbitrary<'a> for $Struct { - fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - - let inner: $ty = u.int_in_range(MIN..=MAX)?; - - Ok(Self::new(inner).expect("value is within bounds")) - - } - } - impl core::str::FromStr for $Struct { type Err = BoundedIntParseError<$ty>; diff --git a/lib/unionlabs/src/cosmos/ics23/inner_spec.rs b/lib/unionlabs/src/cosmos/ics23/inner_spec.rs index aa9e034f41..8b48f9385e 100644 --- a/lib/unionlabs/src/cosmos/ics23/inner_spec.rs +++ b/lib/unionlabs/src/cosmos/ics23/inner_spec.rs @@ -12,13 +12,11 @@ pub type PositiveI32AsUsize = BoundedUsize<0, { i32::MAX as usize }>; #[model(proto(raw(protos::cosmos::ics23::v1::InnerSpec), into, from))] pub struct InnerSpec { - #[cfg_attr(feature = "arbitrary", arbitrary(with = crate::arbitrary_cow_static))] pub child_order: Cow<'static, [PositiveI32AsUsize]>, pub child_size: PositiveI32AsUsize, pub min_prefix_length: PositiveI32AsUsize, pub max_prefix_length: PositiveI32AsUsize, #[serde(with = "::serde_utils::hex_string")] - #[cfg_attr(feature = "arbitrary", arbitrary(with = crate::arbitrary_cow_static))] pub empty_child: Cow<'static, [u8]>, pub hash: HashOp, } diff --git a/lib/unionlabs/src/cosmos/ics23/leaf_op.rs b/lib/unionlabs/src/cosmos/ics23/leaf_op.rs index 9872f77ff3..7fd061278c 100644 --- a/lib/unionlabs/src/cosmos/ics23/leaf_op.rs +++ b/lib/unionlabs/src/cosmos/ics23/leaf_op.rs @@ -15,7 +15,6 @@ pub struct LeafOp { pub length: LengthOp, #[serde(with = "::serde_utils::hex_string")] #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] - #[cfg_attr(feature = "arbitrary", arbitrary(with = crate::arbitrary_cow_static))] pub prefix: Cow<'static, [u8]>, } diff --git a/lib/unionlabs/src/cosmos/tx/tx_body.rs b/lib/unionlabs/src/cosmos/tx/tx_body.rs index 2d44b58f82..31c92b5bbe 100644 --- a/lib/unionlabs/src/cosmos/tx/tx_body.rs +++ b/lib/unionlabs/src/cosmos/tx/tx_body.rs @@ -1,22 +1,32 @@ use macros::model; +use crate::google::protobuf::any::RawAny; + #[model(proto(raw(protos::cosmos::tx::v1beta1::TxBody), into, from))] pub struct TxBody { - pub messages: Vec, + pub messages: Vec, pub memo: String, pub timeout_height: u64, - pub extension_options: Vec, - pub non_critical_extension_options: Vec, + pub extension_options: Vec, + pub non_critical_extension_options: Vec, } impl From for protos::cosmos::tx::v1beta1::TxBody { fn from(value: TxBody) -> Self { Self { - messages: value.messages, + messages: value.messages.into_iter().map(Into::into).collect(), memo: value.memo, timeout_height: value.timeout_height, - extension_options: value.extension_options, - non_critical_extension_options: value.non_critical_extension_options, + extension_options: value + .extension_options + .into_iter() + .map(Into::into) + .collect(), + non_critical_extension_options: value + .non_critical_extension_options + .into_iter() + .map(Into::into) + .collect(), } } } @@ -24,11 +34,19 @@ impl From for protos::cosmos::tx::v1beta1::TxBody { impl From for TxBody { fn from(value: protos::cosmos::tx::v1beta1::TxBody) -> Self { Self { - messages: value.messages, + messages: value.messages.into_iter().map(Into::into).collect(), memo: value.memo, timeout_height: value.timeout_height, - extension_options: value.extension_options, - non_critical_extension_options: value.non_critical_extension_options, + extension_options: value + .extension_options + .into_iter() + .map(Into::into) + .collect(), + non_critical_extension_options: value + .non_critical_extension_options + .into_iter() + .map(Into::into) + .collect(), } } } diff --git a/lib/unionlabs/src/cosmwasm/wasm/union/custom_query.rs b/lib/unionlabs/src/cosmwasm/wasm/union/custom_query.rs index 89fd27375c..f5c18c3a4e 100644 --- a/lib/unionlabs/src/cosmwasm/wasm/union/custom_query.rs +++ b/lib/unionlabs/src/cosmwasm/wasm/union/custom_query.rs @@ -14,10 +14,7 @@ pub enum Error { #[error("invalid public key is returned from `aggregate_public_key`")] InvalidAggregatePublicKey, #[error("abci query for {path} failed: {err}")] - ABCI { - path: Path, - err: String, - }, + ABCI { path: Path, err: String }, } #[derive(serde::Serialize, serde::Deserialize, Clone)] @@ -77,7 +74,6 @@ use { encoding::{Decode, DecodeAs, Proto}, google::protobuf::any::Any, ics24::{ClientConsensusStatePath, ClientStatePath}, - traits::Id, }, cosmwasm_std::{to_json_vec, ContractResult, Env, SystemResult}, prost::Message, @@ -86,11 +82,7 @@ use { #[allow(clippy::missing_panics_doc)] #[cfg(feature = "stargate")] -pub fn query_ibc_abci( - deps: Deps, - env: &Env, - path: Path, -) -> Result +pub fn query_ibc_abci(deps: Deps, env: &Env, path: Path) -> Result where Any: Decode, { @@ -149,10 +141,15 @@ pub fn query_consensus_state( where Any: Decode, { + use crate::validated::ValidateT; + query_ibc_abci::( deps, env, - Path::ClientConsensusState(ClientConsensusStatePath { client_id, height }), + Path::ClientConsensusState(ClientConsensusStatePath { + client_id: client_id.validate().expect("invalid client id"), + height, + }), ) } @@ -167,5 +164,13 @@ pub fn query_client_state( where Any: Decode, { - query_ibc_abci::(deps, env, Path::ClientState(ClientStatePath { client_id })) + use crate::validated::ValidateT; + + query_ibc_abci::( + deps, + env, + Path::ClientState(ClientStatePath { + client_id: client_id.validate().expect("invalid client id"), + }), + ) } diff --git a/lib/unionlabs/src/encoding.rs b/lib/unionlabs/src/encoding.rs index 3fc07acbc2..373dd1f254 100644 --- a/lib/unionlabs/src/encoding.rs +++ b/lib/unionlabs/src/encoding.rs @@ -14,6 +14,9 @@ impl Encoding for Ssz {} pub enum Json {} impl Encoding for Json {} +pub enum Bcs {} +impl Encoding for Bcs {} + impl Encode for T where T: serde::Serialize, @@ -37,6 +40,29 @@ where static_assertions::assert_impl_all!(u8: Encode); static_assertions::assert_impl_all!(&u8: Encode); +impl Encode for T +where + T: serde::Serialize, +{ + fn encode(self) -> Vec { + bcs::to_bytes(&self).expect("json serialization should be infallible") + } +} + +impl Decode for T +where + T: serde::de::DeserializeOwned, +{ + type Error = bcs::Error; + + fn decode(bytes: &[u8]) -> Result { + bcs::from_bytes(bytes) + } +} + +static_assertions::assert_impl_all!(u8: Encode); +static_assertions::assert_impl_all!(&u8: Encode); + pub trait Encode: Sized { fn encode(self) -> Vec; } diff --git a/lib/unionlabs/src/ethereum.rs b/lib/unionlabs/src/ethereum.rs index 492b455ebf..0ae8da5295 100644 --- a/lib/unionlabs/src/ethereum.rs +++ b/lib/unionlabs/src/ethereum.rs @@ -1,29 +1,10 @@ -use core::fmt::Debug; - use hex_literal::hex; -use serde::{Deserialize, Serialize}; use sha2::Digest; use sha3::Keccak256; -use ssz::{ - types::{BitList, List, Vector}, - Ssz, -}; use crate::{ - bls::{BlsPublicKey, BlsSignature}, - ethereum::{ - beacon::BeaconBlock, - config::{ - BYTES_PER_LOGS_BLOOM, DEPOSIT_CONTRACT_TREE_DEPTH, MAX_ATTESTATIONS, - MAX_ATTESTER_SLASHINGS, MAX_BLOB_COMMITMENTS_PER_BLOCK, MAX_BLS_TO_EXECUTION_CHANGES, - MAX_BYTES_PER_TRANSACTION, MAX_DEPOSITS, MAX_EXTRA_DATA_BYTES, MAX_PROPOSER_SLASHINGS, - MAX_TRANSACTIONS_PER_PAYLOAD, MAX_VALIDATORS_PER_COMMITTEE, MAX_VOLUNTARY_EXITS, - MAX_WITHDRAWALS_PER_PAYLOAD, SYNC_COMMITTEE_SIZE, - }, - slot::{MappingKey, Slot}, - }, + ethereum::slot::{MappingKey, Slot}, hash::H256, - ibc::lightclients::ethereum::beacon_block_header::BeaconBlockHeader, macros::hex_string_array_wrapper, uint::U256, }; @@ -49,9 +30,6 @@ pub fn ibc_commitment_key(path: &str, slot: U256) -> U256 { Slot::Mapping(&Slot::Offset(slot), MappingKey::Bytes32(keccak256(path))).slot() } -// REVIEW: Is this needed? Currently unused -pub const BLOCK_BODY_EXECUTION_PAYLOAD_INDEX: usize = 9; - hex_string_array_wrapper! { pub struct Version(pub [u8; 4]); pub struct DomainType(pub [u8; 4]); @@ -75,165 +53,6 @@ impl DomainType { pub const APPLICATION_MASK: Self = Self(hex!("00000001")); } -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct ForkData { - pub current_version: Version, - pub genesis_validators_root: H256, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct SigningData { - pub object_root: H256, - pub domain: Domain, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct SignedBeaconBlockHeader { - pub message: BeaconBlockHeader, - pub signature: BlsSignature, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(bound(serialize = "", deserialize = ""), deny_unknown_fields)] -pub struct SignedBeaconBlock< - C: MAX_PROPOSER_SLASHINGS - + MAX_VALIDATORS_PER_COMMITTEE - + MAX_ATTESTER_SLASHINGS - + MAX_ATTESTATIONS - + DEPOSIT_CONTRACT_TREE_DEPTH - + MAX_DEPOSITS - + MAX_VOLUNTARY_EXITS - + BYTES_PER_LOGS_BLOOM - + MAX_EXTRA_DATA_BYTES - + MAX_BYTES_PER_TRANSACTION - + MAX_TRANSACTIONS_PER_PAYLOAD - + MAX_WITHDRAWALS_PER_PAYLOAD - + MAX_BLS_TO_EXECUTION_CHANGES - + MAX_BLOB_COMMITMENTS_PER_BLOCK - + SYNC_COMMITTEE_SIZE, -> { - pub message: BeaconBlock, - pub signature: BlsSignature, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Eth1Data { - pub deposit_root: H256, - #[serde(with = "::serde_utils::string")] - pub deposit_count: u64, - pub block_hash: H256, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct ProposerSlashing { - pub signed_header_1: SignedBeaconBlockHeader, - pub signed_header_2: SignedBeaconBlockHeader, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(bound(serialize = "", deserialize = ""), deny_unknown_fields)] -pub struct AttesterSlashing { - pub attestation_1: IndexedAttestation, - pub attestation_2: IndexedAttestation, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(bound(serialize = "", deserialize = ""), deny_unknown_fields)] -pub struct IndexedAttestation { - pub attesting_indices: List, - pub data: AttestationData, - pub signature: BlsSignature, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct AttestationData { - #[serde(with = "::serde_utils::string")] - pub slot: u64, - #[serde(with = "::serde_utils::string")] - pub index: u64, - /// LMD GHOST vote - pub beacon_block_root: H256, - /// FFG vote - pub source: Checkpoint, - pub target: Checkpoint, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Checkpoint { - #[serde(with = "::serde_utils::string")] - pub epoch: u64, - pub root: H256, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Attestation { - pub aggregation_bits: BitList, - pub data: AttestationData, - pub signature: BlsSignature, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Deposit { - /// Merkle path to deposit root - pub proof: Vector, - pub data: DepositData, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct DepositData { - pub pubkey: BlsPublicKey, - pub withdrawal_credentials: H256, - #[serde(with = "::serde_utils::string")] - pub amount: u64, - /// Signing over `DepositMessage` - pub signature: BlsSignature, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct SignedVoluntaryExit { - pub message: VoluntaryExit, - pub signature: BlsSignature, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct VoluntaryExit { - /// Earliest epoch when voluntary exit can be processed - #[serde(with = "::serde_utils::string")] - pub epoch: u64, - #[serde(with = "::serde_utils::string")] - pub validator_index: u64, -} - -hex_string_array_wrapper! { - pub struct KZGCommitment(pub [u8; 48]); -} - #[cfg(test)] mod tests { use hex_literal::hex; diff --git a/lib/unionlabs/src/ethereum/beacon.rs b/lib/unionlabs/src/ethereum/beacon.rs index eeb962fb7e..1d12c549f9 100644 --- a/lib/unionlabs/src/ethereum/beacon.rs +++ b/lib/unionlabs/src/ethereum/beacon.rs @@ -1,270 +1,28 @@ -use macros::model; -use serde::{Deserialize, Serialize}; -use ssz::{ - types::{List, Vector}, - Ssz, -}; -use typenum::U; - -use super::{config::MAX_BLOB_COMMITMENTS_PER_BLOCK, KZGCommitment}; -use crate::{ - bls::{BlsPublicKey, BlsSignature}, - ethereum::{ - config::{ - consts::{floorlog2, CURRENT_SYNC_COMMITTEE_INDEX, FINALIZED_ROOT_INDEX}, - BYTES_PER_LOGS_BLOOM, DEPOSIT_CONTRACT_TREE_DEPTH, MAX_ATTESTATIONS, - MAX_ATTESTER_SLASHINGS, MAX_BLS_TO_EXECUTION_CHANGES, MAX_BYTES_PER_TRANSACTION, - MAX_DEPOSITS, MAX_EXTRA_DATA_BYTES, MAX_PROPOSER_SLASHINGS, - MAX_TRANSACTIONS_PER_PAYLOAD, MAX_VALIDATORS_PER_COMMITTEE, MAX_VOLUNTARY_EXITS, - MAX_WITHDRAWALS_PER_PAYLOAD, SYNC_COMMITTEE_SIZE, - }, - Attestation, AttesterSlashing, Deposit, Eth1Data, ProposerSlashing, SignedVoluntaryExit, - Version, - }, - hash::{H160, H256}, - ibc::lightclients::ethereum::{ - beacon_block_header::BeaconBlockHeader, execution_payload_header::ExecutionPayloadHeader, - light_client_header::LightClientHeader, sync_aggregate::SyncAggregate, - sync_committee::SyncCommittee, - }, - uint::U256, -}; - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(bound(serialize = "", deserialize = ""), deny_unknown_fields)] -pub struct BeaconBlock< - C: MAX_PROPOSER_SLASHINGS - + MAX_VALIDATORS_PER_COMMITTEE - + MAX_ATTESTER_SLASHINGS - + MAX_ATTESTATIONS - + DEPOSIT_CONTRACT_TREE_DEPTH - + MAX_DEPOSITS - + MAX_VOLUNTARY_EXITS - + BYTES_PER_LOGS_BLOOM - + MAX_EXTRA_DATA_BYTES - + MAX_BYTES_PER_TRANSACTION - + MAX_TRANSACTIONS_PER_PAYLOAD - + MAX_WITHDRAWALS_PER_PAYLOAD - + MAX_BLS_TO_EXECUTION_CHANGES - + MAX_BLOB_COMMITMENTS_PER_BLOCK - + SYNC_COMMITTEE_SIZE, -> { - #[serde(with = "::serde_utils::string")] - pub slot: u64, - #[serde(with = "::serde_utils::string")] - pub proposer_index: u64, - pub parent_root: H256, - pub state_root: H256, - pub body: BeaconBlockBody, -} - -impl< - C: MAX_PROPOSER_SLASHINGS - + MAX_VALIDATORS_PER_COMMITTEE - + MAX_ATTESTER_SLASHINGS - + MAX_ATTESTATIONS - + DEPOSIT_CONTRACT_TREE_DEPTH - + MAX_DEPOSITS - + MAX_VOLUNTARY_EXITS - + BYTES_PER_LOGS_BLOOM - + MAX_EXTRA_DATA_BYTES - + MAX_BYTES_PER_TRANSACTION - + MAX_TRANSACTIONS_PER_PAYLOAD - + MAX_WITHDRAWALS_PER_PAYLOAD - + MAX_BLS_TO_EXECUTION_CHANGES - + MAX_BLOB_COMMITMENTS_PER_BLOCK - + SYNC_COMMITTEE_SIZE, - > BeaconBlock -{ - #[must_use] - pub fn to_header(self) -> BeaconBlockHeader { - BeaconBlockHeader { - slot: self.slot, - proposer_index: self.proposer_index, - parent_root: self.parent_root, - state_root: self.state_root, - body_root: self.body.tree_hash_root().into(), - } - } -} - -/// -#[derive(Ssz)] -#[model] -#[serde(bound(serialize = "", deserialize = ""))] -pub struct BeaconBlockBody< - C: MAX_PROPOSER_SLASHINGS - + MAX_VALIDATORS_PER_COMMITTEE - + MAX_ATTESTER_SLASHINGS - + MAX_ATTESTATIONS - + DEPOSIT_CONTRACT_TREE_DEPTH - + MAX_DEPOSITS - + MAX_VOLUNTARY_EXITS - + BYTES_PER_LOGS_BLOOM - + MAX_EXTRA_DATA_BYTES - + MAX_BYTES_PER_TRANSACTION - + MAX_TRANSACTIONS_PER_PAYLOAD - + MAX_WITHDRAWALS_PER_PAYLOAD - + MAX_BLS_TO_EXECUTION_CHANGES - + MAX_BLOB_COMMITMENTS_PER_BLOCK - + SYNC_COMMITTEE_SIZE, -> { - pub randao_reveal: BlsSignature, - pub eth1_data: Eth1Data, - pub graffiti: H256, - pub proposer_slashings: List, - pub attester_slashings: List, C::MAX_ATTESTER_SLASHINGS>, - pub attestations: List, C::MAX_ATTESTATIONS>, - pub deposits: List, C::MAX_DEPOSITS>, - pub voluntary_exits: List, - pub sync_aggregate: SyncAggregate, - pub execution_payload: ExecutionPayload, - pub bls_to_execution_changes: List, - pub blob_kzg_commitments: List, -} - -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -pub struct BlsToExecutionChange { - #[serde(with = "::serde_utils::string")] - pub validator_index: u64, - pub from_bls_pubkey: BlsPublicKey, - pub to_execution_address: H160, -} - -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -pub struct SignedBlsToExecutionChange { - message: BlsToExecutionChange, - signature: BlsSignature, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -pub struct ExecutionPayload< - C: BYTES_PER_LOGS_BLOOM - + MAX_EXTRA_DATA_BYTES - + MAX_BYTES_PER_TRANSACTION - + MAX_TRANSACTIONS_PER_PAYLOAD - + MAX_WITHDRAWALS_PER_PAYLOAD, -> { - /// Execution block header fields - pub parent_hash: H256, - pub fee_recipient: H160, - pub state_root: H256, - pub receipts_root: H256, - #[serde(with = "::serde_utils::hex_string")] - pub logs_bloom: Vector, - /// 'difficulty' in the yellow paper - pub prev_randao: H256, - /// 'number' in the yellow paper - #[serde(with = "::serde_utils::string")] - pub block_number: u64, - #[serde(with = "::serde_utils::string")] - pub gas_limit: u64, - #[serde(with = "::serde_utils::string")] - pub gas_used: u64, - #[serde(with = "::serde_utils::string")] - pub timestamp: u64, - #[serde(with = "::serde_utils::hex_string")] - pub extra_data: List, - pub base_fee_per_gas: U256, - /// Extra payload fields - /// Hash of execution block - pub block_hash: H256, - #[serde(with = "::serde_utils::hex_string_list")] - pub transactions: List, C::MAX_TRANSACTIONS_PER_PAYLOAD>, - pub withdrawals: List, - // blob_gas_used: uint64 # [New in Deneb:EIP4844] - #[serde(default, with = "::serde_utils::string")] - pub blob_gas_used: u64, - // excess_blob_gas: uint64 # [New in Deneb:EIP4844] - #[serde(default, with = "::serde_utils::string")] - pub excess_blob_gas: u64, -} - -impl< - C: BYTES_PER_LOGS_BLOOM - + MAX_EXTRA_DATA_BYTES - + MAX_BYTES_PER_TRANSACTION - + MAX_TRANSACTIONS_PER_PAYLOAD - + MAX_WITHDRAWALS_PER_PAYLOAD, - > ExecutionPayload -{ - #[must_use] - pub fn to_header(self) -> ExecutionPayloadHeader { - ExecutionPayloadHeader { - parent_hash: self.parent_hash, - fee_recipient: self.fee_recipient, - state_root: self.state_root, - receipts_root: self.receipts_root, - logs_bloom: self.logs_bloom, - prev_randao: self.prev_randao, - block_number: self.block_number, - gas_limit: self.gas_limit, - gas_used: self.gas_used, - timestamp: self.timestamp, - extra_data: self.extra_data, - base_fee_per_gas: self.base_fee_per_gas, - block_hash: self.block_hash, - transactions_root: self.transactions.tree_hash_root().into(), - withdrawals_root: self.withdrawals.tree_hash_root().into(), - blob_gas_used: self.blob_gas_used, - excess_blob_gas: self.excess_blob_gas, - } - } -} - -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -pub struct Withdrawal { - #[serde(with = "::serde_utils::string")] - pub index: u64, - #[serde(with = "::serde_utils::string")] - pub validator_index: u64, - pub address: H160, - #[serde(with = "::serde_utils::string")] - pub amount: u64, -} - -/// -#[derive(Clone, Debug, PartialEq, Ssz, Serialize, Deserialize)] -#[serde(bound(serialize = "", deserialize = ""), deny_unknown_fields)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct LightClientBootstrap< - C: SYNC_COMMITTEE_SIZE + BYTES_PER_LOGS_BLOOM + MAX_EXTRA_DATA_BYTES, -> { - pub header: LightClientHeader, - /// Current sync committee corresponding to `beacon_header.state_root` - pub current_sync_committee: SyncCommittee, - // TODO: Update tree_hash to support const generic arrays - pub current_sync_committee_branch: Vector>, -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(bound(serialize = "", deserialize = ""), deny_unknown_fields)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct LightClientFinalityUpdate< - C: SYNC_COMMITTEE_SIZE + BYTES_PER_LOGS_BLOOM + MAX_EXTRA_DATA_BYTES, -> { - /// Header attested to by the sync committee - pub attested_header: LightClientHeader, - /// Finalized header corresponding to `attested_header.state_root` - pub finalized_header: LightClientHeader, - pub finality_branch: [H256; floorlog2(FINALIZED_ROOT_INDEX)], - /// Sync committee aggregate signature - pub sync_aggregate: SyncAggregate, - /// Slot at which the aggregate signature was created (untrusted) - #[serde(with = "::serde_utils::string")] - pub signature_slot: u64, -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -pub struct GenesisData { - pub genesis_validators_root: H256, - #[serde(with = "::serde_utils::string")] - pub genesis_time: u64, - pub genesis_fork_version: Version, -} +pub mod attestation; +pub mod attestation_data; +pub mod attester_slashing; +pub mod beacon_block; +pub mod beacon_block_body; +pub mod bls_to_execution_change; +pub mod checkpoint; +pub mod deposit; +pub mod deposit_data; +pub mod eth1_data; +pub mod execution_payload; +pub mod fork_data; +pub mod genesis_data; +pub mod indexed_attestation; +pub mod kzg_commitment; +pub mod light_client_bootstrap; +pub mod light_client_finality_update; +pub mod proposer_slashing; +pub mod signed_beacon_block; +pub mod signed_beacon_block_header; +pub mod signed_bls_to_execution_change; +pub mod signed_voluntary_exit; +pub mod signing_data; +pub mod voluntary_exit; +pub mod withdrawal; #[cfg(test)] mod tests { @@ -273,7 +31,9 @@ mod tests { use super::*; use crate::{ ethereum::config::Minimal, + ibc::lightclients::ethereum::sync_aggregate::SyncAggregate, test_utils::{assert_json_roundtrip, assert_proto_roundtrip}, + uint::U256, }; #[test] @@ -358,8 +118,10 @@ mod tests { "signature_slot": "281" }"#; - let finality_update = - serde_json::from_str::>(JSON).unwrap(); + let finality_update = serde_json::from_str::< + light_client_finality_update::LightClientFinalityUpdate, + >(JSON) + .unwrap(); dbg!(&finality_update); diff --git a/lib/unionlabs/src/ethereum/beacon/attestation.rs b/lib/unionlabs/src/ethereum/beacon/attestation.rs new file mode 100644 index 0000000000..56d9b3288e --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/attestation.rs @@ -0,0 +1,25 @@ +use macros::model; +use ssz::{types::BitList, Ssz}; + +use crate::{ + bls::BlsSignature, + ethereum::{beacon::attestation_data::AttestationData, config::MAX_VALIDATORS_PER_COMMITTEE}, +}; + +/// +#[model] +#[derive(Ssz)] +#[serde(bound(serialize = "", deserialize = ""))] +pub struct Attestation { + pub aggregation_bits: BitList, + pub data: AttestationData, + pub signature: BlsSignature, +} + +#[model] +pub struct UnboundedAttestation { + #[serde(with = "::serde_utils::hex_string")] + pub aggregation_bits: Vec, + pub data: AttestationData, + pub signature: BlsSignature, +} diff --git a/lib/unionlabs/src/ethereum/beacon/attestation_data.rs b/lib/unionlabs/src/ethereum/beacon/attestation_data.rs new file mode 100644 index 0000000000..5523d9e494 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/attestation_data.rs @@ -0,0 +1,19 @@ +use macros::model; +use ssz::Ssz; + +use crate::{ethereum::beacon::checkpoint::Checkpoint, hash::H256}; + +/// +#[model] +#[derive(Ssz)] +pub struct AttestationData { + #[serde(with = "::serde_utils::string")] + pub slot: u64, + #[serde(with = "::serde_utils::string")] + pub index: u64, + /// LMD GHOST vote + pub beacon_block_root: H256, + /// FFG vote + pub source: Checkpoint, + pub target: Checkpoint, +} diff --git a/lib/unionlabs/src/ethereum/beacon/attester_slashing.rs b/lib/unionlabs/src/ethereum/beacon/attester_slashing.rs new file mode 100644 index 0000000000..0253d8a09d --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/attester_slashing.rs @@ -0,0 +1,22 @@ +use macros::model; +use ssz::Ssz; + +use crate::ethereum::{ + beacon::indexed_attestation::{IndexedAttestation, UnboundedIndexedAttestation}, + config::MAX_VALIDATORS_PER_COMMITTEE, +}; + +/// +#[model] +#[derive(Ssz)] +#[serde(bound(serialize = "", deserialize = ""))] +pub struct AttesterSlashing { + pub attestation_1: IndexedAttestation, + pub attestation_2: IndexedAttestation, +} + +#[model] +pub struct UnboundedAttesterSlashing { + pub attestation_1: UnboundedIndexedAttestation, + pub attestation_2: UnboundedIndexedAttestation, +} diff --git a/lib/unionlabs/src/ethereum/beacon/beacon_block.rs b/lib/unionlabs/src/ethereum/beacon/beacon_block.rs new file mode 100644 index 0000000000..62d018f012 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/beacon_block.rs @@ -0,0 +1,88 @@ +use macros::model; +use ssz::Ssz; + +use crate::{ + ethereum::{ + beacon::beacon_block_body::{BeaconBlockBody, UnboundedBeaconBlockBody}, + config::{ + BYTES_PER_LOGS_BLOOM, DEPOSIT_CONTRACT_TREE_DEPTH, MAX_ATTESTATIONS, + MAX_ATTESTER_SLASHINGS, MAX_BLOB_COMMITMENTS_PER_BLOCK, MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BYTES_PER_TRANSACTION, MAX_DEPOSITS, MAX_EXTRA_DATA_BYTES, MAX_PROPOSER_SLASHINGS, + MAX_TRANSACTIONS_PER_PAYLOAD, MAX_VALIDATORS_PER_COMMITTEE, MAX_VOLUNTARY_EXITS, + MAX_WITHDRAWALS_PER_PAYLOAD, SYNC_COMMITTEE_SIZE, + }, + }, + hash::H256, + ibc::lightclients::ethereum::beacon_block_header::BeaconBlockHeader, +}; + +/// +#[model] +#[derive(Ssz)] +#[serde(bound(serialize = "", deserialize = ""))] +pub struct BeaconBlock< + C: MAX_PROPOSER_SLASHINGS + + MAX_VALIDATORS_PER_COMMITTEE + + MAX_ATTESTER_SLASHINGS + + MAX_ATTESTATIONS + + DEPOSIT_CONTRACT_TREE_DEPTH + + MAX_DEPOSITS + + MAX_VOLUNTARY_EXITS + + BYTES_PER_LOGS_BLOOM + + MAX_EXTRA_DATA_BYTES + + MAX_BYTES_PER_TRANSACTION + + MAX_TRANSACTIONS_PER_PAYLOAD + + MAX_WITHDRAWALS_PER_PAYLOAD + + MAX_BLS_TO_EXECUTION_CHANGES + + MAX_BLOB_COMMITMENTS_PER_BLOCK + + SYNC_COMMITTEE_SIZE, +> { + #[serde(with = "::serde_utils::string")] + pub slot: u64, + #[serde(with = "::serde_utils::string")] + pub proposer_index: u64, + pub parent_root: H256, + pub state_root: H256, + pub body: BeaconBlockBody, +} + +impl< + C: MAX_PROPOSER_SLASHINGS + + MAX_VALIDATORS_PER_COMMITTEE + + MAX_ATTESTER_SLASHINGS + + MAX_ATTESTATIONS + + DEPOSIT_CONTRACT_TREE_DEPTH + + MAX_DEPOSITS + + MAX_VOLUNTARY_EXITS + + BYTES_PER_LOGS_BLOOM + + MAX_EXTRA_DATA_BYTES + + MAX_BYTES_PER_TRANSACTION + + MAX_TRANSACTIONS_PER_PAYLOAD + + MAX_WITHDRAWALS_PER_PAYLOAD + + MAX_BLS_TO_EXECUTION_CHANGES + + MAX_BLOB_COMMITMENTS_PER_BLOCK + + SYNC_COMMITTEE_SIZE, + > BeaconBlock +{ + #[must_use] + pub fn to_header(self) -> BeaconBlockHeader { + BeaconBlockHeader { + slot: self.slot, + proposer_index: self.proposer_index, + parent_root: self.parent_root, + state_root: self.state_root, + body_root: self.body.tree_hash_root().into(), + } + } +} + +#[model] +pub struct UnboundedBeaconBlock { + #[serde(with = "::serde_utils::string")] + pub slot: u64, + #[serde(with = "::serde_utils::string")] + pub proposer_index: u64, + pub parent_root: H256, + pub state_root: H256, + pub body: UnboundedBeaconBlockBody, +} diff --git a/lib/unionlabs/src/ethereum/beacon/beacon_block_body.rs b/lib/unionlabs/src/ethereum/beacon/beacon_block_body.rs new file mode 100644 index 0000000000..adb51a5782 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/beacon_block_body.rs @@ -0,0 +1,79 @@ +use macros::model; +use ssz::{types::List, Ssz}; + +use crate::{ + bls::BlsSignature, + ethereum::{ + beacon::{ + attestation::{Attestation, UnboundedAttestation}, + attester_slashing::{AttesterSlashing, UnboundedAttesterSlashing}, + deposit::{Deposit, UnboundedDeposit}, + eth1_data::Eth1Data, + execution_payload::{ExecutionPayload, UnboundedExecutionPayload}, + kzg_commitment::KZGCommitment, + proposer_slashing::ProposerSlashing, + signed_bls_to_execution_change::SignedBlsToExecutionChange, + signed_voluntary_exit::SignedVoluntaryExit, + }, + config::{ + BYTES_PER_LOGS_BLOOM, DEPOSIT_CONTRACT_TREE_DEPTH, MAX_ATTESTATIONS, + MAX_ATTESTER_SLASHINGS, MAX_BLOB_COMMITMENTS_PER_BLOCK, MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BYTES_PER_TRANSACTION, MAX_DEPOSITS, MAX_EXTRA_DATA_BYTES, MAX_PROPOSER_SLASHINGS, + MAX_TRANSACTIONS_PER_PAYLOAD, MAX_VALIDATORS_PER_COMMITTEE, MAX_VOLUNTARY_EXITS, + MAX_WITHDRAWALS_PER_PAYLOAD, SYNC_COMMITTEE_SIZE, + }, + }, + hash::H256, + ibc::lightclients::ethereum::sync_aggregate::{SyncAggregate, UnboundedSyncAggregate}, +}; + +/// +#[model] +#[derive(Ssz)] +#[serde(bound(serialize = "", deserialize = ""))] +pub struct BeaconBlockBody< + C: MAX_PROPOSER_SLASHINGS + + MAX_VALIDATORS_PER_COMMITTEE + + MAX_ATTESTER_SLASHINGS + + MAX_ATTESTATIONS + + DEPOSIT_CONTRACT_TREE_DEPTH + + MAX_DEPOSITS + + MAX_VOLUNTARY_EXITS + + BYTES_PER_LOGS_BLOOM + + MAX_EXTRA_DATA_BYTES + + MAX_BYTES_PER_TRANSACTION + + MAX_TRANSACTIONS_PER_PAYLOAD + + MAX_WITHDRAWALS_PER_PAYLOAD + + MAX_BLS_TO_EXECUTION_CHANGES + + MAX_BLOB_COMMITMENTS_PER_BLOCK + + SYNC_COMMITTEE_SIZE, +> { + pub randao_reveal: BlsSignature, + pub eth1_data: Eth1Data, + pub graffiti: H256, + pub proposer_slashings: List, + pub attester_slashings: List, C::MAX_ATTESTER_SLASHINGS>, + pub attestations: List, C::MAX_ATTESTATIONS>, + pub deposits: List, C::MAX_DEPOSITS>, + pub voluntary_exits: List, + pub sync_aggregate: SyncAggregate, + pub execution_payload: ExecutionPayload, + pub bls_to_execution_changes: List, + pub blob_kzg_commitments: List, +} + +#[model] +pub struct UnboundedBeaconBlockBody { + pub randao_reveal: BlsSignature, + pub eth1_data: Eth1Data, + pub graffiti: H256, + pub proposer_slashings: Vec, + pub attester_slashings: Vec, + pub attestations: Vec, + pub deposits: Vec, + pub voluntary_exits: Vec, + pub sync_aggregate: UnboundedSyncAggregate, + pub execution_payload: UnboundedExecutionPayload, + pub bls_to_execution_changes: Vec, + pub blob_kzg_commitments: Vec, +} diff --git a/lib/unionlabs/src/ethereum/beacon/bls_to_execution_change.rs b/lib/unionlabs/src/ethereum/beacon/bls_to_execution_change.rs new file mode 100644 index 0000000000..a9b7939e6b --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/bls_to_execution_change.rs @@ -0,0 +1,13 @@ +use macros::model; +use ssz::Ssz; + +use crate::{bls::BlsPublicKey, hash::H160}; + +#[model] +#[derive(Ssz)] +pub struct BlsToExecutionChange { + #[serde(with = "::serde_utils::string")] + pub validator_index: u64, + pub from_bls_pubkey: BlsPublicKey, + pub to_execution_address: H160, +} diff --git a/lib/unionlabs/src/ethereum/beacon/checkpoint.rs b/lib/unionlabs/src/ethereum/beacon/checkpoint.rs new file mode 100644 index 0000000000..889eb658ae --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/checkpoint.rs @@ -0,0 +1,13 @@ +use macros::model; +use ssz::Ssz; + +use crate::hash::H256; + +/// +#[model] +#[derive(Ssz)] +pub struct Checkpoint { + #[serde(with = "::serde_utils::string")] + pub epoch: u64, + pub root: H256, +} diff --git a/lib/unionlabs/src/ethereum/beacon/deposit.rs b/lib/unionlabs/src/ethereum/beacon/deposit.rs new file mode 100644 index 0000000000..91cae4fd58 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/deposit.rs @@ -0,0 +1,23 @@ +use macros::model; +use ssz::{types::Vector, Ssz}; + +use crate::{ + ethereum::{beacon::deposit_data::DepositData, config::DEPOSIT_CONTRACT_TREE_DEPTH}, + hash::H256, +}; + +/// +#[model] +#[derive(Ssz)] +#[serde(bound(serialize = "", deserialize = ""))] +pub struct Deposit { + /// Merkle path to deposit root + pub proof: Vector, + pub data: DepositData, +} + +#[model] +pub struct UnboundedDeposit { + pub proof: Vec, + pub data: DepositData, +} diff --git a/lib/unionlabs/src/ethereum/beacon/deposit_data.rs b/lib/unionlabs/src/ethereum/beacon/deposit_data.rs new file mode 100644 index 0000000000..dfdc925596 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/deposit_data.rs @@ -0,0 +1,19 @@ +use macros::model; +use ssz::Ssz; + +use crate::{ + bls::{BlsPublicKey, BlsSignature}, + hash::H256, +}; + +/// +#[model] +#[derive(Ssz)] +pub struct DepositData { + pub pubkey: BlsPublicKey, + pub withdrawal_credentials: H256, + #[serde(with = "::serde_utils::string")] + pub amount: u64, + /// Signing over `DepositMessage` + pub signature: BlsSignature, +} diff --git a/lib/unionlabs/src/ethereum/beacon/eth1_data.rs b/lib/unionlabs/src/ethereum/beacon/eth1_data.rs new file mode 100644 index 0000000000..fd3a2434c0 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/eth1_data.rs @@ -0,0 +1,15 @@ +use macros::model; +use ssz::Ssz; + +use crate::hash::H256; + +/// +#[model] +#[derive(Ssz)] +#[serde(bound(serialize = "", deserialize = ""))] +pub struct Eth1Data { + pub deposit_root: H256, + #[serde(with = "::serde_utils::string")] + pub deposit_count: u64, + pub block_hash: H256, +} diff --git a/lib/unionlabs/src/ethereum/beacon/execution_payload.rs b/lib/unionlabs/src/ethereum/beacon/execution_payload.rs new file mode 100644 index 0000000000..b277090931 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/execution_payload.rs @@ -0,0 +1,135 @@ +use macros::model; +use ssz::{ + types::{List, Vector}, + Ssz, +}; + +use crate::{ + ethereum::{ + beacon::withdrawal::Withdrawal, + config::{ + BYTES_PER_LOGS_BLOOM, MAX_BYTES_PER_TRANSACTION, MAX_EXTRA_DATA_BYTES, + MAX_TRANSACTIONS_PER_PAYLOAD, MAX_WITHDRAWALS_PER_PAYLOAD, + }, + }, + hash::{H160, H256}, + ibc::lightclients::ethereum::execution_payload_header::ExecutionPayloadHeader, + uint::U256, +}; + +/// +#[model] +#[derive(Ssz)] +pub struct ExecutionPayload< + C: BYTES_PER_LOGS_BLOOM + + MAX_EXTRA_DATA_BYTES + + MAX_BYTES_PER_TRANSACTION + + MAX_TRANSACTIONS_PER_PAYLOAD + + MAX_WITHDRAWALS_PER_PAYLOAD, +> { + /// Execution block header fields + pub parent_hash: H256, + pub fee_recipient: H160, + pub state_root: H256, + pub receipts_root: H256, + #[serde(with = "::serde_utils::hex_string")] + pub logs_bloom: Vector, + /// 'difficulty' in the yellow paper + pub prev_randao: H256, + /// 'number' in the yellow paper + #[serde(with = "::serde_utils::string")] + pub block_number: u64, + #[serde(with = "::serde_utils::string")] + pub gas_limit: u64, + #[serde(with = "::serde_utils::string")] + pub gas_used: u64, + #[serde(with = "::serde_utils::string")] + pub timestamp: u64, + #[serde(with = "::serde_utils::hex_string")] + pub extra_data: List, + pub base_fee_per_gas: U256, + /// Extra payload fields + /// Hash of execution block + pub block_hash: H256, + #[serde(with = "::serde_utils::hex_string_list")] + pub transactions: List, C::MAX_TRANSACTIONS_PER_PAYLOAD>, + pub withdrawals: List, + // blob_gas_used: uint64 # [New in Deneb:EIP4844] + #[serde(default, with = "::serde_utils::string")] + pub blob_gas_used: u64, + // excess_blob_gas: uint64 # [New in Deneb:EIP4844] + #[serde(default, with = "::serde_utils::string")] + pub excess_blob_gas: u64, +} + +impl< + C: BYTES_PER_LOGS_BLOOM + + MAX_EXTRA_DATA_BYTES + + MAX_BYTES_PER_TRANSACTION + + MAX_TRANSACTIONS_PER_PAYLOAD + + MAX_WITHDRAWALS_PER_PAYLOAD, + > ExecutionPayload +{ + #[must_use] + pub fn to_header(self) -> ExecutionPayloadHeader { + ExecutionPayloadHeader { + parent_hash: self.parent_hash, + fee_recipient: self.fee_recipient, + state_root: self.state_root, + receipts_root: self.receipts_root, + logs_bloom: self.logs_bloom, + prev_randao: self.prev_randao, + block_number: self.block_number, + gas_limit: self.gas_limit, + gas_used: self.gas_used, + timestamp: self.timestamp, + extra_data: self.extra_data, + base_fee_per_gas: self.base_fee_per_gas, + block_hash: self.block_hash, + transactions_root: self.transactions.tree_hash_root().into(), + withdrawals_root: self.withdrawals.tree_hash_root().into(), + blob_gas_used: self.blob_gas_used, + excess_blob_gas: self.excess_blob_gas, + } + } +} + +#[model] +pub struct UnboundedExecutionPayload { + /// Execution block header fields + pub parent_hash: H256, + pub fee_recipient: H160, + pub state_root: H256, + pub receipts_root: H256, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub logs_bloom: Vec, + /// 'difficulty' in the yellow paper + pub prev_randao: H256, + /// 'number' in the yellow paper + #[serde(with = "::serde_utils::string")] + pub block_number: u64, + #[serde(with = "::serde_utils::string")] + pub gas_limit: u64, + #[serde(with = "::serde_utils::string")] + pub gas_used: u64, + #[serde(with = "::serde_utils::string")] + pub timestamp: u64, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub extra_data: Vec, + pub base_fee_per_gas: U256, + /// Extra payload fields + /// Hash of execution block + pub block_hash: H256, + #[serde(with = "::serde_utils::hex_string_list")] + #[debug(wrap = ::serde_utils::fmt::DebugListAsHex)] + pub transactions: Vec>, + pub withdrawals: Vec, + // blob_gas_used: uint64 # [New in Deneb:EIP4844] + #[serde(default, with = "::serde_utils::string")] + pub blob_gas_used: u64, + // excess_blob_gas: uint64 # [New in Deneb:EIP4844] + #[serde(default, with = "::serde_utils::string")] + pub excess_blob_gas: u64, +} diff --git a/lib/unionlabs/src/ethereum/beacon/fork_data.rs b/lib/unionlabs/src/ethereum/beacon/fork_data.rs new file mode 100644 index 0000000000..99be4e8218 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/fork_data.rs @@ -0,0 +1,11 @@ +use macros::model; +use ssz::Ssz; + +use crate::{ethereum::Version, hash::H256}; + +#[model] +#[derive(Ssz)] +pub struct ForkData { + pub current_version: Version, + pub genesis_validators_root: H256, +} diff --git a/lib/unionlabs/src/ethereum/beacon/genesis_data.rs b/lib/unionlabs/src/ethereum/beacon/genesis_data.rs new file mode 100644 index 0000000000..d59c0bfd79 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/genesis_data.rs @@ -0,0 +1,11 @@ +use macros::model; + +use crate::{ethereum::Version, hash::H256}; + +#[model] +pub struct GenesisData { + pub genesis_validators_root: H256, + #[serde(with = "::serde_utils::string")] + pub genesis_time: u64, + pub genesis_fork_version: Version, +} diff --git a/lib/unionlabs/src/ethereum/beacon/indexed_attestation.rs b/lib/unionlabs/src/ethereum/beacon/indexed_attestation.rs new file mode 100644 index 0000000000..a7928a7ad3 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/indexed_attestation.rs @@ -0,0 +1,24 @@ +use macros::model; +use ssz::{types::List, Ssz}; + +use crate::{ + bls::BlsSignature, + ethereum::{beacon::attestation_data::AttestationData, config::MAX_VALIDATORS_PER_COMMITTEE}, +}; + +/// +#[model] +#[derive(Ssz)] +#[serde(bound(serialize = "", deserialize = ""))] +pub struct IndexedAttestation { + pub attesting_indices: List, + pub data: AttestationData, + pub signature: BlsSignature, +} + +#[model] +pub struct UnboundedIndexedAttestation { + pub attesting_indices: Vec, + pub data: AttestationData, + pub signature: BlsSignature, +} diff --git a/lib/unionlabs/src/ethereum/beacon/kzg_commitment.rs b/lib/unionlabs/src/ethereum/beacon/kzg_commitment.rs new file mode 100644 index 0000000000..5bca71b38a --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/kzg_commitment.rs @@ -0,0 +1,5 @@ +use crate::macros::hex_string_array_wrapper; + +hex_string_array_wrapper! { + pub struct KZGCommitment(pub [u8; 48]); +} diff --git a/lib/unionlabs/src/ethereum/beacon/light_client_bootstrap.rs b/lib/unionlabs/src/ethereum/beacon/light_client_bootstrap.rs new file mode 100644 index 0000000000..fb99d3b3be --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/light_client_bootstrap.rs @@ -0,0 +1,38 @@ +use macros::model; +use ssz::{types::Vector, Ssz}; +use typenum::U; + +use crate::{ + ethereum::config::{ + consts::{floorlog2, CURRENT_SYNC_COMMITTEE_INDEX}, + BYTES_PER_LOGS_BLOOM, MAX_EXTRA_DATA_BYTES, SYNC_COMMITTEE_SIZE, + }, + hash::H256, + ibc::lightclients::ethereum::{ + light_client_header::{LightClientHeader, UnboundedLightClientHeader}, + sync_committee::{SyncCommittee, UnboundedSyncCommittee}, + }, +}; + +/// +#[model] +#[derive(Ssz)] +#[serde(bound(serialize = "", deserialize = ""))] +pub struct LightClientBootstrap< + C: SYNC_COMMITTEE_SIZE + BYTES_PER_LOGS_BLOOM + MAX_EXTRA_DATA_BYTES, +> { + pub header: LightClientHeader, + /// Current sync committee corresponding to `beacon_header.state_root` + pub current_sync_committee: SyncCommittee, + // TODO: Update tree_hash to support const generic arrays + pub current_sync_committee_branch: Vector>, +} + +#[model] +pub struct UnboundedLightClientBootstrap { + pub header: UnboundedLightClientHeader, + /// Current sync committee corresponding to `beacon_header.state_root` + pub current_sync_committee: UnboundedSyncCommittee, + // TODO: Update tree_hash to support const generic arrays + pub current_sync_committee_branch: Vector>, +} diff --git a/lib/unionlabs/src/ethereum/beacon/light_client_finality_update.rs b/lib/unionlabs/src/ethereum/beacon/light_client_finality_update.rs new file mode 100644 index 0000000000..3e385cc25d --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/light_client_finality_update.rs @@ -0,0 +1,46 @@ +use macros::model; +use ssz::Ssz; + +use crate::{ + ethereum::config::{ + consts::{floorlog2, FINALIZED_ROOT_INDEX}, + BYTES_PER_LOGS_BLOOM, MAX_EXTRA_DATA_BYTES, SYNC_COMMITTEE_SIZE, + }, + hash::H256, + ibc::lightclients::ethereum::{ + light_client_header::{LightClientHeader, UnboundedLightClientHeader}, + sync_aggregate::{SyncAggregate, UnboundedSyncAggregate}, + }, +}; + +#[model] +#[derive(Ssz)] +#[serde(bound(serialize = "", deserialize = ""))] +pub struct LightClientFinalityUpdate< + C: SYNC_COMMITTEE_SIZE + BYTES_PER_LOGS_BLOOM + MAX_EXTRA_DATA_BYTES, +> { + /// Header attested to by the sync committee + pub attested_header: LightClientHeader, + /// Finalized header corresponding to `attested_header.state_root` + pub finalized_header: LightClientHeader, + pub finality_branch: [H256; floorlog2(FINALIZED_ROOT_INDEX)], + /// Sync committee aggregate signature + pub sync_aggregate: SyncAggregate, + /// Slot at which the aggregate signature was created (untrusted) + #[serde(with = "::serde_utils::string")] + pub signature_slot: u64, +} + +#[model] +pub struct UnboundedLightClientFinalityUpdate { + /// Header attested to by the sync committee + pub attested_header: UnboundedLightClientHeader, + /// Finalized header corresponding to `attested_header.state_root` + pub finalized_header: UnboundedLightClientHeader, + pub finality_branch: [H256; floorlog2(FINALIZED_ROOT_INDEX)], + /// Sync committee aggregate signature + pub sync_aggregate: UnboundedSyncAggregate, + /// Slot at which the aggregate signature was created (untrusted) + #[serde(with = "::serde_utils::string")] + pub signature_slot: u64, +} diff --git a/lib/unionlabs/src/ethereum/beacon/proposer_slashing.rs b/lib/unionlabs/src/ethereum/beacon/proposer_slashing.rs new file mode 100644 index 0000000000..a1f88bf574 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/proposer_slashing.rs @@ -0,0 +1,12 @@ +use macros::model; +use ssz::Ssz; + +use crate::ethereum::beacon::signed_beacon_block_header::SignedBeaconBlockHeader; + +/// +#[model] +#[derive(Ssz)] +pub struct ProposerSlashing { + pub signed_header_1: SignedBeaconBlockHeader, + pub signed_header_2: SignedBeaconBlockHeader, +} diff --git a/lib/unionlabs/src/ethereum/beacon/signed_beacon_block.rs b/lib/unionlabs/src/ethereum/beacon/signed_beacon_block.rs new file mode 100644 index 0000000000..efc9703616 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/signed_beacon_block.rs @@ -0,0 +1,47 @@ +use macros::model; +use ssz::Ssz; + +use crate::{ + bls::BlsSignature, + ethereum::{ + beacon::beacon_block::{BeaconBlock, UnboundedBeaconBlock}, + config::{ + BYTES_PER_LOGS_BLOOM, DEPOSIT_CONTRACT_TREE_DEPTH, MAX_ATTESTATIONS, + MAX_ATTESTER_SLASHINGS, MAX_BLOB_COMMITMENTS_PER_BLOCK, MAX_BLS_TO_EXECUTION_CHANGES, + MAX_BYTES_PER_TRANSACTION, MAX_DEPOSITS, MAX_EXTRA_DATA_BYTES, MAX_PROPOSER_SLASHINGS, + MAX_TRANSACTIONS_PER_PAYLOAD, MAX_VALIDATORS_PER_COMMITTEE, MAX_VOLUNTARY_EXITS, + MAX_WITHDRAWALS_PER_PAYLOAD, SYNC_COMMITTEE_SIZE, + }, + }, +}; + +/// +#[model] +#[derive(Ssz)] +#[serde(bound(serialize = "", deserialize = ""))] +pub struct SignedBeaconBlock< + C: MAX_PROPOSER_SLASHINGS + + MAX_VALIDATORS_PER_COMMITTEE + + MAX_ATTESTER_SLASHINGS + + MAX_ATTESTATIONS + + DEPOSIT_CONTRACT_TREE_DEPTH + + MAX_DEPOSITS + + MAX_VOLUNTARY_EXITS + + BYTES_PER_LOGS_BLOOM + + MAX_EXTRA_DATA_BYTES + + MAX_BYTES_PER_TRANSACTION + + MAX_TRANSACTIONS_PER_PAYLOAD + + MAX_WITHDRAWALS_PER_PAYLOAD + + MAX_BLS_TO_EXECUTION_CHANGES + + MAX_BLOB_COMMITMENTS_PER_BLOCK + + SYNC_COMMITTEE_SIZE, +> { + pub message: BeaconBlock, + pub signature: BlsSignature, +} + +#[model] +pub struct UnboundedSignedBeaconBlock { + pub message: UnboundedBeaconBlock, + pub signature: BlsSignature, +} diff --git a/lib/unionlabs/src/ethereum/beacon/signed_beacon_block_header.rs b/lib/unionlabs/src/ethereum/beacon/signed_beacon_block_header.rs new file mode 100644 index 0000000000..9e838c71ba --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/signed_beacon_block_header.rs @@ -0,0 +1,14 @@ +use macros::model; +use ssz::Ssz; + +use crate::{ + bls::BlsSignature, ibc::lightclients::ethereum::beacon_block_header::BeaconBlockHeader, +}; + +/// +#[model] +#[derive(Ssz)] +pub struct SignedBeaconBlockHeader { + pub message: BeaconBlockHeader, + pub signature: BlsSignature, +} diff --git a/lib/unionlabs/src/ethereum/beacon/signed_bls_to_execution_change.rs b/lib/unionlabs/src/ethereum/beacon/signed_bls_to_execution_change.rs new file mode 100644 index 0000000000..ee5a4983e6 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/signed_bls_to_execution_change.rs @@ -0,0 +1,11 @@ +use macros::model; +use ssz::Ssz; + +use crate::{bls::BlsSignature, ethereum::beacon::bls_to_execution_change::BlsToExecutionChange}; + +#[model] +#[derive(Ssz)] +pub struct SignedBlsToExecutionChange { + message: BlsToExecutionChange, + signature: BlsSignature, +} diff --git a/lib/unionlabs/src/ethereum/beacon/signed_voluntary_exit.rs b/lib/unionlabs/src/ethereum/beacon/signed_voluntary_exit.rs new file mode 100644 index 0000000000..01874962fe --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/signed_voluntary_exit.rs @@ -0,0 +1,12 @@ +use macros::model; +use ssz::Ssz; + +use crate::{bls::BlsSignature, ethereum::beacon::voluntary_exit::VoluntaryExit}; + +/// +#[model] +#[derive(Ssz)] +pub struct SignedVoluntaryExit { + pub message: VoluntaryExit, + pub signature: BlsSignature, +} diff --git a/lib/unionlabs/src/ethereum/beacon/signing_data.rs b/lib/unionlabs/src/ethereum/beacon/signing_data.rs new file mode 100644 index 0000000000..74269d96f7 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/signing_data.rs @@ -0,0 +1,12 @@ +use macros::model; +use ssz::Ssz; + +use crate::{ethereum::Domain, hash::H256}; + +/// +#[model] +#[derive(Ssz)] +pub struct SigningData { + pub object_root: H256, + pub domain: Domain, +} diff --git a/lib/unionlabs/src/ethereum/beacon/voluntary_exit.rs b/lib/unionlabs/src/ethereum/beacon/voluntary_exit.rs new file mode 100644 index 0000000000..54651cfa66 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/voluntary_exit.rs @@ -0,0 +1,13 @@ +use macros::model; +use ssz::Ssz; + +/// +#[model] +#[derive(Ssz)] +pub struct VoluntaryExit { + /// Earliest epoch when voluntary exit can be processed + #[serde(with = "::serde_utils::string")] + pub epoch: u64, + #[serde(with = "::serde_utils::string")] + pub validator_index: u64, +} diff --git a/lib/unionlabs/src/ethereum/beacon/withdrawal.rs b/lib/unionlabs/src/ethereum/beacon/withdrawal.rs new file mode 100644 index 0000000000..2ab20c5371 --- /dev/null +++ b/lib/unionlabs/src/ethereum/beacon/withdrawal.rs @@ -0,0 +1,16 @@ +use macros::model; +use ssz::Ssz; + +use crate::hash::H160; + +#[model] +#[derive(Ssz)] +pub struct Withdrawal { + #[serde(with = "::serde_utils::string")] + pub index: u64, + #[serde(with = "::serde_utils::string")] + pub validator_index: u64, + pub address: H160, + #[serde(with = "::serde_utils::string")] + pub amount: u64, +} diff --git a/lib/unionlabs/src/ethereum/config.rs b/lib/unionlabs/src/ethereum/config.rs index b4f2baa660..7a6e347ed1 100644 --- a/lib/unionlabs/src/ethereum/config.rs +++ b/lib/unionlabs/src/ethereum/config.rs @@ -1,4 +1,7 @@ -use core::{fmt::Debug, str::FromStr}; +use core::{ + fmt::{self, Debug}, + str::FromStr, +}; use serde::{Deserialize, Serialize}; use typenum::{NonZero, Unsigned}; @@ -10,13 +13,11 @@ use crate::{ }; /// Minimal config. -#[derive(Debug, Clone, PartialEq, Default)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct Minimal; /// Mainnet config. -#[derive(Debug, Clone, PartialEq, Default)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct Mainnet; #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] @@ -26,6 +27,15 @@ pub enum PresetBaseKind { Mainnet, } +impl fmt::Display for PresetBaseKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + PresetBaseKind::Minimal => "minimal", + PresetBaseKind::Mainnet => "mainnet", + }) + } +} + impl FromStr for PresetBaseKind { type Err = String; @@ -46,33 +56,6 @@ impl FromStrExact for Mainnet { const EXPECTING: &'static str = "mainnet"; } -/// A way to emulate HKTs in the context of [`ChainSpec`]s. -/// -/// # Example -/// -/// ```rs -/// struct Foo(PhantomData); -/// -/// struct AnyFoo; -/// -/// impl ChainSpecParameterizable for AnyFoo { -/// type T = Foo; -/// } -/// -/// struct Bar { -/// foo: AnyChainSpec, -/// } -/// ``` -pub trait ChainSpecParameterizable { - type Inner; -} - -// generic_enum! { -pub enum AnyChainSpec { - Mainnet(T::Inner), - Minimal(T::Inner), -} - // https://github.com/rust-lang/rust/issues/35853#issuecomment-415993963 macro_rules! with_dollar_sign { ($($body:tt)*) => { @@ -88,11 +71,11 @@ macro_rules! consts_traits { pub trait $CONST: Send + Sync + Unpin + 'static { // Extra traits are required because the builtin derives bound all generic // types unconditionally - type $CONST: Unsigned + NonZero + Debug + Clone + PartialEq + Send + Sync + Unpin; + type $CONST: Unsigned + NonZero + Debug + Clone + PartialEq + Eq + Send + Sync + Unpin; } )+ - pub trait ChainSpec: 'static + crate::MaybeArbitrary + FromStrExact + Debug + Clone + PartialEq + Default + Send + Sync + Unpin + $($CONST+)+ { + pub trait ChainSpec: 'static + FromStrExact + Debug + Clone + PartialEq + Eq + Default + Send + Sync + Unpin + $($CONST+)+ { const PRESET: preset::Preset; // const PRESET_BASE_KIND: PresetBaseKind; diff --git a/lib/unionlabs/src/events.rs b/lib/unionlabs/src/events.rs index 0b48f327d9..8cb3e510da 100644 --- a/lib/unionlabs/src/events.rs +++ b/lib/unionlabs/src/events.rs @@ -4,14 +4,14 @@ use macros::apply; use crate::{ ibc::core::{channel::order::Order, client::height::Height}, - id::{ChannelId, ConnectionId, PortId}, + id::{ChannelId, ClientId, ConnectionId, PortId}, }; macro_rules! event { ( - pub enum $Enum:ident$(<$($generics:ident),+>)? { + pub enum $Enum:ident { $( - #[event($(generics($($struct_generics:ident),*),)? tag = $tag:literal $(, deprecated($($dep:literal),+)$(,)?)?)] + #[event(tag = $tag:literal $(, deprecated($($dep:literal),+)$(,)?)?)] $Struct:ident { $( $(#[doc = $doc:literal])* @@ -24,23 +24,15 @@ macro_rules! event { )+ } ) => { - #[derive(::macros::Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] + #[derive(::macros::Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, enumorph::Enumorph)] #[serde(tag = "@type", content = "@value", rename_all = "snake_case")] - #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] - pub enum $Enum$(<$($generics),*>)? { + pub enum $Enum { $( - $Struct($Struct$(<$($struct_generics),+>)?), + $Struct($Struct), )+ } - impl$(<$($generics),+>)? IbcEvent$(<$($generics),+>)? - where - $( - $( - $generics: FromStr, - )+ - )? - { + impl IbcEvent { #[must_use] pub fn try_from_tendermint_event( event: crate::tendermint::abci::event::Event, @@ -65,8 +57,7 @@ macro_rules! event { $( #[derive(::macros::Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(deny_unknown_fields)] - #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] - pub struct $Struct$(<$($struct_generics),+>)? { + pub struct $Struct { $( $(#[doc = $doc])* $(#[serde($serde)])? @@ -76,14 +67,7 @@ macro_rules! event { } - impl$(<$($struct_generics),+>)? TryFrom for $Struct$(<$($struct_generics),+>)? - where - $( - $( - $struct_generics: FromStr, - )+ - )? - { + impl TryFrom for $Struct { type Error = TryFromTendermintEventError; fn try_from(value: crate::tendermint::abci::event::Event) -> Result { @@ -118,9 +102,9 @@ macro_rules! event { #[allow(clippy::redundant_closure_call)] (($parse)(&value)) .map_err(|err| { - TryFromTendermintEventError::Parse { + TryFromTendermintEventError::AttributeValueParse { field: stringify!($field), - error: err.to_string(), + error: crate::ErrorReporter(err).to_string(), } }) }))? @@ -132,7 +116,7 @@ macro_rules! event { "msg_index" => {} key => { if !DEPRECATED.contains(&key) { - return Err(TryFromTendermintEventError::UnknownField(attr.key)) + return Err(TryFromTendermintEventError::UnknownAttribute(attr.key)) } }, } @@ -141,7 +125,7 @@ macro_rules! event { Ok(Self { $( $field: $field - .ok_or(TryFromTendermintEventError::MissingField(stringify!($field)))? + .ok_or(TryFromTendermintEventError::MissingAttribute(stringify!($field)))? .1 ),+ }) @@ -151,20 +135,28 @@ macro_rules! event { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, thiserror::Error)] pub enum TryFromTendermintEventError { + #[error("incorrect type, expected `{expected}` but found `{}`", found.ty)] IncorrectType { expected: &'static str, found: crate::tendermint::abci::event::Event, }, + #[error( + "duplicate field `{key}` (first occurrence index {first_occurrence}, \ + second occurrence index {second_occurrence})" + )] DuplicateField { key: String, first_occurrence: usize, second_occurrence: usize, }, - MissingField(&'static str), - UnknownField(String), - Parse { + #[error("missing attribute `{0}`")] + MissingAttribute(&'static str), + #[error("missing attribute `{0}`")] + UnknownAttribute(String), + #[error("unable to parse value for attribute `{field}`: {error}")] + AttributeValueParse { field: &'static str, /// The stringified parse error. // NOTE: Basically just `Box` with `+ Clone + PartialEq` @@ -174,37 +166,31 @@ pub enum TryFromTendermintEventError { // https://github.com/cosmos/ibc-go/blob/5c7f28634ecf9b6f275bfd5712778fedcf06d80d/docs/ibc/events.md #[apply(event)] -pub enum IbcEvent { - #[event(generics(ClientId, ClientType), tag = "create_client")] +pub enum IbcEvent { + #[event(tag = "create_client")] CreateClient { #[parse(ClientId::from_str)] client_id: ClientId, - #[parse(ClientType::from_str)] - client_type: ClientType, + // TODO: Figure out if there's a better type we can use than string + client_type: String, #[parse(Height::from_str)] consensus_height: Height, }, - #[event( - generics(ClientId, ClientType), - tag = "update_client", - deprecated("consensus_height", "header") - )] + #[event(tag = "update_client", deprecated("consensus_height", "header"))] UpdateClient { #[parse(ClientId::from_str)] client_id: ClientId, - #[parse(ClientType::from_str)] - client_type: ClientType, + client_type: String, #[parse(|s: &str| s.split(',').map(Height::from_str).collect::>())] consensus_heights: Vec, }, - #[event(generics(ClientId, ClientType), tag = "client_misbehaviour")] + #[event(tag = "client_misbehaviour")] ClientMisbehaviour { #[parse(ClientId::from_str)] client_id: ClientId, - #[parse(ClientType::from_str)] - client_type: ClientType, + client_type: String, #[parse(Height::from_str)] consensus_height: Height, }, @@ -212,55 +198,48 @@ pub enum IbcEvent { #[event(tag = "submit_evidence")] SubmitEvidence { evidence_hash: String }, - #[event( - generics(ClientId, CounterpartyClientId), - tag = "connection_open_init", - deprecated("counterparty_connection_id") - )] + #[event(tag = "connection_open_init", deprecated("counterparty_connection_id"))] ConnectionOpenInit { #[parse(ConnectionId::from_str)] connection_id: ConnectionId, #[parse(ClientId::from_str)] client_id: ClientId, - #[parse(CounterpartyClientId::from_str)] - counterparty_client_id: CounterpartyClientId, + #[parse(ClientId::from_str)] + counterparty_client_id: ClientId, }, - #[event(generics(ClientId, CounterpartyClientId), tag = "connection_open_try")] + #[event(tag = "connection_open_try")] ConnectionOpenTry { #[parse(ConnectionId::from_str)] connection_id: ConnectionId, #[parse(ClientId::from_str)] client_id: ClientId, - #[parse(CounterpartyClientId::from_str)] - counterparty_client_id: CounterpartyClientId, + #[parse(ClientId::from_str)] + counterparty_client_id: ClientId, #[parse(ConnectionId::from_str)] counterparty_connection_id: ConnectionId, }, - #[event(generics(ClientId, CounterpartyClientId), tag = "connection_open_ack")] + #[event(tag = "connection_open_ack")] ConnectionOpenAck { #[parse(ConnectionId::from_str)] connection_id: ConnectionId, #[parse(ClientId::from_str)] client_id: ClientId, - #[parse(CounterpartyClientId::from_str)] - counterparty_client_id: CounterpartyClientId, + #[parse(ClientId::from_str)] + counterparty_client_id: ClientId, #[parse(ConnectionId::from_str)] counterparty_connection_id: ConnectionId, }, - #[event( - generics(ClientId, CounterpartyClientId), - tag = "connection_open_confirm" - )] + #[event(tag = "connection_open_confirm")] ConnectionOpenConfirm { #[parse(ConnectionId::from_str)] connection_id: ConnectionId, #[parse(ClientId::from_str)] client_id: ClientId, - #[parse(CounterpartyClientId::from_str)] - counterparty_client_id: CounterpartyClientId, + #[parse(ClientId::from_str)] + counterparty_client_id: ClientId, #[parse(ConnectionId::from_str)] counterparty_connection_id: ConnectionId, }, @@ -450,9 +429,8 @@ pub enum IbcEvent { }, } -impl - IbcEvent -{ +impl IbcEvent { + #[must_use] pub fn name(&self) -> &'static str { match self { IbcEvent::CreateClient(_) => "create_client", @@ -517,8 +495,8 @@ mod tests { }), Ok(ConnectionOpenConfirm { connection_id: "connection-11".parse().unwrap(), - client_id: "08-wasm-1".to_string(), - counterparty_client_id: "cometbls-new-0".to_string(), + client_id: "08-wasm-1".parse().unwrap(), + counterparty_client_id: "cometbls-new-0".parse().unwrap(), counterparty_connection_id: "connection-6".parse().unwrap(), }) ); @@ -556,7 +534,7 @@ mod tests { }; let expected_event = UpdateClient { - client_id: "client_id".to_string(), + client_id: "client_id".parse().unwrap(), client_type: "client_type".to_string(), consensus_heights: vec![Height { revision_number: 1, @@ -584,7 +562,7 @@ mod tests { #[test] fn parse() { assert_eq!( - UpdateClient::::try_from(Event { + UpdateClient::try_from(Event { ty: "update_client".to_string(), attributes: vec![ EventAttribute { @@ -609,7 +587,7 @@ mod tests { }, ], }), - Err(TryFromTendermintEventError::Parse { + Err(TryFromTendermintEventError::AttributeValueParse { field: "consensus_heights", error: HeightFromStrError::Invalid.to_string(), }) @@ -619,7 +597,7 @@ mod tests { #[test] fn missing_field() { assert_eq!( - ConnectionOpenConfirm::::try_from(Event { + ConnectionOpenConfirm::try_from(Event { ty: "connection_open_confirm".to_string(), attributes: vec![ EventAttribute { @@ -639,7 +617,7 @@ mod tests { }, ], }), - Err(TryFromTendermintEventError::MissingField("client_id")) + Err(TryFromTendermintEventError::MissingAttribute("client_id")) ); } @@ -651,7 +629,7 @@ mod tests { }; assert_eq!( - ConnectionOpenConfirm::::try_from(event.clone()), + ConnectionOpenConfirm::try_from(event.clone()), Err(TryFromTendermintEventError::IncorrectType { expected: "connection_open_confirm", found: event, @@ -662,7 +640,7 @@ mod tests { #[test] fn unknown_field() { assert_eq!( - ConnectionOpenConfirm::::try_from(Event { + ConnectionOpenConfirm::try_from(Event { ty: "connection_open_confirm".to_string(), attributes: vec![EventAttribute { key: "abracadabra".to_string(), @@ -670,7 +648,7 @@ mod tests { index: true, },], }), - Err(TryFromTendermintEventError::UnknownField( + Err(TryFromTendermintEventError::UnknownAttribute( "abracadabra".to_string() )) ); @@ -710,9 +688,9 @@ mod tests { }; assert_eq!( - CreateClient::::try_from(create_client_event).unwrap(), + CreateClient::try_from(create_client_event).unwrap(), CreateClient { - client_id: client_id.to_owned(), + client_id: client_id.parse().unwrap(), client_type: client_type.to_owned(), consensus_height: consensus_height.parse().unwrap(), } diff --git a/lib/unionlabs/src/google/protobuf/any.rs b/lib/unionlabs/src/google/protobuf/any.rs index ee97625b5b..a8ed141cf8 100644 --- a/lib/unionlabs/src/google/protobuf/any.rs +++ b/lib/unionlabs/src/google/protobuf/any.rs @@ -1,6 +1,7 @@ use core::{fmt::Debug, marker::PhantomData}; use frame_support_procedural::DebugNoBound; +use macros::model; use prost::Message; use serde::{ de::{self, Visitor}, @@ -15,7 +16,6 @@ use crate::{ /// Wrapper type to indicate that a type is to be serialized as an Any. #[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub struct Any(pub T); /// Provides a way to convert a type `T` into an [`Any`], even if `T` is itself an [`Any`]. @@ -49,6 +49,32 @@ impl> IntoAny for Any { } } +#[model] +pub struct RawAny { + pub type_url: String, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub value: Vec, +} + +impl From for RawAny { + fn from(value: protos::google::protobuf::Any) -> Self { + Self { + type_url: value.type_url, + value: value.value.to_vec(), + } + } +} + +impl From for protos::google::protobuf::Any { + fn from(value: RawAny) -> Self { + Self { + type_url: value.type_url, + value: value.value.into(), + } + } +} + /// TODO(unionlabs/union#876): Properly implement google.protobuf.Any json serde impl<'de, T> Deserialize<'de> for Any where diff --git a/lib/unionlabs/src/google/protobuf/duration.rs b/lib/unionlabs/src/google/protobuf/duration.rs index 58ecbc4e2c..7fec825a5e 100644 --- a/lib/unionlabs/src/google/protobuf/duration.rs +++ b/lib/unionlabs/src/google/protobuf/duration.rs @@ -51,7 +51,7 @@ type DurationInner = BoundedI128< /// > of the same sign as the `seconds` field. Must be from -999,999,999 /// > to +999,999,999 inclusive. #[model(proto(raw(protos::google::protobuf::Duration), into, from), no_serde)] -#[derive(PartialOrd, Ord, Eq, Copy)] +#[derive(PartialOrd, Ord, Copy)] #[debug("Duration({})", self)] pub struct Duration(DurationInner); diff --git a/lib/unionlabs/src/google/protobuf/timestamp.rs b/lib/unionlabs/src/google/protobuf/timestamp.rs index def9cd654d..591f1181a9 100644 --- a/lib/unionlabs/src/google/protobuf/timestamp.rs +++ b/lib/unionlabs/src/google/protobuf/timestamp.rs @@ -31,7 +31,7 @@ pub type ValidTimestampUnixNanos = BoundedI128< no_serde )] #[debug("Timestamp({})", self)] -#[derive(Eq, Copy)] +#[derive(Copy)] pub struct Timestamp { /// As per the proto docs: "Must be from 0001-01-01T00:00:00Z to /// 9999-12-31T23:59:59Z inclusive." diff --git a/lib/unionlabs/src/hash.rs b/lib/unionlabs/src/hash.rs index a148a4ec30..b2fa78d60a 100644 --- a/lib/unionlabs/src/hash.rs +++ b/lib/unionlabs/src/hash.rs @@ -41,3 +41,44 @@ impl From for H160 { Self(value.0) } } + +pub struct BytesBitIterator<'a> { + bz: &'a [u8], + pos: core::ops::Range, +} + +impl<'a> BytesBitIterator<'a> { + pub fn new(bz: &'a impl AsRef<[u8]>) -> Self { + BytesBitIterator { + bz: bz.as_ref(), + pos: (0..bz.as_ref().len() * 8), + } + } + + /// Returns the `index`-th bit in the bytes. + fn get_bit(&self, index: usize) -> bool { + // debug_assert_eq!(self.hash_bytes.len(), Hash::LENGTH); // invariant + // debug_assert_lt!(index, Hash::LENGTH_IN_BITS); // assumed precondition + let pos = index / 8; + let bit = 7 - index % 8; + (self.bz[pos] >> bit) & 1 != 0 + } +} + +impl<'a> core::iter::Iterator for BytesBitIterator<'a> { + type Item = bool; + + fn next(&mut self) -> Option { + self.pos.next().map(|x| self.get_bit(x)) + } + + fn size_hint(&self) -> (usize, Option) { + self.pos.size_hint() + } +} + +impl<'a> core::iter::DoubleEndedIterator for BytesBitIterator<'a> { + fn next_back(&mut self) -> Option { + self.pos.next_back().map(|x| self.get_bit(x)) + } +} diff --git a/lib/unionlabs/src/ibc/core/channel/channel.rs b/lib/unionlabs/src/ibc/core/channel/channel.rs index bff97724e3..3453167a3c 100644 --- a/lib/unionlabs/src/ibc/core/channel/channel.rs +++ b/lib/unionlabs/src/ibc/core/channel/channel.rs @@ -42,13 +42,18 @@ impl From for protos::ibc::core::channel::v1::Channel { } } -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq, thiserror::Error)] pub enum TryFromChannelError { - MissingField(MissingField), - State(UnknownEnumVariant), - Counterparty(TryFromChannelCounterpartyError), - Ordering(UnknownEnumVariant), - ConnectionHops(>::Error), + #[error(transparent)] + MissingField(#[from] MissingField), + #[error("invalid state")] + State(#[source] UnknownEnumVariant), + #[error("invalid counterparty")] + Counterparty(#[from] TryFromChannelCounterpartyError), + #[error("invalid ordering")] + Ordering(#[source] UnknownEnumVariant), + #[error("invalid connection_hops")] + ConnectionHops(#[from] >::Error), } impl TryFrom for Channel { diff --git a/lib/unionlabs/src/ibc/core/channel/counterparty.rs b/lib/unionlabs/src/ibc/core/channel/counterparty.rs index 3e57ce55f9..3ede617cb2 100644 --- a/lib/unionlabs/src/ibc/core/channel/counterparty.rs +++ b/lib/unionlabs/src/ibc/core/channel/counterparty.rs @@ -14,6 +14,7 @@ use crate::id::PortId; )] pub struct Counterparty { pub port_id: PortId, + // TODO: Option, same as connection counterparty pub channel_id: String, } @@ -26,7 +27,7 @@ impl From for protos::ibc::core::channel::v1::Counterparty { } } -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Clone, PartialEq, thiserror::Error)] pub enum TryFromChannelCounterpartyError { #[error("error parsing port id")] PortId(#[source] ::Err), diff --git a/lib/unionlabs/src/ibc/core/channel/msg_acknowledgement.rs b/lib/unionlabs/src/ibc/core/channel/msg_acknowledgement.rs index 09d30570cb..70c0e40986 100644 --- a/lib/unionlabs/src/ibc/core/channel/msg_acknowledgement.rs +++ b/lib/unionlabs/src/ibc/core/channel/msg_acknowledgement.rs @@ -1,17 +1,15 @@ use macros::model; -use serde::{Deserialize, Serialize}; -use crate::ibc::core::{channel::packet::Packet, client::height::IsHeight}; +use crate::ibc::core::{channel::packet::Packet, client::height::Height}; #[model(proto(raw(protos::ibc::core::channel::v1::MsgAcknowledgement)))] -#[serde(bound( - serialize = "ProofAcked: Serialize", - deserialize = "ProofAcked: for<'d> Deserialize<'d>", -))] -pub struct MsgAcknowledgement { +pub struct MsgAcknowledgement { pub packet: Packet, #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] pub acknowledgement: Vec, - pub proof_acked: ProofAcked, - pub proof_height: ProofHeight, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof_acked: Vec, + pub proof_height: Height, } diff --git a/lib/unionlabs/src/ibc/core/channel/msg_channel_open_ack.rs b/lib/unionlabs/src/ibc/core/channel/msg_channel_open_ack.rs index 3aee21bc0b..314cfd8e32 100644 --- a/lib/unionlabs/src/ibc/core/channel/msg_channel_open_ack.rs +++ b/lib/unionlabs/src/ibc/core/channel/msg_channel_open_ack.rs @@ -1,22 +1,19 @@ use macros::model; -use serde::{Deserialize, Serialize}; use crate::{ - ibc::core::client::height::IsHeight, + ibc::core::client::height::Height, id::{ChannelId, PortId}, }; #[model(proto(raw(protos::ibc::core::channel::v1::MsgChannelOpenAck)))] -#[serde(bound( - serialize = "ProofTry: Serialize", - deserialize = "ProofTry: for<'d> Deserialize<'d>", -))] -pub struct MsgChannelOpenAck { +pub struct MsgChannelOpenAck { pub port_id: PortId, pub channel_id: ChannelId, pub counterparty_channel_id: ChannelId, // yes, this is actually just an unbounded string pub counterparty_version: String, - pub proof_try: ProofTry, - pub proof_height: ProofHeight, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof_try: Vec, + pub proof_height: Height, } diff --git a/lib/unionlabs/src/ibc/core/channel/msg_channel_open_confirm.rs b/lib/unionlabs/src/ibc/core/channel/msg_channel_open_confirm.rs index c9f75a563a..ed2c40de7b 100644 --- a/lib/unionlabs/src/ibc/core/channel/msg_channel_open_confirm.rs +++ b/lib/unionlabs/src/ibc/core/channel/msg_channel_open_confirm.rs @@ -6,9 +6,11 @@ use crate::{ }; #[model(proto(raw(protos::ibc::core::channel::v1::MsgChannelOpenConfirm)))] -pub struct MsgChannelOpenConfirm { +pub struct MsgChannelOpenConfirm { pub port_id: PortId, pub channel_id: ChannelId, - pub proof_ack: ProofAck, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof_ack: Vec, pub proof_height: Height, } diff --git a/lib/unionlabs/src/ibc/core/channel/msg_channel_open_try.rs b/lib/unionlabs/src/ibc/core/channel/msg_channel_open_try.rs index 2b15b128c9..ad56b01265 100644 --- a/lib/unionlabs/src/ibc/core/channel/msg_channel_open_try.rs +++ b/lib/unionlabs/src/ibc/core/channel/msg_channel_open_try.rs @@ -6,10 +6,12 @@ use crate::{ }; #[model(proto(raw(protos::ibc::core::channel::v1::MsgChannelOpenTry)))] -pub struct MsgChannelOpenTry { +pub struct MsgChannelOpenTry { pub port_id: PortId, pub channel: Channel, pub counterparty_version: String, - pub proof_init: ProofInit, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof_init: Vec, pub proof_height: Height, } diff --git a/lib/unionlabs/src/ibc/core/channel/msg_recv_packet.rs b/lib/unionlabs/src/ibc/core/channel/msg_recv_packet.rs index 51e79eaa29..14a8d07c67 100644 --- a/lib/unionlabs/src/ibc/core/channel/msg_recv_packet.rs +++ b/lib/unionlabs/src/ibc/core/channel/msg_recv_packet.rs @@ -1,15 +1,12 @@ use macros::model; -use serde::{Deserialize, Serialize}; -use crate::ibc::core::{channel::packet::Packet, client::height::IsHeight}; +use crate::ibc::core::{channel::packet::Packet, client::height::Height}; #[model(proto(raw(protos::ibc::core::channel::v1::MsgRecvPacket)))] -#[serde(bound( - serialize = "ProofCommitment: Serialize", - deserialize = "ProofCommitment: for<'d> Deserialize<'d>", -))] -pub struct MsgRecvPacket { +pub struct MsgRecvPacket { pub packet: Packet, - pub proof_commitment: ProofCommitment, - pub proof_height: ProofHeight, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof_commitment: Vec, + pub proof_height: Height, } diff --git a/lib/unionlabs/src/ibc/core/channel/msg_timeout.rs b/lib/unionlabs/src/ibc/core/channel/msg_timeout.rs index f4c17b8b7f..d8ba842661 100644 --- a/lib/unionlabs/src/ibc/core/channel/msg_timeout.rs +++ b/lib/unionlabs/src/ibc/core/channel/msg_timeout.rs @@ -2,16 +2,14 @@ use core::num::NonZeroU64; use macros::model; -use crate::ibc::core::{channel::packet::Packet, client::height::IsHeight}; +use crate::ibc::core::{channel::packet::Packet, client::height::Height}; #[model(proto(raw(protos::ibc::core::channel::v1::MsgRecvPacket)))] -#[serde(bound( - serialize = "ProofUnreceived: serde::Serialize", - deserialize = "ProofUnreceived: for<'d> serde::Deserialize<'d>", -))] -pub struct MsgTimeout { +pub struct MsgTimeout { pub packet: Packet, - pub proof_unreceived: ProofUnreceived, - pub proof_height: ProofHeight, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof_unreceived: Vec, + pub proof_height: Height, pub next_sequence_recv: NonZeroU64, } diff --git a/lib/unionlabs/src/ibc/core/channel/packet.rs b/lib/unionlabs/src/ibc/core/channel/packet.rs index 827158cad7..20991c6c8d 100644 --- a/lib/unionlabs/src/ibc/core/channel/packet.rs +++ b/lib/unionlabs/src/ibc/core/channel/packet.rs @@ -4,7 +4,7 @@ use macros::model; use crate::{ errors::{required, MissingField}, - ibc::core::client::height::{Height, IsHeight}, + ibc::core::client::height::Height, id::{ChannelId, ChannelIdValidator, PortId, PortIdValidator}, validated::{Validate, ValidateT}, }; @@ -32,7 +32,7 @@ impl From for protos::ibc::core::channel::v1::Packet { destination_port: value.destination_port.to_string(), destination_channel: value.destination_channel.to_string(), data: value.data, - timeout_height: Some(value.timeout_height.into_height().into()), + timeout_height: Some(value.timeout_height.into()), timeout_timestamp: value.timeout_timestamp, } } @@ -98,7 +98,7 @@ impl From for contracts::ibc_handler::IbcCoreChannelV1PacketData { destination_port: value.destination_port.to_string(), destination_channel: value.destination_channel.to_string(), data: value.data.into(), - timeout_height: value.timeout_height.into_height().into(), + timeout_height: value.timeout_height.into(), timeout_timestamp: value.timeout_timestamp, } } diff --git a/lib/unionlabs/src/ibc/core/client/height.rs b/lib/unionlabs/src/ibc/core/client/height.rs index 8f488cd990..f9c6adaf09 100644 --- a/lib/unionlabs/src/ibc/core/client/height.rs +++ b/lib/unionlabs/src/ibc/core/client/height.rs @@ -5,13 +5,13 @@ use core::{ }; use macros::model; -use serde::{Deserialize, Serialize}; use ssz::Ssz; #[derive(Ssz, Default, Copy)] #[model(proto(raw(protos::ibc::core::client::v1::Height), into, from))] #[debug("Height({self})")] #[cfg_attr(feature = "schemars", derive(::schemars::JsonSchema))] +#[derive(Hash)] pub struct Height { // REVIEW: Why default? #[serde(default)] @@ -21,11 +21,10 @@ pub struct Height { impl Height { #[must_use] - #[deprecated] - pub fn new(revision_number: u64, revision_height: u64) -> Self { - Height { - revision_number, - revision_height, + pub const fn increment(self) -> Self { + Self { + revision_number: self.revision_number, + revision_height: self.revision_height + 1, } } } @@ -45,7 +44,7 @@ impl FromStr for Height { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub enum HeightFromStrError { ParseIntError(ParseIntError), Invalid, @@ -89,11 +88,17 @@ impl From for protos::ibc::core::client::v1::Height { impl PartialOrd for Height { fn partial_cmp(&self, other: &Self) -> Option { - Some(match self.revision_number.cmp(&other.revision_number) { + Some(self.cmp(other)) + } +} + +impl Ord for Height { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + match self.revision_number.cmp(&other.revision_number) { core::cmp::Ordering::Less => core::cmp::Ordering::Less, core::cmp::Ordering::Equal => self.revision_height.cmp(&other.revision_height), core::cmp::Ordering::Greater => core::cmp::Ordering::Greater, - }) + } } } @@ -123,80 +128,10 @@ impl From for Height { } } -pub trait IsHeight: - FromStr - + Display - + Debug - + Copy - + PartialEq - + Serialize - + for<'de> Deserialize<'de> - + From - + Into - + Send - + Sync - + 'static -{ - fn into_height(self) -> Height { - Into::::into(self) - } - - #[must_use] - fn increment(self) -> Self { - Height { - revision_number: self.revision_number(), - revision_height: self.revision_height() + 1, - } - .into() - } - - #[must_use] - fn decrement(self) -> Self { - Height { - revision_number: self.revision_number(), - revision_height: self.revision_height() - 1, - } - .into() - } - - fn revision_number(&self) -> u64 { - self.into_height().revision_number - } - fn revision_height(&self) -> u64 { - self.into_height().revision_height - } -} - -impl IsHeight for T where - T: FromStr - + Display - + Debug - + Copy - + PartialEq - + Serialize - + for<'de> Deserialize<'de> - + From - + Into - + Send - + Sync - + 'static -{ -} - #[cfg(test)] mod tests { use super::*; - #[test] - fn height_impls_is_height() { - fn f(_: impl IsHeight) {} - - f(Height { - revision_number: 0, - revision_height: 0, - }); - } - #[test] fn debug() { assert_eq!( diff --git a/lib/unionlabs/src/ibc/core/client/msg_create_client.rs b/lib/unionlabs/src/ibc/core/client/msg_create_client.rs index 8d6e1d13fb..e78dd5fe8e 100644 --- a/lib/unionlabs/src/ibc/core/client/msg_create_client.rs +++ b/lib/unionlabs/src/ibc/core/client/msg_create_client.rs @@ -1,7 +1,11 @@ use macros::model; #[model(proto(raw(protos::ibc::core::client::v1::MsgCreateClient)))] -pub struct MsgCreateClient { - pub client_state: ClientState, - pub consensus_state: ConsensusState, +pub struct MsgCreateClient { + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub client_state: Vec, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub consensus_state: Vec, } diff --git a/lib/unionlabs/src/ibc/core/client/msg_update_client.rs b/lib/unionlabs/src/ibc/core/client/msg_update_client.rs index af1c3091ae..13450b981e 100644 --- a/lib/unionlabs/src/ibc/core/client/msg_update_client.rs +++ b/lib/unionlabs/src/ibc/core/client/msg_update_client.rs @@ -1,7 +1,11 @@ use macros::model; +use crate::id::ClientId; + #[model(proto(raw(protos::ibc::core::client::v1::MsgUpdateClient)))] -pub struct MsgUpdateClient { +pub struct MsgUpdateClient { pub client_id: ClientId, - pub client_message: Header, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub client_message: Vec, } diff --git a/lib/unionlabs/src/ibc/core/commitment/merkle_proof.rs b/lib/unionlabs/src/ibc/core/commitment/merkle_proof.rs index 915a22e4ce..7f5f3e7970 100644 --- a/lib/unionlabs/src/ibc/core/commitment/merkle_proof.rs +++ b/lib/unionlabs/src/ibc/core/commitment/merkle_proof.rs @@ -2,10 +2,7 @@ use macros::model; use crate::cosmos::ics23::commitment_proof::{CommitmentProof, TryFromCommitmentProofError}; -#[model( - proto(raw(protos::ibc::core::commitment::v1::MerkleProof), into, from), - ethabi(raw(contracts::glue::IbcCoreCommitmentV1MerkleProofData), from) -)] +#[model(proto(raw(protos::ibc::core::commitment::v1::MerkleProof), into, from))] pub struct MerkleProof { pub proofs: Vec, } @@ -41,11 +38,13 @@ impl From for protos::ibc::core::commitment::v1::MerkleProof { } } -#[cfg(feature = "ethabi")] -impl From for contracts::glue::IbcCoreCommitmentV1MerkleProofData { - fn from(value: MerkleProof) -> Self { - contracts::glue::IbcCoreCommitmentV1MerkleProofData { - proofs: value.proofs.into_iter().map(Into::into).collect::>(), - } +#[cfg(test)] +mod tests { + use super::*; + use crate::test_utils::assert_json_roundtrip; + + #[test] + fn json() { + assert_json_roundtrip::(&serde_json::from_str(r#"{"proofs":[{"@type":"exist","@value":{"key":"0x636f6e6e656374696f6e732f636f6e6e656374696f6e2d34","leaf":{"hash":"sha256","length":"var_proto","prefix":"0x0002fe14","prehash_key":"no_hash","prehash_value":"sha256"},"path":[{"hash":"sha256","prefix":"0x0204fe1420ef76e6b775ddb12b9266a1c6be8f8a0465334edc5d63c4d50ec08acd3222b87120","suffix":"0x0"},{"hash":"sha256","prefix":"0x0408fe14205f20a52bf4eaf1f74bc2fe181f8ffde4007e02431bb098de85f583e7fd2ffab220","suffix":"0x0"},{"hash":"sha256","prefix":"0x060cfe1420d4c306fc76462b92c3888a22f78962e742022a4fa4b272947acf199993820a0720","suffix":"0x0"},{"hash":"sha256","prefix":"0x0814fe1420","suffix":"0x205da3a959acc11540519acc75cddcb1a953daa64ae13c029b0acacb7d3bf42f48"},{"hash":"sha256","prefix":"0x0a26fe14207288844aa9b92616031aa88ac045762ffca46300497d57256576f9e4481a162520","suffix":"0x0"}],"value":"0x0a0930382d7761736d2d3112140a0131120f4f524445525f554e4f524445524544180122130a0a636f6d6574626c732d301a050a03696263"}},{"@type":"exist","@value":{"key":"0x696263","leaf":{"hash":"sha256","length":"var_proto","prefix":"0x00","prehash_key":"no_hash","prehash_value":"sha256"},"path":[{"hash":"sha256","prefix":"0x01","suffix":"0x2cd8b50700950546180ad979135a8708c2ea2098fff6ade31b7e40eb5dcf7c05"},{"hash":"sha256","prefix":"0x012cf3feea58fcdb48b73c2cdd1b018c90c4078f924385675a0e9457168cd47ff1","suffix":"0x0"},{"hash":"sha256","prefix":"0x01668a26eca4c2d85af70ee4cec96ab6fd1dc8c30f6e77964b6ed44a33b5a16d8c","suffix":"0x0"},{"hash":"sha256","prefix":"0x01074d5d4ae17c3219a53737ff36d1528bcd934b9ac7d9a7fc75257464bfbc8b8c","suffix":"0x0"},{"hash":"sha256","prefix":"0x01","suffix":"0x5b70af779b3bfd3c770d0ba038f05691478946ec8336226dc7ca5b6d3c08d9e3"}],"value":"0x3befa6eab5974ef0ba3fca174a9718704a98204f80476042e6ffcf41060cccb9"}}]}"#).unwrap()); } } diff --git a/lib/unionlabs/src/ibc/core/connection/connection_end.rs b/lib/unionlabs/src/ibc/core/connection/connection_end.rs index e810515dc6..e9e326edd9 100644 --- a/lib/unionlabs/src/ibc/core/connection/connection_end.rs +++ b/lib/unionlabs/src/ibc/core/connection/connection_end.rs @@ -1,6 +1,5 @@ use core::str::FromStr; -use frame_support_procedural::DebugNoBound; use macros::model; #[cfg(feature = "ethabi")] @@ -12,60 +11,38 @@ use crate::{ state::State, version::Version, }, - id, - traits::Id, + id::ClientId, }; #[model( proto(raw(protos::ibc::core::connection::v1::ConnectionEnd), into, from), ethabi(raw(contracts::glue::IbcCoreConnectionV1ConnectionEndData), into, from) )] -#[serde(bound( - serialize = " - ClientId: Id, - CounterpartyClientId: Id, - CounterpartyConnectionId: Id, - ", - deserialize = " - ClientId: Id, - CounterpartyClientId: Id, - CounterpartyConnectionId: Id, - ", -))] #[cfg_attr(feature = "schemars", derive(::schemars::JsonSchema))] -pub struct ConnectionEnd< - ClientId: Id, - CounterpartyClientId: Id, - CounterpartyConnectionId: Id = id::ConnectionId, -> { +pub struct ConnectionEnd { pub client_id: ClientId, pub versions: Vec, pub state: State, - pub counterparty: Counterparty, + pub counterparty: Counterparty, pub delay_period: u64, } -#[derive(DebugNoBound)] -pub enum TryFromConnectionEndError< - ClientId: Id, - CounterpartyClientId: Id, - CounterpartyConnectionId: Id, -> { - ClientId(::Err), - Version(UnknownEnumVariant), - State(UnknownEnumVariant), - Counterparty( - TryFromConnectionCounterpartyError, - ), - MissingField(MissingField), +#[derive(Debug, Clone, PartialEq, thiserror::Error)] +pub enum TryFromConnectionEndError { + #[error(transparent)] + MissingField(#[from] MissingField), + #[error("invalid client_id")] + ClientId(#[from] ::Err), + #[error("invalid version")] + Version(#[from] UnknownEnumVariant), + #[error("invalid state")] + State(#[from] UnknownEnumVariant), + #[error("invalid counterparty")] + Counterparty(#[from] TryFromConnectionCounterpartyError), } -impl - TryFrom - for ConnectionEnd -{ - type Error = - TryFromConnectionEndError; +impl TryFrom for ConnectionEnd { + type Error = TryFromConnectionEndError; fn try_from( val: protos::ibc::core::connection::v1::ConnectionEnd, @@ -92,11 +69,8 @@ impl } } -impl - From> - for protos::ibc::core::connection::v1::ConnectionEnd -{ - fn from(val: ConnectionEnd) -> Self { +impl From for protos::ibc::core::connection::v1::ConnectionEnd { + fn from(val: ConnectionEnd) -> Self { Self { client_id: val.client_id.to_string(), versions: val.versions.into_iter().map(Into::into).collect(), @@ -109,26 +83,16 @@ impl #[derive(Debug)] #[cfg(feature = "ethabi")] -pub enum TryFromEthAbiConnectionEndError< - ClientId: Id, - CounterpartyClientId: Id, - CounterpartyConnectionId: Id, -> { +pub enum TryFromEthAbiConnectionEndError { ClientId(::Err), Version(UnknownEnumVariant), State(UnknownEnumVariant), - Counterparty( - TryFromEthAbiConnectionCounterpartyError, - ), + Counterparty(TryFromEthAbiConnectionCounterpartyError), } #[cfg(feature = "ethabi")] -impl - TryFrom - for ConnectionEnd -{ - type Error = - TryFromEthAbiConnectionEndError; +impl TryFrom for ConnectionEnd { + type Error = TryFromEthAbiConnectionEndError; fn try_from( val: contracts::glue::IbcCoreConnectionV1ConnectionEndData, @@ -160,11 +124,8 @@ impl } #[cfg(feature = "ethabi")] -impl - From> - for contracts::glue::IbcCoreConnectionV1ConnectionEndData -{ - fn from(val: ConnectionEnd) -> Self { +impl From for contracts::glue::IbcCoreConnectionV1ConnectionEndData { + fn from(val: ConnectionEnd) -> Self { Self { client_id: val.client_id.to_string(), versions: val.versions.into_iter().map(Into::into).collect(), diff --git a/lib/unionlabs/src/ibc/core/connection/counterparty.rs b/lib/unionlabs/src/ibc/core/connection/counterparty.rs index f70bff5e14..4350420dac 100644 --- a/lib/unionlabs/src/ibc/core/connection/counterparty.rs +++ b/lib/unionlabs/src/ibc/core/connection/counterparty.rs @@ -5,51 +5,44 @@ use macros::model; use crate::{ errors::{required, MissingField}, ibc::core::commitment::merkle_prefix::MerklePrefix, - id, - traits::Id, + id::{ClientId, ConnectionId}, }; #[model(proto(raw(protos::ibc::core::connection::v1::Counterparty), into, from))] -#[serde(bound( - serialize = " - ClientId: Id, - ConnectionId: Id, - ", - deserialize = " - ClientId: Id, - ConnectionId: Id, - ", -))] #[cfg_attr(feature = "schemars", derive(::schemars::JsonSchema))] -pub struct Counterparty { +pub struct Counterparty { pub client_id: ClientId, - pub connection_id: ConnectionId, + // this is really `Either` + pub connection_id: Option, pub prefix: MerklePrefix, } -impl From> - for protos::ibc::core::connection::v1::Counterparty -{ - fn from(value: Counterparty) -> Self { +impl From for protos::ibc::core::connection::v1::Counterparty { + fn from(value: Counterparty) -> Self { Self { client_id: value.client_id.to_string(), - connection_id: value.connection_id.to_string(), + connection_id: value + .connection_id + .as_deref() + .unwrap_or_default() + .to_string(), prefix: Some(value.prefix.into()), } } } -#[derive(Debug)] -pub enum TryFromConnectionCounterpartyError { - MissingField(MissingField), - ClientId(::Err), - ConnectionId(::Err), +#[derive(Debug, Clone, PartialEq, thiserror::Error)] +pub enum TryFromConnectionCounterpartyError { + #[error(transparent)] + MissingField(#[from] MissingField), + #[error("invalid client_id")] + ClientId(#[source] ::Err), + #[error("invalid connection_id")] + ConnectionId(#[source] ::Err), } -impl TryFrom - for Counterparty -{ - type Error = TryFromConnectionCounterpartyError; +impl TryFrom for Counterparty { + type Error = TryFromConnectionCounterpartyError; fn try_from( value: protos::ibc::core::connection::v1::Counterparty, @@ -59,23 +52,31 @@ impl TryFrom From> - for contracts::ibc_handler::IbcCoreConnectionV1CounterpartyData -{ - fn from(value: Counterparty) -> Self { +impl From for contracts::ibc_handler::IbcCoreConnectionV1CounterpartyData { + fn from(value: Counterparty) -> Self { Self { client_id: value.client_id.to_string(), - connection_id: value.connection_id.to_string(), + connection_id: value + .connection_id + .as_deref() + .unwrap_or_default() + .to_string(), prefix: value.prefix.into(), } } @@ -83,17 +84,14 @@ impl From> #[derive(Debug)] #[cfg(feature = "ethabi")] -pub enum TryFromEthAbiConnectionCounterpartyError { +pub enum TryFromEthAbiConnectionCounterpartyError { ClientId(::Err), ConnectionId(::Err), } #[cfg(feature = "ethabi")] -impl - TryFrom - for Counterparty -{ - type Error = TryFromEthAbiConnectionCounterpartyError; +impl TryFrom for Counterparty { + type Error = TryFromEthAbiConnectionCounterpartyError; fn try_from( value: contracts::ibc_handler::IbcCoreConnectionV1CounterpartyData, @@ -103,10 +101,16 @@ impl .client_id .parse() .map_err(TryFromEthAbiConnectionCounterpartyError::ClientId)?, - connection_id: value - .connection_id - .parse() - .map_err(TryFromEthAbiConnectionCounterpartyError::ConnectionId)?, + connection_id: if value.connection_id.is_empty() { + None + } else { + Some( + value + .connection_id + .parse() + .map_err(TryFromEthAbiConnectionCounterpartyError::ConnectionId)?, + ) + }, prefix: value.prefix.into(), }) } diff --git a/lib/unionlabs/src/ibc/core/connection/msg_connection_open_ack.rs b/lib/unionlabs/src/ibc/core/connection/msg_connection_open_ack.rs index 9776194497..1262c09921 100644 --- a/lib/unionlabs/src/ibc/core/connection/msg_connection_open_ack.rs +++ b/lib/unionlabs/src/ibc/core/connection/msg_connection_open_ack.rs @@ -6,16 +6,24 @@ use crate::{ }; #[model(proto(raw(protos::ibc::core::connection::v1::MsgConnectionOpenAck)))] -pub struct MsgConnectionOpenAck { +pub struct MsgConnectionOpenAck { pub connection_id: ConnectionId, pub counterparty_connection_id: ConnectionId, pub version: Version, - pub client_state: ClientState, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub client_state: Vec, // TODO: Make this type generic pub proof_height: Height, - pub proof_try: ProofTry, - pub proof_client: ProofClient, - pub proof_consensus: ProofConsensus, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof_try: Vec, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof_client: Vec, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof_consensus: Vec, // TODO: Make this type generic pub consensus_height: Height, } diff --git a/lib/unionlabs/src/ibc/core/connection/msg_connection_open_confirm.rs b/lib/unionlabs/src/ibc/core/connection/msg_connection_open_confirm.rs index 07364e5b48..6db4c37f49 100644 --- a/lib/unionlabs/src/ibc/core/connection/msg_connection_open_confirm.rs +++ b/lib/unionlabs/src/ibc/core/connection/msg_connection_open_confirm.rs @@ -1,15 +1,12 @@ use macros::model; -use serde::{Deserialize, Serialize}; -use crate::{ibc::core::client::height::IsHeight, id::ConnectionId}; +use crate::{ibc::core::client::height::Height, id::ConnectionId}; #[model(proto(raw(protos::ibc::core::connection::v1::MsgConnectionOpenConfirm)))] -#[serde(bound( - serialize = "ProofAck: Serialize", - deserialize = "ProofAck: for<'d> Deserialize<'d>" -))] -pub struct MsgConnectionOpenConfirm { +pub struct MsgConnectionOpenConfirm { pub connection_id: ConnectionId, - pub proof_ack: ProofAck, - pub proof_height: ProofHeight, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof_ack: Vec, + pub proof_height: Height, } diff --git a/lib/unionlabs/src/ibc/core/connection/msg_connection_open_init.rs b/lib/unionlabs/src/ibc/core/connection/msg_connection_open_init.rs index 2954636b93..328acc818d 100644 --- a/lib/unionlabs/src/ibc/core/connection/msg_connection_open_init.rs +++ b/lib/unionlabs/src/ibc/core/connection/msg_connection_open_init.rs @@ -1,26 +1,14 @@ use macros::model; -use serde::{Deserialize, Serialize}; use crate::{ ibc::core::connection::{counterparty::Counterparty, version::Version}, - traits::Id, - EmptyString, + id::ClientId, }; #[model(proto(raw(protos::ibc::core::connection::v1::MsgConnectionOpenInit)))] -#[serde(bound( - serialize = " - ClientId: Serialize, - CounterpartyClientId: Serialize, - ", - deserialize = " - ClientId: for<'d> Deserialize<'d>, - CounterpartyClientId: for<'d> Deserialize<'d>, - ", -))] -pub struct MsgConnectionOpenInit { +pub struct MsgConnectionOpenInit { pub client_id: ClientId, - pub counterparty: Counterparty, + pub counterparty: Counterparty, pub version: Version, pub delay_period: u64, } diff --git a/lib/unionlabs/src/ibc/core/connection/msg_connection_open_try.rs b/lib/unionlabs/src/ibc/core/connection/msg_connection_open_try.rs index 03796f30be..9ebd780233 100644 --- a/lib/unionlabs/src/ibc/core/connection/msg_connection_open_try.rs +++ b/lib/unionlabs/src/ibc/core/connection/msg_connection_open_try.rs @@ -1,52 +1,36 @@ use macros::model; -use serde::{Deserialize, Serialize}; use crate::{ ibc::core::{ - client::height::IsHeight, + client::height::Height, connection::{counterparty::Counterparty, version::Version}, }, - traits::Id, + id::ClientId, }; #[model(proto(raw(protos::ibc::core::connection::v1::MsgConnectionOpenTry)))] -#[serde(bound( - serialize = " - ClientId: Serialize, - CounterpartyClientId: Serialize, - ClientState: Serialize, - ProofInit: Serialize, - ProofClient: Serialize, - ProofConsensus: Serialize, - ", - deserialize = " - ClientId: for<'d> Deserialize<'d>, - CounterpartyClientId: for<'d> Deserialize<'d>, - ClientState: for<'d> Deserialize<'d>, - ProofInit: for<'d> Deserialize<'d>, - ProofClient: for<'d> Deserialize<'d>, - ProofConsensus: for<'d> Deserialize<'d>, - ", -))] -pub struct MsgConnectionOpenTry< - ClientState, - ClientId: Id, - CounterpartyClientId: Id, - CounterpartyConnectionId: Id, - ProofHeight: IsHeight, - ConsensusHeight: IsHeight, - ProofInit, - ProofClient, - ProofConsensus, -> { +pub struct MsgConnectionOpenTry { pub client_id: ClientId, - pub client_state: ClientState, - pub counterparty: Counterparty, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub client_state: Vec, + pub counterparty: Counterparty, pub delay_period: u64, pub counterparty_versions: Vec, - pub proof_height: ProofHeight, - pub proof_init: ProofInit, - pub proof_client: ProofClient, - pub proof_consensus: ProofConsensus, - pub consensus_height: ConsensusHeight, + pub proof_height: Height, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof_init: Vec, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof_client: Vec, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof_consensus: Vec, + /// The height the counterparty trusts of the chain this is being sent to. + /// + /// Given a connection handshake between A<->B, if the open try is being sent to B, then this is the trusted height of the B client on A. This is used in self client/consensus state verification, where chain B will construct the expected client/consensus states of itself and verify that it's client on A has stored them correctly. + /// + /// This is deprecated in IBC v9. + pub consensus_height: Height, } diff --git a/lib/unionlabs/src/ibc/core/connection/version.rs b/lib/unionlabs/src/ibc/core/connection/version.rs index 39799f4192..80de924371 100644 --- a/lib/unionlabs/src/ibc/core/connection/version.rs +++ b/lib/unionlabs/src/ibc/core/connection/version.rs @@ -6,6 +6,7 @@ use crate::{errors::UnknownEnumVariant, ibc::core::channel::order::Order}; #[cfg_attr(feature = "schemars", derive(::schemars::JsonSchema))] pub struct Version { // TODO(benluelo): "The identifier field specifies a unique version identifier. A value of "1" specifies IBC 1.0.0." + // TODO: Cow pub identifier: String, pub features: Vec, } diff --git a/lib/unionlabs/src/ibc/lightclients/berachain/client_state.rs b/lib/unionlabs/src/ibc/lightclients/berachain/client_state.rs index 56313038ea..aaf3ed71a2 100644 --- a/lib/unionlabs/src/ibc/lightclients/berachain/client_state.rs +++ b/lib/unionlabs/src/ibc/lightclients/berachain/client_state.rs @@ -13,7 +13,6 @@ use crate::{ core::client::height::Height, lightclients::tendermint::fraction::{Fraction, TryFromFractionError}, }, - traits::{self}, uint::U256, }; @@ -118,16 +117,3 @@ impl From for protos::union::ibc::lightclients::berachain::v1::Clie } } } - -impl traits::ClientState for ClientState { - type ChainId = U256; - type Height = Height; - - fn height(&self) -> Self::Height { - self.latest_height - } - - fn chain_id(&self) -> Self::ChainId { - self.execution_chain_id - } -} diff --git a/lib/unionlabs/src/ibc/lightclients/berachain/consensus_state.rs b/lib/unionlabs/src/ibc/lightclients/berachain/consensus_state.rs index f900c8a7e0..32830be36a 100644 --- a/lib/unionlabs/src/ibc/lightclients/berachain/consensus_state.rs +++ b/lib/unionlabs/src/ibc/lightclients/berachain/consensus_state.rs @@ -4,7 +4,6 @@ use crate::{ errors::{required, InvalidLength, MissingField}, google::protobuf::timestamp::{Timestamp, TryFromTimestampError}, hash::H256, - traits, }; #[model(proto( @@ -69,9 +68,3 @@ impl From for protos::union::ibc::lightclients::berachain::v1::C } } } - -impl traits::ConsensusState for ConsensusState { - fn timestamp(&self) -> u64 { - self.eth_timestamp - } -} diff --git a/lib/unionlabs/src/ibc/lightclients/berachain/header.rs b/lib/unionlabs/src/ibc/lightclients/berachain/header.rs index 0857fdc4d3..6bbe7a3af1 100644 --- a/lib/unionlabs/src/ibc/lightclients/berachain/header.rs +++ b/lib/unionlabs/src/ibc/lightclients/berachain/header.rs @@ -4,10 +4,7 @@ use crate::{ berachain::BerachainChainSpec, errors::{required, MissingField}, ibc::{ - core::{ - client::height::Height, - commitment::merkle_proof::{MerkleProof, TryFromMerkleProofError}, - }, + core::commitment::merkle_proof::{MerkleProof, TryFromMerkleProofError}, lightclients::{ ethereum::{ account_proof::{AccountProof, TryFromAccountProofError}, @@ -18,7 +15,6 @@ use crate::{ tendermint, }, }, - traits, }; #[model(proto( @@ -33,16 +29,6 @@ pub struct Header { pub account_proof: AccountProof, } -impl traits::Header for Header { - fn trusted_height(&self) -> Height { - Height { - // TODO: Change to `ETHEREUM_REVISION_NUMBER` once that has been moved into this crate - revision_number: 0, - revision_height: self.execution_header.block_number, - } - } -} - impl From
for protos::union::ibc::lightclients::berachain::v1::Header { fn from(value: Header) -> Self { Self { diff --git a/lib/unionlabs/src/ibc/lightclients/cometbls/light_header.rs b/lib/unionlabs/src/ibc/lightclients/cometbls/light_header.rs index 71905dde5d..5f4a3c67ff 100644 --- a/lib/unionlabs/src/ibc/lightclients/cometbls/light_header.rs +++ b/lib/unionlabs/src/ibc/lightclients/cometbls/light_header.rs @@ -7,7 +7,6 @@ use crate::{ errors::{required, InvalidLength, MissingField}, google::protobuf::timestamp::{Timestamp, TryFromTimestampError}, hash::H256, - tendermint::types::signed_header::SignedHeader, }; #[model( @@ -43,18 +42,6 @@ impl From for protos::union::ibc::lightclients::cometbls::v1::Light } } -impl From for LightHeader { - fn from(value: SignedHeader) -> Self { - Self { - height: value.header.height, - time: value.header.time, - validators_hash: value.header.validators_hash, - next_validators_hash: value.header.next_validators_hash, - app_hash: value.header.app_hash, - } - } -} - #[derive(Debug, Clone, PartialEq, thiserror::Error)] pub enum TryFromLightHeaderError { #[error(transparent)] diff --git a/lib/unionlabs/src/ibc/lightclients/ethereum/account_proof.rs b/lib/unionlabs/src/ibc/lightclients/ethereum/account_proof.rs index f015390101..0d464b4d15 100644 --- a/lib/unionlabs/src/ibc/lightclients/ethereum/account_proof.rs +++ b/lib/unionlabs/src/ibc/lightclients/ethereum/account_proof.rs @@ -16,9 +16,9 @@ pub struct AccountProof { #[derive(Debug, PartialEq, Clone, thiserror::Error)] pub enum TryFromAccountProofError { - #[error("invalid contract address")] + #[error("invalid `contract_address`")] ContractAddress(#[source] InvalidLength), - #[error("invalid storage root")] + #[error("invalid `storage_root`")] StorageRoot(#[source] InvalidLength), } diff --git a/lib/unionlabs/src/ibc/lightclients/ethereum/account_update.rs b/lib/unionlabs/src/ibc/lightclients/ethereum/account_update.rs index 5a19057f70..cfd39ecb5e 100644 --- a/lib/unionlabs/src/ibc/lightclients/ethereum/account_update.rs +++ b/lib/unionlabs/src/ibc/lightclients/ethereum/account_update.rs @@ -22,10 +22,12 @@ impl From for protos::union::ibc::lightclients::ethereum::v1::Acc } } -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, thiserror::Error)] pub enum TryFromAccountUpdateError { + #[error(transparent)] MissingField(MissingField), - AccountProof(TryFromAccountProofError), + #[error("invalid `account_proof`")] + AccountProof(#[from] TryFromAccountProofError), } impl TryFrom for AccountUpdate { @@ -35,9 +37,7 @@ impl TryFrom for value: protos::union::ibc::lightclients::ethereum::v1::AccountUpdate, ) -> Result { Ok(Self { - account_proof: required!(value.account_proof)? - .try_into() - .map_err(TryFromAccountUpdateError::AccountProof)?, + account_proof: required!(value.account_proof)?.try_into()?, }) } } diff --git a/lib/unionlabs/src/ibc/lightclients/ethereum/beacon_block_header.rs b/lib/unionlabs/src/ibc/lightclients/ethereum/beacon_block_header.rs index 4d66c63a48..1c031e7fb1 100644 --- a/lib/unionlabs/src/ibc/lightclients/ethereum/beacon_block_header.rs +++ b/lib/unionlabs/src/ibc/lightclients/ethereum/beacon_block_header.rs @@ -48,11 +48,14 @@ impl From for protos::union::ibc::lightclients::ethereum::v1: } } -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, thiserror::Error)] pub enum TryFromBeaconBlockHeaderError { - ParentRoot(InvalidLength), - StateRoot(InvalidLength), - BodyRoot(InvalidLength), + #[error("invalid `parent_root`")] + ParentRoot(#[source] InvalidLength), + #[error("invalid `state_root`")] + StateRoot(#[source] InvalidLength), + #[error("invalid `body_root`")] + BodyRoot(#[source] InvalidLength), } impl TryFrom diff --git a/lib/unionlabs/src/ibc/lightclients/ethereum/execution_payload_header.rs b/lib/unionlabs/src/ibc/lightclients/ethereum/execution_payload_header.rs index 1664e1bf4a..fb38dbfcc0 100644 --- a/lib/unionlabs/src/ibc/lightclients/ethereum/execution_payload_header.rs +++ b/lib/unionlabs/src/ibc/lightclients/ethereum/execution_payload_header.rs @@ -12,13 +12,8 @@ use crate::{ uint::U256, }; -#[derive(Ssz)] #[model] -// #[model(proto( -// raw(protos::union::ibc::lightclients::ethereum::v1::ExecutionPayloadHeader), -// into, -// from -// ))] +#[derive(Ssz)] pub struct CapellaExecutionPayloadHeader { pub parent_hash: H256, pub fee_recipient: H160, @@ -71,7 +66,11 @@ impl From { @@ -92,7 +91,7 @@ pub struct ExecutionPayloadHeader, pub base_fee_per_gas: U256, pub block_hash: H256, @@ -155,32 +154,6 @@ impl From TryFrom for ExecutionPayloadHeader @@ -246,3 +219,93 @@ impl }) } } + +#[derive(Debug, PartialEq, Clone, thiserror::Error)] +pub enum TryFromExecutionPayloadHeaderError { + #[error("invalid parent hash")] + ParentHash(#[source] InvalidLength), + #[error("invalid fee recipient")] + FeeRecipient(#[source] InvalidLength), + #[error("invalid state root")] + StateRoot(#[source] InvalidLength), + #[error("invalid receipts root")] + ReceiptsRoot(#[source] InvalidLength), + #[error("invalid logs bloom")] + LogsBloom(#[source] InvalidLength), + #[error("invalid prev randao")] + PrevRandao(#[source] InvalidLength), + #[error("invalid extra data")] + ExtraData(#[source] InvalidLength), + #[error("invalid base fee per gas")] + BaseFeePerGas(#[source] InvalidLength), + #[error("invalid block hash")] + BlockHash(#[source] InvalidLength), + #[error("invalid transactions root")] + TransactionsRoot(#[source] InvalidLength), + #[error("invalid withdrawals root")] + WithdrawalsRoot(#[source] InvalidLength), +} + +#[model(proto( + raw(protos::union::ibc::lightclients::ethereum::v1::ExecutionPayloadHeader), + from +))] +pub struct UnboundedExecutionPayloadHeader { + pub parent_hash: H256, + pub fee_recipient: H160, + pub state_root: H256, + pub receipts_root: H256, + #[serde(with = "::serde_utils::hex_string")] + #[debug("{}", serde_utils::to_hex(&logs_bloom))] + pub logs_bloom: Vec, + pub prev_randao: H256, + #[serde(with = "::serde_utils::string")] + pub block_number: u64, + #[serde(with = "::serde_utils::string")] + pub gas_limit: u64, + #[serde(with = "::serde_utils::string")] + pub gas_used: u64, + #[serde(with = "::serde_utils::string")] + pub timestamp: u64, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub extra_data: Vec, + pub base_fee_per_gas: U256, + pub block_hash: H256, + #[serde(default)] + pub transactions_root: H256, + #[serde(default)] + pub withdrawals_root: H256, + // blob_gas_used: uint64 # [New in Deneb:EIP4844] + #[serde(default, with = "::serde_utils::string")] + pub blob_gas_used: u64, + // excess_blob_gas: uint64 # [New in Deneb:EIP4844] + #[serde(default, with = "::serde_utils::string")] + pub excess_blob_gas: u64, +} + +impl From + for protos::union::ibc::lightclients::ethereum::v1::ExecutionPayloadHeader +{ + fn from(value: UnboundedExecutionPayloadHeader) -> Self { + Self { + parent_hash: value.parent_hash.into(), + fee_recipient: value.fee_recipient.into(), + state_root: value.state_root.into(), + receipts_root: value.receipts_root.into(), + logs_bloom: value.logs_bloom, + prev_randao: value.prev_randao.into(), + block_number: value.block_number, + gas_limit: value.gas_limit, + gas_used: value.gas_used, + timestamp: value.timestamp, + extra_data: value.extra_data, + base_fee_per_gas: value.base_fee_per_gas.to_be_bytes().into(), + block_hash: value.block_hash.into(), + transactions_root: value.transactions_root.into(), + withdrawals_root: value.withdrawals_root.into(), + blob_gas_used: value.blob_gas_used, + excess_blob_gas: value.excess_blob_gas, + } + } +} diff --git a/lib/unionlabs/src/ibc/lightclients/ethereum/header.rs b/lib/unionlabs/src/ibc/lightclients/ethereum/header.rs index 0d2ac58a12..cb96fdb63f 100644 --- a/lib/unionlabs/src/ibc/lightclients/ethereum/header.rs +++ b/lib/unionlabs/src/ibc/lightclients/ethereum/header.rs @@ -5,8 +5,12 @@ use crate::{ ethereum::config::{BYTES_PER_LOGS_BLOOM, MAX_EXTRA_DATA_BYTES, SYNC_COMMITTEE_SIZE}, ibc::lightclients::ethereum::{ account_update::{AccountUpdate, TryFromAccountUpdateError}, - light_client_update::{LightClientUpdate, TryFromLightClientUpdateError}, - trusted_sync_committee::{TrustedSyncCommittee, TryFromTrustedSyncCommitteeError}, + light_client_update::{ + LightClientUpdate, TryFromLightClientUpdateError, UnboundedLightClientUpdate, + }, + trusted_sync_committee::{ + TrustedSyncCommittee, TryFromTrustedSyncCommitteeError, UnboundedTrustedSyncCommittee, + }, }, }; @@ -34,12 +38,16 @@ impl From< } } -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, thiserror::Error)] pub enum TryFromHeaderError { + #[error(transparent)] MissingField(MissingField), - TrustedSyncCommittee(TryFromTrustedSyncCommitteeError), - ConsensusUpdate(TryFromLightClientUpdateError), - AccountUpdate(TryFromAccountUpdateError), + #[error("invalid `trusted_sync_committee`")] + TrustedSyncCommittee(#[from] TryFromTrustedSyncCommitteeError), + #[error("invalid `consensus_update`")] + ConsensusUpdate(#[from] TryFromLightClientUpdateError), + #[error("invalid `account_update`")] + AccountUpdate(#[from] TryFromAccountUpdateError), } impl @@ -63,3 +71,20 @@ impl }) } } + +#[model(proto(raw(protos::union::ibc::lightclients::ethereum::v1::Header), from))] +pub struct UnboundedHeader { + pub trusted_sync_committee: UnboundedTrustedSyncCommittee, + pub consensus_update: UnboundedLightClientUpdate, + pub account_update: AccountUpdate, +} + +impl From for protos::union::ibc::lightclients::ethereum::v1::Header { + fn from(value: UnboundedHeader) -> Self { + Self { + trusted_sync_committee: Some(value.trusted_sync_committee.into()), + consensus_update: Some(value.consensus_update.into()), + account_update: Some(value.account_update.into()), + } + } +} diff --git a/lib/unionlabs/src/ibc/lightclients/ethereum/light_client_header.rs b/lib/unionlabs/src/ibc/lightclients/ethereum/light_client_header.rs index f96f019f73..fd38370251 100644 --- a/lib/unionlabs/src/ibc/lightclients/ethereum/light_client_header.rs +++ b/lib/unionlabs/src/ibc/lightclients/ethereum/light_client_header.rs @@ -11,16 +11,19 @@ use crate::{ hash::H256, ibc::lightclients::ethereum::{ beacon_block_header::{BeaconBlockHeader, TryFromBeaconBlockHeaderError}, - execution_payload_header::{ExecutionPayloadHeader, TryFromExecutionPayloadHeaderError}, + execution_payload_header::{ + ExecutionPayloadHeader, TryFromExecutionPayloadHeaderError, + UnboundedExecutionPayloadHeader, + }, }, }; -#[derive(Ssz)] #[model(proto( raw(protos::union::ibc::lightclients::ethereum::v1::LightClientHeader), into, from ))] +#[derive(Ssz)] #[serde(bound(serialize = "", deserialize = ""))] pub struct LightClientHeader { pub beacon: BeaconBlockHeader, @@ -43,13 +46,18 @@ impl From> } } -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, thiserror::Error)] pub enum TryFromLightClientHeaderError { + #[error(transparent)] MissingField(MissingField), - BeaconBlockHeader(TryFromBeaconBlockHeaderError), - ExecutionPayloadHeader(TryFromExecutionPayloadHeaderError), - ExecutionBranch(InvalidLength), - ExecutionBranchNode(InvalidLength), + #[error("invalid `beacon_block_header`")] + BeaconBlockHeader(#[from] TryFromBeaconBlockHeaderError), + #[error("invalid `execution_payload_header`")] + ExecutionPayloadHeader(#[from] TryFromExecutionPayloadHeaderError), + #[error("invalid `execution_branch`")] + ExecutionBranch(#[source] InvalidLength), + #[error("invalid `execution_branch_node`")] + ExecutionBranchNode(#[source] InvalidLength), } impl @@ -92,3 +100,28 @@ impl }) } } + +#[model(proto( + raw(protos::union::ibc::lightclients::ethereum::v1::LightClientHeader), + from +))] +pub struct UnboundedLightClientHeader { + pub beacon: BeaconBlockHeader, + pub execution: UnboundedExecutionPayloadHeader, + pub execution_branch: [H256; floorlog2(EXECUTION_PAYLOAD_INDEX)], +} + +impl From + for protos::union::ibc::lightclients::ethereum::v1::LightClientHeader +{ + fn from(value: UnboundedLightClientHeader) -> Self { + Self { + beacon: Some(value.beacon.into()), + execution: Some(value.execution.into()), + execution_branch: Vec::from(value.execution_branch) + .into_iter() + .map(H256::into_bytes) + .collect(), + } + } +} diff --git a/lib/unionlabs/src/ibc/lightclients/ethereum/light_client_update.rs b/lib/unionlabs/src/ibc/lightclients/ethereum/light_client_update.rs index f1b07bfce7..965eddfd27 100644 --- a/lib/unionlabs/src/ibc/lightclients/ethereum/light_client_update.rs +++ b/lib/unionlabs/src/ibc/lightclients/ethereum/light_client_update.rs @@ -10,9 +10,11 @@ use crate::{ }, hash::H256, ibc::lightclients::ethereum::{ - light_client_header::{LightClientHeader, TryFromLightClientHeaderError}, - sync_aggregate::{SyncAggregate, TryFromSyncAggregateError}, - sync_committee::{SyncCommittee, TryFromSyncCommitteeError}, + light_client_header::{ + LightClientHeader, TryFromLightClientHeaderError, UnboundedLightClientHeader, + }, + sync_aggregate::{SyncAggregate, TryFromSyncAggregateError, UnboundedSyncAggregate}, + sync_committee::{SyncCommittee, TryFromSyncCommitteeError, UnboundedSyncCommittee}, }, }; @@ -74,15 +76,22 @@ impl } } -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, thiserror::Error)] pub enum TryFromLightClientUpdateError { + #[error(transparent)] MissingField(MissingField), - AttestedHeader(TryFromLightClientHeaderError), - NextSyncCommittee(TryFromSyncCommitteeError), - NextSyncCommitteeBranch(TryFromBranchError), - FinalityBranch(TryFromBranchError), - SyncAggregate(TryFromSyncAggregateError), - FinalizedHeader(TryFromLightClientHeaderError), + #[error("invalid `attested_header`")] + AttestedHeader(#[source] TryFromLightClientHeaderError), + #[error("invalid `next_sync_committee`")] + NextSyncCommittee(#[from] TryFromSyncCommitteeError), + #[error("invalid `next_sync_committee_branch`")] + NextSyncCommitteeBranch(#[from] TryFromBranchError), + #[error("invalid `finality_branch`")] + FinalityBranch(#[from] TryFromBranchError), + #[error("invalid `sync_aggregate`")] + SyncAggregate(#[from] TryFromSyncAggregateError), + #[error("invalid `finalized_header`")] + FinalizedHeader(#[source] TryFromLightClientHeaderError), } impl @@ -138,11 +147,64 @@ where } // TODO: Remove the bounds on T::Error and only require said bounds when implementing the respective traits, will clean up try_from_proto_branch as well -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, thiserror::Error)] pub enum TryFromBranchError where T: TryFrom, Error: Debug + PartialEq + Eq + Clone>, { + #[error("error decoding branch: {0:?}")] Branch(>>::Error), - BranchNode(InvalidLength), + #[error("error decoding branch node")] + BranchNode(#[source] InvalidLength), +} + +#[model(proto( + raw(protos::union::ibc::lightclients::ethereum::v1::LightClientUpdate), + from +))] +pub struct UnboundedLightClientUpdate { + /// Header attested to by the sync committee + pub attested_header: UnboundedLightClientHeader, + /// Next sync committee corresponding to `attested_header.state_root` + // NOTE: These fields aren't actually optional, they are just because of the current structure of the ethereum Header. + // TODO: Remove the Option and improve ethereum::header::Header to be an enum, instead of using optional fields and bools. + #[serde(default)] + pub next_sync_committee: Option, + #[serde(default)] + pub next_sync_committee_branch: Option, + /// Finalized header corresponding to `attested_header.state_root` + pub finalized_header: UnboundedLightClientHeader, + pub finality_branch: FinalityBranch, + /// Sync committee aggregate signature + pub sync_aggregate: UnboundedSyncAggregate, + /// Slot at which the aggregate signature was created (untrusted) + #[serde(with = "::serde_utils::string")] + pub signature_slot: u64, +} + +impl From + for protos::union::ibc::lightclients::ethereum::v1::LightClientUpdate +{ + fn from(value: UnboundedLightClientUpdate) -> Self { + Self { + attested_header: Some(value.attested_header.into()), + next_sync_committee: value.next_sync_committee.map(Into::into), + next_sync_committee_branch: value + .next_sync_committee_branch + .unwrap_or_default() + .iter() + .copied() + .map(H256::into_bytes) + .collect(), + finalized_header: Some(value.finalized_header.into()), + finality_branch: value + .finality_branch + .iter() + .copied() + .map(H256::into_bytes) + .collect(), + sync_aggregate: Some(value.sync_aggregate.into()), + signature_slot: value.signature_slot, + } + } } diff --git a/lib/unionlabs/src/ibc/lightclients/ethereum/sync_aggregate.rs b/lib/unionlabs/src/ibc/lightclients/ethereum/sync_aggregate.rs index d75ea324d4..dc7d788787 100644 --- a/lib/unionlabs/src/ibc/lightclients/ethereum/sync_aggregate.rs +++ b/lib/unionlabs/src/ibc/lightclients/ethereum/sync_aggregate.rs @@ -3,12 +3,12 @@ use ssz::{types::BitVector, Ssz}; use crate::{bls::BlsSignature, errors::InvalidLength, ethereum::config::SYNC_COMMITTEE_SIZE}; -#[derive(Ssz)] #[model(proto( raw(protos::union::ibc::lightclients::ethereum::v1::SyncAggregate), into, from ))] +#[derive(Ssz)] #[serde(bound(serialize = "", deserialize = ""))] pub struct SyncAggregate { // TODO: Change debug print for this type in ssz::types @@ -17,17 +17,6 @@ pub struct SyncAggregate { pub sync_committee_signature: BlsSignature, } -// pub fn bit_vector_debug( -// bv: &BitVector, -// f: &mut fmt::Formatter, -// ) -> fmt::Result { -// for b in bv.iter() { -// write!(f, "BitVector({})", if b { '1' } else { '0' })?; -// } - -// Ok(()) -// } - impl From> for protos::union::ibc::lightclients::ethereum::v1::SyncAggregate { @@ -39,10 +28,12 @@ impl From> } } -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, thiserror::Error)] pub enum TryFromSyncAggregateError { - Bits(ssz::types::bitfield::BitlistFromBytesError), - Signature(InvalidLength), + #[error("invalid `sync_committee_bits`")] + SyncCommitteeBits(#[from] ssz::types::bitfield::BitlistFromBytesError), + #[error("invalid `sync_committee_signature`")] + SyncCommitteeSignature(#[from] InvalidLength), } impl TryFrom @@ -56,11 +47,32 @@ impl TryFrom, + pub sync_committee_signature: BlsSignature, +} + +impl From + for protos::union::ibc::lightclients::ethereum::v1::SyncAggregate +{ + fn from(value: UnboundedSyncAggregate) -> Self { + Self { + sync_committee_bits: value.sync_committee_bits, + sync_committee_signature: value.sync_committee_signature.into_bytes().into(), + } + } +} diff --git a/lib/unionlabs/src/ibc/lightclients/ethereum/sync_committee.rs b/lib/unionlabs/src/ibc/lightclients/ethereum/sync_committee.rs index 03305b72e0..e218d90ef3 100644 --- a/lib/unionlabs/src/ibc/lightclients/ethereum/sync_committee.rs +++ b/lib/unionlabs/src/ibc/lightclients/ethereum/sync_committee.rs @@ -4,12 +4,12 @@ use typenum::Unsigned; use crate::{bls::BlsPublicKey, errors::InvalidLength, ethereum::config::SYNC_COMMITTEE_SIZE}; -#[derive(Ssz)] #[model(proto( raw(protos::union::ibc::lightclients::ethereum::v1::SyncCommittee), into, from ))] +#[derive(Ssz)] #[serde(bound(serialize = "", deserialize = ""))] pub struct SyncCommittee { #[serde(with = "::serde_utils::hex_string_list")] @@ -29,14 +29,14 @@ impl From> } } -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, thiserror::Error)] pub enum TryFromSyncCommitteeError { - /// One of the `pubkeys` had an invalid length - PubKey(InvalidLength), - /// Invalid amount of `pubkeys` - PubKeys(InvalidLength), - /// The `aggregate_pubkey` had an invalid length - AggregatePubKey(InvalidLength), + #[error("invalid `pubkeys`")] + PubKey(#[source] InvalidLength), + #[error("invalid amount of `pubkeys`")] + PubKeys(#[source] InvalidLength), + #[error("invalid `aggregate_pubkey`")] + AggregatePubKey(#[source] InvalidLength), } impl TryFrom @@ -71,3 +71,25 @@ impl TryFrom, + #[serde(with = "::serde_utils::hex_string")] + pub aggregate_pubkey: BlsPublicKey, +} + +impl From + for protos::union::ibc::lightclients::ethereum::v1::SyncCommittee +{ + fn from(value: UnboundedSyncCommittee) -> Self { + Self { + pubkeys: value.pubkeys.iter().copied().map(Into::into).collect(), + aggregate_pubkey: value.aggregate_pubkey.into(), + } + } +} diff --git a/lib/unionlabs/src/ibc/lightclients/ethereum/trusted_sync_committee.rs b/lib/unionlabs/src/ibc/lightclients/ethereum/trusted_sync_committee.rs index bed0083b6c..123556d873 100644 --- a/lib/unionlabs/src/ibc/lightclients/ethereum/trusted_sync_committee.rs +++ b/lib/unionlabs/src/ibc/lightclients/ethereum/trusted_sync_committee.rs @@ -6,7 +6,9 @@ use crate::{ ethereum::config::SYNC_COMMITTEE_SIZE, ibc::{ core::client::height::Height, - lightclients::ethereum::sync_committee::{SyncCommittee, TryFromSyncCommitteeError}, + lightclients::ethereum::sync_committee::{ + SyncCommittee, TryFromSyncCommitteeError, UnboundedSyncCommittee, + }, }, }; @@ -43,12 +45,12 @@ impl ActiveSyncCommittee { } } -#[derive(Ssz)] #[model(proto( raw(protos::union::ibc::lightclients::ethereum::v1::TrustedSyncCommittee), into, from ))] +#[derive(Ssz)] #[serde(bound(serialize = "", deserialize = ""))] pub struct TrustedSyncCommittee { pub trusted_height: Height, @@ -74,9 +76,11 @@ impl From> } } -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, thiserror::Error)] pub enum TryFromTrustedSyncCommitteeError { + #[error(transparent)] MissingField(MissingField), + #[error("invalid sync committee")] SyncCommittee(TryFromSyncCommitteeError), } @@ -111,3 +115,37 @@ impl }) } } + +#[model(proto( + raw(protos::union::ibc::lightclients::ethereum::v1::TrustedSyncCommittee), + from +))] +pub struct UnboundedTrustedSyncCommittee { + pub trusted_height: Height, + pub sync_committee: UnboundedActiveSyncCommittee, +} + +#[model] +pub enum UnboundedActiveSyncCommittee { + Current(UnboundedSyncCommittee), + Next(UnboundedSyncCommittee), +} + +impl From + for protos::union::ibc::lightclients::ethereum::v1::TrustedSyncCommittee +{ + fn from(value: UnboundedTrustedSyncCommittee) -> Self { + match value.sync_committee { + UnboundedActiveSyncCommittee::Current(committee) => Self { + trusted_height: Some(value.trusted_height.into()), + current_sync_committee: Some(committee.into()), + next_sync_committee: None, + }, + UnboundedActiveSyncCommittee::Next(committee) => Self { + trusted_height: Some(value.trusted_height.into()), + current_sync_committee: None, + next_sync_committee: Some(committee.into()), + }, + } + } +} diff --git a/lib/unionlabs/src/ibc/lightclients/movement/client_state.rs b/lib/unionlabs/src/ibc/lightclients/movement/client_state.rs index e7fcce4f60..c95d7554fc 100644 --- a/lib/unionlabs/src/ibc/lightclients/movement/client_state.rs +++ b/lib/unionlabs/src/ibc/lightclients/movement/client_state.rs @@ -3,11 +3,8 @@ use core::str::FromStr; use macros::model; use crate::{ - aptos::account::AccountAddress, - errors::{ExpectedLength, InvalidLength}, - hash::H160, - ibc::core::client::height::Height, - id::ClientId, + aptos::account::AccountAddress, errors::InvalidLength, hash::H160, + ibc::core::client::height::Height, id::ClientId, }; #[model(proto( @@ -31,7 +28,7 @@ impl From for protos::union::ibc::lightclients::movement::v1::Clien l1_client_id: value.l1_client_id.to_string(), l1_contract_address: value.l1_contract_address.into(), l2_contract_address: value.l2_contract_address.into(), - table_handle: value.table_handle.0.to_vec(), + table_handle: value.table_handle.0 .0.to_vec(), frozen_height: Some(value.frozen_height.into()), latest_block_num: value.latest_block_num, } @@ -67,14 +64,13 @@ impl TryFrom for Cl .l2_contract_address .try_into() .map_err(TryFromClientStateError::L2ContractAddress)?, - table_handle: AccountAddress::new(value.table_handle.as_slice().try_into().map_err( - |_| { - TryFromClientStateError::TableHandle(InvalidLength { - expected: ExpectedLength::Exact(AccountAddress::LENGTH), - found: value.table_handle.len(), - }) - }, - )?), + table_handle: AccountAddress( + value + .table_handle + .as_slice() + .try_into() + .map_err(TryFromClientStateError::TableHandle)?, + ), frozen_height: value.frozen_height.unwrap_or_default().into(), latest_block_num: value.latest_block_num, }) diff --git a/lib/unionlabs/src/ibc/lightclients/movement/consensus_state.rs b/lib/unionlabs/src/ibc/lightclients/movement/consensus_state.rs index 8b52c43619..02a9358c7c 100644 --- a/lib/unionlabs/src/ibc/lightclients/movement/consensus_state.rs +++ b/lib/unionlabs/src/ibc/lightclients/movement/consensus_state.rs @@ -1,6 +1,6 @@ use macros::model; -use crate::{aptos::hash_value::HashValue, errors::InvalidLength, hash::H256}; +use crate::{errors::InvalidLength, hash::H256}; #[model(proto( raw(protos::union::ibc::lightclients::movement::v1::ConsensusState), @@ -8,7 +8,7 @@ use crate::{aptos::hash_value::HashValue, errors::InvalidLength, hash::H256}; from ))] pub struct ConsensusState { - pub state_root: HashValue, + pub state_root: H256, pub timestamp: u64, /// This is the hash of the `StateProof` which is committed to l1 pub state_proof_hash: H256, diff --git a/lib/unionlabs/src/ibc/lightclients/wasm/client_message.rs b/lib/unionlabs/src/ibc/lightclients/wasm/client_message.rs index 116e953960..aad98a7915 100644 --- a/lib/unionlabs/src/ibc/lightclients/wasm/client_message.rs +++ b/lib/unionlabs/src/ibc/lightclients/wasm/client_message.rs @@ -1,3 +1,4 @@ +use frame_support_procedural::DebugNoBound; use macros::model; use crate::encoding::{Decode, DecodeErrorOf, Encode, Proto}; @@ -22,9 +23,10 @@ impl> From> } } -#[derive(Debug)] +#[derive(DebugNoBound, thiserror::Error)] pub enum TryFromClientMessageError> { - Data(DecodeErrorOf), + #[error("error decoding `data`")] + Data(#[source] DecodeErrorOf), } impl> TryFrom diff --git a/lib/unionlabs/src/ics24.rs b/lib/unionlabs/src/ics24.rs index 2e38f3481e..07154aab8e 100644 --- a/lib/unionlabs/src/ics24.rs +++ b/lib/unionlabs/src/ics24.rs @@ -1,55 +1,32 @@ use core::{fmt::Display, num::NonZeroU64, str::FromStr}; -use macros::ibc_path; +use macros::{ibc_path, model}; use serde::{Deserialize, Serialize}; +use serde_utils::Hex; use crate::{ hash::H256, ibc::core::{ - channel::channel::Channel, client::height::IsHeight, + channel::channel::Channel, client::height::Height, connection::connection_end::ConnectionEnd, }, - id::{ChannelId, ConnectionId, PortId}, - traits::{self, Chain, ClientIdOf, HeightOf, Member}, + id::{ChannelId, ClientId, ConnectionId, PortId}, + traits::Member, }; /// `IbcPath` represents the path to a light client's ibc storage. The values stored at each path /// are strongly typed, i.e. `connections/{connection_id}` always stores a [`ConnectionEnd`]. -pub trait IbcPath: - Member - + Display - + TryFrom, HeightOf>, Error = Path, HeightOf>> - + Into, HeightOf>> -{ +pub trait IbcPath: Member + Display + TryFrom + Into { type Value: Member; } -#[derive( - Debug, - Clone, - PartialEq, - Serialize, - Deserialize, - derive_more::Display, - clap::Subcommand, - enumorph::Enumorph, -)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[serde( - bound( - serialize = "ClientId: Serialize", - deserialize = "ClientId: for<'d> Deserialize<'d>", - ), - tag = "@type", - content = "@value", - rename_all = "snake_case", - deny_unknown_fields -)] -pub enum Path { +#[model] +#[derive(Hash, derive_more::Display, clap::Subcommand, enumorph::Enumorph)] +pub enum Path { #[display(fmt = "{_0}")] - ClientState(ClientStatePath), + ClientState(ClientStatePath), #[display(fmt = "{_0}")] - ClientConsensusState(ClientConsensusStatePath), + ClientConsensusState(ClientConsensusStatePath), #[display(fmt = "{_0}")] Connection(ConnectionPath), #[display(fmt = "{_0}")] @@ -72,7 +49,7 @@ pub enum Path { NextClientSequence(NextClientSequencePath), } -impl FromStr for Path { +impl FromStr for Path { type Err = PathParseError; fn from_str(s: &str) -> Result { @@ -91,121 +68,89 @@ impl FromStr for Path } } -#[ibc_path("clients/{client_id}/clientState")] -pub struct ClientStatePath { +/// The raw client state bytes as encoded by the light client. +#[ibc_path("clients/{client_id}/clientState", Hex>)] +pub struct ClientStatePath { pub client_id: ClientId, } -impl IbcPath for ClientStatePath { - type Value = Hc::StoredClientState; -} - -#[ibc_path("clients/{client_id}/consensusStates/{height}")] -pub struct ClientConsensusStatePath { +/// The raw consensus state bytes as encoded by the light client. +#[ibc_path("clients/{client_id}/consensusStates/{height}", Hex>)] +pub struct ClientConsensusStatePath { pub client_id: ClientId, pub height: Height, } -impl IbcPath for ClientConsensusStatePath { - type Value = Hc::StoredConsensusState; -} - -#[ibc_path("connections/{connection_id}")] +// REVIEW: Make this an `Option`? +#[ibc_path("connections/{connection_id}", Option)] pub struct ConnectionPath { pub connection_id: ConnectionId, } -impl IbcPath for ConnectionPath { - type Value = ConnectionEnd; -} - -#[ibc_path("channelEnds/ports/{port_id}/channels/{channel_id}")] +// REVIEW: Make this an `Option`? +#[ibc_path( + "channelEnds/ports/{port_id}/channels/{channel_id}", + Option +)] pub struct ChannelEndPath { pub port_id: PortId, pub channel_id: ChannelId, } -impl IbcPath for ChannelEndPath { - type Value = Channel; -} - -#[ibc_path("commitments/ports/{port_id}/channels/{channel_id}/sequences/{sequence}")] +#[ibc_path( + "commitments/ports/{port_id}/channels/{channel_id}/sequences/{sequence}", + Option +)] pub struct CommitmentPath { pub port_id: PortId, pub channel_id: ChannelId, pub sequence: NonZeroU64, } -impl IbcPath for CommitmentPath { - type Value = H256; -} - -#[ibc_path("acks/ports/{port_id}/channels/{channel_id}/sequences/{sequence}")] +/// SHA-256 of the packet acknowledgement. +/// If the packet has not yet been acknowledged (either because the packet does not exist or the packet has not been acknowledged yet), then the acknowledgement commitment is unset. +#[ibc_path("acks/ports/{port_id}/channels/{channel_id}/sequences/{sequence}", Option)] pub struct AcknowledgementPath { pub port_id: PortId, pub channel_id: ChannelId, pub sequence: NonZeroU64, } -impl IbcPath for AcknowledgementPath { - type Value = H256; -} - -#[ibc_path("receipts/ports/{port_id}/channels/{channel_id}/sequences/{sequence}")] +/// This defaults to `false` for packets which have not yet been received. +#[ibc_path( + "receipts/ports/{port_id}/channels/{channel_id}/sequences/{sequence}", + bool +)] pub struct ReceiptPath { pub port_id: PortId, pub channel_id: ChannelId, pub sequence: NonZeroU64, } -impl IbcPath for ReceiptPath { - type Value = bool; -} - -#[ibc_path("nextSequenceSend/ports/{port_id}/channels/{channel_id}")] +#[ibc_path("nextSequenceSend/ports/{port_id}/channels/{channel_id}", u64)] pub struct NextSequenceSendPath { pub port_id: PortId, pub channel_id: ChannelId, } -impl IbcPath for NextSequenceSendPath { - type Value = u64; -} - -#[ibc_path("nextSequenceRecv/ports/{port_id}/channels/{channel_id}")] +#[ibc_path("nextSequenceRecv/ports/{port_id}/channels/{channel_id}", u64)] pub struct NextSequenceRecvPath { pub port_id: PortId, pub channel_id: ChannelId, } -impl IbcPath for NextSequenceRecvPath { - type Value = u64; -} - -#[ibc_path("nextSequenceAck/ports/{port_id}/channels/{channel_id}")] +#[ibc_path("nextSequenceAck/ports/{port_id}/channels/{channel_id}", u64)] pub struct NextSequenceAckPath { pub port_id: PortId, pub channel_id: ChannelId, } -impl IbcPath for NextSequenceAckPath { - type Value = u64; -} - -#[ibc_path("nextConnectionSequence")] +#[ibc_path("nextConnectionSequence", u64)] pub struct NextConnectionSequencePath {} -impl IbcPath for NextConnectionSequencePath { - type Value = u64; -} - -#[ibc_path("nextClientSequence")] +#[ibc_path("nextClientSequence", u64)] pub struct NextClientSequencePath {} -impl IbcPath for NextClientSequencePath { - type Value = u64; -} - #[derive(Debug, Clone, PartialEq, thiserror::Error)] pub enum PathParseError { #[error("invalid static segment, expected `{expected}` but found `{found}`")] @@ -232,19 +177,18 @@ mod tests { #[test] fn parse_ibc_paths_from_str() { - type PathT = Path; assert_eq!( - "clients/08-wasm-0/clientState".parse::().unwrap(), + "clients/08-wasm-0/clientState".parse::().unwrap(), Path::ClientState(ClientStatePath { - client_id: "08-wasm-0".to_string() + client_id: "08-wasm-0".to_string().validate().unwrap() }) ); assert_eq!( "clients/08-wasm-0/consensusStates/0-1" - .parse::() + .parse::() .unwrap(), Path::ClientConsensusState(ClientConsensusStatePath { - client_id: "08-wasm-0".to_string(), + client_id: "08-wasm-0".to_string().validate().unwrap(), height: Height { revision_number: 0, revision_height: 1 @@ -252,14 +196,14 @@ mod tests { }) ); assert_eq!( - "connections/connection-0".parse::().unwrap(), + "connections/connection-0".parse::().unwrap(), Path::Connection(ConnectionPath { connection_id: "connection-0".to_string().validate().unwrap() }) ); assert_eq!( "channelEnds/ports/port/channels/channel-0" - .parse::() + .parse::() .unwrap(), Path::ChannelEnd(ChannelEndPath { port_id: "port".to_string().validate().unwrap(), @@ -268,7 +212,7 @@ mod tests { ); assert_eq!( "commitments/ports/port/channels/channel-0/sequences/1" - .parse::() + .parse::() .unwrap(), Path::Commitment(CommitmentPath { port_id: "port".to_string().validate().unwrap(), @@ -278,7 +222,7 @@ mod tests { ); assert_eq!( "acks/ports/port/channels/channel-0/sequences/1" - .parse::() + .parse::() .unwrap(), Path::Acknowledgement(AcknowledgementPath { port_id: "port".to_string().validate().unwrap(), @@ -287,63 +231,4 @@ mod tests { }) ); } - - // TODO: Migrate these to fuzz targets - // mod arbtest { - // use arbitrary::Arbitrary; - - // use crate::{ - // ibc::core::client::height::Height, - // id::ClientId, - // proof::Path, - // test_utils::{assert_json_roundtrip, assert_string_roundtrip}, - // }; - - // #[test] - // pub(crate) fn parse() { - // arbtest::builder().budget_ms(4000).minimize().run(|u| { - // // we don't care if it succeeds (it probably won't), we just want to ensure it doesn't panic - // let _ = String::arbitrary(u)?.parse::>(); - // Ok(()) - // }); - // } - - // #[test] - // pub(crate) fn roundtrip() { - // let mut oks = 0; - // let mut errs = 0; - // arbtest::builder().budget_ms(4000).minimize().run(|u| { - // dbg!(u.len()); - // let mut tries = 0; - // loop { - // if u.is_empty() { - // eprintln!("exhausted buffer"); - // break; - // } - - // if let Ok(ok) = >::arbitrary(u) { - // oks += 1; - // assert_json_roundtrip(&ok); - // assert_string_roundtrip(&ok); - // break; - // } - - // tries += 1; - // if tries >= 1024 { - // errs += 1; - // break; - // }; - // } - // Ok(()) - // }); - - // dbg!(oks, errs); - // } - // } - - // const _: fn() = || { - // fn assert_impl_all Arbitrary<'a>>() {} - - // assert_impl_all::>(); - // }; } diff --git a/lib/unionlabs/src/id.rs b/lib/unionlabs/src/id.rs index 99c1352e23..66bd1878d9 100644 --- a/lib/unionlabs/src/id.rs +++ b/lib/unionlabs/src/id.rs @@ -27,13 +27,11 @@ pub struct Ics024IdentifierCharacters; #[error("invalid ics-024 identifier character: `{0}`")] pub struct InvalidIcs024IdentifierCharacter(char); -impl + From> Validate for Ics024IdentifierCharacters { +impl> Validate for Ics024IdentifierCharacters { type Error = InvalidIcs024IdentifierCharacter; - fn validate(t: T) -> Result { - let s = t.into(); - - for c in s.chars() { + fn validate(s: T) -> Result { + for c in s.as_ref().chars() { match c { 'a'..='z' | 'A'..='Z' @@ -51,58 +49,22 @@ impl + From> Validate for Ics024IdentifierCharacters } } - Ok(T::from(s)) - } -} - -#[cfg(feature = "arbitrary")] -impl + From> crate::validated::ValidateExt - for Ics024IdentifierCharacters -{ - fn restrict(t: T, u: &mut arbitrary::Unstructured) -> arbitrary::Result { - const VALID_CHARS: [u8; 71] = - *b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890._+-#[]<>"; - - let s: String = t.into(); - - Ok(T::from( - s.bytes() - .map(|c| match c { - b'a'..=b'z' - | b'A'..=b'Z' - | b'0'..=b'9' - | b'.' - | b'_' - | b'+' - | b'-' - | b'#' - | b'[' - | b']' - | b'<' - | b'>' => Ok(c as char), - _ => Ok(*u.choose(&VALID_CHARS)? as char), - }) - .collect::>()?, - )) + Ok(s) } } pub struct Bounded; -impl + From, const MIN: usize, const MAX: usize> Validate - for Bounded -{ +impl, const MIN: usize, const MAX: usize> Validate for Bounded { type Error = InvalidLength; - fn validate(t: T) -> Result { + fn validate(s: T) -> Result { const { assert!(MIN <= MAX) }; - let s: String = t.into(); - - let len = s.len(); + let len = s.as_ref().len(); if (MIN..=MAX).contains(&len) { - Ok(T::from(s)) + Ok(s) } else { Err(InvalidLength { expected: ExpectedLength::Between(MIN, MAX), @@ -112,38 +74,6 @@ impl + From, const MIN: usize, const MAX: usize> Validat } } -#[cfg(feature = "arbitrary")] -impl + From, const MIN: usize, const MAX: usize> - crate::validated::ValidateExt for Bounded -{ - fn restrict(t: T, u: &mut arbitrary::Unstructured) -> arbitrary::Result { - const { assert!(MIN <= MAX) }; - - let s: String = t.into(); - - let len = s.len(); - - if len < MIN { - // can't add more data, since that might invalidate other validations run before this - Err(arbitrary::Error::IncorrectFormat) - } else if len > MAX { - fn floor_char_boundary(string: &str, index: usize) -> &str { - if string.is_char_boundary(index) { - &string[..index] - } else { - floor_char_boundary(string, index - 1) - } - } - - Ok(T::from( - floor_char_boundary(&s, u.int_in_range(MIN..=MAX)?).to_owned(), - )) - } else { - Ok(T::from(s)) - } - } -} - #[cfg(test)] mod tests { use alloc::borrow::Cow; diff --git a/lib/unionlabs/src/lib.rs b/lib/unionlabs/src/lib.rs index 13993dc940..8dc3ef3698 100644 --- a/lib/unionlabs/src/lib.rs +++ b/lib/unionlabs/src/lib.rs @@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize}; pub use typenum; use crate::{ - ibc::core::client::height::{HeightFromStrError, IsHeight}, + ibc::core::client::height::{Height, HeightFromStrError}, id::Bounded, validated::Validated, }; @@ -119,9 +119,11 @@ pub trait TypeUrl { } #[cfg(feature = "ethabi")] -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum TryFromEthAbiBytesError { - TryFromEthAbi(E), + #[error("unable to convert from the raw ethers type")] + TryFromEthAbi(#[source] E), + #[error("unable to decode from raw ethabi bytes")] Decode(ethers_core::abi::AbiError), } @@ -148,7 +150,6 @@ macro_rules! export_wasm_client_type { /// We need to be able to determine the light client from the light client code itself (not instantiated yet). /// Light clients supported by voyager must export a `#[no_mangle] static WASM_CLIENT_TYPE_: u8 = 0` variable. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[serde(rename_all = "snake_case")] pub enum WasmClientType { EthereumMinimal, @@ -158,13 +159,13 @@ pub enum WasmClientType { Scroll, Arbitrum, Linea, + // TODO: Rename to beacon-kit Berachain, EvmInCosmos, Movement, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[serde(rename_all = "snake_case")] pub enum ClientType { Wasm(WasmClientType), @@ -265,19 +266,21 @@ pub fn parse_wasm_client_type( } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde( - try_from = "&str", - into = "String", - bound(serialize = "", deserialize = "") -)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] // REVIEW: Add a variant "greater than" to indicate that any height >= H is valid? Might help with optimization passes -pub enum QueryHeight { +pub enum QueryHeight { + #[serde(rename = "latest")] Latest, - Specific(H), + #[serde(untagged)] + Specific(Height), +} + +impl From for QueryHeight { + fn from(height: Height) -> Self { + Self::Specific(height) + } } -impl Display for QueryHeight { +impl Display for QueryHeight { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { QueryHeight::Latest => f.write_str("latest"), @@ -286,13 +289,7 @@ impl Display for QueryHeight { } } -impl From> for String { - fn from(val: QueryHeight) -> Self { - val.to_string() - } -} - -impl FromStr for QueryHeight { +impl FromStr for QueryHeight { type Err = HeightFromStrError; fn from_str(s: &str) -> Result { @@ -303,14 +300,6 @@ impl FromStr for QueryHeight { } } -impl TryFrom<&'_ str> for QueryHeight { - type Error = HeightFromStrError; - - fn try_from(value: &'_ str) -> Result { - value.parse() - } -} - // TODO: remove this as it is unused pub trait MaybeRecoverableError: std::error::Error { fn is_recoverable(&self) -> bool; @@ -318,24 +307,6 @@ pub trait MaybeRecoverableError: std::error::Error { fn _is_object_safe(_: &dyn MaybeRecoverableError) {} -#[cfg(not(feature = "arbitrary"))] -pub trait MaybeArbitrary =; -#[cfg(feature = "arbitrary")] -pub trait MaybeArbitrary = for<'a> arbitrary::Arbitrary<'a>; - -pub fn impl_maybe_arbitrary() {} - -#[cfg(feature = "arbitrary")] -fn arbitrary_cow_static( - u: &mut arbitrary::Unstructured, -) -> arbitrary::Result> -where - T: ToOwned + ?Sized, - T::Owned: for<'a> arbitrary::Arbitrary<'a>, -{ - u.arbitrary::().map(alloc::borrow::Cow::Owned) -} - pub fn ensure(expr: bool, err: E) -> Result<(), E> { expr.then_some(()).ok_or(err) } diff --git a/lib/unionlabs/src/linea/proof.rs b/lib/unionlabs/src/linea/proof.rs index 927ff635d4..42b99a82a4 100644 --- a/lib/unionlabs/src/linea/proof.rs +++ b/lib/unionlabs/src/linea/proof.rs @@ -9,7 +9,7 @@ pub enum TryFromMerkleProofError { MissingField(#[from] MissingField), } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct MerklePath { #[serde(with = "::serde_utils::hex_string")] diff --git a/lib/unionlabs/src/macros.rs b/lib/unionlabs/src/macros.rs index 7ca08ccc79..ad0cff7b52 100644 --- a/lib/unionlabs/src/macros.rs +++ b/lib/unionlabs/src/macros.rs @@ -15,17 +15,78 @@ macro_rules! hex_string_array_wrapper { PartialOrd, Ord, ::ssz::Ssz, - ::serde::Serialize, - ::serde::Deserialize, Hash )] #[ssz(transparent)] - #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] - pub struct $Struct(#[serde(with = "::serde_utils::hex_string")] pub [u8; $N]); + pub struct $Struct(pub [u8; $N]); + + impl ::serde::Serialize for $Struct { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeTupleStruct; + + if serializer.is_human_readable() { + serializer.serialize_str(&::serde_utils::to_hex(self)) + } else { + let mut s = serializer.serialize_tuple_struct(stringify!($Struct), $N)?; + for b in self.0 { + s.serialize_field(&b)?; + } + s.end() + } + } + } + + impl<'de> ::serde::Deserialize<'de> for $Struct { + fn deserialize(deserializer: D) -> Result + where + D: ::serde::Deserializer<'de>, + { + if deserializer.is_human_readable() { + String::deserialize(deserializer) + .and_then(|x| ::serde_utils::parse_hex::(x).map_err(::serde::de::Error::custom)) + } else { + struct ArrayVisitor; + + impl<'de> serde::de::Visitor<'de> for ArrayVisitor { + type Value = [u8; $N]; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(formatter, "an array of length {}", $N) + } + + fn visit_seq(self, mut seq: A) -> ::core::result::Result<[u8; $N], A::Error> + where + A: serde::de::SeqAccess<'de>, + { + let mut arr = [0_u8; $N]; + + for (i, b) in arr.iter_mut().enumerate() { + let val = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(i, &self))?; + + *b = val; + } + + Ok(arr) + } + } + + Ok(Self(deserializer.deserialize_tuple($N, ArrayVisitor)?)) + } + } + } impl $Struct { pub const BYTES_LEN: usize = $N; + pub const BITS_LEN: usize = $N * 8; + + pub const ZERO: Self = Self([0; $N]); + #[doc = concat!("The [`Display`](core::fmt::Display) impl for [`", stringify!($Struct), "`]")] /// prefixes the output with `0x`, which may not be desirable in all contexts. /// This fn serves as a convenience around [`hex::encode(&self)`](hex::encode). @@ -37,6 +98,11 @@ macro_rules! hex_string_array_wrapper { pub fn iter(&self) -> core::slice::Iter { (&self).into_iter() } + + #[must_use] + pub fn iter_bits(&self) -> $crate::hash::BytesBitIterator<'_> { + $crate::hash::BytesBitIterator::new(self) + } } impl core::str::FromStr for $Struct { @@ -265,7 +331,6 @@ macro_rules! wrapper_enum { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "snake_case")] $(#[$meta])* - #[cfg_attr(feature = "arbitrary", derive(::arbitrary::Arbitrary))] #[cfg_attr(feature = "schemars", derive(::schemars::JsonSchema))] pub enum $Enum { $( @@ -448,3 +513,18 @@ macro_rules! iter { } }}; } + +#[macro_export] +macro_rules! assert_all_eq ( + ($a:expr, $b:expr) => { + assert_eq!($a, $b); + }; + ($a:expr, $b:expr, $c:expr) => { + assert_eq!($a, $b); + assert_eq!($b, $c); + }; + ($a:expr, $b:expr, $c:expr, $($rest:expr),*$(,)?) => { + assert_eq!($a, $b); + assert_all_eq!($b, $c, $($rest),*); + } +); diff --git a/lib/unionlabs/src/never.rs b/lib/unionlabs/src/never.rs index f0dd171cfd..c4029dbdad 100644 --- a/lib/unionlabs/src/never.rs +++ b/lib/unionlabs/src/never.rs @@ -2,9 +2,8 @@ use core::fmt::Display; use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] /// The empty/ "bottom" type. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub enum Never {} impl Display for Never { diff --git a/lib/unionlabs/src/scroll/account.rs b/lib/unionlabs/src/scroll/account.rs index d23d540de3..82055a0302 100644 --- a/lib/unionlabs/src/scroll/account.rs +++ b/lib/unionlabs/src/scroll/account.rs @@ -5,18 +5,16 @@ use crate::{ ByteArrayExt, }; -/* -(The following scheme assumes the big-endian encoding) -[0:32] (bytes in big-endian) -[0:16] Reserved with all 0 -[16:24] CodeSize, uint64 in big-endian -[24:32] Nonce, uint64 in big-endian -[32:64] Balance -[64:96] StorageRoot -[96:128] KeccakCodeHash -[128:160] PoseidonCodehash -(total 160 bytes) - */ +// (The following scheme assumes the big-endian encoding) +// [0:32] (bytes in big-endian) +// [0:16] Reserved with all 0 +// [16:24] CodeSize, uint64 in big-endian +// [24:32] Nonce, uint64 in big-endian +// [32:64] Balance +// [64:96] StorageRoot +// [96:128] KeccakCodeHash +// [128:160] PoseidonCodehash +// (total 160 bytes) // https://github.com/scroll-tech/zktrie/blob/a12f2f262ad3e82301e39ecdf9bfe235befc7074/docs/zktrie.md pub struct Account { pub code_size: u64, diff --git a/lib/unionlabs/src/tendermint/abci.rs b/lib/unionlabs/src/tendermint/abci.rs index 1dd8d593aa..e28e8021a3 100644 --- a/lib/unionlabs/src/tendermint/abci.rs +++ b/lib/unionlabs/src/tendermint/abci.rs @@ -1,3 +1,4 @@ pub mod event; pub mod event_attribute; +pub mod exec_tx_result; pub mod response_query; diff --git a/lib/unionlabs/src/tendermint/abci/exec_tx_result.rs b/lib/unionlabs/src/tendermint/abci/exec_tx_result.rs new file mode 100644 index 0000000000..4db638026a --- /dev/null +++ b/lib/unionlabs/src/tendermint/abci/exec_tx_result.rs @@ -0,0 +1,88 @@ +use macros::model; + +use crate::{ + bounded::{BoundedI64, BoundedIntError}, + tendermint::abci::event::Event, +}; + +#[model(proto(raw(protos::tendermint::abci::ExecTxResult), into, from))] +pub struct ExecTxResult { + pub code: u32, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub data: Vec, + /// nondeterministic + pub log: String, + /// nondeterministic + pub info: String, + pub gas_wanted: BoundedI64<0, { i64::MAX }>, + pub gas_used: BoundedI64<0, { i64::MAX }>, + /// nondeterministic + pub events: Vec, + pub codespace: String, +} + +impl From for protos::tendermint::abci::ExecTxResult { + fn from(value: ExecTxResult) -> Self { + Self { + code: value.code, + data: value.data, + log: value.log, + info: value.info, + gas_wanted: value.gas_wanted.into(), + gas_used: value.gas_used.into(), + events: value.events.into_iter().map(Into::into).collect(), + codespace: value.codespace, + } + } +} + +impl TryFrom for ExecTxResult { + type Error = TryFromExecTxResultError; + + fn try_from(value: protos::tendermint::abci::ExecTxResult) -> Result { + Ok(Self { + code: value.code, + data: value.data, + log: value.log, + info: value.info, + gas_wanted: value + .gas_wanted + .try_into() + .map_err(TryFromExecTxResultError::GasWanted)?, + gas_used: value + .gas_used + .try_into() + .map_err(TryFromExecTxResultError::GasUsed)?, + events: value.events.into_iter().map(Into::into).collect(), + codespace: value.codespace, + }) + } +} + +#[derive(Debug, PartialEq, Clone, thiserror::Error)] +pub enum TryFromExecTxResultError { + #[error("invalid gas_wanted")] + GasWanted(#[source] BoundedIntError), + #[error("invalid gas_used")] + GasUsed(#[source] BoundedIntError), +} + +#[cfg(test)] +mod tests { + #[test] + fn json() { + let json = serde_json::from_str::(r#"{ + "code": 5, + "data": null, + "log": "failed to execute message; message index: 0: spendable balance 2173muno is smaller than 2400muno: insufficient funds", + "info": "", + "gas_wanted": "249046", + "gas_used": "133330", + "events": [], + "codespace": "sdk" + }"#).unwrap(); + + dbg!(json); + } +} diff --git a/lib/unionlabs/src/tendermint/crypto.rs b/lib/unionlabs/src/tendermint/crypto.rs index 58b0f26e38..4166851383 100644 --- a/lib/unionlabs/src/tendermint/crypto.rs +++ b/lib/unionlabs/src/tendermint/crypto.rs @@ -1,3 +1,4 @@ +pub mod proof; pub mod proof_op; pub mod proof_ops; pub mod public_key; diff --git a/lib/unionlabs/src/tendermint/crypto/proof.rs b/lib/unionlabs/src/tendermint/crypto/proof.rs new file mode 100644 index 0000000000..600aaefd3b --- /dev/null +++ b/lib/unionlabs/src/tendermint/crypto/proof.rs @@ -0,0 +1,51 @@ +use macros::model; + +use crate::{ + bounded::{BoundedI64, BoundedIntError}, + errors::InvalidLength, + hash::H256, +}; + +#[model(proto(raw(protos::tendermint::crypto::Proof), into, from))] +pub struct Proof { + pub total: BoundedI64<0, { i64::MAX }>, + pub index: BoundedI64<0, { i64::MAX }>, + pub leaf_hash: H256, + #[serde(with = "::serde_utils::hex_string_list")] + #[debug(wrap = ::serde_utils::fmt::DebugListAsHex)] + pub aunts: Vec>, +} + +impl From for protos::tendermint::crypto::Proof { + fn from(value: Proof) -> Self { + Self { + total: value.total.into(), + index: value.index.into(), + leaf_hash: value.leaf_hash.into(), + aunts: value.aunts, + } + } +} + +impl TryFrom for Proof { + type Error = TryFromProofError; + + fn try_from(value: protos::tendermint::crypto::Proof) -> Result { + Ok(Self { + total: value.total.try_into().map_err(TryFromProofError::Total)?, + index: value.index.try_into().map_err(TryFromProofError::Index)?, + leaf_hash: value.leaf_hash.try_into()?, + aunts: value.aunts, + }) + } +} + +#[derive(Debug, PartialEq, Clone, thiserror::Error)] +pub enum TryFromProofError { + #[error("invalid total")] + Total(#[source] BoundedIntError), + #[error("invalid index")] + Index(#[source] BoundedIntError), + #[error("invalid leaf hash")] + LeafHash(#[from] InvalidLength), +} diff --git a/lib/unionlabs/src/tendermint/types.rs b/lib/unionlabs/src/tendermint/types.rs index f1de0aea25..fe2a6f4b19 100644 --- a/lib/unionlabs/src/tendermint/types.rs +++ b/lib/unionlabs/src/tendermint/types.rs @@ -17,6 +17,7 @@ pub mod part_set_header; pub mod signed_header; pub mod signed_msg_type; pub mod simple_validator; +pub mod tx_proof; pub mod validator; pub mod validator_set; pub mod vote; diff --git a/lib/unionlabs/src/tendermint/types/tx_proof.rs b/lib/unionlabs/src/tendermint/types/tx_proof.rs new file mode 100644 index 0000000000..dfdf04340e --- /dev/null +++ b/lib/unionlabs/src/tendermint/types/tx_proof.rs @@ -0,0 +1,48 @@ +use macros::model; + +use crate::{ + errors::{required, InvalidLength, MissingField}, + hash::H256, + tendermint::crypto::proof::{Proof, TryFromProofError}, +}; + +#[model(proto(raw(protos::tendermint::types::TxProof), into, from))] +pub struct TxProof { + pub root_hash: H256, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub data: Vec, + pub proof: Proof, +} + +impl From for protos::tendermint::types::TxProof { + fn from(value: TxProof) -> Self { + Self { + root_hash: value.root_hash.into(), + data: value.data, + proof: Some(value.proof.into()), + } + } +} + +impl TryFrom for TxProof { + type Error = TryFromTxProofError; + + fn try_from(value: protos::tendermint::types::TxProof) -> Result { + Ok(Self { + root_hash: value.root_hash.try_into()?, + data: value.data, + proof: required!(value.proof)?.try_into()?, + }) + } +} + +#[derive(Debug, PartialEq, Clone, thiserror::Error)] +pub enum TryFromTxProofError { + #[error(transparent)] + MissingField(#[from] MissingField), + #[error("invalid root_hash")] + RootHash(#[from] InvalidLength), + #[error("invalid proof")] + Proof(#[from] TryFromProofError), +} diff --git a/lib/unionlabs/src/traits.rs b/lib/unionlabs/src/traits.rs index c13745ce47..631df7d555 100644 --- a/lib/unionlabs/src/traits.rs +++ b/lib/unionlabs/src/traits.rs @@ -1,38 +1,7 @@ -use core::{ - fmt::{Debug, Display}, - future::Future, - hash::Hash, - str::FromStr, -}; -use std::error::Error; +use core::fmt::Debug; use serde::{Deserialize, Serialize}; -use crate::{ - encoding::Encoding, - ethereum::config::ChainSpec, - google::protobuf::any::Any, - ibc::{ - core::client::height::{Height, IsHeight}, - lightclients::{arbitrum, cometbls, ethereum, scroll, tendermint, wasm}, - }, - id::ClientId, - uint::U256, - MaybeArbitrary, TypeUrl, -}; - -/// A convenience trait for a string id (`ChainId`, `ClientId`, `ConnectionId`, etc) -pub trait Id = Debug - + Clone - + PartialEq - + Serialize - + for<'de> Deserialize<'de> - + FromStr - + Display - + Send - + Sync - + 'static; - /// [`Serialize`] and [`Deserialize`] only as exactly [`Self::EXPECTING`]. pub trait FromStrExact: Default + Sized { const EXPECTING: &'static str; @@ -76,275 +45,4 @@ pub trait Member = Debug + Send + Sync + Unpin - + MaybeArbitrary + 'static; - -/// Represents a chain. -pub trait Chain: Sized + Send + Sync + 'static { - /// Expected to be unique across all implementations. - type ChainType: FromStrExact; - - /// The client state of this chain. - type SelfClientState: Member - + TypeUrl // hack - // TODO: Bound ChainId in the same way - + ClientState; - - /// The consensus state of this chain. - type SelfConsensusState: Member - + TypeUrl // hack - + ConsensusState; - - /// The block header (aka light client update message) for this chain. - type Header: Member + Header; - - /// Some chains store the counterparty client state differently than just storing the state directly, for example wrapping it in [`Any`]. - type StoredClientState: Member - + ClientState, Height = Tr::Height>; - /// Some chains store the counterparty consensus state differently than just storing the state directly, for example wrapping it in [`Any`]. - type StoredConsensusState: Member; - - // this is just Height - type Height: Member + IsHeight + MaybeArbitrary + PartialOrd; - - type ClientId: Member + Id + TryFrom + Into + MaybeArbitrary; - - /// The encoding this chain uses in it's IBC store. - type IbcStateEncoding: Encoding; - - type StateProof: Member; - - /// Available client types for this chain. - type ClientType: Member + Id; - - type Error: Debug; - - fn chain_id(&self) -> ::ChainId; - - /// Query the latest finalized height of this chain. - fn query_latest_height(&self) -> impl Future> + '_; - - /// Query the latest (non-finalized) height of this chain. - fn query_latest_height_as_destination( - &self, - ) -> impl Future> + '_; - - /// Query the latest finalized timestamp of this chain. - fn query_latest_timestamp(&self) -> impl Future> + '_; - - /// The client state on this chain at the specified `Height`. - fn self_client_state( - &self, - height: Self::Height, - ) -> impl Future + '_; - - /// The consensus state on this chain at the specified `Height`. - fn self_consensus_state( - &self, - height: Self::Height, - ) -> impl Future + '_; -} - -pub trait ClientState { - type ChainId: Member + Display + Eq + Hash; - type Height: Member + IsHeight + MaybeArbitrary; - - fn height(&self) -> Self::Height; - fn chain_id(&self) -> Self::ChainId; -} - -impl ClientState for ethereum::client_state::ClientState { - type ChainId = U256; - type Height = Height; - - fn height(&self) -> Self::Height { - Height { - // TODO: Make ETHEREUM_REVISION_NUMBER a constant in this crate - revision_number: 0, - revision_height: self.latest_slot, - } - } - - fn chain_id(&self) -> Self::ChainId { - self.chain_id - } -} - -impl ClientState for scroll::client_state::ClientState { - type ChainId = U256; - type Height = Height; - - fn height(&self) -> Self::Height { - Height { - // TODO: Make ETHEREUM_REVISION_NUMBER a constant in this crate - revision_number: 0, - revision_height: self.latest_slot, - } - } - - fn chain_id(&self) -> Self::ChainId { - self.chain_id - } -} - -impl ClientState for arbitrum::client_state::ClientState { - type ChainId = U256; - type Height = Height; - - fn height(&self) -> Self::Height { - Height { - // TODO: Make ETHEREUM_REVISION_NUMBER a constant in this crate - revision_number: 0, - revision_height: self.l1_latest_slot, - } - } - - fn chain_id(&self) -> Self::ChainId { - self.chain_id - } -} - -impl ClientState for wasm::client_state::ClientState { - type ChainId = Data::ChainId; - type Height = Data::Height; - - fn height(&self) -> Data::Height { - self.data.height() - } - - fn chain_id(&self) -> Self::ChainId { - self.data.chain_id() - } -} - -impl ClientState for cometbls::client_state::ClientState { - type ChainId = String; - type Height = Height; - - fn height(&self) -> Height { - self.latest_height - } - - fn chain_id(&self) -> Self::ChainId { - self.chain_id.clone() - } -} - -impl ClientState for tendermint::client_state::ClientState { - type ChainId = String; - type Height = Height; - - fn height(&self) -> Height { - self.latest_height - } - - fn chain_id(&self) -> Self::ChainId { - self.chain_id.clone() - } -} - -impl ClientState for Any -where - T: ClientState, -{ - type ChainId = T::ChainId; - type Height = T::Height; - - fn height(&self) -> Self::Height { - self.0.height() - } - - fn chain_id(&self) -> Self::ChainId { - self.0.chain_id() - } -} - -pub trait Header { - fn trusted_height(&self) -> Height; -} - -impl Header for ethereum::header::Header { - fn trusted_height(&self) -> Height { - self.trusted_sync_committee.trusted_height - } -} - -impl Header for scroll::header::Header { - fn trusted_height(&self) -> Height { - self.l1_height - } -} - -impl Header for arbitrum::header::Header { - fn trusted_height(&self) -> Height { - self.l1_height - } -} - -impl Header for wasm::client_message::ClientMessage { - fn trusted_height(&self) -> Height { - self.data.trusted_height() - } -} - -impl Header for cometbls::header::Header { - fn trusted_height(&self) -> Height { - self.trusted_height - } -} - -impl Header for tendermint::header::Header { - fn trusted_height(&self) -> Height { - self.trusted_height - } -} - -pub trait ConsensusState { - fn timestamp(&self) -> u64; -} - -impl ConsensusState for ethereum::consensus_state::ConsensusState { - fn timestamp(&self) -> u64 { - self.timestamp - } -} - -impl ConsensusState for scroll::consensus_state::ConsensusState { - fn timestamp(&self) -> u64 { - self.timestamp - } -} - -impl ConsensusState for arbitrum::consensus_state::ConsensusState { - fn timestamp(&self) -> u64 { - self.timestamp - } -} - -impl ConsensusState for wasm::consensus_state::ConsensusState { - fn timestamp(&self) -> u64 { - self.data.timestamp() - } -} - -impl ConsensusState for cometbls::consensus_state::ConsensusState { - fn timestamp(&self) -> u64 { - self.timestamp - } -} - -impl ConsensusState for tendermint::consensus_state::ConsensusState { - fn timestamp(&self) -> u64 { - // REVIEW: Perhaps this fn should return Timestamp - self.timestamp.seconds.inner().try_into().unwrap() - } -} - -pub type ClientStateOf = ::SelfClientState; -pub type ConsensusStateOf = ::SelfConsensusState; -pub type HeaderOf = ::Header; -pub type HeightOf = ::Height; -pub type IbcStateEncodingOf = ::IbcStateEncoding; -pub type ChainIdOf = <::SelfClientState as ClientState>::ChainId; -pub type ClientIdOf = ::ClientId; -pub type ClientTypeOf = ::ClientType; diff --git a/lib/unionlabs/src/uint.rs b/lib/unionlabs/src/uint.rs index 4c7252911e..1497d8e1ae 100644 --- a/lib/unionlabs/src/uint.rs +++ b/lib/unionlabs/src/uint.rs @@ -31,7 +31,6 @@ use crate::{ Serialize, Deserialize, )] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[repr(transparent)] #[debug("U256({})", self)] pub struct U256(#[serde(with = "::serde_utils::u256_from_dec_str")] pub primitive_types::U256); diff --git a/lib/unionlabs/src/union/galois/poll_response.rs b/lib/unionlabs/src/union/galois/poll_response.rs index 7cabddba7e..e568fced45 100644 --- a/lib/unionlabs/src/union/galois/poll_response.rs +++ b/lib/unionlabs/src/union/galois/poll_response.rs @@ -1,5 +1,4 @@ use macros::model; -use serde::{Deserialize, Serialize}; use crate::{ errors::{required, MissingField}, @@ -13,12 +12,12 @@ pub enum PollResponse { Done(ProveRequestDone), } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[model] pub struct ProveRequestFailed { pub message: String, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[model] pub struct ProveRequestDone { pub response: ProveResponse, } diff --git a/lib/unionlabs/src/union/ics23/merkle_proof.rs b/lib/unionlabs/src/union/ics23/merkle_proof.rs index 1549818858..239a012d35 100644 --- a/lib/unionlabs/src/union/ics23/merkle_proof.rs +++ b/lib/unionlabs/src/union/ics23/merkle_proof.rs @@ -6,6 +6,7 @@ use crate::{ }; #[model(proto(raw(protos::ibc::core::commitment::v1::MerkleProof), into, from))] +// TODO: Rename to optimized merkle proof pub enum MerkleProof { Membership(ExistenceProof, ExistenceProof), NonMembership(NonExistenceProof, ExistenceProof), diff --git a/lib/unionlabs/src/validated.rs b/lib/unionlabs/src/validated.rs index 1c047d310a..95f99d8f68 100644 --- a/lib/unionlabs/src/validated.rs +++ b/lib/unionlabs/src/validated.rs @@ -1,4 +1,11 @@ -use core::{fmt::Display, marker::PhantomData, ops::Deref, str::FromStr}; +use core::{ + cmp::Ordering, + fmt::Display, + hash::{Hash, Hasher}, + marker::PhantomData, + ops::Deref, + str::FromStr, +}; use either::Either; use serde::{Deserialize, Serialize}; @@ -15,6 +22,26 @@ pub struct Validated>( PhantomData V>, ); +impl> Hash for Validated { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + +impl> PartialOrd for Validated { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } +} + +impl> Ord for Validated { + fn cmp(&self, other: &Self) -> Ordering { + self.0.cmp(&other.0) + } +} + +impl> Eq for Validated {} + #[cfg(feature = "schemars")] impl> schemars::JsonSchema for Validated { fn schema_name() -> String { @@ -26,20 +53,6 @@ impl> schemars::JsonSchema for Validated } } -#[cfg(feature = "arbitrary")] -impl<'a, T: arbitrary::Arbitrary<'a>, V: ValidateExt> arbitrary::Arbitrary<'a> - for Validated -where - V::Error: Debug, -{ - fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - // NOTE: This is super inefficient and practically always produces an error, figure out a way for V to guide the input - T::arbitrary(u).and_then(|t| { - V::restrict(t, u).map(|t| t.validate().expect("restricted data is valid")) - }) - } -} - pub trait ValidateT: Sized { fn validate>(self) -> Result, V::Error> { Validated::new(self) @@ -116,12 +129,6 @@ pub trait Validate: Sized { fn validate(t: T) -> Result; } -#[cfg(feature = "arbitrary")] -pub trait ValidateExt: Validate + Sized { - // Given a value of the inner validated type `T`, restrict it such that it fits within the validation of `Self`. - fn restrict(t: T, u: &mut arbitrary::Unstructured) -> arbitrary::Result; -} - impl, V2: Validate> Validate for (V1, V2) { type Error = Either; @@ -134,19 +141,6 @@ impl, V2: Validate> Validate for (V1, V2) { } } -#[cfg(feature = "arbitrary")] -impl, V2: ValidateExt> ValidateExt for (V1, V2) { - fn restrict(t: T, u: &mut arbitrary::Unstructured) -> arbitrary::Result { - if u.arbitrary()? { - // V2::restrict(V1::restrict(V2::restrict(V1::restrict(t, u)?, u)?, u)?, u) - V2::restrict(V1::restrict(t, u)?, u) - } else { - // V1::restrict(V2::restrict(V1::restrict(V2::restrict(t, u)?, u)?, u)?, u) - V1::restrict(V2::restrict(t, u)?, u) - } - } -} - impl Validate for () { type Error = (); @@ -155,13 +149,6 @@ impl Validate for () { } } -#[cfg(feature = "arbitrary")] -impl ValidateExt for () { - fn restrict(t: T, _: &mut arbitrary::Unstructured) -> arbitrary::Result { - Ok(t) - } -} - #[cfg(test)] mod tests { use core::marker::PhantomData; @@ -261,10 +248,4 @@ mod tests { Ok(Validated(9, PhantomData)) ); } - - // const _: fn() = || { - // fn assert_impl_all arbitrary::Arbitrary<'a>>() {} - - // assert_impl_all::>(); - // }; } diff --git a/lib/voyager-message/Cargo.toml b/lib/voyager-message/Cargo.toml index fc3b46ffd7..e39da5b554 100644 --- a/lib/voyager-message/Cargo.toml +++ b/lib/voyager-message/Cargo.toml @@ -3,26 +3,55 @@ edition = { workspace = true } license-file = { workspace = true } name = "voyager-message" repository = { workspace = true } +resolver = "2" version = "0.1.0" -[dependencies] -arbitrary = { workspace = true, optional = true, features = ["derive"] } -block-message = { workspace = true } -chain-utils = { workspace = true } -futures.workspace = true -macros.workspace = true -queue-msg = { workspace = true } -relay-message = { workspace = true } -serde = { workspace = true, features = ["derive"] } -tracing = { workspace = true } -unionlabs = { workspace = true } - [lints] workspace = true +[dependencies] +beacon-api = { workspace = true } +chain-utils = { workspace = true } +clap = { workspace = true, features = ["derive"] } +contracts = { workspace = true, features = ["providers"] } +dashmap = { workspace = true } +enumorph = { workspace = true } +ethers = { workspace = true, features = ["rustls", "ws"] } +frame-support-procedural = { workspace = true } +frunk = { workspace = true } +futures = { workspace = true } +hex = { workspace = true } +jaq-core = "1.5.1" +jaq-interpret = "1.5.0" +jaq-std = "1.6.0" +jaq-syn = "1.6.0" +jsonrpsee = { workspace = true, features = ["server", "client", "async-client", "macros", "tracing"] } +macros = { workspace = true } +moka = { version = "0.12.8", features = ["future", "sync"] } +num-bigint = { workspace = true } +prost = { workspace = true } +protos = { workspace = true, features = ["proto_full", "client"] } +queue-msg = { workspace = true } +reconnecting-jsonrpc-ws-client = { workspace = true } +reth-ipc = { git = "https://github.com/paradigmxyz/reth", version = "1.0.3" } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +serde_json = { workspace = true } +soketto = "0.8.0" +tendermint = { workspace = true } +tendermint-proto = { workspace = true } +tendermint-rpc = { workspace = true, features = ["http-client", "websocket-client"] } +thiserror = { workspace = true } +tokio = { workspace = true, features = ["time", "process", "fs"] } +tokio-util = "0.7.11" +tonic = { workspace = true, features = ["transport", "tls", "tls-roots", "tls-webpki-roots"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["json"] } +typenum = { workspace = true } +unionlabs = { workspace = true, features = ["ethabi"] } + [dev-dependencies] hex-literal = { workspace = true } -serde_json = "1.0.115" [features] -arbitrary = ["dep:arbitrary", "block-message/arbitrary", "relay-message/arbitrary"] +default = [] diff --git a/lib/voyager-message/src/call.rs b/lib/voyager-message/src/call.rs new file mode 100644 index 0000000000..71885c96ce --- /dev/null +++ b/lib/voyager-message/src/call.rs @@ -0,0 +1,1438 @@ +#![allow(unused_imports)] // TODO: Remove + +use enumorph::Enumorph; +use jsonrpsee::{ + core::RpcResult, + types::{ErrorObject, ErrorObjectOwned}, +}; +use macros::apply; +use queue_msg::{ + call, conc, data, defer, noop, now, promise, queue_msg, seq, HandleCall, Op, QueueError, +}; +use serde_json::{json, Value}; +use serde_utils::Hex; +use tracing::{debug, info, info_span, instrument, trace, Instrument}; +use unionlabs::{ + ibc::core::{ + channel::{ + self, channel::Channel, msg_acknowledgement::MsgAcknowledgement, + msg_channel_open_ack::MsgChannelOpenAck, + msg_channel_open_confirm::MsgChannelOpenConfirm, + msg_channel_open_try::MsgChannelOpenTry, msg_recv_packet::MsgRecvPacket, + }, + client::{height::Height, msg_create_client::MsgCreateClient}, + commitment::merkle_prefix::MerklePrefix, + connection::{ + self, connection_end::ConnectionEnd, msg_connection_open_ack::MsgConnectionOpenAck, + msg_connection_open_confirm::MsgConnectionOpenConfirm, + msg_connection_open_try::MsgConnectionOpenTry, + }, + }, + ics24::{ + AcknowledgementPath, ChannelEndPath, ClientConsensusStatePath, ClientStatePath, + CommitmentPath, ConnectionPath, Path, ReceiptPath, + }, + id::{ClientId, ConnectionId}, + traits::Member, + QueryHeight, DELAY_PERIOD, +}; + +use crate::{ + callback::AggregateFetchBlockRange, + data::{ + ClientInfo, DecodedClientStateMeta, DecodedConsensusStateMeta, EncodedClientState, + EncodedConsensusState, EncodedHeader, IbcMessage, IbcProof, IbcState, LatestHeight, + MsgCreateClientData, RawIbcProof, SelfClientState, SelfConsensusState, WithChainId, + }, + error_object_to_queue_error, json_rpc_error_to_queue_error, + module::{ + ChainModuleClient, ClientModuleClient, ConsensusModuleClient, QueueInteractionsClient, + }, + rpc::{json_rpc_error_to_rpc_error, VoyagerRpcServer}, + top_level_identifiable_enum, ChainId, Context, IbcInterface, PluginMessage, VoyagerMessage, + FATAL_JSONRPC_ERROR_CODE, +}; + +#[apply(top_level_identifiable_enum)] +#[queue_msg] +#[derive(Enumorph)] +pub enum Call { + FetchBlock(FetchBlock), + FetchBlockRange(FetchBlockRange), + + UnfinalizedTrustedClientState(FetchUnfinalizedTrustedClientState), + + UpdateHeaders(FetchUpdateHeaders), + + MakeMsgCreateClient(MakeMsgCreateClient), + + MakeMsgConnectionOpenTry(MakeMsgConnectionOpenTry), + MakeMsgConnectionOpenAck(MakeMsgConnectionOpenAck), + MakeMsgConnectionOpenConfirm(MakeMsgConnectionOpenConfirm), + + MakeMsgChannelOpenTry(MakeMsgChannelOpenTry), + MakeMsgChannelOpenAck(MakeMsgChannelOpenAck), + MakeMsgChannelOpenConfirm(MakeMsgChannelOpenConfirm), + + MakeMsgAcknowledgement(MakeMsgAcknowledgement), + MakeMsgRecvPacket(MakeMsgRecvPacket), + + WaitForHeight(WaitForHeight), + WaitForHeightRelative(WaitForHeightRelative), + WaitForTimestamp(WaitForTimestamp), + WaitForTrustedHeight(WaitForTrustedHeight), + + Plugin(PluginMessage), +} + +#[queue_msg] +pub struct FetchBlockRange { + pub chain_id: ChainId<'static>, + pub from_height: Height, + pub to_height: Height, +} + +#[queue_msg] +pub struct FetchBlock { + pub chain_id: ChainId<'static>, + pub height: Height, +} + +#[queue_msg] +pub struct FetchSelfClientState { + pub chain_id: ChainId<'static>, + pub at: QueryHeight, + /// The counterparty IBC interface that the state must be encoded for. + pub ibc_interface: IbcInterface<'static>, + #[serde(default, skip_serializing_if = "Value::is_null")] + /// Additional metadata that will be passed to + /// [`ClientModulePlugin::encode_client_state`]. This field is analogous to + /// [`ClientInfo::metadata`]. + pub metadata: Value, +} + +#[queue_msg] +pub struct FetchSelfConsensusState { + pub chain_id: ChainId<'static>, + pub at: QueryHeight, + /// The counterparty IBC interface that the state must be encoded for. + pub ibc_interface: IbcInterface<'static>, +} + +// TODO: This should have a height field +#[queue_msg] +pub struct FetchClientInfo { + pub chain_id: ChainId<'static>, + pub client_id: ClientId, +} + +#[queue_msg] +pub struct DecodeClientStateMeta { + pub ibc_state: IbcState, + pub client_info: ClientInfo, +} + +#[queue_msg] +pub struct DecodeConsensusStateMeta { + pub ibc_state: IbcState, + pub client_info: ClientInfo, +} + +#[queue_msg] +pub struct EncodeClientState { + pub client_state: Value, + pub client_info: ClientInfo, +} + +#[queue_msg] +pub struct EncodeConsensusState { + pub consensus_state: Value, + pub client_info: ClientInfo, +} + +#[queue_msg] +pub struct EncodeHeader { + pub header: Value, + pub client_info: ClientInfo, +} + +#[queue_msg] +pub struct EncodeProof { + pub raw_proof: RawIbcProof, + pub client_info: ClientInfo, +} + +/// Fetches a raw, unencoded IBC proof from the specified chain. +#[queue_msg] +pub struct FetchRawProof { + pub chain_id: ChainId<'static>, + pub at: Height, + pub path: Path, +} + +#[queue_msg] +pub struct FetchState { + pub chain_id: ChainId<'static>, + pub at: QueryHeight, + pub path: Path, +} + +#[queue_msg] +pub struct FetchUpdateHeaders { + pub chain_id: ChainId<'static>, + pub counterparty_chain_id: ChainId<'static>, + pub update_from: Height, + pub update_to: Height, +} + +#[queue_msg] +pub struct FetchLatestHeight { + pub chain_id: ChainId<'static>, +} + +#[queue_msg] +pub struct FetchUnfinalizedTrustedClientState { + pub chain_id: ChainId<'static>, + pub client_id: ClientId, +} + +/// Build a [`MsgCreateClient`] [`IbcMessage`]. +#[queue_msg] +pub struct MakeMsgCreateClient { + /// The chain to create the client on. + pub chain_id: ChainId<'static>, + /// The height of the counterparty that the client will trust. The + /// [`SelfClientState`] and [`SelfConsensusState`] will be queried at this + /// height. + pub height: QueryHeight, + #[serde(default, skip_serializing_if = "Value::is_null")] + /// Additional metadata that will be passed to + /// [`ClientModulePlugin::encode_client_state`]. This field is analogous to + /// [`ClientInfo::metadata`]. + pub metadata: Value, + /// The chain to create a client of. + pub counterparty_chain_id: ChainId<'static>, + /// The IBC interface to create the client on. + pub ibc_interface: IbcInterface<'static>, +} + +#[queue_msg] +pub struct MakeMsgConnectionOpenTry { + /// The chain id of the chain that the event was emitted on. + pub origin_chain_id: ChainId<'static>, + /// The height to generate the state proofs at. + pub origin_chain_proof_height: Height, + /// The chain id of the chain that the message will be sent to. + pub target_chain_id: ChainId<'static>, + /// The original event that was emitted on the origin chain. + pub connection_open_init_event: crate::data::ConnectionOpenInit, +} + +#[queue_msg] +pub struct MakeMsgConnectionOpenAck { + /// The chain id of the chain that the event was emitted on. + pub origin_chain_id: ChainId<'static>, + /// The height to generate the state proofs at. + pub origin_chain_proof_height: Height, + /// The chain id of the chain that the message will be sent to. + pub target_chain_id: ChainId<'static>, + /// The original event that was emitted on the origin chain. + pub connection_open_try_event: crate::data::ConnectionOpenTry, +} + +#[queue_msg] +pub struct MakeMsgConnectionOpenConfirm { + /// The chain id of the chain that the event was emitted on. + pub origin_chain_id: ChainId<'static>, + /// The height to generate the state proofs at. + pub origin_chain_proof_height: Height, + /// The chain id of the chain that the message will be sent to. + pub target_chain_id: ChainId<'static>, + /// The original event that was emitted on the origin chain. + pub connection_open_ack_event: crate::data::ConnectionOpenAck, +} + +#[queue_msg] +pub struct MakeMsgChannelOpenTry { + /// The chain id of the chain that the event was emitted on. + pub origin_chain_id: ChainId<'static>, + /// The height to generate the state proofs at. + pub origin_chain_proof_height: Height, + /// The chain id of the chain that the message will be sent to. + pub target_chain_id: ChainId<'static>, + /// The original event that was emitted on the origin chain. + pub channel_open_init_event: crate::data::ChannelOpenInit, +} + +#[queue_msg] +pub struct MakeMsgChannelOpenAck { + /// The chain id of the chain that the event was emitted on. + pub origin_chain_id: ChainId<'static>, + /// The height to generate the state proofs at. + pub origin_chain_proof_height: Height, + /// The chain id of the chain that the message will be sent to. + pub target_chain_id: ChainId<'static>, + /// The original event that was emitted on the origin chain. + pub channel_open_try_event: crate::data::ChannelOpenTry, +} + +#[queue_msg] +pub struct MakeMsgChannelOpenConfirm { + /// The chain id of the chain that the event was emitted on. + pub origin_chain_id: ChainId<'static>, + /// The height to generate the state proofs at. + pub origin_chain_proof_height: Height, + /// The chain id of the chain that the message will be sent to. + pub target_chain_id: ChainId<'static>, + /// The original event that was emitted on the origin chain. + pub channel_open_ack_event: crate::data::ChannelOpenAck, +} + +#[queue_msg] +pub struct MakeMsgRecvPacket { + /// The chain id of the chain that the event was emitted on. + pub origin_chain_id: ChainId<'static>, + /// The height to generate the state proofs at. + pub origin_chain_proof_height: Height, + /// The chain id of the chain that the message will be sent to. + pub target_chain_id: ChainId<'static>, + /// The original event that was emitted on the origin chain. + pub send_packet_event: crate::data::SendPacket, +} + +#[queue_msg] +pub struct MakeMsgAcknowledgement { + /// The chain id of the chain that the event was emitted on. + pub origin_chain_id: ChainId<'static>, + /// The height to generate the state proofs at. + pub origin_chain_proof_height: Height, + /// The chain id of the chain that the message will be sent to. + pub target_chain_id: ChainId<'static>, + /// The original event that was emitted on the origin chain. + pub write_acknowledgement_event: crate::data::WriteAcknowledgement, +} + +#[queue_msg] +pub struct WaitForHeight { + pub chain_id: ChainId<'static>, + pub height: Height, +} + +#[queue_msg] +pub struct WaitForHeightRelative { + pub chain_id: ChainId<'static>, + pub height: u64, +} + +#[queue_msg] +pub struct WaitForTimestamp { + pub chain_id: ChainId<'static>, + /// THIS IS NANOSECONDS + pub timestamp: i64, +} + +/// Wait for the client `.client_id` on `.chain_id` to trust a height >= `.height`. +#[queue_msg] +pub struct WaitForTrustedHeight { + pub chain_id: ChainId<'static>, + pub client_id: ClientId, + pub height: Height, +} + +impl HandleCall> for Call { + // #[instrument(skip_all, fields(chain_id = %self.chain_id))] + async fn handle(self, ctx: &Context) -> Result>, QueueError> { + match self { + Call::FetchBlock(FetchBlock { height, chain_id }) => { + info!(%height, "fetch_block"); + + Ok(promise( + [call(WaitForHeight { + chain_id, + height: height.increment(), + })], + [], + AggregateFetchBlockRange { + from_height: height, + }, + )) + } + + Call::FetchBlockRange(FetchBlockRange { + chain_id, + from_height, + to_height, + }) => { + info!(%from_height, %to_height, "fetch_block_range"); + + Ok(conc([ + ctx.chain_module(&chain_id) + .map_err(error_object_to_queue_error)? + .fetch_block_range(from_height, to_height) + .await + .map_err(json_rpc_error_to_queue_error)?, + call(FetchBlock { + chain_id, + height: to_height, + }), + ])) + } + + // TODO: This is currently unused, but there is a wait that uses this call that needs to + // be refactored to be an aggregation using this + Call::UnfinalizedTrustedClientState(FetchUnfinalizedTrustedClientState { + chain_id: _, + client_id: _, + }) => { + // let client_state = ctx + // .chain_module(&chain_id) + // ? + // .query_raw_unfinalized_trusted_client_state(client_id) + // .await + // .map_err(json_rpc_error_to_queue_error)?; + + // let decoded = ctx + // .client_module(&client_state.client_type, &client_state.ibc_interface) + // ? + // .decode_client_state_meta(client_state.bytes, client_state.ibc_interface) + // .await + // .map_err(json_rpc_error_to_queue_error)?; + + // Ok(data(id( + // self.chain_id, + // UnfinalizedTrustedClientState { + // height, + // client_state, + // }, + // ))) + todo!() + } + + Call::MakeMsgConnectionOpenTry(MakeMsgConnectionOpenTry { + origin_chain_id, + origin_chain_proof_height, + target_chain_id, + connection_open_init_event, + }) => { + let ConnectionHandshakeStateAndProofs { + connection_state, + encoded_client_state, + encoded_client_state_proof, + encoded_consensus_state_proof, + encoded_connection_state_proof, + consensus_height, + } = mk_connection_handshake_state_and_proofs( + ctx, + origin_chain_id, + target_chain_id, + connection_open_init_event.client_id.clone(), + connection_open_init_event.counterparty_client_id.clone(), + connection_open_init_event.connection_id.clone(), + origin_chain_proof_height, + ) + .await + .map_err(error_object_to_queue_error)?; + + Ok(data(IbcMessage::from(MsgConnectionOpenTry { + client_id: connection_open_init_event.counterparty_client_id, + client_state: encoded_client_state, + counterparty: connection::counterparty::Counterparty { + client_id: connection_open_init_event.client_id, + connection_id: Some(connection_open_init_event.connection_id), + prefix: MerklePrefix { + // TODO: Make configurable + key_prefix: b"ibc".to_vec(), + }, + }, + // TODO: Make configurable + delay_period: DELAY_PERIOD, + counterparty_versions: connection_state.versions, + proof_height: origin_chain_proof_height, + proof_init: encoded_connection_state_proof, + proof_client: encoded_client_state_proof, + proof_consensus: encoded_consensus_state_proof, + consensus_height, + }))) + } + + Call::MakeMsgConnectionOpenAck(MakeMsgConnectionOpenAck { + origin_chain_id, + origin_chain_proof_height, + target_chain_id, + connection_open_try_event, + }) => { + let ConnectionHandshakeStateAndProofs { + connection_state, + encoded_client_state, + encoded_client_state_proof, + encoded_consensus_state_proof, + encoded_connection_state_proof, + consensus_height, + } = mk_connection_handshake_state_and_proofs( + ctx, + origin_chain_id, + target_chain_id, + connection_open_try_event.client_id, + connection_open_try_event.counterparty_client_id, + connection_open_try_event.connection_id.clone(), + origin_chain_proof_height, + ) + .await + .map_err(error_object_to_queue_error)?; + + Ok(queue_msg::data(IbcMessage::from(MsgConnectionOpenAck { + connection_id: connection_open_try_event.counterparty_connection_id, + counterparty_connection_id: connection_open_try_event.connection_id, + client_state: encoded_client_state, + version: connection_state.versions[0].clone(), + proof_height: origin_chain_proof_height, + proof_try: encoded_connection_state_proof, + proof_client: encoded_client_state_proof, + proof_consensus: encoded_consensus_state_proof, + consensus_height, + }))) + } + + Call::MakeMsgConnectionOpenConfirm(MakeMsgConnectionOpenConfirm { + origin_chain_id, + origin_chain_proof_height, + target_chain_id, + connection_open_ack_event, + }) => { + // info of the client on the target chain that will verify the storage + // proofs + let target_client_info = ctx + .rpc_server + // counterparty_client_id from open_try is the client on the target chain + .client_info( + &target_chain_id, + connection_open_ack_event.counterparty_client_id.clone(), + ) + .await + .map_err(error_object_to_queue_error)?; + + // proof of connection_state, encoded for the client on the target chain + // this is encoded via the client module for the client on the origin chain + // (the chain the event was emitted on) + let connection_proof = ctx + .rpc_server + .encode_proof( + &target_client_info.client_type, + &target_client_info.ibc_interface, + ctx.rpc_server + .query_ibc_proof( + &origin_chain_id, + origin_chain_proof_height, + ConnectionPath { + connection_id: connection_open_ack_event.connection_id.clone(), + } + .into(), + ) + .await + .map_err(error_object_to_queue_error)? + .proof, + ) + .await + .map_err(error_object_to_queue_error)?; + + Ok(queue_msg::data(IbcMessage::from( + MsgConnectionOpenConfirm { + connection_id: connection_open_ack_event.counterparty_connection_id, + proof_height: origin_chain_proof_height, + proof_ack: connection_proof, + }, + ))) + } + + Call::MakeMsgChannelOpenTry(MakeMsgChannelOpenTry { + origin_chain_id, + origin_chain_proof_height, + target_chain_id, + channel_open_init_event: event, + }) => { + let origin_channel_path = ChannelEndPath { + port_id: event.port_id.clone(), + channel_id: event.channel_id.clone(), + }; + + let origin_channel = ctx + .rpc_server + .query_ibc_state_typed( + &origin_chain_id, + origin_chain_proof_height, + origin_channel_path.clone(), + ) + .await + .map_err(json_rpc_error_to_queue_error)?; + + let proof_init = ctx + .rpc_server + .query_ibc_proof( + &origin_chain_id, + origin_chain_proof_height, + origin_channel_path.into(), + ) + .await + .map_err(error_object_to_queue_error)?; + + let client_info = ctx + .rpc_server + .client_info(&target_chain_id, event.connection.counterparty.client_id) + .await + .map_err(error_object_to_queue_error)?; + + let encoded_proof_init = ctx + .rpc_server + .encode_proof( + &client_info.client_type, + &client_info.ibc_interface, + proof_init.proof, + ) + .await + .map_err(error_object_to_queue_error)?; + + Ok(data(IbcMessage::from(MsgChannelOpenTry { + port_id: event.counterparty_port_id, + channel: Channel { + state: channel::state::State::Tryopen, + ordering: origin_channel + .state + .ok_or(QueueError::Fatal("channel must exist".into()))? + .ordering, + counterparty: channel::counterparty::Counterparty { + port_id: event.port_id, + channel_id: event.channel_id.to_string(), + }, + connection_hops: vec![event.connection.counterparty.connection_id.unwrap()], + version: event.version.clone(), + }, + counterparty_version: event.version, + proof_init: encoded_proof_init, + proof_height: origin_chain_proof_height, + }))) + } + + Call::MakeMsgChannelOpenAck(MakeMsgChannelOpenAck { + origin_chain_id, + origin_chain_proof_height, + target_chain_id, + channel_open_try_event, + }) => { + let origin_channel_path = ChannelEndPath { + port_id: channel_open_try_event.port_id.clone(), + channel_id: channel_open_try_event.channel_id.clone(), + }; + + let proof_try = ctx + .rpc_server + .query_ibc_proof( + &origin_chain_id, + origin_chain_proof_height, + origin_channel_path.into(), + ) + .await + .map_err(error_object_to_queue_error)?; + + let client_info = ctx + .rpc_server + .client_info( + &target_chain_id, + channel_open_try_event.connection.counterparty.client_id, + ) + .await + .map_err(error_object_to_queue_error)?; + + let encoded_proof_try = ctx + .rpc_server + .encode_proof( + &client_info.client_type, + &client_info.ibc_interface, + proof_try.proof, + ) + .await + .map_err(error_object_to_queue_error)?; + + Ok(data(IbcMessage::from(MsgChannelOpenAck { + port_id: channel_open_try_event.counterparty_port_id, + channel_id: channel_open_try_event.counterparty_channel_id, + counterparty_channel_id: channel_open_try_event.channel_id, + counterparty_version: channel_open_try_event.version, + proof_try: encoded_proof_try, + proof_height: origin_chain_proof_height, + }))) + } + + Call::MakeMsgChannelOpenConfirm(MakeMsgChannelOpenConfirm { + origin_chain_id, + origin_chain_proof_height, + target_chain_id, + channel_open_ack_event, + }) => { + let origin_channel_path = ChannelEndPath { + port_id: channel_open_ack_event.port_id.clone(), + channel_id: channel_open_ack_event.channel_id.clone(), + }; + + let proof_ack = ctx + .rpc_server + .query_ibc_proof( + &origin_chain_id, + origin_chain_proof_height, + origin_channel_path.into(), + ) + .await + .map_err(error_object_to_queue_error)?; + + let client_info = ctx + .rpc_server + .client_info( + &target_chain_id, + channel_open_ack_event.connection.counterparty.client_id, + ) + .await + .map_err(error_object_to_queue_error)?; + + let encoded_proof_ack = ctx + .rpc_server + .encode_proof( + &client_info.client_type, + &client_info.ibc_interface, + proof_ack.proof, + ) + .await + .map_err(error_object_to_queue_error)?; + + Ok(queue_msg::data(IbcMessage::from(MsgChannelOpenConfirm { + port_id: channel_open_ack_event.counterparty_port_id, + channel_id: channel_open_ack_event.counterparty_channel_id, + proof_ack: encoded_proof_ack, + proof_height: origin_chain_proof_height, + }))) + } + + Call::MakeMsgRecvPacket(msg) => make_msg_recv_packet(ctx, msg).await, + + Call::MakeMsgAcknowledgement(msg) => make_msg_acknowledgement(ctx, msg).await, + + // Fetch::UpdateHeaders(FetchUpdateHeaders { + // chain_id, + // counterparty_chain_id, + // counterparty_client_id, + // update_from, + // update_to, + // }) => Ok(aggregate( + // [ + // ctx.consensus_module(&chain_id)? + // .fetch_update_headers(update_from, update_to) + // .await + // .map_err(json_rpc_error_to_queue_error)?, + // // REVIEW: If we notice that this causes too much latency, it can be + // pre-fetched and put into the data section. I would prefer to keep all fetch messages + // "single-purpose" if possible though. fetch(FetchClientInfo { + // chain_id: counterparty_chain_id.clone(), + // client_id: counterparty_client_id.clone(), + // }), + // ], + // [], + // AggregateMsgUpdateClientsFromOrderedHeaders { + // counterparty_chain_id, + // counterparty_client_id, + // }, + // )), + Call::UpdateHeaders(FetchUpdateHeaders { + chain_id, + counterparty_chain_id, + update_from, + update_to, + }) => { + info!( + %chain_id, + %counterparty_chain_id, + %update_from, + %update_to, + "fetching update headers", + ); + if update_from >= update_to { + Err(QueueError::Fatal( + format!( + "update range is invalid ({update_to} >= {update_to}), \ + chain_id: {chain_id}, counterparty_chain_id: \ + {counterparty_chain_id}" + ) + .into(), + )) + } else { + ctx.consensus_module(&chain_id) + .map_err(error_object_to_queue_error)? + .fetch_update_headers(update_from, update_to, counterparty_chain_id) + .await + .map_err(json_rpc_error_to_queue_error) + } + } + + Call::MakeMsgCreateClient(MakeMsgCreateClient { + chain_id, + height, + metadata, + counterparty_chain_id, + ibc_interface, + }) => { + make_msg_create_client( + ctx, + counterparty_chain_id, + height, + chain_id, + ibc_interface, + metadata, + ) + .await + } + + // TODO: Replace this with an aggregation + Call::WaitForHeight(WaitForHeight { chain_id, height }) => { + let chain_height = ctx + .rpc_server + .query_latest_height(&chain_id) + .await + .map_err(error_object_to_queue_error)?; + + if chain_height.revision_number != height.revision_number { + return Err(QueueError::Fatal( + format!( + "revision number mismatch, \ + chain_height: {chain_height}, height: {height}" + ) + .into(), + )); + } + + debug!("latest height is {chain_height}, waiting for {height}"); + + if chain_height.revision_height >= height.revision_height { + Ok(data(LatestHeight { + chain_id, + height: chain_height, + })) + } else { + Ok(seq([ + defer(now() + 1), + call(WaitForHeight { chain_id, height }), + ])) + } + } + // REVIEW: Perhaps remove, unused + Call::WaitForHeightRelative(WaitForHeightRelative { chain_id, height }) => { + let chain_height = ctx + .rpc_server + .query_latest_height(&chain_id) + .await + .map_err(error_object_to_queue_error)?; + + Ok(call(WaitForHeight { + chain_id, + height: Height { + revision_number: chain_height.revision_number, + revision_height: chain_height.revision_height + height, + }, + })) + } + + Call::WaitForTimestamp(WaitForTimestamp { + chain_id, + timestamp, + }) => { + let chain_timestamp = ctx + .rpc_server + .query_latest_timestamp(&chain_id) + .await + .map_err(error_object_to_queue_error)?; + + if chain_timestamp >= timestamp { + info!(%chain_id, %timestamp, %chain_timestamp, "timestamp reached"); + Ok(noop()) + } else { + debug!(%chain_id, %timestamp, %chain_timestamp, "timestamp not yet reached"); + Ok(seq([ + // REVIEW: Defer until `now + chain.block_time()`? Would require a new + // method on chain + defer(now() + 1), + call(WaitForTimestamp { + chain_id, + timestamp, + }), + ])) + } + } + + Call::WaitForTrustedHeight(WaitForTrustedHeight { + chain_id, + client_id, + height, + }) => { + let client_state = ctx + .chain_module::(&chain_id) + .map_err(error_object_to_queue_error)? + .query_raw_unfinalized_trusted_client_state(client_id.clone()) + .await + .map_err(json_rpc_error_to_queue_error)?; + + let trusted_client_state_meta = ctx + .rpc_server + .decode_client_state_meta( + &client_state.client_type, + &client_state.ibc_interface, + client_state.bytes.into(), + ) + .await + .map_err(error_object_to_queue_error)?; + + if trusted_client_state_meta.height.revision_height >= height.revision_height { + debug!( + "client height reached ({} >= {})", + trusted_client_state_meta.height, height + ); + + Ok(noop()) + } else { + Ok(seq([ + // REVIEW: Defer until `now + counterparty_chain.block_time()`? Would + // require a new method on chain + defer(now() + 1), + call(WaitForTrustedHeight { + chain_id, + client_id, + height, + }), + ])) + } + } + Call::Plugin(PluginMessage { plugin, message }) => Ok(ctx + .plugin(plugin)? + .call(message) + .await + .map_err(json_rpc_error_to_queue_error)?), + } + } +} + +#[instrument( + skip_all, + fields( + %origin_chain_id, + %origin_chain_proof_height, + %target_chain_id, + %send_packet_event.packet.sequence, + %send_packet_event.packet.source_channel.port_id, + %send_packet_event.packet.source_channel.channel_id, + %send_packet_event.packet.destination_channel.port_id, + %send_packet_event.packet.destination_channel.channel_id, + %send_packet_event.packet.channel_ordering, + %send_packet_event.packet.timeout_height, + %send_packet_event.packet.timeout_timestamp, + ) +)] +async fn make_msg_recv_packet( + ctx: &Context, + MakeMsgRecvPacket { + origin_chain_id, + origin_chain_proof_height, + target_chain_id, + send_packet_event, + }: MakeMsgRecvPacket, +) -> Result>, QueueError> { + let target_chain_latest_height = ctx + .rpc_server + .query_latest_height(&target_chain_id) + .await + .map_err(error_object_to_queue_error)?; + + let commitment = ctx + .rpc_server + .query_ibc_state_typed( + &target_chain_id, + target_chain_latest_height, + ReceiptPath { + port_id: send_packet_event.packet.destination_channel.port_id.clone(), + channel_id: send_packet_event + .packet + .destination_channel + .channel_id + .clone(), + sequence: send_packet_event.packet.sequence, + }, + ) + .await + .map_err(json_rpc_error_to_queue_error)? + .state; + + if commitment { + info!("packet already received on the target chain"); + return Ok(noop()); + } + + let proof_commitment = ctx + .rpc_server + .query_ibc_proof( + &origin_chain_id, + origin_chain_proof_height, + CommitmentPath { + port_id: send_packet_event.packet.source_channel.port_id.clone(), + channel_id: send_packet_event.packet.source_channel.channel_id.clone(), + sequence: send_packet_event.packet.sequence, + } + .into(), + ) + .await + .map_err(error_object_to_queue_error)? + .proof; + + let client_info = ctx + .rpc_server + .client_info( + &target_chain_id, + send_packet_event + .packet + .destination_channel + .connection + .client_id, + ) + .await + .map_err(error_object_to_queue_error)?; + + let encoded_proof_commitment = ctx + .rpc_server + .encode_proof( + &client_info.client_type, + &client_info.ibc_interface, + proof_commitment, + ) + .await + .map_err(error_object_to_queue_error)?; + + Ok(queue_msg::data(IbcMessage::from(MsgRecvPacket { + packet: channel::packet::Packet { + sequence: send_packet_event.packet.sequence, + source_port: send_packet_event.packet.source_channel.port_id, + source_channel: send_packet_event.packet.source_channel.channel_id, + destination_port: send_packet_event.packet.destination_channel.port_id, + destination_channel: send_packet_event.packet.destination_channel.channel_id, + data: send_packet_event.packet_data, + timeout_height: send_packet_event.packet.timeout_height, + timeout_timestamp: send_packet_event.packet.timeout_timestamp, + }, + proof_commitment: encoded_proof_commitment, + proof_height: origin_chain_proof_height, + }))) +} + +#[instrument( + skip_all, + fields( + %origin_chain_id, + %origin_chain_proof_height, + %target_chain_id, + %write_acknowledgement_event.packet.sequence, + %write_acknowledgement_event.packet.source_channel.port_id, + %write_acknowledgement_event.packet.source_channel.channel_id, + %write_acknowledgement_event.packet.destination_channel.port_id, + %write_acknowledgement_event.packet.destination_channel.channel_id, + %write_acknowledgement_event.packet.channel_ordering, + %write_acknowledgement_event.packet.timeout_height, + %write_acknowledgement_event.packet.timeout_timestamp, + ) +)] +async fn make_msg_acknowledgement( + ctx: &Context, + MakeMsgAcknowledgement { + origin_chain_id, + origin_chain_proof_height, + target_chain_id, + write_acknowledgement_event, + }: MakeMsgAcknowledgement, +) -> Result>, QueueError> { + let target_chain_latest_height = ctx + .rpc_server + .query_latest_height(&target_chain_id) + .await + .map_err(error_object_to_queue_error)?; + + let commitment = ctx + .rpc_server + .query_ibc_state_typed( + &target_chain_id, + target_chain_latest_height, + CommitmentPath { + port_id: write_acknowledgement_event + .packet + .source_channel + .port_id + .clone(), + channel_id: write_acknowledgement_event + .packet + .source_channel + .channel_id + .clone(), + sequence: write_acknowledgement_event.packet.sequence, + }, + ) + .await + .map_err(json_rpc_error_to_queue_error)? + .state; + + if commitment.is_none() { + info!("packet already acknowledged on the target chain"); + return Ok(noop()); + } + + let proof_acked = ctx + .rpc_server + .query_ibc_proof( + &origin_chain_id, + origin_chain_proof_height, + AcknowledgementPath { + port_id: write_acknowledgement_event + .packet + .destination_channel + .port_id + .clone(), + channel_id: write_acknowledgement_event + .packet + .destination_channel + .channel_id + .clone(), + sequence: write_acknowledgement_event.packet.sequence, + } + .into(), + ) + .await + .map_err(error_object_to_queue_error)? + .proof; + + let client_info = ctx + .rpc_server + .client_info( + &target_chain_id, + write_acknowledgement_event + .packet + .source_channel + .connection + .client_id, + ) + .await + .map_err(error_object_to_queue_error)?; + + let encoded_proof_acked = ctx + .rpc_server + .encode_proof( + &client_info.client_type, + &client_info.ibc_interface, + proof_acked, + ) + .await + .map_err(error_object_to_queue_error)?; + + Ok(queue_msg::data(IbcMessage::from(MsgAcknowledgement { + packet: channel::packet::Packet { + sequence: write_acknowledgement_event.packet.sequence, + source_port: write_acknowledgement_event.packet.source_channel.port_id, + source_channel: write_acknowledgement_event.packet.source_channel.channel_id, + destination_port: write_acknowledgement_event + .packet + .destination_channel + .port_id, + destination_channel: write_acknowledgement_event + .packet + .destination_channel + .channel_id, + data: write_acknowledgement_event.packet_data, + timeout_height: write_acknowledgement_event.packet.timeout_height, + timeout_timestamp: write_acknowledgement_event.packet.timeout_timestamp, + }, + acknowledgement: write_acknowledgement_event.packet_ack, + proof_acked: encoded_proof_acked, + proof_height: origin_chain_proof_height, + }))) +} + +#[instrument( + skip_all, + fields( + %counterparty_chain_id, + %height, + %chain_id, + %ibc_interface, + %metadata, + ) + )] +async fn make_msg_create_client( + ctx: &Context, + counterparty_chain_id: ChainId<'static>, + height: QueryHeight, + chain_id: ChainId<'static>, + ibc_interface: IbcInterface<'_>, + metadata: Value, +) -> Result>, QueueError> { + let height = ctx + .rpc_server + .query_latest_height(&counterparty_chain_id) + .await + .map_err(error_object_to_queue_error)?; + + let counterparty_consensus_module = ctx + .consensus_module::(&counterparty_chain_id) + .map_err(error_object_to_queue_error)?; + + let self_client_state = counterparty_consensus_module + .self_client_state(height) + .await + .map_err(json_rpc_error_to_queue_error)?; + trace!(%self_client_state); + + let self_consensus_state = counterparty_consensus_module + .self_consensus_state(height) + .await + .map_err(json_rpc_error_to_queue_error)?; + trace!(%self_consensus_state); + + let client_type = counterparty_consensus_module + .consensus_info() + .await + .map_err(json_rpc_error_to_queue_error)? + .client_type; + + let client_module = ctx + .client_module::(&client_type, &ibc_interface) + .map_err(error_object_to_queue_error)?; + + Ok(data(WithChainId { + chain_id, + message: IbcMessage::from(MsgCreateClientData { + msg: MsgCreateClient { + client_state: client_module + .encode_client_state(self_client_state, metadata) + .await + .map_err(json_rpc_error_to_queue_error)? + .0, + consensus_state: client_module + .encode_consensus_state(self_consensus_state) + .await + .map_err(json_rpc_error_to_queue_error)? + .0, + }, + client_type, + }), + })) +} + +/// Used to fetch and construct the state and proofs for +/// MsgConnectionOpenTry/Ack. +#[instrument( + skip_all, + fields( + %origin_chain_id, + %target_chain_id, + %client_id, + %counterparty_client_id, + %connection_id, + %origin_chain_proof_height, + ) +)] +async fn mk_connection_handshake_state_and_proofs( + ctx: &Context, + origin_chain_id: ChainId<'static>, + target_chain_id: ChainId<'static>, + client_id: ClientId, + counterparty_client_id: ClientId, + connection_id: ConnectionId, + origin_chain_proof_height: Height, +) -> RpcResult { + // info of the client on the target chain that will verify the storage + // proofs + let target_client_info = ctx + .rpc_server + // counterparty_client_id from open_init/try is the client on the target chain + .client_info(&target_chain_id, counterparty_client_id.clone()) + .await?; + + debug!( + %counterparty_client_id, + %target_client_info.client_type, + %target_client_info.ibc_interface, + %target_client_info.metadata, + ); + + // info of the client on the origin chain, this is used to decode the stored + // client state + let origin_client_info = ctx + .rpc_server + // client_id from open_init/try is the client on the origin chain + .client_info(&origin_chain_id, client_id.clone()) + .await?; + + debug!( + %client_id, + %origin_client_info.client_type, + %origin_client_info.ibc_interface, + %origin_client_info.metadata, + ); + + // client state of the destination on the source + let client_state_path = ClientStatePath { + client_id: client_id.clone(), + }; + let client_state = ctx + .rpc_server + .query_ibc_state_typed( + &origin_chain_id, + origin_chain_proof_height, + client_state_path, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state; + + debug!(%client_state); + + // the client state meta of the target chain on the origin chain, that + // contains a trusted height of the destination TODO: maybe assert the + // chain_id is as expected? + let client_meta = ctx + .rpc_server + .decode_client_state_meta( + &origin_client_info.client_type, + &origin_client_info.ibc_interface, + client_state.0.clone(), + ) + .await?; + + debug!( + %client_meta.height, + %client_meta.chain_id, + ); + + let reencoded_client_state = ctx + .client_module::( + &target_client_info.client_type, + &target_client_info.ibc_interface, + )? + .reencode_counterparty_client_state(client_state.clone(), origin_client_info.client_type) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + debug!(%reencoded_client_state); + + // the connection end as stored by the origin chain after open_init/try + let connection_state = ctx + .rpc_server + .query_ibc_state_typed( + &origin_chain_id, + origin_chain_proof_height, + ConnectionPath { + connection_id: connection_id.clone(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or(ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + "connection must exist", + None::<()>, + ))?; + debug!( + connection_state = %serde_json::to_string(&connection_state).unwrap(), + ); + + // proof of connection_state, encoded for the client on the target chain + let connection_proof = ctx + .rpc_server + .query_ibc_proof( + &origin_chain_id, + origin_chain_proof_height, + ConnectionPath { + connection_id: connection_id.clone(), + } + .into(), + ) + .await? + .proof; + debug!(%connection_proof); + + let encoded_connection_state_proof = ctx + .rpc_server + .encode_proof( + &target_client_info.client_type, + &target_client_info.ibc_interface, + connection_proof, + ) + .await?; + debug!(encoded_connection_state_proof = %Hex(&encoded_connection_state_proof)); + + let client_state_proof = ctx + .rpc_server + .query_ibc_proof( + &origin_chain_id, + origin_chain_proof_height, + ClientStatePath { + client_id: client_id.clone(), + } + .into(), + ) + .await? + .proof; + debug!(%client_state_proof); + + let encoded_client_state_proof = ctx + .rpc_server + .encode_proof( + &target_client_info.client_type, + &target_client_info.ibc_interface, + client_state_proof, + ) + .await?; + debug!(encoded_client_state_proof = %Hex(&encoded_client_state_proof)); + + let consensus_state_proof = ctx + .rpc_server + .query_ibc_proof( + &origin_chain_id, + origin_chain_proof_height, + ClientConsensusStatePath { + client_id: client_id.clone(), + height: client_meta.height, + } + .into(), + ) + .await? + .proof; + debug!(%consensus_state_proof); + + let encoded_consensus_state_proof = ctx + .rpc_server + .encode_proof( + &target_client_info.client_type, + &target_client_info.ibc_interface, + consensus_state_proof, + ) + .await?; + debug!(encoded_consensus_state_proof = %Hex(&encoded_consensus_state_proof)); + + Ok(ConnectionHandshakeStateAndProofs { + connection_state, + encoded_client_state: reencoded_client_state.0, + encoded_client_state_proof, + encoded_consensus_state_proof, + encoded_connection_state_proof, + consensus_height: client_meta.height, + }) +} + +struct ConnectionHandshakeStateAndProofs { + connection_state: ConnectionEnd, + /// The raw client state, exactly as stored in the counterparty's state. + encoded_client_state: Vec, + encoded_client_state_proof: Vec, + encoded_consensus_state_proof: Vec, + encoded_connection_state_proof: Vec, + consensus_height: Height, +} diff --git a/lib/voyager-message/src/callback.rs b/lib/voyager-message/src/callback.rs new file mode 100644 index 0000000000..15753ac9ba --- /dev/null +++ b/lib/voyager-message/src/callback.rs @@ -0,0 +1,136 @@ +use std::collections::VecDeque; + +use enumorph::Enumorph; +use frunk::{hlist_pat, HList}; +use futures::{stream, StreamExt, TryFutureExt, TryStreamExt}; +use macros::apply; +use queue_msg::{ + aggregation::{do_callback, DoCallback, HListTryFromIterator}, + call, queue_msg, HandleCallback, Op, QueueError, +}; +use serde_json::Value; +use unionlabs::{ + ibc::core::client::{height::Height, msg_update_client::MsgUpdateClient}, + id::ClientId, + traits::Member, +}; + +use crate::{ + call::FetchBlockRange, + data::{ClientInfo, Data, LatestHeight, OrderedHeaders, OrderedMsgUpdateClients}, + error_object_to_queue_error, json_rpc_error_to_queue_error, + module::{ClientModuleClient, QueueInteractionsClient}, + top_level_identifiable_enum, ChainId, Context, PluginMessage, VoyagerMessage, +}; + +#[apply(top_level_identifiable_enum)] +#[queue_msg] +#[derive(Enumorph)] +pub enum Callback { + // originally block + FetchBlockRange(AggregateFetchBlockRange), + + AggregateMsgUpdateClientsFromOrderedHeaders(AggregateMsgUpdateClientsFromOrderedHeaders), + + Plugin(PluginMessage), +} + +impl HandleCallback> for Callback { + // #[instrument(skip_all, fields(chain_id = %self.chain_id))] + async fn handle( + self, + ctx: &Context, + data: VecDeque>, + ) -> Result>, QueueError> { + match self { + Callback::FetchBlockRange(aggregate) => Ok(do_callback(aggregate, data)), + + Callback::AggregateMsgUpdateClientsFromOrderedHeaders( + AggregateMsgUpdateClientsFromOrderedHeaders { + chain_id, + counterparty_client_id, + }, + ) => { + let Ok(hlist_pat![OrderedHeaders { headers }]) = + HListTryFromIterator::try_from_iter(data) + else { + panic!("bad data") + }; + + let ClientInfo { + client_type, + ibc_interface, + .. + } = ctx + .rpc_server + .client_info(&chain_id, counterparty_client_id.clone()) + .await + .map_err(error_object_to_queue_error)?; + + let client_module = ctx + .client_module::(&client_type, &ibc_interface) + .map_err(error_object_to_queue_error)?; + + Ok(queue_msg::data(OrderedMsgUpdateClients { + // REVIEW: Use FuturesOrdered here? + updates: stream::iter(headers.into_iter()) + .then(|(meta, header)| { + client_module + .encode_header(header) + .map_ok(|encoded_header| { + ( + meta, + MsgUpdateClient { + client_id: counterparty_client_id.clone(), + client_message: encoded_header.0, + }, + ) + }) + .map_err(json_rpc_error_to_queue_error) + }) + .try_collect::>() + .await?, + })) + } + Callback::Plugin(PluginMessage { plugin, message }) => Ok(ctx + .plugin(&plugin)? + .callback(message, data) + .await + .map_err(json_rpc_error_to_queue_error)?), + } + } +} + +#[queue_msg] +pub struct AggregateFetchBlockRange { + pub from_height: Height, +} + +impl DoCallback> + for AggregateFetchBlockRange +{ + type Params = HList![LatestHeight]; + + fn call( + Self { from_height }: Self, + hlist_pat![LatestHeight { + chain_id, + height: to_height + }]: Self::Params, + ) -> Op> { + assert!(to_height.revision_height > from_height.revision_height); + + call(FetchBlockRange { + chain_id, + from_height, + to_height, + }) + } +} + +/// Required data: [`OrderedHeaders`] +#[queue_msg] +pub struct AggregateMsgUpdateClientsFromOrderedHeaders { + pub chain_id: ChainId<'static>, + pub counterparty_client_id: ClientId, +} diff --git a/lib/voyager-message/src/context.rs b/lib/voyager-message/src/context.rs new file mode 100644 index 0000000000..52ed11c9ce --- /dev/null +++ b/lib/voyager-message/src/context.rs @@ -0,0 +1,671 @@ +use std::{collections::HashMap, process::Stdio, sync::Arc, time::Duration}; + +use futures::{stream::FuturesUnordered, Future, StreamExt, TryStreamExt}; +use jsonrpsee::{ + core::RpcResult, + types::{ErrorObject, ErrorObjectOwned}, +}; +use macros::model; +use queue_msg::{BoxDynError, QueueError}; +use serde_json::Value; +use tokio::time::sleep; +use tokio_util::sync::CancellationToken; +use tracing::{debug, debug_span, error, info, instrument, warn, Instrument}; +use unionlabs::{ethereum::keccak256, traits::Member, ErrorReporter}; + +use crate::{ + module::{ + ChainModuleClient, ChainModuleInfo, ClientModuleClient, ClientModuleInfo, + ConsensusModuleClient, ConsensusModuleInfo, ModuleInfo, ModuleKindInfo, PluginModuleInfo, + QueueInteractionsClient, + }, + rpc::{server::Server, VoyagerRpcServer}, + ChainId, ClientType, IbcInterface, FATAL_JSONRPC_ERROR_CODE, +}; + +pub const INVALID_CONFIG_EXIT_CODE: u8 = 13; +pub const STARTUP_ERROR_EXIT_CODE: u8 = 14; + +#[derive(Debug)] +pub struct Context { + pub rpc_server: Server, + + plugin_modules: HashMap, + + interest_filters: HashMap, + + cancellation_token: CancellationToken, + // module_servers: Vec, +} + +#[derive(Debug, Clone)] +pub struct Modules { + /// map of chain id to chain module. + chain_modules: HashMap, ModuleRpcClient>, + + /// map of chain id to consensus module. + consensus_modules: HashMap, ModuleRpcClient>, + + /// map of client type to ibc interface to client module. + client_modules: HashMap, HashMap, ModuleRpcClient>>, +} + +impl queue_msg::Context for Context { + fn tags(&self) -> Vec<&str> { + self.interest_filters.keys().map(|s| s.as_str()).collect() + } +} + +#[derive(macros::Debug, Clone)] +pub struct ModuleRpcClient { + #[debug(skip)] + client: reconnecting_jsonrpc_ws_client::Client, + #[allow(dead_code)] + name: String, +} + +impl ModuleRpcClient { + fn new(name: &str) -> Self { + let socket = Self::make_socket_path(name); + + let client = reconnecting_jsonrpc_ws_client::Client::new({ + // NOTE: This needs to be leaked because the return type of the .build() method below captures the lifetime of the `name` parameter(?) + let socket: &'static str = Box::leak(socket.clone().into_boxed_str()); + let name = name.to_owned(); + move || { + async move { + debug!("connecting to socket at {socket}"); + reth_ipc::client::IpcClientBuilder::default() + .build(socket) + .await + } + .instrument(debug_span!("module_ipc_client", %name)) + } + }); + + Self { + client, + name: name.to_owned(), + } + } + + fn make_socket_path(name: &str) -> String { + format!( + "/tmp/voyager-to-module-{}.sock", + keccak256(name).to_string_unprefixed() + ) + } + + pub fn client(&self) -> &impl jsonrpsee::core::client::ClientT { + &self.client + } +} + +async fn module_rpc_server( + name: &str, + server: Server, +) -> Result, BoxDynError> { + let socket = make_module_rpc_server_socket_path(name); + let rpc_server = reth_ipc::server::Builder::default().build(socket.clone()); + + let server = rpc_server.start(server.into_rpc()).await?; + + Ok(server + .stopped() + .instrument(debug_span!("module_rpc_server", %name))) +} + +fn make_module_rpc_server_socket_path(name: &str) -> String { + format!( + "/tmp/module-to-voyager-{}.sock", + keccak256(name).to_string_unprefixed() + ) +} + +#[model] +#[derive(Hash)] +pub struct ModuleConfig { + pub path: String, + pub config: Value, + #[serde(default = "default_enabled")] + pub enabled: bool, +} + +fn default_enabled() -> bool { + true +} + +impl Context { + #[instrument(name = "context_new", skip_all)] + pub async fn new(module_configs: Vec) -> Result { + let cancellation_token = CancellationToken::new(); + + let mut modules = Modules { + chain_modules: Default::default(), + client_modules: Default::default(), + consensus_modules: Default::default(), + }; + let mut plugin_modules = HashMap::default(); + // let mut module_servers = Vec::default(); + let mut interest_filters = HashMap::default(); + + let main_rpc_server = Server::new(); + + let module_configs = module_configs + .into_iter() + .filter(|module_config| { + if !module_config.enabled { + info!(module_path = %module_config.path, "module is not enabled, skipping"); + false + } else { + true + } + }) + .collect::>(); + + info!("fetching module info"); + + let module_configs = module_configs + .into_iter() + .map(|module_config| { + let server = main_rpc_server.clone(); + async move { + let module_info = get_module_info(&module_config)?; + + info!("starting rpc server for module {}", module_info.name); + tokio::spawn(module_rpc_server(&module_info.name, server).await?); + + Ok::<_, BoxDynError>((module_config, module_info)) + } + }) + .collect::>() + .try_collect::>() + .await?; + + for (module_config, ModuleInfo { name, kind }) in module_configs { + info!("registering module {name}"); + + // tokio::spawn(module_rpc_server(&name, main_rpc_server.clone()).await?); + + tokio::spawn(run_module( + name.clone(), + module_config.clone(), + cancellation_token.clone(), + )); + + let rpc_client = ModuleRpcClient::new(&name); + + plugin_modules.insert(name.clone(), rpc_client.clone()); + + match kind { + ModuleKindInfo::Plugin(PluginModuleInfo { interest_filter }) => { + info!( + %name, + "registered plugin module" + ); + + interest_filters.insert(name.clone(), interest_filter); + } + ModuleKindInfo::Chain(ChainModuleInfo { chain_id }) => { + let prev = modules.chain_modules.insert(chain_id.clone(), rpc_client); + + if prev.is_some() { + return Err(format!( + "multiple chain modules configured for chain id `{chain_id}`" + ) + .into()); + } + + info!( + %name, + %chain_id, + "registered chain module" + ); + } + ModuleKindInfo::Client(ClientModuleInfo { + client_type, + ibc_interface, + }) => { + let prev = modules + .client_modules + .entry(client_type.clone()) + .or_default() + .insert(ibc_interface.clone(), rpc_client.clone()); + + if prev.is_some() { + return Err(format!( + "multiple client modules configured for \ + client type `{client_type}` and IBC \ + interface `{ibc_interface}`", + ) + .into()); + } + + info!( + %name, + %client_type, + %ibc_interface, + "registered client module" + ); + } + ModuleKindInfo::Consensus(ConsensusModuleInfo { + chain_id, + client_type, + }) => { + let prev = modules + .consensus_modules + .insert(chain_id.clone(), rpc_client.clone()); + + if prev.is_some() { + return Err(format!( + "multiple consensus modules configured for chain id `{chain_id}`" + ) + .into()); + } + + info!( + %name, + %chain_id, + %client_type, + "registered consensus module" + ); + } + } + } + + main_rpc_server.start(Arc::new(modules)); + + info!("checking for plugin health..."); + + { + let mut futures = plugin_modules + .iter() + .map(|(name, client)| async move { + match client + .client + .wait_until_connected(Duration::from_secs(10)) + .instrument(debug_span!("health check", %name)) + .await + { + Ok(_) => { + info!("plugin {name} connected") + } + Err(_) => { + warn!("plugin {name} failed to connect after 10 seconds") + } + } + }) + .collect::>(); + + while let Some(()) = futures.next().await {} + } + + Ok(Self { + rpc_server: main_rpc_server, + plugin_modules, + interest_filters, + cancellation_token, + // module_servers, + }) + } + + pub async fn shutdown(self) { + self.cancellation_token.cancel(); + + for (name, client) in self.plugin_modules { + debug!("shutting down plugin client for {name}"); + client.client.shutdown(); + } + } + + pub fn plugin( + &self, + name: impl AsRef, + ) -> Result<&(impl QueueInteractionsClient + '_), PluginNotFound> { + Ok(self + .plugin_modules + .get(name.as_ref()) + .ok_or_else(|| PluginNotFound { + name: name.as_ref().into(), + })? + .client()) + } + + pub fn plugin_client_raw( + &self, + name: impl AsRef, + ) -> Result<&ModuleRpcClient, PluginNotFound> { + self.plugin_modules + .get(name.as_ref()) + .ok_or_else(|| PluginNotFound { + name: name.as_ref().into(), + }) + } + + pub fn interest_filters(&self) -> &HashMap { + &self.interest_filters + } + + pub fn chain_module<'a: 'b, 'b, 'c: 'a, D: Member, C: Member, Cb: Member>( + &'a self, + chain_id: &'b ChainId<'c>, + ) -> RpcResult<&'a (impl ChainModuleClient + 'a)> { + Ok(self.rpc_server.modules()?.chain_module(chain_id)?) + } + + pub fn consensus_module<'a: 'b, 'b, 'c: 'a, D: Member, C: Member, Cb: Member>( + &'a self, + chain_id: &'b ChainId<'c>, + ) -> RpcResult<&'a (impl ConsensusModuleClient + 'a)> { + Ok(self.rpc_server.modules()?.consensus_module(chain_id)?) + } + + pub fn client_module<'a: 'b, 'b, 'c: 'a, D: Member, C: Member, Cb: Member>( + &'a self, + client_type: &'b ClientType<'c>, + ibc_interface: &'b IbcInterface<'c>, + ) -> RpcResult<&'a (impl ClientModuleClient + 'a)> { + Ok(self + .rpc_server + .modules()? + .client_module(client_type, ibc_interface)?) + } + + // pub fn modules(&self) -> Arc { + // self.modules.clone() + // } +} + +impl Modules { + pub fn loaded_chain_modules(&self) -> impl Iterator> { + self.chain_modules.keys() + } + + pub fn loaded_consensus_modules(&self) -> impl Iterator> { + self.consensus_modules.keys() + } + + pub fn loaded_client_modules( + &self, + ) -> impl Iterator< + Item = ( + &ClientType<'static>, + impl Iterator>, + ), + > { + self.client_modules + .iter() + .map(|(client_type, ibc_interfaces)| (client_type, ibc_interfaces.keys())) + } + + pub fn chain_module<'a: 'b, 'b, 'c: 'a, D: Member, C: Member, Cb: Member>( + &'a self, + chain_id: &'b ChainId<'c>, + ) -> Result<&'a (impl ChainModuleClient + 'a), ChainModuleNotFound> { + Ok(self + .chain_modules + .get(chain_id) + .ok_or_else(|| ChainModuleNotFound(chain_id.clone().into_static()))? + .client()) + } + + pub fn consensus_module<'a: 'b, 'b, 'c: 'a, D: Member, C: Member, Cb: Member>( + &'a self, + chain_id: &'b ChainId<'c>, + ) -> Result<&'a (impl ConsensusModuleClient + 'a), ConsensusModuleNotFound> { + Ok(self + .consensus_modules + .get(chain_id) + .ok_or_else(|| ConsensusModuleNotFound(chain_id.clone().into_static()))? + .client()) + } + + pub fn client_module<'a: 'b, 'b, 'c: 'a, D: Member, C: Member, Cb: Member>( + &'a self, + client_type: &'b ClientType<'c>, + ibc_interface: &'b IbcInterface<'c>, + ) -> Result<&'a (impl ClientModuleClient + 'a), ClientModuleNotFound> { + match self.client_modules.get(client_type) { + Some(ibc_interfaces) => match ibc_interfaces.get(ibc_interface) { + Some(client_module) => Ok(client_module.client()), + None => Err(ClientModuleNotFound::IbcInterfaceNotFound { + client_type: client_type.clone().into_static(), + ibc_interface: ibc_interface.clone().into_static(), + }), + }, + None => Err(ClientModuleNotFound::ClientTypeNotFound { + client_type: client_type.clone().into_static(), + }), + } + } +} + +#[instrument(skip_all, fields(%name))] +async fn run_module( + name: String, + module_config: ModuleConfig, + cancellation_token: CancellationToken, +) { + let mut attempt = 0; + + loop { + debug!(%attempt, "spawning plugin child process"); + + let mut cmd = tokio::process::Command::new(&module_config.path); + cmd.arg("run"); + cmd.arg(ModuleRpcClient::make_socket_path(&name)); + cmd.arg(make_module_rpc_server_socket_path(&name)); + cmd.arg(module_config.config.to_string()); + + let mut child = loop { + match cmd.spawn() { + Ok(child) => { + let id = child.id().unwrap(); + + info!(%id, "spawned plugin"); + + break child; + } + Err(err) => { + error!( + err = %ErrorReporter(err), + path = ?module_config.path, + "unable to spawn plugin" + ); + + sleep(Duration::from_secs(1)).await; + } + } + }; + + let id = child.id().unwrap(); + + tokio::select! { + _ = cancellation_token.cancelled() => { + debug!(%id, "killing plugin"); + match child.kill().await { + Ok(()) => { + debug!(%id, "plugin received kill signal"); + match child.wait().await { + Ok(exit_status) => { + debug!(%id, %exit_status, "child exited successfully") + } + Err(err) => { + error!(%id, err = %ErrorReporter(err), "child exited unsuccessfully") + } + } + } + Err(err) => { + error!(%id, err = %ErrorReporter(err), "unable to kill plugin") + } + } + + break + } + res = child.wait() => { + match res { + Ok(exit_status) => { + info!(%id, %exit_status, "child exited"); + + if exit_status + .code() + .is_some_and(|c| c == INVALID_CONFIG_EXIT_CODE as i32) + { + error!(%id, %exit_status, "invalid config for plugin"); + cancellation_token.cancel(); + } + } + Err(err) => { + error!(%id, err = %ErrorReporter(err), "child exited"); + } + } + + // TODO: Exponential backoff + sleep(Duration::from_secs(1)).await; + } + } + + attempt += 1; + } +} + +#[derive(Debug, Clone, PartialEq, thiserror::Error)] +#[error("no module loaded for chain `{0}`")] +pub struct ChainModuleNotFound(pub ChainId<'static>); + +impl From for QueueError { + fn from(value: ChainModuleNotFound) -> Self { + Self::Fatal(Box::new(value)) + } +} + +impl From for ErrorObjectOwned { + fn from(value: ChainModuleNotFound) -> Self { + ErrorObject::owned(FATAL_JSONRPC_ERROR_CODE, value.to_string(), None::<()>) + } +} + +impl From for jsonrpsee::core::client::Error { + fn from(value: ChainModuleNotFound) -> Self { + ErrorObject::from(value).into() + } +} + +#[derive(Debug, Clone, PartialEq, thiserror::Error)] +#[error("no module loaded for consensus on chain `{0}`")] +pub struct ConsensusModuleNotFound(pub ChainId<'static>); + +impl From for QueueError { + fn from(value: ConsensusModuleNotFound) -> Self { + Self::Fatal(Box::new(value)) + } +} + +impl From for jsonrpsee::core::client::Error { + fn from(value: ConsensusModuleNotFound) -> Self { + ErrorObject::from(value).into() + } +} + +impl From for ErrorObjectOwned { + fn from(value: ConsensusModuleNotFound) -> Self { + ErrorObject::owned(FATAL_JSONRPC_ERROR_CODE, value.to_string(), None::<()>) + } +} + +#[derive(Debug, Clone, PartialEq, thiserror::Error)] +pub enum ClientModuleNotFound { + #[error("no module loaded for client type `{}`", client_type.0)] + ClientTypeNotFound { client_type: ClientType<'static> }, + #[error( + "no module loaded supporting IBC interface `{}` and client type `{}`", + client_type.0, + ibc_interface.0, + )] + IbcInterfaceNotFound { + client_type: ClientType<'static>, + ibc_interface: IbcInterface<'static>, + }, +} + +impl From for QueueError { + fn from(value: ClientModuleNotFound) -> Self { + Self::Fatal(Box::new(value)) + } +} + +impl From for jsonrpsee::core::client::Error { + fn from(value: ClientModuleNotFound) -> Self { + ErrorObject::from(value).into() + } +} + +impl From for ErrorObjectOwned { + fn from(value: ClientModuleNotFound) -> Self { + ErrorObject::owned(FATAL_JSONRPC_ERROR_CODE, value.to_string(), None::<()>) + } +} + +#[derive(Debug, Clone, PartialEq, thiserror::Error)] +#[error("plugin `{name}` not found")] +pub struct PluginNotFound { + pub name: String, +} + +impl From for QueueError { + fn from(value: PluginNotFound) -> Self { + Self::Fatal(Box::new(value)) + } +} + +impl From for ErrorObjectOwned { + fn from(value: PluginNotFound) -> Self { + ErrorObject::owned(FATAL_JSONRPC_ERROR_CODE, value.to_string(), None::<()>) + } +} + +impl From for jsonrpsee::core::client::Error { + fn from(value: PluginNotFound) -> Self { + ErrorObject::from(value).into() + } +} + +pub fn get_module_info(module_config: &ModuleConfig) -> Result, String> { + debug!( + "querying module info from module at {}", + &module_config.path + ); + + let mut cmd = std::process::Command::new(&module_config.path); + cmd.arg("info"); + cmd.arg(module_config.config.to_string()); + + let output = cmd + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .unwrap() + .wait_with_output() + .unwrap(); + + if !output.status.success() { + match output.status.code() { + Some(code) if code == INVALID_CONFIG_EXIT_CODE as i32 => { + return Err(format!( + "invalid config for module at path {}:\n{}", + &module_config.path, + String::from_utf8_lossy(&output.stdout) + )); + } + Some(_) | None => { + return Err(format!( + "unable to query info for module at path {}:\n{}", + &module_config.path, + String::from_utf8_lossy(&output.stdout) + )) + } + } + } + + Ok(serde_json::from_slice(&output.stdout).unwrap()) +} diff --git a/lib/voyager-message/src/data.rs b/lib/voyager-message/src/data.rs new file mode 100644 index 0000000000..bcb8e75082 --- /dev/null +++ b/lib/voyager-message/src/data.rs @@ -0,0 +1,706 @@ +use std::num::NonZeroU64; + +use enumorph::Enumorph; +use macros::{apply, model}; +use queue_msg::{queue_msg, SubsetOf}; +use serde_json::Value; +use tracing::info; +#[cfg(doc)] +use unionlabs::events::IbcEvent; +use unionlabs::{ + hash::H256, + ibc::core::{ + channel::{ + msg_acknowledgement::MsgAcknowledgement, msg_channel_open_ack::MsgChannelOpenAck, + msg_channel_open_confirm::MsgChannelOpenConfirm, + msg_channel_open_init::MsgChannelOpenInit, msg_channel_open_try::MsgChannelOpenTry, + msg_recv_packet::MsgRecvPacket, msg_timeout::MsgTimeout, order::Order, + }, + client::{ + height::Height, msg_create_client::MsgCreateClient, msg_update_client::MsgUpdateClient, + }, + connection::{ + connection_end::ConnectionEnd, msg_connection_open_ack::MsgConnectionOpenAck, + msg_connection_open_confirm::MsgConnectionOpenConfirm, + msg_connection_open_init::MsgConnectionOpenInit, + msg_connection_open_try::MsgConnectionOpenTry, + }, + }, + ics24::{ClientConsensusStatePath, ClientStatePath, IbcPath, Path}, + id::{ChannelId, ClientId, ConnectionId, PortId}, + traits::Member, +}; + +use crate::{ + module::{ClientStateMeta, ConsensusStateMeta}, + top_level_identifiable_enum, ChainId, ClientType, IbcInterface, PluginMessage, +}; + +#[apply(top_level_identifiable_enum)] +#[queue_msg] +#[derive(Enumorph, SubsetOf)] +pub enum Data { + IbcEvent(ChainEvent), + IbcMessage(IbcMessage), + + // TODO: Remove this + LatestHeight(LatestHeight), + + ClientInfo(ClientInfo), + + OrderedHeaders(OrderedHeaders), + OrderedMsgUpdateClients(OrderedMsgUpdateClients), + + IdentifiedIbcMessage(WithChainId), + IdentifiedIbcMessageBatch(WithChainId>), + + #[subset_of(ignore)] + Plugin(PluginMessage), +} + +#[queue_msg] +pub struct ChainEvent { + /// The chain where this event was emitted. + pub chain_id: ChainId<'static>, + /// The underlying client of this event, on [`Self::chain_id`]. + pub client_info: ClientInfo, + /// The chain on the other end of this IBC event. + pub counterparty_chain_id: ChainId<'static>, + pub tx_hash: H256, + /// The 'provable height' of the event. This is the minimum height at which the effect of the IBC action that caused this event is provable in the state root of the chain identified by [`Self::chain_id`]. + pub provable_height: Height, + pub event: FullIbcEvent, +} + +impl ChainEvent { + pub fn client_id(&self) -> &ClientId { + match self.event { + FullIbcEvent::CreateClient(ref event) => &event.client_id, + FullIbcEvent::UpdateClient(ref event) => &event.client_id, + FullIbcEvent::ConnectionOpenInit(ref event) => &event.client_id, + FullIbcEvent::ConnectionOpenTry(ref event) => &event.client_id, + FullIbcEvent::ConnectionOpenAck(ref event) => &event.client_id, + FullIbcEvent::ConnectionOpenConfirm(ref event) => &event.client_id, + FullIbcEvent::ChannelOpenInit(ref event) => &event.connection.client_id, + FullIbcEvent::ChannelOpenTry(ref event) => &event.connection.client_id, + FullIbcEvent::ChannelOpenAck(ref event) => &event.connection.client_id, + FullIbcEvent::ChannelOpenConfirm(ref event) => &event.connection.client_id, + FullIbcEvent::SendPacket(ref event) => { + &event.packet.source_channel.connection.client_id + } + FullIbcEvent::RecvPacket(ref event) => { + &event.packet.source_channel.connection.client_id + } + FullIbcEvent::WriteAcknowledgement(ref event) => { + &event.packet.source_channel.connection.client_id + } + FullIbcEvent::AcknowledgePacket(ref event) => { + &event.packet.source_channel.connection.client_id + } + FullIbcEvent::TimeoutPacket(ref event) => { + &event.packet.source_channel.connection.client_id + } + } + } + + /// Returns the counterparty client id of this ibc event, if there is a + /// counterparty. This will return `None` for `UpdateClient` and + /// `CreateClient`. + pub fn counterparty_client_id(&self) -> Option<&ClientId> { + match self.event { + FullIbcEvent::ConnectionOpenInit(ref event) => Some(&event.counterparty_client_id), + FullIbcEvent::ConnectionOpenTry(ref event) => Some(&event.counterparty_client_id), + FullIbcEvent::ConnectionOpenAck(ref event) => Some(&event.counterparty_client_id), + FullIbcEvent::ConnectionOpenConfirm(ref event) => Some(&event.counterparty_client_id), + FullIbcEvent::ChannelOpenInit(ref event) => { + Some(&event.connection.counterparty.client_id) + } + FullIbcEvent::ChannelOpenTry(ref event) => { + Some(&event.connection.counterparty.client_id) + } + FullIbcEvent::ChannelOpenAck(ref event) => { + Some(&event.connection.counterparty.client_id) + } + FullIbcEvent::ChannelOpenConfirm(ref event) => { + Some(&event.connection.counterparty.client_id) + } + FullIbcEvent::SendPacket(ref event) => { + Some(&event.packet.destination_channel.connection.client_id) + } + FullIbcEvent::RecvPacket(ref event) => { + Some(&event.packet.source_channel.connection.client_id) + } + FullIbcEvent::WriteAcknowledgement(ref event) => { + Some(&event.packet.source_channel.connection.client_id) + } + FullIbcEvent::AcknowledgePacket(ref event) => { + Some(&event.packet.destination_channel.connection.client_id) + } + FullIbcEvent::TimeoutPacket(ref event) => { + Some(&event.packet.destination_channel.connection.client_id) + } + _ => None, + } + } +} + +#[queue_msg] +#[derive(Enumorph, Eq)] +pub enum IbcMessage { + CreateClient(MsgCreateClientData), + UpdateClient(MsgUpdateClient), + + ConnectionOpenInit(MsgConnectionOpenInit), + ConnectionOpenTry(MsgConnectionOpenTry), + ConnectionOpenAck(MsgConnectionOpenAck), + ConnectionOpenConfirm(MsgConnectionOpenConfirm), + + ChannelOpenInit(MsgChannelOpenInit), + ChannelOpenTry(MsgChannelOpenTry), + ChannelOpenAck(MsgChannelOpenAck), + ChannelOpenConfirm(MsgChannelOpenConfirm), + + RecvPacket(MsgRecvPacket), + AcknowledgePacket(MsgAcknowledgement), + TimeoutPacket(MsgTimeout), +} + +impl IbcMessage { + /// Returns the proof height of the IBC message, if it has one. (ConnectionOpenInit does not contain a proof, for example) + pub fn proof_height(&self) -> Option { + match self { + IbcMessage::CreateClient(_) => None, + IbcMessage::UpdateClient(_) => None, + IbcMessage::ConnectionOpenInit(_) => None, + IbcMessage::ConnectionOpenTry(msg) => Some(msg.proof_height), + IbcMessage::ConnectionOpenAck(msg) => Some(msg.proof_height), + IbcMessage::ConnectionOpenConfirm(msg) => Some(msg.proof_height), + IbcMessage::ChannelOpenInit(_) => None, + IbcMessage::ChannelOpenTry(msg) => Some(msg.proof_height), + IbcMessage::ChannelOpenAck(msg) => Some(msg.proof_height), + IbcMessage::ChannelOpenConfirm(msg) => Some(msg.proof_height), + IbcMessage::RecvPacket(msg) => Some(msg.proof_height), + IbcMessage::AcknowledgePacket(msg) => Some(msg.proof_height), + IbcMessage::TimeoutPacket(msg) => Some(msg.proof_height), + } + } +} + +#[queue_msg] +pub struct CreateClient { + pub client_id: ClientId, + pub client_type: ClientType<'static>, + pub consensus_height: Height, +} + +#[queue_msg] +pub struct UpdateClient { + pub client_id: ClientId, + pub client_type: ClientType<'static>, + pub consensus_heights: Vec, +} + +#[queue_msg] +pub struct ConnectionOpenInit { + pub connection_id: ConnectionId, + pub client_id: ClientId, + pub counterparty_client_id: ClientId, +} + +#[queue_msg] +pub struct ConnectionOpenTry { + pub connection_id: ConnectionId, + pub client_id: ClientId, + pub counterparty_client_id: ClientId, + pub counterparty_connection_id: ConnectionId, +} + +#[queue_msg] +pub struct ConnectionOpenAck { + pub connection_id: ConnectionId, + pub client_id: ClientId, + pub counterparty_client_id: ClientId, + pub counterparty_connection_id: ConnectionId, +} + +#[queue_msg] +pub struct ConnectionOpenConfirm { + pub connection_id: ConnectionId, + pub client_id: ClientId, + pub counterparty_client_id: ClientId, + pub counterparty_connection_id: ConnectionId, +} + +#[queue_msg] +pub struct ChannelOpenInit { + pub port_id: PortId, + pub channel_id: ChannelId, + + pub counterparty_port_id: PortId, + + pub connection: ConnectionEnd, + + pub version: String, +} + +#[queue_msg] +pub struct ChannelOpenTry { + pub port_id: PortId, + pub channel_id: ChannelId, + + pub counterparty_port_id: PortId, + pub counterparty_channel_id: ChannelId, + + pub connection: ConnectionEnd, + + pub version: String, +} + +#[queue_msg] +pub struct ChannelOpenAck { + pub port_id: PortId, + pub channel_id: ChannelId, + + pub counterparty_port_id: PortId, + pub counterparty_channel_id: ChannelId, + + pub connection: ConnectionEnd, + + pub version: String, +} + +#[queue_msg] +pub struct ChannelOpenConfirm { + pub port_id: PortId, + pub channel_id: ChannelId, + + pub counterparty_port_id: PortId, + pub counterparty_channel_id: ChannelId, + + pub connection: ConnectionEnd, + + pub version: String, +} + +#[queue_msg] +pub struct WriteAcknowledgement { + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub packet_data: Vec, + + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub packet_ack: Vec, + + pub packet: PacketMetadata, +} + +#[queue_msg] +pub struct RecvPacket { + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub packet_data: Vec, + + pub packet: PacketMetadata, +} + +#[queue_msg] +pub struct SendPacket { + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub packet_data: Vec, + + pub packet: PacketMetadata, +} + +#[queue_msg] +pub struct AcknowledgePacket { + pub packet: PacketMetadata, +} + +#[queue_msg] +pub struct TimeoutPacket { + pub packet: PacketMetadata, +} + +#[queue_msg] +pub struct PacketMetadata { + pub sequence: NonZeroU64, + + pub source_channel: ChannelMetadata, + pub destination_channel: ChannelMetadata, + + pub channel_ordering: Order, + + pub timeout_height: Height, + pub timeout_timestamp: u64, +} + +#[queue_msg] +pub struct ChannelMetadata { + pub port_id: PortId, + pub channel_id: ChannelId, + // REVIEW: Can this be different on either end of a channel? + pub version: String, + pub connection: ConnectionMetadata, +} + +#[queue_msg] +pub struct ConnectionMetadata { + pub client_id: ClientId, + // this is really `Either` + // REVIEW: Is it? + pub connection_id: ConnectionId, +} + +/// Similar to [`IbcEvent`], but contains more information (counterparty +/// clients, channel version, etc) +#[queue_msg] +#[derive(Enumorph, SubsetOf)] +pub enum FullIbcEvent { + CreateClient(CreateClient), + + UpdateClient(UpdateClient), + + ConnectionOpenInit(ConnectionOpenInit), + ConnectionOpenTry(ConnectionOpenTry), + ConnectionOpenAck(ConnectionOpenAck), + ConnectionOpenConfirm(ConnectionOpenConfirm), + + ChannelOpenInit(ChannelOpenInit), + ChannelOpenTry(ChannelOpenTry), + ChannelOpenAck(ChannelOpenAck), + ChannelOpenConfirm(ChannelOpenConfirm), + + SendPacket(SendPacket), + RecvPacket(RecvPacket), + WriteAcknowledgement(WriteAcknowledgement), + AcknowledgePacket(AcknowledgePacket), + TimeoutPacket(TimeoutPacket), +} + +#[queue_msg] +pub struct LatestHeight { + pub chain_id: ChainId<'static>, + pub height: Height, +} + +/// The type of a light client on a chain, along with the IBC interface it's on +/// (and any associated metadata). +/// +/// # Examples +/// +/// - 08-wasm client on union, tracking ethereum mainnet: `(ibc-go-v8/08-wasm, +/// ethereum_mainnet, {"checksum": "0x..."})` +/// - 07-tendermint client on stargaze, tracking osmosis: `(ibc-go-v8/native, +/// tendermint)` +/// - 08-wasm client on babylon, tracking union: `(ibc-go-v8/08-wasm, cometbls, {"checksum": "0x..."}))` +/// - cometbls client on scroll, tracking union: `(ibc-solidity, cometbls)` +#[queue_msg] +pub struct ClientInfo { + pub client_type: ClientType<'static>, + pub ibc_interface: IbcInterface<'static>, + /// Additional metadata about this client. + /// + /// This is currently only used for threading the checksum for ibc-go + /// 08-wasm clients, and can likely be removed when support for that IBC + /// interface is dropped. + #[serde(default)] + pub metadata: Value, +} + +#[queue_msg] +pub struct SelfClientState { + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub self_client_state: Vec, +} + +#[queue_msg] +pub struct SelfConsensusState { + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub self_consensus_state: Vec, +} + +#[queue_msg] +pub struct UnfinalizedTrustedClientState { + pub height: Height, + // pub client_state: Hc::StoredClientState, + pub client_state: ClientStateMeta, +} + +#[queue_msg] +#[serde(bound(serialize = "", deserialize = ""))] +pub struct IbcState { + pub chain_id: ChainId<'static>, + pub path: P, + /// The height that the state was read at. + pub height: Height, + pub state: P::Value, +} + +#[queue_msg] +#[serde(bound(serialize = "", deserialize = ""))] +pub struct IbcProof { + pub path: P, + pub height: Height, + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub proof: Vec, +} + +#[queue_msg] +pub struct RawIbcProof { + pub path: Path, + pub height: Height, + /// The raw proof, encoded as JSON, which will be encoded by the relevant + /// client module. + pub proof: Value, +} + +#[queue_msg] +pub struct DecodedClientStateMeta { + pub path: ClientStatePath, + /// The height that the state was read at. Same as [`IbcState::height`]. + pub height: Height, + pub state: ClientStateMeta, +} + +#[queue_msg] +pub struct DecodedConsensusStateMeta { + pub path: ClientConsensusStatePath, + pub height: Height, + pub state: ConsensusStateMeta, +} + +#[queue_msg] +pub struct DecodedHeaderMeta { + /// The new trusted height that the header provides a consensus update to. + pub height: Height, +} + +#[queue_msg] +pub struct OrderedHeaders { + pub headers: Vec<(DecodedHeaderMeta, Value)>, +} + +#[queue_msg] +pub struct OrderedMsgUpdateClients { + pub updates: Vec<(DecodedHeaderMeta, MsgUpdateClient)>, +} + +#[queue_msg] +pub struct EncodedClientState { + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub encoded_client_state: Vec, +} + +#[queue_msg] +pub struct EncodedConsensusState { + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub encoded_consensus_state: Vec, +} + +#[queue_msg] +pub struct EncodedHeader { + #[serde(with = "::serde_utils::hex_string")] + #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + pub encoded_header: Vec, +} + +#[queue_msg] +pub struct WithChainId { + pub chain_id: ChainId<'static>, + pub message: T, +} + +#[model] +pub struct MsgCreateClientData { + pub msg: MsgCreateClient, + pub client_type: ClientType<'static>, +} + +pub fn log_msg(chain_id: &str, effect: &IbcMessage) { + match effect.clone() { + IbcMessage::ConnectionOpenInit(message) => { + info!( + %chain_id, + %message.client_id, + %message.counterparty.client_id, + message.counterparty.connection_id = %message.counterparty.connection_id.as_deref().unwrap_or_default(), + message.counterparty.prefix.key_prefix = %::serde_utils::to_hex(message.counterparty.prefix.key_prefix), + %message.version.identifier, + message.version.features = %message + .version + .features + .into_iter() + .map(|x| x.to_string()) + .collect::>() + .join(","), + %message.delay_period, + ) + } + IbcMessage::ConnectionOpenTry(message) => { + info!( + %chain_id, + %message.client_id, + %message.counterparty.client_id, + message.counterparty.connection_id = %message.counterparty.connection_id.as_deref().unwrap_or_default(), + message.counterparty.prefix.key_prefix = %::serde_utils::to_hex(message.counterparty.prefix.key_prefix), + %message.delay_period, + // TODO: This needs `valuable` + // message.counterparty_versions = %message + // .counterparty_versions + // .into_iter() + // .map(Into::into) + // .collect(), + %message.proof_height, + %message.consensus_height, + ) + } + IbcMessage::ConnectionOpenAck(message) => { + info!( + %chain_id, + // client_state.height = message.%data.message.client_state.height(), + %message.proof_height, + %message.consensus_height, + %message.connection_id, + %message.counterparty_connection_id, + %message.version.identifier, + message.version.features = %message + .version + .features + .into_iter() + .map(|x| x.to_string()) + .collect::>() + .join(","), + ) + } + IbcMessage::ConnectionOpenConfirm(message) => { + info!( + %chain_id, + %message.connection_id, + %message.proof_height, + ) + } + IbcMessage::ChannelOpenInit(message) => { + info!( + %chain_id, + %message.port_id, + %message.channel.state, + %message.channel.ordering, + %message.channel.counterparty.port_id, + %message.channel.counterparty.channel_id, + message.channel.connection_hops = %message + .channel + .connection_hops + .into_iter() + .map(|x| x.to_string()) + .collect::>() + .join(","), + %message.channel.version, + ) + } + IbcMessage::ChannelOpenTry(message) => { + info!( + %chain_id, + + %message.port_id, + %message.channel.state, + %message.channel.ordering, + %message.channel.counterparty.port_id, + %message.channel.counterparty.channel_id, + message.channel.connection_hops = %message + .channel + .connection_hops + .into_iter() + .map(|x| x.to_string()) + .collect::>() + .join(","), + %message.channel.version, + %message.counterparty_version, + %message.proof_height, + ) + } + IbcMessage::ChannelOpenAck(message) => { + info!( + %chain_id, + %message.port_id, + %message.channel_id, + %message.counterparty_version, + %message.counterparty_channel_id, + %message.proof_height, + ) + } + IbcMessage::ChannelOpenConfirm(message) => { + info!( + %chain_id, + %message.port_id, + %message.channel_id, + %message.proof_height, + ) + } + IbcMessage::RecvPacket(message) => { + info!( + %chain_id, + %message.packet.sequence, + %message.packet.source_port, + %message.packet.source_channel, + %message.packet.destination_port, + %message.packet.destination_channel, + message.data = %::serde_utils::to_hex(message.packet.data), + %message.packet.timeout_height, + %message.packet.timeout_timestamp, + + %message.proof_height, + ) + } + IbcMessage::AcknowledgePacket(message) => { + info!( + %chain_id, + %message.packet.sequence, + %message.packet.source_port, + %message.packet.source_channel, + %message.packet.destination_port, + %message.packet.destination_channel, + message.data = %::serde_utils::to_hex(message.packet.data), + %message.packet.timeout_height, + %message.packet.timeout_timestamp, + + message.data = %::serde_utils::to_hex(message.acknowledgement), + %message.proof_height, + ) + } + IbcMessage::TimeoutPacket(message) => { + info!( + %chain_id, + %message.packet.sequence, + %message.packet.source_port, + %message.packet.source_channel, + %message.packet.destination_port, + %message.packet.destination_channel, + message.data = %::serde_utils::to_hex(message.packet.data), + %message.packet.timeout_height, + %message.packet.timeout_timestamp, + + %message.proof_height, + %message.next_sequence_recv, + ) + } + IbcMessage::CreateClient(message) => { + info!( + %chain_id, + %message.client_type, + ) + } + IbcMessage::UpdateClient(message) => { + info!( + %chain_id, + %message.client_id, + ) + } + } +} diff --git a/lib/voyager-message/src/lib.rs b/lib/voyager-message/src/lib.rs index 0d2a4ee1f9..4671055d27 100644 --- a/lib/voyager-message/src/lib.rs +++ b/lib/voyager-message/src/lib.rs @@ -1,1235 +1,460 @@ -#![feature(min_exhaustive_patterns)] -#![allow(clippy::large_enum_variant)] -#![warn(clippy::large_futures)] +#![feature(trait_alias)] + +use std::{env::VarError, fmt::Debug, marker::PhantomData, time::Duration}; + +use chain_utils::BoxDynError; +use jsonrpsee::types::{error::METHOD_NOT_FOUND_CODE, ErrorObject}; +use macros::apply; +use queue_msg::{aggregation::SubsetOf, queue_msg, QueueError, QueueMessage}; +use reth_ipc::client::IpcClientBuilder; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde_json::Value; +use tracing::{debug, debug_span, error, info, trace, Instrument}; +use unionlabs::{never::Never, traits::Member, ErrorReporter}; + +use crate::{ + call::Call, + callback::Callback, + context::{Context, INVALID_CONFIG_EXIT_CODE, STARTUP_ERROR_EXIT_CODE}, + data::Data, + module::{IModuleKindInfo, IntoRpc, ModuleInfo, ModuleKindInfo}, +}; -use std::{collections::VecDeque, fmt::Debug, str::FromStr}; +pub mod call; +pub mod callback; +pub mod data; -use block_message::BlockMessage; -use chain_utils::{ - arbitrum::Arbitrum, berachain::Berachain, cosmos::Cosmos, ethereum::Ethereum, scroll::Scroll, - union::Union, wasm::Wasm, Chains, -}; -use futures::TryFutureExt; -use queue_msg::{ - event, noop, queue_msg, HandleAggregate, HandleData, HandleEffect, HandleEvent, HandleFetch, - HandleWait, Op, QueueError, QueueMessage, -}; -use relay_message::{AnyLightClientIdentified, RelayMessage}; -use tracing::{info_span, Instrument}; -use unionlabs::{ - ethereum::config::{Mainnet, Minimal}, - events::{ - AcknowledgePacket, ChannelOpenAck, ChannelOpenConfirm, ChannelOpenInit, ChannelOpenTry, - ClientMisbehaviour, ConnectionOpenAck, ConnectionOpenConfirm, ConnectionOpenInit, - ConnectionOpenTry, CreateClient, IbcEvent, RecvPacket, SendPacket, SubmitEvidence, - TimeoutPacket, UpdateClient, WriteAcknowledgement, - }, - traits::{ChainIdOf, ClientIdOf, ClientTypeOf, HeightOf}, - ClientType, WasmClientType, -}; +pub mod context; +pub mod module; +pub mod pass; -pub enum VoyagerMessage {} +pub mod rpc; -impl QueueMessage for VoyagerMessage { - type Event = VoyagerEvent; - type Data = VoyagerData; - type Fetch = VoyagerFetch; - type Effect = VoyagerEffect; - type Wait = VoyagerWait; - type Aggregate = VoyagerAggregate; +pub use reconnecting_jsonrpc_ws_client; +pub use reth_ipc; - type Store = Chains; +pub struct VoyagerMessage { + #[allow(clippy::type_complexity)] // it's a phantom data bro fight me + __marker: PhantomData (D, F, A)>, + __unconstructable: Never, } -pub trait FromOp: QueueMessage + Sized { - fn from_op(value: Op) -> Op; +impl QueueMessage for VoyagerMessage { + type Call = Call; + type Data = Data; + type Callback = Callback; + + type Context = Context; } -impl FromOp for VoyagerMessage { - fn from_op(value: Op) -> Op { - match value { - Op::Event(event) => Op::Event(VoyagerEvent::Relay(event)), - Op::Data(data) => Op::Data(VoyagerData::Relay(data)), - Op::Fetch(fetch) => Op::Fetch(VoyagerFetch::Relay(fetch)), - Op::Effect(msg) => Op::Effect(VoyagerEffect::Relay(msg)), - Op::Wait(wait) => Op::Wait(VoyagerWait::Relay(wait)), - Op::Defer(defer) => Op::Defer(defer), - Op::Repeat { times, msg } => Op::Repeat { - times, - msg: Box::new(Self::from_op(*msg)), - }, - Op::Timeout { - timeout_timestamp, - msg, - } => Op::Timeout { - timeout_timestamp, - msg: Box::new(Self::from_op(*msg)), - }, - Op::Seq(seq) => Op::Seq(seq.into_iter().map(Self::from_op).collect()), - Op::Conc(seq) => Op::Conc(seq.into_iter().map(Self::from_op).collect()), - Op::Retry { remaining, msg } => Op::Retry { - remaining, - msg: Box::new(Self::from_op(*msg)), - }, - Op::Aggregate { - queue, - data, - receiver, - } => Op::Aggregate { - queue: queue.into_iter().map(Self::from_op).collect(), - data: data.into_iter().map(VoyagerData::Relay).collect(), - receiver: VoyagerAggregate::Relay(receiver), - }, - Op::Race(seq) => Op::Race(seq.into_iter().map(Self::from_op).collect()), - Op::Void(msg) => Op::Void(Box::new(Self::from_op(*msg))), - Op::Noop => noop(), - } +/// Error code for fatal errors. If a plugin responds with this error code, it will be treated as failed and not retried. +pub const FATAL_JSONRPC_ERROR_CODE: i32 = -0xBADBEEF; + +pub fn json_rpc_error_to_queue_error(error: jsonrpsee::core::client::Error) -> QueueError { + match error { + jsonrpsee::core::client::Error::Call(error) => error_object_to_queue_error(error), + value => QueueError::Retry(Box::new(value)), } } -impl FromOp for VoyagerMessage { - fn from_op(value: Op) -> Op { - match value { - Op::Data(data) => Op::Data(VoyagerData::Block(data)), - Op::Fetch(fetch) => Op::Fetch(VoyagerFetch::Block(fetch)), - Op::Wait(wait) => Op::Wait(VoyagerWait::Block(wait)), - Op::Defer(defer) => Op::Defer(defer), - Op::Repeat { times, msg } => Op::Repeat { - times, - msg: Box::new(Self::from_op(*msg)), - }, - Op::Timeout { - timeout_timestamp, - msg, - } => Op::Timeout { - timeout_timestamp, - msg: Box::new(Self::from_op(*msg)), - }, - Op::Seq(seq) => Op::Seq(seq.into_iter().map(Self::from_op).collect()), - Op::Conc(seq) => Op::Conc(seq.into_iter().map(Self::from_op).collect()), - Op::Race(seq) => Op::Race(seq.into_iter().map(Self::from_op).collect()), - Op::Retry { remaining, msg } => Op::Retry { - remaining, - msg: Box::new(Self::from_op(*msg)), - }, - Op::Aggregate { - queue, - data, - receiver, - } => Op::Aggregate { - queue: queue.into_iter().map(Self::from_op).collect(), - data: data.into_iter().map(VoyagerData::Block).collect(), - receiver: VoyagerAggregate::Block(receiver), - }, - Op::Void(msg) => Op::Void(Box::new(Self::from_op(*msg))), - Op::Noop => noop(), - } +pub fn error_object_to_queue_error(error: ErrorObject<'_>) -> QueueError { + if error.code() == FATAL_JSONRPC_ERROR_CODE || error.code() == METHOD_NOT_FOUND_CODE { + QueueError::Fatal(Box::new(error.into_owned())) + } else { + QueueError::Retry(Box::new(error.into_owned())) } } -#[queue_msg] -pub enum VoyagerEffect { - Block(::Effect), - Relay(::Effect), -} +macro_rules! str_newtype { + ( + $(#[doc = $doc:literal])+ + $vis:vis struct $Struct:ident; + ) => { + #[derive(macros::Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] + // I tested this and apparently it's not required (newtype is automatically transparent?) but + // keeping it here for clarity + #[serde(transparent)] + #[debug("{}({:?})", stringify!($Struct), self.0)] + $vis struct $Struct<'a>(#[doc(hidden)] ::std::borrow::Cow<'a, str>); + + impl<'a> ::core::fmt::Display for $Struct<'a> { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + ::core::fmt::Display::fmt(&self.0, f) + } + } -impl HandleEffect for VoyagerEffect { - async fn handle( - self, - store: &::Store, - ) -> Result, QueueError> { - Ok(match self { - Self::Relay(msg) => { - Box::pin(msg.handle(store)) - .map_ok(VoyagerMessage::from_op) - .instrument(info_span!("relay")) - .await? + #[allow(unused)] + impl $Struct<'static> { + pub const fn new_static(ibc_interface: &'static str) -> Self { + Self(::std::borrow::Cow::Borrowed(ibc_interface)) } - }) - } -} + } -#[queue_msg] -pub enum VoyagerWait { - Block(::Wait), - Relay(::Wait), -} -impl HandleWait for VoyagerWait { - async fn handle( - self, - store: &::Store, - ) -> Result, QueueError> { - Ok(match self { - Self::Block(msg) => { - Box::pin(HandleWait::::handle(msg, store)) - .map_ok(VoyagerMessage::from_op) - .instrument(info_span!("block")) - .await? + #[allow(unused)] + impl<'a> $Struct<'a> { + pub fn new(s: impl Into<::std::borrow::Cow<'a, str>>) -> Self { + Self(s.into()) } - Self::Relay(msg) => { - Box::pin(HandleWait::::handle(msg, store)) - .map_ok(VoyagerMessage::from_op) - .instrument(info_span!("relay")) - .await? - } - }) - } -} -#[queue_msg] -pub enum VoyagerAggregate { - Block(::Aggregate), - Relay(::Aggregate), -} + pub fn into_static(self) -> $Struct<'static> { + $Struct(match self.0 { + ::std::borrow::Cow::Borrowed(x) => ::std::borrow::Cow::Owned(x.to_owned()), + ::std::borrow::Cow::Owned(x) => ::std::borrow::Cow::Owned(x), + }) + } -impl HandleAggregate for VoyagerAggregate { - fn handle( - self, - data: VecDeque<::Data>, - ) -> Result, QueueError> { - match self { - Self::Block(aggregate) => { - let _span = info_span!("block").entered(); - aggregate - .handle( - data.into_iter() - .map(|d| match d { - VoyagerData::Block(d) => d, - VoyagerData::Relay(_) => { - panic!("found relay message in data of block message aggregate") - } - }) - .collect(), - ) - .map(VoyagerMessage::from_op) + pub fn as_str(&self) -> &str { + self.0.as_ref() } - Self::Relay(aggregate) => { - let _span = info_span!("relay").entered(); - aggregate - .handle( - data.into_iter() - .map(|d| match d { - VoyagerData::Block(_) => { - panic!("found block message in data of relay message aggregate") - } - VoyagerData::Relay(d) => d, - }) - .collect(), - ) - .map(VoyagerMessage::from_op) + + + /// Borrow this [` + #[doc = stringify!($Struct)] + /// `], returning a new owned value pointing to the same data. + /// + /// ``` + #[doc = concat!("let t = ", stringify!($Struct), "::new_static(\"static\");")] + /// + /// takes_ownership(t.borrow()); + /// takes_ownership(t); + /// + #[doc = concat!("fn takes_ownership<'a>(c: ", stringify!($Struct), "<'a>) {}")] + /// ``` + pub fn borrow<'b>(&'a self) -> $Struct<'b> + where + 'a: 'b, + { + use std::borrow::Cow; + + match self.0 { + Cow::Borrowed(s) => Self(Cow::Borrowed(s)), + Cow::Owned(ref s) => Self(Cow::Borrowed(s.as_str())), + } } } - } + }; } -#[queue_msg] -pub enum VoyagerEvent { - Block(::Event), - Relay(::Event), +/// Represents the IBC interface of a chain. Since multiple chains with +/// different consensus mechanisms can have the same execution environment, this +/// value is used to describe how the IBC state is stored on-chain and how the +/// IBC stack is to be interacted with. +#[apply(str_newtype)] +pub struct IbcInterface; + +/// Well-known IBC interfaces, defined as constants for reusability and to allow +/// for pattern matching. +impl IbcInterface<'static> { + /// Native light clients in ibc-go, through the client v1 router. This + /// entrypoint uses protobuf [`Any`] wrapping to route to the correct + /// module, such as "/ibc.lightclients.tendermint.v1.ClientState" for native + /// 07-tendermint clients. + /// + /// [`Any`]: https://protobuf.dev/programming-guides/proto3/#any + pub const IBC_GO_V8_NATIVE: &'static str = "ibc-go-v8/native"; + + /// 08-wasm light clients in ibc-go, through the client v1 router. Similar + /// to the ibc-go-v8/native entrypoint, this module also uses [`Any`] + /// wrapping for client routing, however, there is another level of + /// indirection, since the `Any` routing only routes to the wasm module. All + /// state for wasm clients is [wrapped](wasm-protos), with the internal + /// state being opaque bytes to be interpreted by the light client. + /// + /// [`Any`]: https://protobuf.dev/programming-guides/proto3/#any + /// [wasm-protos]: https://github.com/cosmos/ibc-go/blob/release/v8.4.x/proto/ibc/lightclients/wasm/v1/wasm.proto + pub const IBC_GO_V8_08_WASM: &'static str = "ibc-go-v8/08-wasm"; + + /// Solidity light clients, run via Union's IBC solidity stack. This stack + /// is fully virtualized in the EVM, and as such can be run on any chain + /// running the EVM as part of their execution layer (ethereum, ethereum + /// L2s, berachain, etc). + pub const IBC_SOLIDITY: &'static str = "ibc-solidity"; + + pub const IBC_MOVE_APTOS: &'static str = "ibc-move/aptos"; + + // lots more to come - near, fuel - stay tuned } -impl HandleEvent for VoyagerEvent { - fn handle( - self, - store: &::Store, - ) -> Result, QueueError> { - match self { - Self::Relay(event) => { - let _span = info_span!("relay").entered(); - HandleEvent::handle(event, store).map(VoyagerMessage::from_op) - } - } - } +/// Newtype for client types. Clients of the same type have the same client +/// state, consensus state, and header (client update) types. +#[apply(str_newtype)] +pub struct ClientType; + +/// Well-known client types, defined as constants for reusability and to allow +/// for pattern matching. +impl ClientType<'static> { + /// A client tracking CometBLS consensus. + pub const COMETBLS: &'static str = "cometbls"; + + /// A client tracking vanilla Tendermint (CometBFT). + pub const TENDERMINT: &'static str = "tendermint"; + + /// A client tracking the Ethereum beacon chain consensus, with the mainnet + /// configuration. + pub const ETHEREUM_MAINNET: &'static str = "ethereum-mainnet"; + + /// A client tracking the Ethereum beacon chain consensus, with the minimal + /// configuration. + pub const ETHEREUM_MINIMAL: &'static str = "ethereum-minimal"; + + /// A client tracking the state of the Scroll zkevm L2, settling on + /// Ethereum. + pub const SCROLL: &'static str = "scroll"; + + /// A client tracking the state of the Arbitrum optimistic L2, settling on + /// Ethereum. + pub const ARBITRUM: &'static str = "arbitrum"; + + /// A client tracking the state of a BeaconKit chain. + pub const BEACON_KIT: &'static str = "beacon-kit"; + + /// A client tracking the state of a Movement chain. + pub const MOVEMENT: &'static str = "movement"; + + // lots more to come - near, linea, polygon - stay tuned } +/// Identifier used to uniquely identify the chain, as provided by the chain itself. +/// +/// # Examples +/// +/// 1 -> ethereum mainnet +/// 11155111 -> ethereum sepolia testnet +/// union-testnet-8 -> union testnet +/// stargaze-1 -> stargaze mainnet +#[apply(str_newtype)] +pub struct ChainId; + #[queue_msg] -pub enum VoyagerData { - Block(::Data), - Relay(::Data), +pub struct PluginMessage { + pub plugin: String, + pub message: T, } -impl HandleData for VoyagerData { - fn handle( - self, - store: &::Store, - ) -> Result, QueueError> { - Ok(match self { - Self::Block(data) => { - macro_rules! block_data_to_relay_event { - ($($Variant:ident => {$( - $ClientType:pat => ($Hc:ty, $BlockHc:ty, $Tr:ty), - )*})*) => { - match data.handle(store)? { - $(Op::Data(block_message::AnyChainIdentified::$Variant( - block_message::Identified { - chain_id, - t: block_message::data::Data::IbcEvent(ibc_event), - }, - )) => >::from_op( - match ibc_event.client_type { - $($ClientType => { - mk_relay_event::<$Hc, $BlockHc, $Tr>(chain_id, ibc_event) - })* - _ => unimplemented!(), - }, - ),)* - msg => VoyagerMessage::from_op(msg), - } - }; - } +impl SubsetOf> for PluginMessage +where + U: SubsetOf, +{ + fn try_from_super(data: Data) -> Result> { + match data { + Data::Plugin(PluginMessage { plugin, message }) => match U::try_from_super(message) { + Ok(message) => Ok(PluginMessage { plugin, message }), + Err(message) => Err(Data::plugin(plugin, message)), + }, + data => Err(data), + } + } - let _span = info_span!("block").entered(); + fn into_super(self) -> Data { + Data::::plugin(self.plugin, self.message.into_super()) + } +} - block_data_to_relay_event!( - Cosmos => { - ClientType::Wasm(WasmClientType::Cometbls) => (Wasm, Cosmos, Union), - ClientType::Tendermint => (Cosmos, Cosmos, Cosmos), - ClientType::_11Cometbls => (Cosmos, Cosmos, Union), - } - Union => { - ClientType::Wasm(WasmClientType::EthereumMinimal) => (Wasm, Union, Ethereum), - ClientType::Wasm(WasmClientType::EthereumMainnet) => (Wasm, Union, Ethereum), - ClientType::Wasm(WasmClientType::Scroll) => (Wasm, Union, Scroll), - ClientType::Wasm(WasmClientType::Arbitrum) => (Wasm, Union, Arbitrum), - ClientType::Wasm(WasmClientType::Berachain) => (Wasm, Union, Berachain), - ClientType::Tendermint => (Union, Union, Wasm), - } - EthMainnet => { - ClientType::Cometbls => (Ethereum, Ethereum, Wasm), - } - EthMinimal => { - ClientType::Cometbls => (Ethereum, Ethereum, Wasm), - } - Scroll => { - ClientType::Cometbls => (Scroll, Scroll, Wasm), - } - Arbitrum => { - ClientType::Cometbls => (Arbitrum, Arbitrum, Wasm), - } - Berachain => { - ClientType::Cometbls => (Berachain, Berachain, Wasm), - } - ) - } - Self::Relay(data) => { - let _span = info_span!("relay").entered(); - VoyagerMessage::from_op(data.handle(store)?) +macro_rules! top_level_identifiable_enum { + ( + $(#[$meta:meta])* + pub enum $Enum:ident$(<$Inner:ident = serde_json::Value>)? { + $( + $(#[$inner_meta:meta])* + $Variant:ident($VariantInner:ty$(,)?), + )* + } + ) => { + $(#[$meta])* + pub enum $Enum$(<$Inner = serde_json::Value>)? { + $( + $(#[$inner_meta])* + $Variant($VariantInner), + )* + } + + $( + impl<$Inner> $Enum<$Inner> { + pub fn plugin(plugin: impl Into, message: impl Into<$Inner>) -> $Enum<$Inner> { + Self::Plugin(PluginMessage { plugin: plugin.into(), message: message.into() }).into() + } } - }) - } + )* + }; } +pub(crate) use top_level_identifiable_enum; -#[queue_msg] -pub enum VoyagerFetch { - Block(::Fetch), - Relay(::Fetch), +#[derive(clap::Subcommand)] +pub enum DefaultCmd {} + +pub async fn default_subcommand_handler(_: T, cmd: DefaultCmd) -> Result<(), Never> { + match cmd {} } -impl HandleFetch for VoyagerFetch { - async fn handle( - self, - store: &::Store, - ) -> Result, QueueError> { - match self { - Self::Block(fetch) => { - fetch - .handle(store) - .map_ok(VoyagerMessage::from_op) - .instrument(info_span!("block")) - .await - } - Self::Relay(fetch) => { - Box::pin(fetch.handle(store)) - .map_ok(VoyagerMessage::from_op) - .instrument(info_span!("relay")) - .await - } +pub fn init_log() { + enum LogFormat { + Text, + Json, + } + + let format = match std::env::var("RUST_LOG_FORMAT").as_deref() { + Err(VarError::NotPresent) | Ok("text") => LogFormat::Text, + Ok("json") => LogFormat::Json, + Err(VarError::NotUnicode(invalid)) => { + eprintln!("invalid non-utf8 log format {invalid:?}, defaulting to text"); + LogFormat::Text + } + Ok(invalid) => { + eprintln!("invalid log format {invalid}, defaulting to text"); + LogFormat::Text + } + }; + + match format { + LogFormat::Text => { + tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + // .with_span_events(FmtSpan::CLOSE) + .init(); + } + LogFormat::Json => { + tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + // .with_span_events(FmtSpan::CLOSE) + .json() + .init(); } } } -fn mk_relay_event( - chain_id: ChainIdOf, - ibc_event: block_message::data::ChainEvent, -) -> Op -where - Hc: relay_message::ChainExt< - Height = HeightOf, - ClientId = ClientIdOf, - ClientType = ClientTypeOf, - >, - BlockHc: block_message::ChainExt, - Tr: relay_message::ChainExt>, - - AnyLightClientIdentified: - From>>, -{ - event::(relay_message::id::( - chain_id, - relay_message::event::IbcEvent { - tx_hash: ibc_event.tx_hash, - height: ibc_event.height, - event: chain_event_to_lc_event::(ibc_event.event), - }, - )) +#[allow(async_fn_in_trait)] +pub trait ModuleContext: Sized { + type Config: DeserializeOwned + Clone; + type Cmd: clap::Subcommand; + type Info: IModuleKindInfo; + + async fn new(config: Self::Config) -> Result; + + fn info(config: Self::Config) -> ModuleInfo; + + async fn cmd(config: Self::Config, cmd: Self::Cmd); } -// poor man's monad -fn chain_event_to_lc_event( - event: IbcEvent, -) -> IbcEvent +#[derive(Debug, Clone)] +pub struct ModuleServer { + pub voyager_rpc_client: reconnecting_jsonrpc_ws_client::Client, + pub ctx: Ctx, +} + +#[derive(clap::Parser)] +enum App { + Run { + socket: String, + voyager_socket: String, + config: String, + }, + Info { + config: String, + }, + Cmd { + #[command(subcommand)] + cmd: Cmd, + #[arg(long)] + config: String, + }, +} + +pub async fn run_module_server() where - Hc: relay_message::ChainExt, - Tr: relay_message::ChainExt>, + T: ModuleContext, + (T::Info, T): IntoRpc>, { - match event { - IbcEvent::CreateClient(CreateClient { - client_id, - client_type, - consensus_height, - }) => IbcEvent::CreateClient(CreateClient { - client_id, - client_type, - consensus_height, - }), - IbcEvent::UpdateClient(UpdateClient { - client_id, - client_type, - consensus_heights, - }) => IbcEvent::UpdateClient(UpdateClient { - client_id, - client_type, - consensus_heights, - }), - IbcEvent::ClientMisbehaviour(ClientMisbehaviour { - client_id, - client_type, - consensus_height, - }) => IbcEvent::ClientMisbehaviour(ClientMisbehaviour { - client_id, - client_type, - consensus_height, - }), - IbcEvent::SubmitEvidence(SubmitEvidence { evidence_hash }) => { - IbcEvent::SubmitEvidence(SubmitEvidence { evidence_hash }) - } - IbcEvent::ConnectionOpenInit(ConnectionOpenInit { - connection_id, - client_id, - counterparty_client_id, - }) => IbcEvent::ConnectionOpenInit(ConnectionOpenInit { - connection_id, - client_id, - counterparty_client_id: counterparty_client_id.parse().unwrap(), - }), - IbcEvent::ConnectionOpenTry(ConnectionOpenTry { - connection_id, - client_id, - counterparty_client_id, - counterparty_connection_id, - }) => IbcEvent::ConnectionOpenTry(ConnectionOpenTry { - connection_id, - client_id, - counterparty_client_id: counterparty_client_id.parse().unwrap(), - counterparty_connection_id, - }), - IbcEvent::ConnectionOpenAck(ConnectionOpenAck { - connection_id, - client_id, - counterparty_client_id, - counterparty_connection_id, - }) => IbcEvent::ConnectionOpenAck(ConnectionOpenAck { - connection_id, - client_id, - counterparty_client_id: counterparty_client_id.parse().unwrap(), - counterparty_connection_id, - }), - IbcEvent::ConnectionOpenConfirm(ConnectionOpenConfirm { - connection_id, - client_id, - counterparty_client_id, - counterparty_connection_id, - }) => IbcEvent::ConnectionOpenConfirm(ConnectionOpenConfirm { - connection_id, - client_id, - counterparty_client_id: counterparty_client_id.parse().unwrap(), - counterparty_connection_id, - }), - IbcEvent::ChannelOpenInit(ChannelOpenInit { - port_id, - channel_id, - counterparty_port_id, - connection_id, - version, - }) => IbcEvent::ChannelOpenInit(ChannelOpenInit { - port_id, - channel_id, - counterparty_port_id, - connection_id, - version, - }), - IbcEvent::ChannelOpenTry(ChannelOpenTry { - port_id, - channel_id, - counterparty_port_id, - counterparty_channel_id, - connection_id, - version, - }) => IbcEvent::ChannelOpenTry(ChannelOpenTry { - port_id, - channel_id, - counterparty_port_id, - counterparty_channel_id, - connection_id, - version, - }), - IbcEvent::ChannelOpenAck(ChannelOpenAck { - port_id, - channel_id, - counterparty_port_id, - counterparty_channel_id, - connection_id, - }) => IbcEvent::ChannelOpenAck(ChannelOpenAck { - port_id, - channel_id, - counterparty_port_id, - counterparty_channel_id, - connection_id, - }), - IbcEvent::ChannelOpenConfirm(ChannelOpenConfirm { - port_id, - channel_id, - counterparty_port_id, - counterparty_channel_id, - connection_id, - }) => IbcEvent::ChannelOpenConfirm(ChannelOpenConfirm { - port_id, - channel_id, - counterparty_port_id, - counterparty_channel_id, - connection_id, - }), - IbcEvent::WriteAcknowledgement(WriteAcknowledgement { - packet_data_hex, - packet_timeout_height, - packet_timeout_timestamp, - packet_sequence, - packet_src_port, - packet_src_channel, - packet_dst_port, - packet_dst_channel, - packet_ack_hex, - connection_id, - }) => IbcEvent::WriteAcknowledgement(WriteAcknowledgement { - packet_data_hex, - packet_timeout_height, - packet_timeout_timestamp, - packet_sequence, - packet_src_port, - packet_src_channel, - packet_dst_port, - packet_dst_channel, - packet_ack_hex, - connection_id, - }), - IbcEvent::RecvPacket(RecvPacket { - packet_data_hex, - packet_timeout_height, - packet_timeout_timestamp, - packet_sequence, - packet_src_port, - packet_src_channel, - packet_dst_port, - packet_dst_channel, - packet_channel_ordering, - connection_id, - }) => IbcEvent::RecvPacket(RecvPacket { - packet_data_hex, - packet_timeout_height, - packet_timeout_timestamp, - packet_sequence, - packet_src_port, - packet_src_channel, - packet_dst_port, - packet_dst_channel, - packet_channel_ordering, - connection_id, - }), - IbcEvent::SendPacket(SendPacket { - packet_data_hex, - packet_timeout_height, - packet_timeout_timestamp, - packet_sequence, - packet_src_port, - packet_src_channel, - packet_dst_port, - packet_dst_channel, - packet_channel_ordering, - connection_id, - }) => IbcEvent::SendPacket(SendPacket { - packet_data_hex, - packet_timeout_height, - packet_timeout_timestamp, - packet_sequence, - packet_src_port, - packet_src_channel, - packet_dst_port, - packet_dst_channel, - packet_channel_ordering, - connection_id, - }), - IbcEvent::AcknowledgePacket(AcknowledgePacket { - packet_timeout_height, - packet_timeout_timestamp, - packet_sequence, - packet_src_port, - packet_src_channel, - packet_dst_port, - packet_dst_channel, - packet_channel_ordering, - connection_id, - }) => IbcEvent::AcknowledgePacket(AcknowledgePacket { - packet_timeout_height, - packet_timeout_timestamp, - packet_sequence, - packet_src_port, - packet_src_channel, - packet_dst_port, - packet_dst_channel, - packet_channel_ordering, - connection_id, - }), - IbcEvent::TimeoutPacket(TimeoutPacket { - packet_timeout_height, - packet_timeout_timestamp, - packet_sequence, - packet_src_port, - packet_src_channel, - packet_dst_port, - packet_dst_channel, - packet_channel_ordering, - connection_id, - }) => IbcEvent::TimeoutPacket(TimeoutPacket { - packet_timeout_height, - packet_timeout_timestamp, - packet_sequence, - packet_src_port, - packet_src_channel, - packet_dst_port, - packet_dst_channel, - packet_channel_ordering, - connection_id, - }), - } -} + init_log(); -#[cfg(test)] -mod tests { - use std::marker::PhantomData; + let app = as clap::Parser>::parse(); - use block_message::BlockMessage; - use chain_utils::{ - berachain::Berachain, cosmos::Cosmos, ethereum::Ethereum, scroll::Scroll, union::Union, - wasm::Wasm, - }; - use hex_literal::hex; - use queue_msg::{ - aggregate, defer_relative, effect, event, fetch, repeat, seq, Op, QueueMessage, - }; - use relay_message::{ - aggregate::AggregateMsgCreateClient, - chain::{ - cosmos_sdk::{ - fetch::{AbciQueryType, FetchAbciQuery}, - wasm::WasmConfig, - }, - ethereum::EthereumConfig, - }, - effect::{MsgChannelOpenInitData, MsgConnectionOpenInitData}, - event::IbcEvent, - fetch::{FetchSelfClientState, FetchSelfConsensusState}, - RelayMessage, - }; - use unionlabs::{ - ethereum::config::Minimal, - events::ConnectionOpenTry, - hash::H256, - ibc::core::{ - channel::{ - self, channel::Channel, msg_channel_open_init::MsgChannelOpenInit, order::Order, - }, - commitment::merkle_prefix::MerklePrefix, - connection::{self, msg_connection_open_init::MsgConnectionOpenInit, version::Version}, - }, - ics24, - uint::U256, - QueryHeight, DELAY_PERIOD, + let parse_config = |config_str| match serde_json::from_str::(config_str) { + Ok(ok) => ok, + Err(err) => { + error!("invalid config: {}", ErrorReporter(err)); + std::process::exit(INVALID_CONFIG_EXIT_CODE as i32); + } }; - use crate::{FromOp, VoyagerMessage}; + match app { + App::Run { + socket, + voyager_socket, + config, + } => { + let config = parse_config(&config); + + let ModuleInfo { name, kind: _ } = T::info(config.clone()); + + let name_ = name.clone(); + async move { + let voyager_rpc_client = reconnecting_jsonrpc_ws_client::Client::new({ + let voyager_socket: &'static str = voyager_socket.leak(); + let name_ = name_.clone(); + move || { + async move { + debug!("connecting to socket at {voyager_socket}"); + IpcClientBuilder::default().build(voyager_socket).await + } + .instrument(debug_span!("voyager_ipc_client", name = %name_)) + } + }); + + if let Err(err) = voyager_rpc_client + .wait_until_connected(Duration::from_millis(500)) + .await + { + error!("unable to connect to voyager socket: {err}"); + std::process::exit(STARTUP_ERROR_EXIT_CODE as i32); + }; - macro_rules! parse { - ($expr:expr) => { - $expr.parse().unwrap() - }; - } + info!("connected to voyager socket"); - #[test] - fn msg_serde() { - let union_chain_id: String = parse!("union-devnet-1"); - let eth_chain_id: U256 = parse!("32382"); - let simd_chain_id: String = parse!("simd-devnet-1"); - let scroll_chain_id: U256 = parse!("534351"); - let stargaze_chain_id: String = parse!("stargaze-devnet-1"); - let osmosis_chain_id: String = parse!("osmosis-devnet-1"); - - println!("---------------------------------------"); - println!("Union - Eth (Sending to Union) Connection Open: "); - println!("---------------------------------------"); - print_json::(effect( - relay_message::id::, Ethereum, _>( - union_chain_id.clone(), - MsgConnectionOpenInitData(MsgConnectionOpenInit { - client_id: parse!("08-wasm-0"), - counterparty: connection::counterparty::Counterparty { - client_id: parse!("cometbls-0"), - connection_id: parse!(""), - prefix: MerklePrefix { - key_prefix: b"ibc".to_vec(), - }, - }, - version: Version { - identifier: "1".into(), - features: [Order::Ordered, Order::Unordered].into_iter().collect(), - }, - delay_period: DELAY_PERIOD, - }), - ), - )); - - println!("---------------------------------------"); - println!("Fetch Client State: "); - println!("---------------------------------------"); - print_json::(fetch( - relay_message::id::, Ethereum, _>( - union_chain_id.clone(), - relay_message::fetch::Fetch::specific(FetchAbciQuery { - path: ics24::Path::ClientState(ics24::ClientStatePath { - client_id: parse!("client-id"), - }), - height: parse!("123-456"), - ty: AbciQueryType::State, - }), - ), - )); - - println!("---------------------------------------"); - println!("Eth - Union (Sending to Union) Channel Open: "); - println!("---------------------------------------"); - print_json::(effect( - relay_message::id::, Ethereum, _>( - union_chain_id.clone(), - MsgChannelOpenInitData { - msg: MsgChannelOpenInit { - port_id: parse!("WASM_PORT_ID"), - channel: Channel { - state: channel::state::State::Init, - ordering: channel::order::Order::Unordered, - counterparty: channel::counterparty::Counterparty { - port_id: parse!("ucs01-relay"), - channel_id: parse!(""), - }, - connection_hops: vec![parse!("connection-8")], - version: "ucs01-0".to_string(), - }, - }, - __marker: PhantomData, - }, - ), - )); - - println!("---------------------------------------"); - println!("Eth - Union (Starting on Union) Channel Open: "); - println!("---------------------------------------"); - print_json::(effect( - relay_message::id::, Wasm, _>( - eth_chain_id, - MsgChannelOpenInitData { - msg: MsgChannelOpenInit { - port_id: parse!("ucs01-relay"), - channel: Channel { - state: channel::state::State::Init, - ordering: channel::order::Order::Ordered, - counterparty: channel::counterparty::Counterparty { - port_id: parse!("ucs01-relay"), - channel_id: parse!(""), - }, - connection_hops: vec![parse!("connection-8")], - version: "ucs001-pingpong".to_string(), - }, - }, - __marker: PhantomData, - }, - ), - )); - - println!("---------------------------------------"); - println!("Eth - Union (Sending to Eth) Connection Open: "); - println!("---------------------------------------"); - print_json::(effect( - relay_message::id::, Wasm, _>( - eth_chain_id, - MsgConnectionOpenInitData(MsgConnectionOpenInit { - client_id: parse!("cometbls-0"), - counterparty: connection::counterparty::Counterparty { - client_id: parse!("08-wasm-0"), - connection_id: parse!(""), - prefix: MerklePrefix { - key_prefix: b"ibc".to_vec(), - }, - }, - version: Version { - identifier: "1".into(), - features: [Order::Ordered, Order::Unordered].into_iter().collect(), - }, - delay_period: DELAY_PERIOD, - }), - ), - )); - - println!("---------------------------------------"); - println!("Eth - Union (Sending to Eth) Connection Try: "); - println!("---------------------------------------"); - print_json::(event( - relay_message::id::, Wasm, _>( - eth_chain_id, - IbcEvent { - tx_hash: H256([0; 32]), - height: parse!("0-2941"), - event: unionlabs::events::IbcEvent::ConnectionOpenTry(ConnectionOpenTry { - connection_id: parse!("connection-0"), - client_id: parse!("cometbls-0"), - counterparty_client_id: parse!("08-wasm-1"), - counterparty_connection_id: parse!("connection-14"), - }), - }, - ), - )); - - println!("---------------------------------------"); - println!("Eth - Union (Sending to Eth) Update Client: "); - println!("---------------------------------------"); - print_json::(repeat( - None, - seq([ - event(relay_message::id::, Wasm, _>( - eth_chain_id, - relay_message::event::Command::UpdateClient { - client_id: parse!("cometbls-0"), - __marker: PhantomData, - }, - )), - defer_relative(10), - ]), - )); - - println!("---------------------------------------"); - println!("Eth - Union (Sending to Union) Update Client: "); - println!("---------------------------------------"); - print_json::(repeat( - None, - seq([ - event(relay_message::id::, Ethereum, _>( - union_chain_id.clone(), - relay_message::event::Command::UpdateClient { - client_id: parse!("08-wasm-0"), - __marker: PhantomData, - }, - )), - defer_relative(10), - ]), - )); - - println!("---------------------------------------"); - println!("Cosmos - Union (Sending to Cosmos) Update Client: "); - println!("---------------------------------------"); - print_json::(repeat( - None, - seq([ - event(relay_message::id::, Union, _>( - simd_chain_id.clone(), - relay_message::event::Command::UpdateClient { - client_id: parse!("08-wasm-0"), - __marker: PhantomData, - }, - )), - defer_relative(10), - ]), - )); - - println!("---------------------------------------"); - println!("Cosmos - Union (Sending to Union) Update Client: "); - println!("---------------------------------------"); - print_json::(repeat( - None, - seq([ - event(relay_message::id::, _>( - union_chain_id.clone(), - relay_message::event::Command::UpdateClient { - client_id: parse!("07-tendermint-0"), - __marker: PhantomData, - }, - )), - defer_relative(10), - ]), - )); - - println!("---------------------------------------"); - println!("Scroll - Union (Sending to Union) Create Scroll lightclient on Union: "); - println!("---------------------------------------"); - print_json::(aggregate( - [ - fetch(relay_message::id::, _>( - scroll_chain_id, - FetchSelfClientState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - fetch(relay_message::id::, _>( - scroll_chain_id, - FetchSelfConsensusState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - ], - [], - relay_message::id::, Scroll, _>( - union_chain_id.clone(), - AggregateMsgCreateClient { - config: WasmConfig { - checksum: H256(hex!( - "c4c38c95b12a03dabe366dab1a19671193b5f8de7abf53eb3ecabbb946a4ac88" - )), - }, - __marker: PhantomData, - }, - ), - )); - - println!("---------------------------------------"); - println!("Scroll - single update client"); - println!("---------------------------------------"); - print_json::(event(relay_message::id::, _>( - scroll_chain_id, - relay_message::event::Command::UpdateClient { - client_id: parse!("cometbls-0"), - __marker: PhantomData, - }, - ))); - - println!("---------------------------------------"); - println!("Union - Eth Create Both Clients: "); - println!("---------------------------------------"); - print_json::(seq([ - aggregate( - [ - fetch(relay_message::id::, Ethereum, _>( - union_chain_id.clone(), - FetchSelfClientState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - fetch(relay_message::id::, Ethereum, _>( - union_chain_id.clone(), - FetchSelfConsensusState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - ], - [], - relay_message::id::, Wasm, _>( - eth_chain_id, - AggregateMsgCreateClient { - config: EthereumConfig { - client_type: "cometbls".to_string(), - }, - __marker: PhantomData, - }, - ), - ), - aggregate( - [ - fetch(relay_message::id::, Wasm, _>( - eth_chain_id, - FetchSelfClientState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - fetch(relay_message::id::, Wasm, _>( - eth_chain_id, - FetchSelfConsensusState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - ], - [], - relay_message::id::, Ethereum, _>( - union_chain_id.clone(), - AggregateMsgCreateClient { - config: WasmConfig { - checksum: H256(hex!( - "78266014ea77f3b785e45a33d1f8d3709444a076b3b38b2aeef265b39ad1e494" - )), - }, - __marker: PhantomData, - }, - ), - ), - ])); - - println!("---------------------------------------"); - println!("Union - Cosmos Create Both Client: "); - println!("---------------------------------------"); - print_json::(seq([ - aggregate( - [ - fetch(relay_message::id::, Union, _>( - simd_chain_id.clone(), - FetchSelfClientState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - fetch(relay_message::id::, Union, _>( - simd_chain_id.clone(), - FetchSelfConsensusState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - ], - [], - relay_message::id::, _>( - union_chain_id.clone(), - AggregateMsgCreateClient { - config: (), - __marker: PhantomData, + let module_server = match T::new(config).await { + Ok(ctx) => ModuleServer { + voyager_rpc_client, + ctx, }, - ), - ), - aggregate( - [ - fetch(relay_message::id::, _>( - union_chain_id.clone(), - FetchSelfClientState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - fetch(relay_message::id::, _>( - union_chain_id.clone(), - FetchSelfConsensusState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - ], - [], - relay_message::id::, Union, _>( - simd_chain_id, - AggregateMsgCreateClient { - config: WasmConfig { - checksum: H256(hex!( - "78266014ea77f3b785e45a33d1f8d3709444a076b3b38b2aeef265b39ad1e494" - )), - }, - __marker: PhantomData, - }, - ), - ), - ])); - - println!("---------------------------------------"); - println!("Cosmos - Cosmos Create Both Client: "); - println!("---------------------------------------"); - print_json::(seq([ - aggregate( - [ - fetch(relay_message::id::( - stargaze_chain_id.clone(), - FetchSelfClientState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - fetch(relay_message::id::( - stargaze_chain_id.clone(), - FetchSelfConsensusState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - ], - [], - relay_message::id::( - osmosis_chain_id.clone(), - AggregateMsgCreateClient { - config: (), - __marker: PhantomData, - }, - ), - ), - aggregate( - [ - fetch(relay_message::id::( - osmosis_chain_id.clone(), - FetchSelfClientState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - fetch(relay_message::id::( - osmosis_chain_id.clone(), - FetchSelfConsensusState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - ], - [], - relay_message::id::( - stargaze_chain_id.clone(), - AggregateMsgCreateClient { - config: (), - __marker: PhantomData, - }, - ), - ), - ])); - - println!("---------------------------------------"); - println!("Scroll - single update client"); - println!("---------------------------------------"); - print_json::(event(relay_message::id::, _>( - scroll_chain_id, - relay_message::event::Command::UpdateClient { - client_id: parse!("cometbls-0"), - __marker: PhantomData, - }, - ))); - - println!("---------------------------------------"); - println!("Scroll - fetch update header"); - println!("---------------------------------------"); - print_json::(fetch(relay_message::id::, _>( - scroll_chain_id, - relay_message::fetch::Fetch::UpdateHeaders(relay_message::fetch::FetchUpdateHeaders { - counterparty_chain_id: union_chain_id.clone(), - counterparty_client_id: parse!("08-wasm-0"), - update_from: parse!("0-1"), - update_to: parse!("0-4846816"), - }), - ))); - - print_json::(fetch(block_message::id::( - "simd-devnet-1".parse().unwrap(), - block_message::fetch::FetchBlock { - height: unionlabs::ibc::core::client::height::Height { - revision_number: 1, - revision_height: 1, - }, - }, - ))); - - print_json::(fetch(block_message::id::( - "union-devnet-1".parse().unwrap(), - block_message::fetch::FetchBlock { - height: unionlabs::ibc::core::client::height::Height { - revision_number: 1, - revision_height: 1, - }, - }, - ))); - - print_json::(fetch(relay_message::id::, Berachain, _>( - parse!("union-testnet-8"), - relay_message::fetch::FetchUpdateHeaders { - counterparty_client_id: parse!("cometbls-4"), - counterparty_chain_id: parse!("80084"), - update_from: parse!("8-969001"), - update_to: parse!("8-969002"), - }, - ))); - - print_json::(seq([ - aggregate( - [ - fetch(relay_message::id::, Berachain, _>( - parse!("union-testnet-8"), - FetchSelfClientState { - at: parse!("8-968996"), - __marker: PhantomData, - }, - )), - fetch(relay_message::id::, Berachain, _>( - parse!("union-testnet-8"), - FetchSelfConsensusState { - at: parse!("8-968996"), - __marker: PhantomData, - }, - )), - ], - [], - relay_message::id::, _>( - parse!("80084"), - AggregateMsgCreateClient { - config: EthereumConfig { - client_type: "cometbls".to_owned(), - }, - __marker: PhantomData, - }, - ), - ), - fetch(relay_message::id::, Berachain, _>( - parse!("union-testnet-8"), - relay_message::fetch::FetchUpdateHeaders { - counterparty_client_id: parse!("cometbls-5"), - counterparty_chain_id: parse!("80084"), - update_from: parse!("8-968996"), - update_to: parse!("8-969001"), - }, - )), - fetch(relay_message::id::, Berachain, _>( - parse!("union-testnet-8"), - relay_message::fetch::FetchUpdateHeaders { - counterparty_client_id: parse!("cometbls-5"), - counterparty_chain_id: parse!("80084"), - update_from: parse!("8-969001"), - update_to: parse!("8-969002"), - }, - )), - ])); - } + Err(err) => { + error!("startup error: {err:?}"); + std::process::exit(STARTUP_ERROR_EXIT_CODE as i32); + } + }; + + let ipc_server = reth_ipc::server::Builder::default().build(socket); + + let addr = ipc_server.endpoint(); - fn print_json(msg: Op) - where - VoyagerMessage: FromOp, - { - let msg = VoyagerMessage::from_op(msg); + let rpcs = <(T::Info, T)>::into_rpc(module_server); - let json = serde_json::to_string(&msg).unwrap(); + trace!(methods = ?*rpcs, "registered methods"); - println!("{json}\n"); + let server_handle = ipc_server.start(rpcs).await.unwrap(); - let from_json = serde_json::from_str(&json).unwrap(); + info!("listening on {addr}"); - assert_eq!(&msg, &from_json, "json roundtrip failed"); + tokio::spawn( + server_handle + .stopped() + .instrument(debug_span!("module_server", name = %name_)), + ) + .await + .unwrap(); + } + .instrument(debug_span!("run_module_server", %name)) + .await + } + App::Info { config } => { + let info = T::info(parse_config(&config)); + + let info = ModuleInfo:: { + name: info.name, + kind: info.kind.into(), + }; + + print!("{}", serde_json::to_string(&info).unwrap()) + } + App::Cmd { cmd, config } => T::cmd(parse_config(&config), cmd).await, } } diff --git a/lib/voyager-message/src/module.rs b/lib/voyager-message/src/module.rs new file mode 100644 index 0000000000..a568f212b8 --- /dev/null +++ b/lib/voyager-message/src/module.rs @@ -0,0 +1,437 @@ +use std::{borrow::Cow, collections::VecDeque}; + +use enumorph::Enumorph; +use jsonrpsee::{core::RpcResult, proc_macros::rpc, types::ErrorObject, RpcModule}; +use macros::model; +use queue_msg::{optimize::OptimizationResult, Op}; +use serde_json::{json, Value}; +use serde_utils::Hex; +use tracing::debug; +use unionlabs::{ + hash::H256, + ibc::core::client::height::Height, + ics24::{IbcPath, Path}, + id::ClientId, + traits::Member, + ErrorReporter, +}; + +use crate::{ + data::{ClientInfo, Data}, + ChainId, ClientType, IbcInterface, ModuleContext, ModuleServer, VoyagerMessage, + FATAL_JSONRPC_ERROR_CODE, +}; + +#[model] +pub struct ModuleInfo { + pub name: String, + pub kind: K, +} + +#[model] +#[derive(Enumorph)] +pub enum ModuleKindInfo { + Chain(ChainModuleInfo), + Consensus(ConsensusModuleInfo), + Client(ClientModuleInfo), + Plugin(PluginModuleInfo), +} + +pub trait IModuleKindInfo: Member + Into {} + +#[model] +pub struct ChainModuleInfo { + pub chain_id: ChainId<'static>, +} + +impl IModuleKindInfo for ChainModuleInfo {} + +#[model] +pub struct ConsensusModuleInfo { + pub chain_id: ChainId<'static>, + pub client_type: ClientType<'static>, +} + +impl IModuleKindInfo for ConsensusModuleInfo {} + +#[model] +pub struct ClientModuleInfo { + /// The client type that this client module provides functionality for. + pub client_type: ClientType<'static>, + + /// The IBC interface that this client module provides functionality for. + pub ibc_interface: IbcInterface<'static>, +} + +impl IModuleKindInfo for ClientModuleInfo {} + +#[model] +pub struct PluginModuleInfo { + /// A jaq filter to run on every message before pushing them to the queue. + /// This ***MUST*** return a bool. If this returns true, the message will be + /// pushed to the optimization queue with this plugin's name as the tag, + /// else it will be passed on to the next plugin to be filtered. If this is + /// None, this plugin will not be registered as an + /// [`OptimizationPassPlugin`]. + pub interest_filter: String, +} + +impl IModuleKindInfo for PluginModuleInfo {} + +// REVIEW: Rename? +#[rpc( + client, + server, + client_bounds(Self: Send + Sync), + server_bounds(Self: Send + Sync), + namespace = "plugin", +)] +// TODO: Rename this lol +pub trait QueueInteractions { + /// Handle a custom `Call` message for this module. + #[method(name = "call")] + async fn call(&self, call: C) -> RpcResult>>; + + /// Handle a custom `Callback` message for this module. + #[method(name = "callback")] + async fn callback( + &self, + aggregate: Cb, + data: VecDeque>, + ) -> RpcResult>>; +} + +pub trait IntoRpc: Sized { + type RpcModule; + + fn into_rpc(t: Self::RpcModule) -> RpcModule; +} + +impl IntoRpc for (PluginModuleInfo, T) +where + T: ModuleContext, + ModuleServer: Clone + QueueInteractionsServer + PluginModuleServer, +{ + type RpcModule = ModuleServer; + + fn into_rpc(t: Self::RpcModule) -> RpcModule { + let mut rpcs = QueueInteractionsServer::into_rpc(t.clone()); + rpcs.merge(PluginModuleServer::into_rpc(t)).unwrap(); + rpcs + } +} + +impl IntoRpc for (ChainModuleInfo, T) +where + T: ModuleContext, + ModuleServer: Clone + QueueInteractionsServer + ChainModuleServer, +{ + type RpcModule = ModuleServer; + + fn into_rpc(t: Self::RpcModule) -> RpcModule { + let mut rpcs = QueueInteractionsServer::into_rpc(t.clone()); + rpcs.merge(ChainModuleServer::into_rpc(t)).unwrap(); + rpcs + } +} + +impl IntoRpc for (ClientModuleInfo, T) +where + T: ModuleContext, + ModuleServer: Clone + QueueInteractionsServer + ClientModuleServer, +{ + type RpcModule = ModuleServer; + + fn into_rpc(t: Self::RpcModule) -> RpcModule { + let mut rpcs = QueueInteractionsServer::into_rpc(t.clone()); + rpcs.merge(ClientModuleServer::into_rpc(t)).unwrap(); + rpcs + } +} + +impl IntoRpc for (ConsensusModuleInfo, T) +where + T: ModuleContext, + ModuleServer: Clone + QueueInteractionsServer + ConsensusModuleServer, +{ + type RpcModule = ModuleServer; + + fn into_rpc(t: Self::RpcModule) -> RpcModule { + let mut rpcs = QueueInteractionsServer::into_rpc(t.clone()); + rpcs.merge(ConsensusModuleServer::into_rpc(t)).unwrap(); + rpcs + } +} + +#[rpc( + client, + server, + client_bounds(Self: QueueInteractionsClient), + server_bounds(Self: QueueInteractionsServer), + namespace = "plugin" +)] +pub trait PluginModule { + #[method(name = "runPass")] + async fn run_pass( + &self, + msgs: Vec>>, + ) -> RpcResult>>; +} + +/// Chain modules provide functionality to interact with a single chain, +/// providing interfaces to interact with the +#[rpc( + client, + server, + client_bounds(Self: QueueInteractionsClient), + server_bounds(Self: QueueInteractionsServer), + namespace = "chain" +)] +pub trait ChainModule { + /// Register this chain module with Voyager, returning the chain id of the + /// chain this module tracks. + // TODO: This can probably be removed + #[method(name = "chainId")] + fn chain_id(&self) -> RpcResult>; + + /// Query the latest finalized height of this chain. + #[method(name = "queryLatestHeight")] + async fn query_latest_height(&self) -> RpcResult; + + /// Query the latest (non-finalized) height of this chain. + #[method(name = "queryLatestHeightAsDestination")] + async fn query_latest_height_as_destination(&self) -> RpcResult; + + /// Query the latest finalized timestamp of this chain. + #[method(name = "queryLatestTimestamp")] + // TODO: Make this return a better type than i64 + async fn query_latest_timestamp(&self) -> RpcResult; + + #[method(name = "fetchBlockRange")] + async fn fetch_block_range( + &self, + from_height: Height, + to_height: Height, + ) -> RpcResult>>; + + /// Query the latest raw, unfinalized trusted client state of the client + /// `client_id`. + // SEE: + #[method(name = "queryRawUnfinalizedTrustedClientState")] + async fn query_raw_unfinalized_trusted_client_state( + &self, + client_id: ClientId, + ) -> RpcResult>; + + // TODO: For the state and proof query functions, it would be best if they + // weren't concerned with the encoding of them; this should be handed off to a + // different module + + /// Fetch the client info of a client on this chain. + #[method(name = "clientInfo")] + async fn client_info(&self, client_id: ClientId) -> RpcResult; + + /// Query IBC state on this chain, at the specified [`Height`], returning + /// the value as a JSON [`Value`]. + #[method(name = "queryIbcState")] + async fn query_ibc_state(&self, at: Height, path: Path) -> RpcResult; + + /// Query a proof of IBC state on this chain, at the specified [`Height`], + /// returning the proof as a JSON [`Value`]. + #[method(name = "queryIbcProof")] + async fn query_ibc_proof(&self, at: Height, path: Path) -> RpcResult; +} + +/// Raw, un-decoded client state, as queried directly from the client store. +#[model] +pub struct RawClientState<'a> { + pub client_type: ClientType<'a>, + pub ibc_interface: IbcInterface<'a>, + pub bytes: Cow<'a, [u8]>, +} + +pub trait ChainModuleClientExt: ChainModuleClient + Send + Sync { + // TODO: Maybe rename? Cor likes "_checked" + // TODO: Maybe take by ref here? + #[allow(async_fn_in_trait)] + async fn query_ibc_state_typed( + &self, + at: Height, + path: P, + ) -> Result { + debug!(%path, %at, "querying ibc state"); + + let state = self.query_ibc_state(at, path.clone().into()).await?; + + Ok( + serde_json::from_value::(state.clone()).map_err(|e| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to deserialize state: {}", ErrorReporter(e)), + Some(json!({ + "path": path, + "state": state + })), + ) + })?, + ) + } +} + +impl ChainModuleClientExt for T where T: ChainModuleClient + Send + Sync {} + +/// Client modules provide functionality to interact with a single light client +/// type, on a single IBC interface. This can also be thought of as a "client +/// codec", as all of the endpoints it exposes are related to encoding and +/// decoding state. +#[rpc( + client, + server, + client_bounds(Self: QueueInteractionsClient), + server_bounds(Self: QueueInteractionsServer), + namespace = "client" +)] +// TODO: Rename to client codec module +pub trait ClientModule { + /// Register this module with Voyager. + // TODO: This can probably be removed + #[method(name = "supportedInterface")] + async fn supported_interface(&self) -> RpcResult; + + /// Decode the raw client state, returning the decoded metadata common + /// between all client state types. + #[method(name = "decodeClientStateMeta")] + async fn decode_client_state_meta( + &self, + client_state: Hex>, + ) -> RpcResult; + + /// Decode the raw consensus state, returning the decoded metadata common + /// between all consensus state types. + #[method(name = "decodeConsensusStateMeta")] + async fn decode_consensus_state_meta( + &self, + consensus_state: Hex>, + ) -> RpcResult; + + /// Decode the raw client state, returning the decoded state as JSON. + #[method(name = "decodeClientState")] + async fn decode_client_state(&self, client_state: Hex>) -> RpcResult; + + /// Decode the raw consensus state, returning the decoded state as JSON. + #[method(name = "decodeConsensusState")] + async fn decode_consensus_state(&self, consensus_state: Hex>) -> RpcResult; + + /// Encode the client state, provided as JSON. + #[method(name = "encodeClientState")] + async fn encode_client_state( + &self, + client_state: Value, + metadata: Value, + ) -> RpcResult>>; + + /// Encode the consensus state, provided as JSON. + #[method(name = "encodeConsensusState")] + async fn encode_consensus_state(&self, consensus_state: Value) -> RpcResult>>; + + /// Re-encode the client state of the specified counterparty client type. + /// + /// This is required due to limitations with ibc-go v8, and can likely be + /// removed once support for that IBC interface is dropped. In most cases, + /// this will simply be a pass-through of the bytes provided. + #[method(name = "reencodeCounterpartyClientState")] + async fn reencode_counterparty_client_state( + &self, + client_state: Hex>, + client_type: ClientType<'static>, + ) -> RpcResult>>; + + /// Re-encode the client state of the specified counterparty client type. + /// + /// This is required due to limitations with ibc-go v8, and can likely be + /// removed once support for that IBC interface is dropped. In most cases, + /// this will simply be a pass-through of the bytes provided. + #[method(name = "reencodeCounterpartyConsensusState")] + async fn reencode_counterparty_consensus_state( + &self, + consensus_state: Hex>, + client_type: ClientType<'static>, + ) -> RpcResult>>; + + /// Encode the header, provided as JSON. + #[method(name = "encodeHeader")] + async fn encode_header(&self, header: Value) -> RpcResult>>; + + /// Encode the proof, provided as JSON. + #[method(name = "encodeProof")] + async fn encode_proof(&self, proof: Value) -> RpcResult>>; +} + +/// Client modules provide functionality for interacting with a specific chain +/// consensus. +#[rpc( + client, + server, + client_bounds(Self: QueueInteractionsClient), + server_bounds(Self: QueueInteractionsServer), + namespace = "consensus" +)] +pub trait ConsensusModule { + /// Register this module with Voyager. + // TODO: This can probably be removed + #[method(name = "info")] + async fn consensus_info(&self) -> RpcResult; + + /// The client state of this chain at the specified [`Height`]. + /// + /// Returns the client state value as JSON, which will then be encoded to + /// bytes by a ClientModule. + #[method(name = "selfClientState")] + async fn self_client_state(&self, height: Height) -> RpcResult; + + /// The consensus state of this chain at the specified [`Height`]. + /// + /// Returns the consensus state value as JSON, which will then be encoded to + /// bytes by a ClientModule. + #[method(name = "selfConsensusState")] + async fn self_consensus_state(&self, height: Height) -> RpcResult; + + /// Generate a client update for this module's client type. + /// + /// # Implementor's Note + /// + /// The returned [`Op`] ***MUST*** resolve to an [`OrderedHeaders`] data. + /// This is the entrypoint called when a client update is requested, and + /// is intended to be called in the queue of an + /// [`AggregateMsgUpdateClientsFromOrderedHeaders`] message, which will + /// be used to build the actual [`MsgUpdateClient`]s. + #[method(name = "fetchUpdateHeaders")] + async fn fetch_update_headers( + &self, + update_from: Height, + update_to: Height, + counterparty_chain_id: ChainId<'static>, + ) -> RpcResult>>; +} + +#[model] +pub struct ClientStateMeta { + /// The counterparty height this client has been updated to. A consensus + /// state will exist at this height. + pub height: Height, + + /// The chain id of the counterparty chain this client tracks. + pub chain_id: ChainId<'static>, +} + +#[model] +pub struct ConsensusStateMeta { + /// The timestamp of the counterparty at the height represented by this + /// consensus state. + pub timestamp_nanos: u64, +} + +#[model] +pub struct IbcGo08WasmClientMetadata { + pub checksum: H256, +} diff --git a/lib/voyager-message/src/pass.rs b/lib/voyager-message/src/pass.rs new file mode 100644 index 0000000000..8763c659f7 --- /dev/null +++ b/lib/voyager-message/src/pass.rs @@ -0,0 +1,130 @@ +use std::rc::Rc; + +use jaq_interpret::{Ctx, Filter, FilterT, ParseCtx, RcIter, Val}; +use queue_msg::{ + optimize::{OptimizationResult, PurePass}, + BoxDynError, Op, +}; +use tracing::{error, trace, trace_span}; +use unionlabs::ErrorReporter; + +use crate::VoyagerMessage; + +#[derive(Debug, Clone)] +pub struct JaqInterestFilter { + pub filters: Vec<(Filter, String)>, +} + +impl JaqInterestFilter { + /// `(plugin_name, filter)[]` + pub fn new(filters: Vec<(String, String)>) -> Result { + Ok(Self { + filters: filters + .into_iter() + .map(|(plugin_name, filter)| { + let mut ctx = ParseCtx::new(["PLUGIN_NAME".to_owned()].into()); + + ctx.insert_natives(jaq_core::core()); + ctx.insert_defs(jaq_std::std()); + + // parse the filter + let lexed = jaq_syn::Lexer::new(&filter).lex().map_err(|es| { + es.iter() + .map(|(expect, s)| format!("({}: {s})", expect.as_str())) + .collect::>() + .join(",") + })?; + let f = jaq_syn::Parser::new(&lexed) + .parse(|p| p.module(|p| p.term())) + .map_err(|es| { + es.iter() + .map(|(expect, maybe_token)| match maybe_token { + Some(token) => { + format!("({}, {})", expect.as_str(), token.as_str()) + } + None => format!("({})", expect.as_str()), + }) + .collect::>() + .join(",") + }); + // let f = jaq_syn::parse(&filter, |p| p.module(|p| p.term())) + // .map(|m| m.conv(&filter)); + + // compile the filter in the context of the given definitions + let filter = ctx.compile(f?.conv(&filter)); + + assert!( + ctx.errs.is_empty(), + "{:?}", + ctx.errs + .into_iter() + .map(|x| x.0.to_string()) + .collect::>() + ); + + Ok((filter, plugin_name)) + }) + .collect::>()?, + }) + } +} + +impl PurePass for JaqInterestFilter { + fn run_pass_pure(&self, msgs: Vec>) -> OptimizationResult { + let mut opt_res = OptimizationResult::default(); + + let inputs = RcIter::new(core::iter::empty()); + + 'outer: for (idx, msg) in msgs.into_iter().enumerate() { + let msg_json = Val::from(serde_json::to_value(msg.clone()).unwrap()); + + for (filter, plugin_name) in &self.filters { + let _span = trace_span!("checking interest", %plugin_name).entered(); + + let mut out = filter.run(( + Ctx::new([Val::Str(Rc::new(plugin_name.clone()))], &inputs), + msg_json.clone(), + )); + + let Some(result) = out.next() else { + error!("filter didn't return any values"); + + continue; + }; + + let result = match result { + Ok(ok) => ok, + Err(err) => { + error!(%msg_json, err = %ErrorReporter(err), "filter failed"); + + continue; + } + }; + + if out.next().is_some() { + error!("filter returned multiple values, only a single boolean value is valid"); + } else { + match result { + Val::Bool(true) => { + trace!(%msg_json, "interest"); + + opt_res + .optimize_further + .push((vec![idx], msg, plugin_name.clone())); + + continue 'outer; + } + Val::Bool(false) => { + trace!(%msg_json, "no interest"); + } + _ => error!("filter returned a non-boolean value: {result:?}"), + } + } + } + + opt_res.ready.push((vec![idx], msg)); + } + + opt_res + } +} diff --git a/lib/voyager-message/src/rpc.rs b/lib/voyager-message/src/rpc.rs new file mode 100644 index 0000000000..89fbeef57f --- /dev/null +++ b/lib/voyager-message/src/rpc.rs @@ -0,0 +1,211 @@ +use jsonrpsee::{ + self, + core::RpcResult, + proc_macros::rpc, + types::{ErrorObject, ErrorObjectOwned}, +}; +use macros::model; +use serde_json::{json, Value}; +use serde_utils::Hex; +use tracing::debug; +use unionlabs::{ + ibc::core::client::height::Height, + ics24::{IbcPath, Path}, + id::ClientId, + ErrorReporter, QueryHeight, +}; + +use crate::{ + data::ClientInfo, module::ClientStateMeta, ChainId, ClientType, IbcInterface, + FATAL_JSONRPC_ERROR_CODE, +}; + +pub mod server; + +#[rpc( + client, + server, + client_bounds(Self: Send + Sync), + server_bounds(Self:), + namespace = "voyager", +)] +pub trait VoyagerRpc { + #[method(name = "info")] + async fn info(&self) -> RpcResult; + + #[method(name = "queryLatestHeight")] + async fn query_latest_height(&self, chain_id: ChainId<'static>) -> RpcResult; + + #[method(name = "queryLatestTimestamp")] + // TODO: Make this return a better type than i64 + async fn query_latest_timestamp(&self, chain_id: ChainId<'static>) -> RpcResult; + + #[method(name = "clientInfo")] + async fn client_info( + &self, + chain_id: ChainId<'static>, + client_id: ClientId, + ) -> RpcResult; + + #[method(name = "clientMeta")] + async fn client_meta( + &self, + chain_id: ChainId<'static>, + at: QueryHeight, + client_id: ClientId, + ) -> RpcResult; + + #[method(name = "queryIbcState")] + async fn query_ibc_state( + &self, + chain_id: ChainId<'static>, + height: QueryHeight, + path: Path, + ) -> RpcResult; + + #[method(name = "queryIbcProof")] + async fn query_ibc_proof( + &self, + chain_id: ChainId<'static>, + height: QueryHeight, + path: Path, + ) -> RpcResult; + + #[method(name = "selfClientState")] + async fn self_client_state( + &self, + chain_id: ChainId<'static>, + height: QueryHeight, + ) -> RpcResult; + + #[method(name = "selfConsensusState")] + async fn self_consensus_state( + &self, + chain_id: ChainId<'static>, + height: QueryHeight, + ) -> RpcResult; + + #[method(name = "encodeProof")] + async fn encode_proof( + &self, + client_type: ClientType<'static>, + ibc_interface: IbcInterface<'static>, + proof: Value, + ) -> RpcResult>>; + + #[method(name = "decodeClientStateMeta")] + async fn decode_client_state_meta( + &self, + client_type: ClientType<'static>, + ibc_interface: IbcInterface<'static>, + client_state: Hex>, + ) -> RpcResult; + + #[method(name = "decodeClientState")] + async fn decode_client_state( + &self, + client_type: ClientType<'static>, + ibc_interface: IbcInterface<'static>, + client_state: Hex>, + ) -> RpcResult; + + #[method(name = "decodeConsensusState")] + async fn decode_consensus_state( + &self, + client_type: ClientType<'static>, + ibc_interface: IbcInterface<'static>, + consensus_state: Hex>, + ) -> RpcResult; +} + +#[model] +pub struct Info { + chain: Vec>, + consensus: Vec>, + client: Vec<(ClientType<'static>, IbcInterface<'static>)>, +} + +#[model] +// TODO: Flip these parameters +pub struct IbcState { + pub chain_id: ChainId<'static>, + pub path: P, + /// The height that the state was read at. + pub height: Height, + pub state: State, +} + +#[model] +pub struct IbcProof { + pub path: Path, + /// The height that the proof was read at. + pub height: Height, + pub proof: Value, +} + +#[model] +pub struct SelfClientState { + pub height: Height, + pub state: Value, +} + +#[model] +pub struct SelfConsensusState { + pub height: Height, + pub state: Value, +} + +/// Serves the same purpose as `ChainModuleClientExt`. +pub trait VoyagerRpcClientExt: VoyagerRpcClient { + // TODO: Maybe rename? Cor likes "_checked" + // TODO: Maybe take by ref here? + #[allow(async_fn_in_trait)] + async fn query_ibc_state_typed( + &self, + chain_id: ChainId<'static>, + at: QueryHeight, + path: P, + ) -> Result, jsonrpsee::core::client::Error> { + debug!(%path, %at, "querying ibc state"); + + let ibc_state = self + .query_ibc_state(chain_id.clone(), at, path.clone().into()) + .await?; + + Ok(serde_json::from_value::(ibc_state.state.clone()) + .map(|value| IbcState { + chain_id: ibc_state.chain_id, + path: path.clone(), + height: ibc_state.height, + state: value, + }) + .map_err(|e| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to deserialize state: {}", ErrorReporter(e)), + Some(json!({ + "chain_id": chain_id, + "path": path, + "state": ibc_state.state + })), + ) + })?) + } +} + +impl VoyagerRpcClientExt for T where T: VoyagerRpcClient {} + +pub fn json_rpc_error_to_rpc_error(value: jsonrpsee::core::client::Error) -> ErrorObjectOwned { + match value { + jsonrpsee::core::client::Error::Call(error) => error, + value => ErrorObject::owned(-1, format!("error: {}", ErrorReporter(value)), None::<()>), + } +} + +/// Some required state was missing (connection/channel end, packet commitment, ..) +pub fn missing_state( + message: impl Into, + data: Option, +) -> impl FnOnce() -> ErrorObjectOwned { + move || ErrorObject::owned(FATAL_JSONRPC_ERROR_CODE, message, data) +} diff --git a/lib/voyager-message/src/rpc/server.rs b/lib/voyager-message/src/rpc/server.rs new file mode 100644 index 0000000000..9bb2e096b6 --- /dev/null +++ b/lib/voyager-message/src/rpc/server.rs @@ -0,0 +1,689 @@ +use std::sync::{Arc, OnceLock}; + +use jsonrpsee::{ + core::RpcResult, + types::{ErrorObject, ErrorObjectOwned}, +}; +use serde_json::{json, Value}; +use serde_utils::Hex; +use tonic::async_trait; +use tracing::{debug, error, info_span, instrument, Instrument}; +use unionlabs::{ + ibc::core::client::height::Height, + ics24::{ClientStatePath, IbcPath, Path}, + id::ClientId, + ErrorReporter, QueryHeight, +}; + +use crate::{ + context::Modules, + data::ClientInfo, + module::{ + ChainModuleClient, ChainModuleClientExt, ClientModuleClient, ClientStateMeta, + ConsensusModuleClient, + }, + rpc::{ + json_rpc_error_to_rpc_error, IbcProof, IbcState, Info, SelfClientState, SelfConsensusState, + VoyagerRpcServer, + }, + ChainId, ClientType, IbcInterface, FATAL_JSONRPC_ERROR_CODE, +}; + +#[derive(Debug, Clone)] +pub struct Server { + inner: Arc, +} + +#[derive(macros::Debug, Clone)] +pub struct ServerInner { + modules: OnceLock>, + #[debug("Cache({:?}, {})", self.ibc_state_cache.name(), self.ibc_state_cache.entry_count())] + ibc_state_cache: moka::future::Cache<(ChainId<'static>, Path, Height), Value>, +} + +// #[derive(Debug, Clone, Hash, PartialEq, Eq)] +// pub struct IbcStateCacheKey<'a> { +// chain_id: ChainId<'a>, +// path: Cow<'a, Path>, +// // height is copy so don't bother wrapping it +// height: Height, +// } + +// impl<'a> IbcStateCacheKey<'a> { +// pub fn new(chain_id: ChainId<'a>, path: &'a Path, height: Height) -> Self { +// Self { +// chain_id, +// path: Cow::Borrowed(path), +// height, +// } +// } +// } + +// impl IbcStateCacheKey<'static> { +// pub fn new_owned(chain_id: ChainId<'static>, path: Path, height: Height) -> Self { +// Self { +// chain_id, +// path: Cow::Owned(path), +// height, +// } +// } +// } + +impl Server { + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + Server { + inner: Arc::new(ServerInner { + modules: OnceLock::new(), + ibc_state_cache: moka::future::Cache::builder() + .eviction_listener(|k, v, why| { + error!(?k, ?v, ?why, "value evicted from the cache") + }) + .max_capacity(10_000) + .name("ibc_state_cache") + .build(), + }), + } + } + + pub fn start(&self, modules: Arc) { + let was_already_started = self.inner.modules.set(modules).is_ok(); + + assert!(was_already_started, "server has already been started"); + } + + /// Returns the contained modules, if they have been loaded. + pub fn modules(&self) -> RpcResult<&Modules> { + self.inner.modules() + } + + #[instrument(skip_all, fields(%height, %chain_id))] + pub async fn query_height( + &self, + chain_id: &ChainId<'_>, + height: QueryHeight, + ) -> RpcResult { + match height { + QueryHeight::Latest => { + let latest_height = self + .modules()? + .chain_module::(chain_id) + .map_err(fatal_error)? + .query_latest_height() + .await + .map_err(json_rpc_error_to_rpc_error)?; + + debug!(%latest_height, "queried latest height"); + + Ok(latest_height) + } + QueryHeight::Specific(height) => Ok(height), + } + } +} + +impl ServerInner { + /// Returns the contained modules, if they have been loaded. + fn modules(&self) -> RpcResult<&Modules> { + self.modules + .get() + .map(|x| &**x) + .ok_or_else(|| ErrorObject::owned(-2, "server has not started", None::<()>)) + } + + async fn query_ibc_state_cached<'a>( + &self, + chain_id: &ChainId<'a>, + at: Height, + path: Path, + ) -> Result { + let key = (chain_id.clone().into_static(), path.clone(), at); + + let state = self + .ibc_state_cache + .entry_by_ref(&key) + .or_try_insert_with( + async { + debug!(%chain_id, %path, %at, "querying ibc state (not yet cached)"); + + let state = self + .modules()? + .chain_module::(chain_id) + .map_err(fatal_error)? + .query_ibc_state(at, path) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + RpcResult::Ok(state) + } + .instrument(info_span!("ibc state cache fetcher")), + ) + .await + .map_err(Arc::unwrap_or_clone)?; + + let (chain_id, path, height) = key; + + if !state.is_fresh() { + debug!( + cache = %self.ibc_state_cache.name().unwrap_or_default(), + key.chain_id = %chain_id, + key.path = %path, + key.height = %height, + raw_key = %format_args!("chain_id:{chain_id};path:{path};height:{height}"), + "cache hit" + ); + } + + Ok(IbcState { + chain_id, + path, + height, + state: state.into_value(), + }) + + // Ok( + // serde_json::from_value::(state.clone()).map_err(|e| { + // ErrorObject::owned( + // FATAL_JSONRPC_ERROR_CODE, + // format!("unable to deserialize state: {}", ErrorReporter(e)), + // Some(json!({ + // "path": path, + // "state": state + // })), + // ) + // })?, + // ) + } +} + +impl Server { + #[instrument(skip_all, fields(%chain_id))] + pub async fn query_latest_height(&self, chain_id: &ChainId<'static>) -> RpcResult { + debug!("querying latest height"); + + let latest_height = self + .inner + .modules()? + .chain_module::(chain_id) + .map_err(fatal_error)? + .query_latest_height() + .await + .map_err(json_rpc_error_to_rpc_error)?; + + debug!(%latest_height, "queried latest height"); + + Ok(latest_height) + } + + #[instrument(skip_all, fields(%chain_id))] + pub async fn query_latest_timestamp(&self, chain_id: &ChainId<'static>) -> RpcResult { + debug!("querying latest timestamp"); + + let latest_timestamp = self + .inner + .modules()? + .chain_module::(chain_id) + .map_err(fatal_error)? + .query_latest_timestamp() + .await + .map_err(json_rpc_error_to_rpc_error)?; + + debug!(%latest_timestamp, "queried latest timestamp"); + + Ok(latest_timestamp) + } + + #[instrument(skip_all, fields(%chain_id, %client_id))] + pub async fn client_info( + &self, + chain_id: &ChainId<'static>, + client_id: ClientId, + ) -> RpcResult { + debug!("fetching client info"); + + let client_info = self + .inner + .modules()? + .chain_module::(chain_id) + .map_err(fatal_error)? + .client_info(client_id) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + debug!( + %client_info.ibc_interface, + %client_info.client_type, + "fetched client info" + ); + + Ok(client_info) + } + + #[instrument(skip_all, fields(%chain_id, height = %at, %client_id))] + pub async fn client_meta( + &self, + chain_id: ChainId<'static>, + at: QueryHeight, + client_id: ClientId, + ) -> RpcResult { + debug!("fetching client meta"); + + let height = self.query_height(&chain_id, at).await?; + + let client_info = self + .inner + .modules()? + .chain_module::(&chain_id) + .map_err(fatal_error)? + .client_info(client_id.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_state = self + .inner + .modules()? + .chain_module::(&chain_id) + .map_err(fatal_error)? + .query_ibc_state_typed(height, ClientStatePath { client_id }) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let meta = self + .inner + .modules()? + .client_module::( + &client_info.client_type, + &client_info.ibc_interface, + ) + .map_err(fatal_error)? + .decode_client_state_meta(client_state) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + debug!( + client_state_meta.height = %meta.height, + client_state_meta.chain_id = %meta.chain_id, + %client_info.ibc_interface, + %client_info.client_type, + "fetched client meta" + ); + + Ok(meta) + } + + #[instrument(skip_all, fields(%chain_id, %path, %height))] + pub async fn query_ibc_state( + &self, + chain_id: &ChainId<'_>, + height: Height, + path: Path, + ) -> RpcResult { + debug!("fetching ibc state"); + + // let height = self.inner.query_height(&chain_id, height).await?; + + let state = self + .inner + .query_ibc_state_cached(chain_id, height, path.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + // TODO: Use valuable here + debug!(state = %state.state, "fetched ibc state"); + + Ok(state) + } + + #[instrument(skip_all, fields(%chain_id, %path, %height))] + pub async fn query_ibc_proof( + &self, + chain_id: &ChainId<'_>, + height: Height, + path: Path, + ) -> RpcResult { + debug!("fetching ibc state"); + + let chain_module = self + .inner + .modules()? + .chain_module::(chain_id) + .map_err(fatal_error)?; + + // let height = self.inner.query_height(&chain_id, height).await?; + + let proof = chain_module + .query_ibc_proof(height, path.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + // TODO: Use valuable here + debug!(%proof, "fetched ibc proof"); + + Ok(IbcProof { + path, + height, + proof, + }) + } + + #[instrument(skip_all, fields(%chain_id, %height))] + pub async fn self_client_state( + &self, + chain_id: ChainId<'static>, + height: Height, + ) -> RpcResult { + debug!("querying self client state"); + + let chain_module = self + .inner + .modules()? + .consensus_module::(&chain_id) + .map_err(fatal_error)?; + + let state = chain_module + .self_client_state(height) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + // TODO: Use valuable here + debug!(%state, "fetched self client state"); + + Ok(SelfClientState { height, state }) + } + + #[instrument(skip_all, fields(%chain_id, %height))] + pub async fn self_consensus_state( + &self, + chain_id: ChainId<'static>, + height: QueryHeight, + ) -> RpcResult { + debug!("querying self consensus state"); + + let chain_module = self + .inner + .modules()? + .consensus_module::(&chain_id) + .map_err(fatal_error)?; + + let height = self.query_height(&chain_id, height).await?; + + let state = chain_module + .self_consensus_state(height) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + // TODO: Use valuable here + debug!(%state, "fetched self consensus state"); + + Ok(SelfConsensusState { height, state }) + } + + // TODO: Use valuable here + #[instrument(skip_all, fields(%client_type, %ibc_interface, %proof))] + pub async fn encode_proof( + &self, + client_type: &ClientType<'static>, + ibc_interface: &IbcInterface<'static>, + proof: Value, + ) -> RpcResult> { + debug!("encoding proof"); + + let client_module = self + .inner + .modules()? + .client_module::(client_type, ibc_interface) + .map_err(fatal_error)?; + + let proof = client_module + .encode_proof(proof) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + debug!(%proof, "encoded proof"); + + Ok(proof.0) + } + + // TODO: Use valuable here + #[instrument(skip_all, fields(%client_type, %ibc_interface))] + pub async fn decode_client_state_meta( + &self, + client_type: &ClientType<'static>, + ibc_interface: &IbcInterface<'static>, + client_state: Vec, + ) -> RpcResult { + debug!("decoding client state meta"); + + let client_module = self + .inner + .modules()? + .client_module::(client_type, ibc_interface) + .map_err(fatal_error)?; + + let meta = client_module + .decode_client_state_meta(Hex(client_state)) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + debug!( + height = %meta.height, + chain_id = %meta.chain_id, + "decoded client state meta" + ); + + Ok(meta) + } + + #[instrument(skip_all, fields(%client_type, %ibc_interface))] + pub async fn decode_client_state( + &self, + client_type: &ClientType<'static>, + ibc_interface: &IbcInterface<'static>, + client_state: Vec, + ) -> RpcResult { + self.inner + .modules()? + .client_module::(client_type, ibc_interface) + .map_err(fatal_error)? + .decode_client_state(Hex(client_state)) + .await + .map_err(json_rpc_error_to_rpc_error) + } + + #[instrument(skip_all, fields(%client_type, %ibc_interface))] + pub async fn decode_consensus_state( + &self, + client_type: &ClientType<'static>, + ibc_interface: &IbcInterface<'static>, + consensus_state: Vec, + ) -> RpcResult { + self.inner + .modules()? + .client_module::(client_type, ibc_interface) + .map_err(fatal_error)? + .decode_consensus_state(Hex(consensus_state)) + .await + .map_err(json_rpc_error_to_rpc_error) + } + + pub async fn query_ibc_state_typed( + &self, + chain_id: &ChainId<'_>, + at: Height, + path: P, + ) -> Result, jsonrpsee::core::client::Error> { + debug!(%chain_id, %path, %at, "querying ibc state"); + + let ibc_state = self + .query_ibc_state(chain_id, at, path.clone().into()) + .await?; + + Ok(serde_json::from_value::(ibc_state.state.clone()) + .map(|value| IbcState { + chain_id: ibc_state.chain_id, + path: path.clone(), + height: ibc_state.height, + state: value, + }) + .map_err(|e| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to deserialize state: {}", ErrorReporter(e)), + Some(json!({ + "chain_id": chain_id, + "path": path, + "state": ibc_state.state + })), + ) + })?) + } +} + +/// rpc impl +#[async_trait] +impl VoyagerRpcServer for Server { + async fn info(&self) -> RpcResult { + dbg!(self.inner.ibc_state_cache.iter().collect::>()); + + let chain = self + .inner + .modules()? + .loaded_chain_modules() + .cloned() + .collect(); + let consensus = self + .inner + .modules()? + .loaded_consensus_modules() + .cloned() + .collect(); + let client = self + .inner + .modules()? + .loaded_client_modules() + .flat_map(|(c, is)| is.map(|i| (c.clone(), i.clone()))) + .collect(); + + Ok(Info { + chain, + consensus, + client, + }) + } + + async fn query_latest_height(&self, chain_id: ChainId<'static>) -> RpcResult { + self.query_latest_height(&chain_id).await + } + + async fn query_latest_timestamp(&self, chain_id: ChainId<'static>) -> RpcResult { + self.query_latest_timestamp(&chain_id).await + } + + async fn client_info( + &self, + chain_id: ChainId<'static>, + client_id: ClientId, + ) -> RpcResult { + self.client_info(&chain_id, client_id).await + } + + async fn client_meta( + &self, + chain_id: ChainId<'static>, + at: QueryHeight, + client_id: ClientId, + ) -> RpcResult { + self.client_meta(chain_id, at, client_id).await + } + + async fn query_ibc_state( + &self, + chain_id: ChainId<'static>, + height: QueryHeight, + path: Path, + ) -> RpcResult { + let height = self.query_height(&chain_id, height).await?; + + self.query_ibc_state(&chain_id, height, path).await + } + + async fn query_ibc_proof( + &self, + chain_id: ChainId<'static>, + height: QueryHeight, + path: Path, + ) -> RpcResult { + let height = self.query_height(&chain_id, height).await?; + + self.query_ibc_proof(&chain_id, height, path).await + } + + async fn self_client_state( + &self, + chain_id: ChainId<'static>, + height: QueryHeight, + ) -> RpcResult { + let height = self.query_height(&chain_id, height).await?; + + self.self_client_state(chain_id, height).await + } + + async fn self_consensus_state( + &self, + chain_id: ChainId<'static>, + height: QueryHeight, + ) -> RpcResult { + self.self_consensus_state(chain_id, height).await + } + + // TODO: Use valuable here + async fn encode_proof( + &self, + client_type: ClientType<'static>, + ibc_interface: IbcInterface<'static>, + proof: Value, + ) -> RpcResult>> { + self.encode_proof(&client_type, &ibc_interface, proof) + .await + .map(Hex) + } + + // TODO: Use valuable here + async fn decode_client_state_meta( + &self, + client_type: ClientType<'static>, + ibc_interface: IbcInterface<'static>, + client_state: Hex>, + ) -> RpcResult { + self.decode_client_state_meta(&client_type, &ibc_interface, client_state.0) + .await + } + + async fn decode_client_state( + &self, + client_type: ClientType<'static>, + ibc_interface: IbcInterface<'static>, + client_state: Hex>, + ) -> RpcResult { + self.decode_client_state(&client_type, &ibc_interface, client_state.0) + .await + } + + async fn decode_consensus_state( + &self, + client_type: ClientType<'static>, + ibc_interface: IbcInterface<'static>, + consensus_state: Hex>, + ) -> RpcResult { + self.decode_consensus_state(&client_type, &ibc_interface, consensus_state.0) + .await + } +} + +pub(crate) fn fatal_error(t: impl std::error::Error) -> ErrorObjectOwned { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + ErrorReporter(t).to_string(), + None::<()>, + ) +} diff --git a/lib/zktrie-rs/src/zktrie.rs b/lib/zktrie-rs/src/zktrie.rs index 202e902a6f..19e80b2d52 100644 --- a/lib/zktrie-rs/src/zktrie.rs +++ b/lib/zktrie-rs/src/zktrie.rs @@ -95,7 +95,7 @@ impl ZkTrie { let k = to_secure_key::(key)?; let key_hash = k.into(); - //mitigate the create-delete issue: do not delete non-existent key + // mitigate the create-delete issue: do not delete non-existent key match self.try_get_node(db, &key_hash) { Ok(_) => {} Err(Error::KeyNotFound) => return Ok(()), diff --git a/light-clients/arbitrum-light-client/Cargo.toml b/light-clients/arbitrum-light-client/Cargo.toml index d79d1a8d2b..df36b3f00f 100644 --- a/light-clients/arbitrum-light-client/Cargo.toml +++ b/light-clients/arbitrum-light-client/Cargo.toml @@ -17,7 +17,7 @@ arbitrum-verifier = { workspace = true } cosmwasm-std = { workspace = true, features = ["abort"] } ethereum-light-client = { workspace = true, features = ["mainnet", "library"] } ethereum-verifier = { workspace = true } -ethers-core.workspace = true +ethers-core = { workspace = true } hex = { workspace = true } ics008-wasm-client = { workspace = true } protos = { workspace = true } diff --git a/light-clients/berachain-light-client/Cargo.toml b/light-clients/berachain-light-client/Cargo.toml index 8baa346195..0c91bde243 100644 --- a/light-clients/berachain-light-client/Cargo.toml +++ b/light-clients/berachain-light-client/Cargo.toml @@ -32,11 +32,11 @@ tendermint-light-client = { workspace = true, features = ["library"] } tendermint-verifier = { workspace = true } thiserror = { workspace = true } -ethereum-verifier.workspace = true -hex-literal.workspace = true -ics008-wasm-client = { workspace = true } -ics23 = { workspace = true } -unionlabs = { workspace = true } +ethereum-verifier = { workspace = true } +hex-literal = { workspace = true } +ics008-wasm-client = { workspace = true } +ics23 = { workspace = true } +unionlabs = { workspace = true } [dev-dependencies] base64 = { workspace = true } diff --git a/light-clients/cometbls-light-client/src/client.rs b/light-clients/cometbls-light-client/src/client.rs index 50d7c68ebf..3af579d0c2 100644 --- a/light-clients/cometbls-light-client/src/client.rs +++ b/light-clients/cometbls-light-client/src/client.rs @@ -24,7 +24,6 @@ use unionlabs::{ client_state::ClientState, consensus_state::ConsensusState, header::Header, }, }, - traits::ClientState as _, }; use crate::{ @@ -170,7 +169,7 @@ impl IbcClient for CometblsLightClient { } T::verify_zkp( - &client_state.chain_id(), + &client_state.data.chain_id, trusted_validators_hash, &header.signed_header, &header.zero_knowledge_proof, diff --git a/light-clients/ethereum-light-client/src/client.rs b/light-clients/ethereum-light-client/src/client.rs index 1a313ef45b..a54991b489 100644 --- a/light-clients/ethereum-light-client/src/client.rs +++ b/light-clients/ethereum-light-client/src/client.rs @@ -40,7 +40,6 @@ use unionlabs::{ }, }, ics24::Path, - id::ClientId, uint::U256, }; @@ -495,12 +494,15 @@ pub fn do_verify_membership( .map_err(Error::VerifyStorageProof) } +// this is required because ibc-go requires the client state to be a protobuf Any, even though +// the counterparty (ethereum in this case) stores it as raw bytes. this will no longer be +// required with ibc-go v9. pub fn canonicalize_stored_value( path: String, raw_value: Vec, ) -> Result, CanonicalizeStoredValueError> { let path = path - .parse::>() + .parse::() .map_err(|_| CanonicalizeStoredValueError::UnknownIbcPath(path))?; let canonical_value = match path { @@ -578,7 +580,6 @@ mod test { encoding::Encode, ethereum::config::Mainnet, ibc::{core::connection::connection_end::ConnectionEnd, lightclients::ethereum}, - id::ClientId, }; use super::*; @@ -925,18 +926,14 @@ mod test { #[test] fn membership_verification_works_for_connection_end() { - do_membership_test::>( - "src/test/memberships/valid_connection_end.json", - ) - .expect("Membership verification of client state failed"); + do_membership_test::("src/test/memberships/valid_connection_end.json") + .expect("Membership verification of client state failed"); } #[test] fn membership_verification_fails_for_incorrect_proofs() { let (mut proof, commitment_path, slot, storage_root, connection_end) = - membership_data::>( - "src/test/memberships/valid_connection_end.json", - ); + membership_data::("src/test/memberships/valid_connection_end.json"); let proofs = vec![ { @@ -965,9 +962,7 @@ mod test { #[test] fn membership_verification_fails_for_incorrect_storage_root() { let (proof, commitment_path, slot, mut storage_root, connection_end) = - membership_data::>( - "src/test/memberships/valid_connection_end.json", - ); + membership_data::("src/test/memberships/valid_connection_end.json"); storage_root.0[10] ^= u8::MAX; @@ -984,9 +979,7 @@ mod test { #[test] fn membership_verification_fails_for_incorrect_data() { let (proof, commitment_path, slot, storage_root, mut connection_end) = - membership_data::>( - "src/test/memberships/valid_connection_end.json", - ); + membership_data::("src/test/memberships/valid_connection_end.json"); connection_end.client_id = unionlabs::validated::Validated::new("08-client-1".into()).unwrap(); @@ -1013,9 +1006,7 @@ mod test { #[test] fn non_membership_verification_fails_when_value_not_empty() { let (proof, commitment_path, slot, storage_root, _) = - membership_data::>( - "src/test/memberships/valid_connection_end.json", - ); + membership_data::("src/test/memberships/valid_connection_end.json"); assert_eq!( do_verify_non_membership(commitment_path, storage_root, slot, proof), Err(Error::CounterpartyStorageNotNil) diff --git a/light-clients/evm-in-cosmos-light-client/src/client.rs b/light-clients/evm-in-cosmos-light-client/src/client.rs index 68f8abe2ee..c198baa593 100644 --- a/light-clients/evm-in-cosmos-light-client/src/client.rs +++ b/light-clients/evm-in-cosmos-light-client/src/client.rs @@ -112,7 +112,7 @@ impl IbcClient for EvmInCosmosLightClient { ) .map_err(Error::CustomQuery)?; let client_consensus_state_path = Path::ClientConsensusState(ClientConsensusStatePath { - client_id: client_state.data.l2_client_id, + client_id: client_state.data.l2_client_id.parse().unwrap(), height: Height { revision_number: 0, revision_height: header.l2_slot, diff --git a/light-clients/linea-light-client/Cargo.toml b/light-clients/linea-light-client/Cargo.toml index 678e12f845..dab5604edc 100644 --- a/light-clients/linea-light-client/Cargo.toml +++ b/light-clients/linea-light-client/Cargo.toml @@ -16,7 +16,7 @@ crate-type = ["cdylib", "rlib"] cosmwasm-std = { workspace = true, features = ["abort"] } ethereum-light-client = { workspace = true, features = ["mainnet", "library"] } ethereum-verifier = { workspace = true } -ethers-core.workspace = true +ethers-core = { workspace = true } gnark-mimc = { workspace = true } hex = { workspace = true } ics008-wasm-client = { workspace = true } diff --git a/light-clients/movement/ics08-movement/Cargo.toml b/light-clients/movement/ics08-movement/Cargo.toml index 1a58a8077b..3f7b279813 100644 --- a/light-clients/movement/ics08-movement/Cargo.toml +++ b/light-clients/movement/ics08-movement/Cargo.toml @@ -1,9 +1,9 @@ [package] -edition.workspace = true -license-file.workspace = true -name = "ics08-movement" -repository.workspace = true -version = "0.1.0" +edition = { workspace = true } +license-file = { workspace = true } +name = "ics08-movement" +repository = { workspace = true } +version = "0.1.0" [dependencies] hex = { workspace = true, features = ["alloc"] } diff --git a/light-clients/movement/ics08-movement/src/client.rs b/light-clients/movement/ics08-movement/src/client.rs index 1d8bf4328f..f723dbee25 100644 --- a/light-clients/movement/ics08-movement/src/client.rs +++ b/light-clients/movement/ics08-movement/src/client.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Deps, Empty}; +use cosmwasm_std::Deps; use ics008_wasm_client::{ storage_utils::{ read_client_state, read_consensus_state, save_client_state, save_consensus_state, @@ -6,10 +6,10 @@ use ics008_wasm_client::{ IbcClient, IbcClientError, StorageState, }; use unionlabs::{ - aptos::{account::AccountAddress, hash_value::HashValue, transaction_info::TransactionInfo}, + aptos::{account::AccountAddress, transaction_info::TransactionInfo}, cosmwasm::wasm::union::custom_query::{query_consensus_state, UnionCustomQuery}, encoding::Proto, - hash::{H160, H256}, + hash::H256, ibc::{ core::{client::height::Height, commitment::merkle_path::MerklePath}, lightclients::{ @@ -248,7 +248,7 @@ impl IbcClient for MovementLightClient { fn do_verify_membership( _path: String, - state_root: HashValue, + state_root: H256, _table_handle: AccountAddress, proof: Vec, value: Vec, @@ -256,7 +256,7 @@ fn do_verify_membership( aptos_verifier::verify_existence_proof( &proof, state_root, - HashValue::default(), + H256::default(), value.try_into().unwrap(), ) .unwrap(); diff --git a/light-clients/movement/ics08-movement/src/lib.rs b/light-clients/movement/ics08-movement/src/lib.rs index ded3c1f1f6..70855225d4 100644 --- a/light-clients/movement/ics08-movement/src/lib.rs +++ b/light-clients/movement/ics08-movement/src/lib.rs @@ -1,8 +1,6 @@ mod client; mod contract; mod errors; -mod sparse_merkle_proof; -mod types; // use aptos_types::{proof::TransactionInfoWithProof, state_proof::StateProof}; // use aptos_crypto::{hash::CryptoHash, HashValue}; diff --git a/light-clients/movement/ics08-movement/src/sparse_merkle_proof.rs b/light-clients/movement/ics08-movement/src/sparse_merkle_proof.rs deleted file mode 100644 index a3e6e5a9fb..0000000000 --- a/light-clients/movement/ics08-movement/src/sparse_merkle_proof.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::fmt; - -use hex::FromHex; -use hex_literal::hex; -use serde::{de, ser, Deserialize, Serialize}; -use sha3::{Digest, Sha3_256}; -use unionlabs::aptos::hash_value::HashValue; - -/// A proof that can be used to authenticate an element in a Sparse Merkle Tree given trusted root -/// hash. For example, `TransactionInfoToAccountProof` can be constructed on top of this structure. -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct SparseMerkleProof { - /// This proof can be used to authenticate whether a given leaf exists in the tree or not. - /// - If this is `Some(leaf_node)` - /// - If `leaf_node.key` equals requested key, this is an inclusion proof and - /// `leaf_node.value_hash` equals the hash of the corresponding account blob. - /// - Otherwise this is a non-inclusion proof. `leaf_node.key` is the only key - /// that exists in the subtree and `leaf_node.value_hash` equals the hash of the - /// corresponding account blob. - /// - If this is `None`, this is also a non-inclusion proof which indicates the subtree is - /// empty. - leaf: Option, - - /// All siblings in this proof, including the default ones. Siblings are ordered from the root - /// level to the bottom level. - siblings: Vec, -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] -pub struct SparseMerkleLeafNode { - key: HashValue, - value_hash: HashValue, -} diff --git a/light-clients/movement/ics08-movement/src/types.rs b/light-clients/movement/ics08-movement/src/types.rs deleted file mode 100644 index 8b13789179..0000000000 --- a/light-clients/movement/ics08-movement/src/types.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/light-clients/scroll-light-client/Cargo.toml b/light-clients/scroll-light-client/Cargo.toml index 7f9deff936..e4e2db8d6f 100644 --- a/light-clients/scroll-light-client/Cargo.toml +++ b/light-clients/scroll-light-client/Cargo.toml @@ -13,23 +13,23 @@ workspace = true crate-type = ["cdylib", "rlib"] [dependencies] -cosmwasm-std = { workspace = true, features = ["abort"] } -ethereum-light-client = { workspace = true, features = ["mainnet", "library"] } -ethereum-verifier = { workspace = true } -ethers-core.workspace = true -hex = { workspace = true } -ics008-wasm-client = { workspace = true } -protos = { workspace = true } -rlp = { workspace = true } -schemars = { workspace = true } -scroll-codec.workspace = true -scroll-verifier = { workspace = true } -serde = { workspace = true, features = ["derive"] } -serde-json-wasm = { workspace = true } -sha3 = { workspace = true } -thiserror = { workspace = true } -tiny-keccak = { workspace = true, features = ["keccak"] } -unionlabs = { workspace = true, features = ["ethabi", "stargate"] } +cosmwasm-std = { workspace = true, features = ["abort"] } +ethereum-light-client = { workspace = true, features = ["mainnet", "library"] } +ethereum-verifier = { workspace = true } +ethers-core = { workspace = true } +hex = { workspace = true } +ics008-wasm-client = { workspace = true } +protos = { workspace = true } +rlp = { workspace = true } +schemars = { workspace = true } +scroll-codec = { workspace = true } +scroll-verifier = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-json-wasm = { workspace = true } +sha3 = { workspace = true } +thiserror = { workspace = true } +tiny-keccak = { workspace = true, features = ["keccak"] } +unionlabs = { workspace = true, features = ["ethabi", "stargate"] } [dev-dependencies] base64 = { workspace = true } diff --git a/move/mock_ibc_module.move b/move/mock_ibc_module.move new file mode 100644 index 0000000000..c1dd7e5c7c --- /dev/null +++ b/move/mock_ibc_module.move @@ -0,0 +1,97 @@ +module IBCModuleAddr::IBCModule { + use std::vector; + use aptos_std::string::{String}; + // use IBC::Core; + use IBC::packet::{Packet}; + + + // Order Enums + const ORDER_UNORDERED: u8 = 1; + const ORDER_ORDERED: u8 = 2; + + public fun on_chan_open_init( + _order: u8, // ORDER_ORDERED or ORDER_UNORDERED + _connection_hops: vector, + _port_id: String, + _channel_id: String, + _counterparty_port_id: String, + _counterparty_channel_id: String, + _version: String, + ): u8 { + // Implement your logic here + 0 // Return 0 for success + } + + public fun on_chan_open_try( + _order: u8, // ORDER_ORDERED or ORDER_UNORDERED + _connection_hops: vector, + _port_id: String, + _channel_id: String, + _counterparty_port_id: String, + _counterparty_channel_id: String, + _version: String, + _counterparty_version: String, + ): u8 { + // Implement your logic here + 0 // Return 0 for success + } + + public fun on_chan_open_ack( + _port_id: String, + _channel_id: String, + _counterparty_channel_id: String, + _counterparty_version: String, + ): u8 { + // Implement your logic here + 0 // Return 0 for success + } + + public fun on_chan_open_confirm( + _port_id: String, + _channel_id: String, + ): u8 { + // Implement your logic here + 0 // Return 0 for success + } + + public fun on_chan_close_init( + _port_id: String, + _channel_id: String, + ): u8 { + // Implement your logic here + 0 // Return 0 for success + } + + public fun on_chan_close_confirm( + _port_id: String, + _channel_id: String, + ): u8 { + // Implement your logic here + 0 // Return 0 for success + } + + public fun on_recv_packet( + _packet: Packet, + _relayer: address + ): vector { + // Implement your logic here + vector::empty() // Return an empty vector for success + } + + public fun on_acknowledgement_packet( + _packet: Packet, + _acknowledgement: vector, + _relayer: address + ): u8 { + // Implement your logic here + 0 // Return 0 for success + } + + public fun on_timeout_packet( + _packet: Packet, + _relayer: address + ): u8 { + // Implement your logic here + 0 // Return 0 for success + } +} \ No newline at end of file diff --git a/move/move-ibc/.movement/config.yaml b/move/move-ibc/.movement/config.yaml new file mode 100644 index 0000000000..9f7020c691 --- /dev/null +++ b/move/move-ibc/.movement/config.yaml @@ -0,0 +1,15 @@ +profiles: + default: + network: Custom + private_key: "0x0000000000000000000000000000000000000000000000000000000000000001" + public_key: "0x4cb5abf6ad79fbf5abbccafcc269d85cd2651ed4b885b5869f241aedf0a5ba29" + account: f90391c81027f03cdea491ed8b36ffaced26b6df208a9b569e5baf2590eb9b16 + rest_url: "http://localhost:30731/" + faucet_url: "http://localhost:30732/" + default2: + network: Custom + private_key: "0x0000000000000000000000000000000000000000000000000000000000000002" + public_key: "0x7422B9887598068E32C4448A949ADB290D0F4E35B9E01B0EE5F1A1E600FE2674" + account: 666991e71f97612af2872dbc611812ef4afc3e2850563c65443111736b6be87b + rest_url: "http://localhost:30731/" + faucet_url: "http://localhost:30732/" diff --git a/move/move-ibc/sources/ibc.move b/move/move-ibc/sources/ibc.move index 109bbcd45a..cee24701ac 100644 --- a/move/move-ibc/sources/ibc.move +++ b/move/move-ibc/sources/ibc.move @@ -289,7 +289,7 @@ module IBC::Core { // Initializes the IBCStore resource in the signer's account - fun init_module(account: &signer) { + fun init_module(account: &signer) { assert!(signer::address_of(account) == @IBC, E_NOT_ENOUGH_PERMISSIONS_TO_INITIALIZE); let vault_constructor_ref = &object::create_named_object(account, VAULT_SEED); let vault_signer = &object::generate_signer(vault_constructor_ref); diff --git a/networks/devnet.nix b/networks/devnet.nix index 1d12f2902f..a817b1e337 100644 --- a/networks/devnet.nix +++ b/networks/devnet.nix @@ -60,7 +60,7 @@ self'.packages.ethereum-light-client-minimal # self'.packages.ethereum-light-client-mainnet # self'.packages.scroll-light-client - self'.packages.arbitrum-light-client + # self'.packages.arbitrum-light-client # self'.packages.berachain-light-client self'.packages.ics08-movement ]; @@ -102,7 +102,7 @@ instances = [ ]; } ]; - portIncrease = 0; + portIncrease = 100; has08Wasm = true; }; diff --git a/networks/services/postgres.nix b/networks/services/postgres.nix index 9b32f62d10..899af98c89 100644 --- a/networks/services/postgres.nix +++ b/networks/services/postgres.nix @@ -20,6 +20,11 @@ in environment = { POSTGRES_PASSWORD = "postgrespassword"; POSTGRES_DB = "default"; + POSTGRES_HOST_AUTH_METHOD = "trust"; }; + # authentication = pkgs.lib.mkOverride 10 '' + # #type database DBuser auth-method + # local all all trust + # ''; }; } diff --git a/tools/devnet-utils/Cargo.toml b/tools/devnet-utils/Cargo.toml index ee45df50b4..687a9e7c9f 100644 --- a/tools/devnet-utils/Cargo.toml +++ b/tools/devnet-utils/Cargo.toml @@ -9,12 +9,12 @@ version = "0.1.0" workspace = true [dependencies] -base64 = { workspace = true } -bip39 = "2.0.0" -clap = { workspace = true, features = ["derive", "error-context", "help"] } -cosmwasm-std = "2.0.3" -ed25519-compact = { version = "2.1.1", default-features = false, features = ["ed25519"] } -hex = { workspace = true, features = ["std"] } -strum = { version = "0.26.1", features = ["derive"] } -tiny-hderive = "0.3.0" -unionlabs.workspace = true +base64 = { workspace = true } +bip39 = "2.0.0" +clap = { workspace = true, features = ["derive", "error-context", "help"] } +cosmwasm-std = "2.0.3" +ed25519-compact = { version = "2.1.1", default-features = false, features = ["ed25519"] } +hex = { workspace = true, features = ["std"] } +strum = { version = "0.26.1", features = ["derive"] } +tiny-hderive = "0.3.0" +unionlabs = { workspace = true } diff --git a/tools/move-bindgen/Cargo.toml b/tools/move-bindgen/Cargo.toml new file mode 100644 index 0000000000..313c2228a9 --- /dev/null +++ b/tools/move-bindgen/Cargo.toml @@ -0,0 +1,23 @@ +[package] +edition = { workspace = true } +license-file = { workspace = true } +name = "move-bindgen" +publish = false +repository = { workspace = true } +version = "0.0.0" + +[dependencies] +aptos-crypto = { workspace = true } +aptos-rest-client = { workspace = true } +aptos-types = { workspace = true } +futures = { workspace = true } +move-bindgen-derive = { workspace = true } +move-core-types = { workspace = true } +prettyplease = "0.2.22" +proc-macro2 = "*" +quote = "1.0.35" +syn = { version = "2.0.52", default-features = false, features = ["clone-impls", "parsing", "printing", "proc-macro", "derive", "extra-traits"] } +tokio = { workspace = true, features = ["full"] } + +[lints] +workspace = true diff --git a/tools/move-bindgen/src/lib.rs b/tools/move-bindgen/src/lib.rs new file mode 100644 index 0000000000..fcf0f75e81 --- /dev/null +++ b/tools/move-bindgen/src/lib.rs @@ -0,0 +1,143 @@ +pub use move_bindgen_derive::TypeTagged; +pub use move_core_types; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + language_storage::{StructTag, TypeTag}, +}; + +pub trait TypeTagged { + type Ctx; + + fn type_tag(ctx: Self::Ctx) -> TypeTag; +} + +impl TypeTagged for u8 { + type Ctx = (); + + fn type_tag(_ctx: Self::Ctx) -> TypeTag { + TypeTag::U8 + } +} + +impl TypeTagged for u16 { + type Ctx = (); + + fn type_tag(_ctx: Self::Ctx) -> TypeTag { + TypeTag::U16 + } +} + +impl TypeTagged for u32 { + type Ctx = (); + + fn type_tag(_ctx: Self::Ctx) -> TypeTag { + TypeTag::U32 + } +} + +impl TypeTagged for u64 { + type Ctx = (); + + fn type_tag(_ctx: Self::Ctx) -> TypeTag { + TypeTag::U64 + } +} + +impl TypeTagged for aptos_rest_client::aptos_api_types::U64 { + type Ctx = (); + + fn type_tag(_ctx: Self::Ctx) -> TypeTag { + TypeTag::U64 + } +} + +impl TypeTagged for u128 { + type Ctx = (); + + fn type_tag(_ctx: Self::Ctx) -> TypeTag { + TypeTag::U128 + } +} + +impl TypeTagged for aptos_rest_client::aptos_api_types::U128 { + type Ctx = (); + + fn type_tag(_ctx: Self::Ctx) -> TypeTag { + TypeTag::U128 + } +} + +// TODO: impl this in unionlabs +// impl TypeTagged for U256 { +// fn type_tag(_ctx: Self::Ctx) -> TypeTag { +// TypeTag::U128 +// } +// } + +impl TypeTagged for String { + type Ctx = (); + + fn type_tag(_ctx: Self::Ctx) -> TypeTag { + TypeTag::Struct(Box::new(StructTag { + address: AccountAddress::ONE, + module: ident_str!("string").into(), + name: ident_str!("String").into(), + type_args: vec![], + })) + } +} + +impl TypeTagged for Vec { + type Ctx = T::Ctx; + + fn type_tag(ctx: Self::Ctx) -> TypeTag { + TypeTag::Vector(Box::new(T::type_tag(ctx))) + } +} + +impl TypeTagged for Option { + type Ctx = T::Ctx; + + fn type_tag(ctx: Self::Ctx) -> TypeTag { + TypeTag::Struct(Box::new(StructTag { + address: AccountAddress::ONE, + module: ident_str!("option").into(), + name: ident_str!("Option").into(), + type_args: vec![T::type_tag(ctx)], + })) + } +} + +pub struct Struct { + pub field: String, +} + +impl TypeTagged for Struct { + type Ctx = AccountAddress; + + fn type_tag(ctx: Self::Ctx) -> TypeTag { + TypeTag::Struct(Box::new(StructTag { + address: ctx, + module: ident_str!("struct_module").into(), + name: ident_str!("Struct").into(), + type_args: vec![], + })) + } +} + +pub trait IntoTypeTagged { + fn into_type_tagged(self) -> (T, T::Ctx); +} + +impl> IntoTypeTagged for T { + fn into_type_tagged(self) -> (T, ::Ctx) { + (self, ()) + } +} + +impl IntoTypeTagged for (T, T::Ctx) { + fn into_type_tagged(self) -> (T, T::Ctx) { + self + } +} diff --git a/tools/move-bindgen/src/main.rs b/tools/move-bindgen/src/main.rs new file mode 100644 index 0000000000..e400c41f66 --- /dev/null +++ b/tools/move-bindgen/src/main.rs @@ -0,0 +1,512 @@ +//! buon appetito, hope you like italian +//! +//! cuz this is pure spaghetti + +use std::{ + collections::{HashMap, HashSet}, + error::Error, + fmt::Write, +}; + +use aptos_rest_client::{ + aptos_api_types::{Address, MoveFunctionVisibility, MoveStruct, MoveStructTag, MoveType}, + Client, +}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; +use syn::{parse_quote, GenericArgument, Ident, ItemFn, ItemStruct, PathArguments, Type}; + +type Bde = Box; + +#[tokio::main] +async fn main() -> Result<(), Bde> { + let [base_url, module, outfile] = std::env::args() + .skip(1) + .collect::>() + .try_into() + .map_err(|v| format!("expected `[base_url, module, outfile]`, but found `{v:?}`"))?; + + let module: Address = module.parse()?; + + let client = Client::new(base_url.parse()?); + + let abis = client + .get_account_modules(module.into()) + .await? + .into_inner() + .into_iter() + .flat_map(|m| m.try_parse_abi().unwrap().abi) + .collect::>(); + + let mut mod_map = HashMap::<_, HashMap<_, _>>::new(); + + let mut referenced_structs = HashSet::new(); + + let mut already_found_structs = HashSet::new(); + + let mk_struct = |module: Address, mod_name: &Ident, t: &MoveStruct| { + let ident = format_ident!("{}", t.name.to_string()); + println!("{ident}"); + + let generics = t + .generic_type_params + .iter() + .enumerate() + .map(|(i, _)| format_ident!("T{i}")); + + t.fields + .iter() + .map(|f| { + let ident = format_ident!("{}", f.name.to_string()); + // println!(" {ident}: {:?}", f.typ); + + move_type_to_rust_type(module, &f.typ).map(|(_param_ty, field_ty)| { + ( + quote! { + pub #ident: #field_ty, + }, + find_struct_types_in_type(&field_ty), + ) + }) + }) + .collect::, _>>() + .map::<(ItemStruct, Vec<_>), _>(|fs| { + let (fs, rs): (Vec<_>, Vec<_>) = fs.into_iter().unzip(); + + ( + parse_quote! { + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = #mod_name)] + pub struct #ident<#(#generics)*> { + #(#fs)* + } + }, + rs.into_iter().flatten().collect(), + ) + }) + }; + + // resolve events + for abi in &abis { + assert_eq!(abi.address, module); + + let mod_name = format_ident!("{}", abi.name.to_string()); + + let events = abi + .structs + .iter() + .filter(|t| t.is_event) + .map(|t| mk_struct(module, &mod_name, t)); + + for event in events { + match event { + Ok((event, rs)) => { + referenced_structs.extend(rs); + already_found_structs.insert((mod_name.clone(), event.ident.clone())); + + mod_map + .entry(mod_name.clone()) + .or_default() + .insert(event.ident.clone(), event); + } + Err(err) => { + eprintln!("{err}"); + } + } + } + } + + let mut output_ts = HashMap::<_, TokenStream>::new(); + + // resolve fns + for abi in &abis { + assert_eq!(abi.address, module); + + let mod_name = format_ident!("{}", abi.name.to_string()); + + let (fns, rs): (Vec<_>, Vec<_>) = abi + .exposed_functions + .iter() + .filter(|f| { + matches!(f.visibility, MoveFunctionVisibility::Public) && (f.is_entry || f.is_view) + }) + .map(|f| { + let ident = format_ident!("{}", f.name.to_string()); + println!("======= {ident}"); + + let (ret, ret_rs): (Vec<_>, Vec<_>) = f + .return_ + .iter() + .map(|r| move_type_to_rust_type(module, r).map(|(param_ty, field_ty)| (param_ty, find_struct_types_in_type(&field_ty)))) + .collect::, _>>()?.into_iter().unzip(); + + f.params + .iter() + .enumerate() + .map(|(i, p)| { + move_type_to_rust_type(module, p).map(|(param, field)| { + let ident = format_ident!("_{i}"); + let rs = find_struct_types_in_type(&field); + + // dbg!(&rs); + + (p, (ident, ((param, field), rs))) + }) + }) + .collect::, _>>() + .map(|ps| { + #[allow(clippy::type_complexity)] // all hail our lord and saviour `unzip` + let (mts, (idents, ((param_tys, field_tys), rs))): (Vec<_>, (Vec<_>, ((Vec<_>, Vec<_>), Vec<_>))) = ps.into_iter().unzip(); + + let mts_ts = mts.iter().map(|typ| move_type_to_type_literal(typ)); + + let raw_ret = quote!((#(#ret,)*)); + + let (ret, ret_expr) = if ret.len() == 1 { + let ret = &ret[0]; + (quote!(#ret), quote!(ret.0)) + } else { + (quote!((#(#ret,)*)), quote!(ret)) + }; + + let params = if param_tys.is_empty() { + quote!() + } else { + quote!((#(#idents,)*): (#(#param_tys,)*),) + }; + + let ts = if f.is_view { + parse_quote! { + async fn #ident( + &self, + #params + ledger_version: Option + ) -> ::core::result::Result<#ret, ::aptos_rest_client::error::RestError> + { + let response = self + .client() + .view( + &::aptos_rest_client::aptos_api_types::ViewRequest { + function: ::aptos_rest_client::aptos_api_types::EntryFunctionId { + module: + ::aptos_rest_client::aptos_api_types::MoveModuleId { + address: self.module_address().into(), + name: stringify!(#mod_name).parse().unwrap(), + }, + name: stringify!(#ident).parse().unwrap(), + }, + type_arguments: vec![#(#mts_ts,)*], + arguments: vec![#(serde_json::to_value(#field_tys::from(#idents)).unwrap(),)*], + }, + ledger_version, + ) + .await? + .into_inner(); + + let ret = ::serde_json::from_value::<#raw_ret>(::serde_json::Value::from(response))?; + + Ok(#ret_expr) + } + } + } else { + let generic_type_params = f.generic_type_params + .iter().enumerate() + .map(|(index, _)| format_ident!("T{index}")); + + let params = if param_tys.is_empty() { + quote!() + } else { + quote!((#(#idents,)*): (#(impl ::move_bindgen::IntoTypeTagged<#param_tys>,)*),) + }; + + parse_quote! { + fn #ident< + #(#generic_type_params: ::serde::Serialize + ::move_bindgen::TypeTagged,)* + >(&self, #params) -> ::aptos_types::transaction::EntryFunction + { + let (values, type_args): (Vec<_>, Vec<_>) = vec![#({ + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(#idents); + ( + bcs::to_bytes(&t).unwrap(), + <#param_tys as ::move_bindgen::TypeTagged>::type_tag(ctx), + ) + },)*].into_iter().unzip(); + + ::aptos_types::transaction::EntryFunction::new( + ::aptos_rest_client::aptos_api_types::MoveModuleId { + address: self.module_address().into(), + name: stringify!(#mod_name).parse().unwrap(), + }.into(), + stringify!(#ident).parse().unwrap(), + type_args, + values, + ) + } + } + }; + + (ts, ret_rs.into_iter().chain(rs)) + }) + }) + .collect::, _>>()? + .into_iter() + .unzip(); + + referenced_structs.extend(rs.into_iter().flatten().flatten()); + + // dbg!(&mod_map); + + if !fns.is_empty() { + output_ts.entry(mod_name).or_default().extend(quote! { + pub trait ClientExt { + fn client(&self) -> &::aptos_rest_client::Client; + fn module_address(&self) -> ::aptos_types::account_address::AccountAddress; + + #(#fns)* + } + }); + }; + } + + let mut output = String::new(); + + output += "#![allow(async_fn_in_trait, +non_snake_case, +clippy::useless_conversion, +clippy::unused_unit, +clippy::too_many_arguments)] +"; + + // resolve types referenced in events and fns + while !referenced_structs.is_empty() { + // dbg!(&referenced_structs, &already_found_structs); + + for abi in &abis { + let mod_name = format_ident!("{}", abi.name.to_string()); + println!("{mod_name}"); + + let structs = abi + .structs + .iter() + .filter(|t| { + let key = (mod_name.clone(), format_ident!("{}", t.name.to_string())); + // not an event, referenced, but not already found + !t.is_event + && referenced_structs.contains(&key) + && !already_found_structs.contains(&key) + }) + .map(|t| mk_struct(module, &mod_name, t)) + .collect::>(); + + for s in structs { + match s { + Ok((s, rs)) => { + let key = (mod_name.clone(), s.ident.clone()); + referenced_structs.remove(&key); + already_found_structs.insert(key); + + // dbg!(&rs); + for r in rs { + if !already_found_structs.contains(&r) { + referenced_structs.insert(r); + } + } + + mod_map + .entry(mod_name.clone()) + .or_default() + .insert(s.ident.clone(), s); + } + Err(err) => { + eprintln!("{err}"); + } + } + } + } + } + + for (k, v) in mod_map { + let structs = v.into_iter().map(|m| { + // dbg!(m.keys()); + + m.1 + }); + + output_ts.entry(k).or_default().extend(quote!(#(#structs)*)); + } + + for (k, v) in output_ts { + writeln!(&mut output).unwrap(); + + output += &prettyplease::unparse(&syn::parse_quote! { + pub mod #k { + #v + } + }); + } + + std::fs::write(outfile, &output)?; + + Ok(()) +} + +fn find_struct_types_in_type(ty: &Type) -> Vec<(Ident, Ident)> { + match ty { + Type::Path(ty) => { + if ty.path.segments.first().unwrap().ident == "super" { + vec![( + ty.path.segments.get(1).unwrap().ident.clone(), + ty.path.segments.get(2).unwrap().ident.clone(), + )] + } else if let PathArguments::AngleBracketed(args) = + &ty.path.segments.last().unwrap().arguments + { + args.args + .iter() + .flat_map(|t| { + if let GenericArgument::Type(ty) = t { + find_struct_types_in_type(ty) + } else { + vec![] + } + }) + .collect() + } else { + vec![] + } + // TODO: Recurse into the generics here to find all types + } + _ => vec![], + } +} + +/// (param type, field type) +fn move_type_to_rust_type(this_module: Address, typ: &MoveType) -> Result<(Type, Type), Bde> { + let is_string = |mt: &MoveStructTag| { + mt.address == "0x1".parse().unwrap() + && mt.module == "string".parse().unwrap() + && mt.name == "String".parse().unwrap() + && mt.generic_type_params.is_empty() + }; + + Ok(match typ { + MoveType::Bool => (parse_quote!(bool), parse_quote!(bool)), + MoveType::U8 => (parse_quote!(u8), parse_quote!(u8)), + MoveType::U16 => ( + parse_quote!(u16), + parse_quote!(::aptos_rest_client::aptos_api_types::U16), + ), + MoveType::U32 => ( + parse_quote!(u32), + parse_quote!(::aptos_rest_client::aptos_api_types::U32), + ), + MoveType::U64 => ( + parse_quote!(u64), + parse_quote!(::aptos_rest_client::aptos_api_types::U64), + ), + MoveType::U128 => ( + parse_quote!(u128), + parse_quote!(::aptos_rest_client::aptos_api_types::U128), + ), + MoveType::U256 => ( + parse_quote!(U256), + parse_quote!(::aptos_rest_client::aptos_api_types::U256), + ), + MoveType::Address => ( + parse_quote!(::aptos_rest_client::aptos_api_types::Address), + parse_quote!(::aptos_rest_client::aptos_api_types::Address), + ), + MoveType::Signer => (parse_quote!(Signer), parse_quote!(Signer)), + MoveType::Vector { items } => { + let (param, field) = move_type_to_rust_type(this_module, items)?; + (parse_quote!(Vec<#param>), parse_quote!(Vec<#field>)) + } + MoveType::Struct(s) if is_string(s) => (parse_quote!(String), parse_quote!(String)), + // MoveType::Struct(s) if is_smart_table(&s) => { + // let t0 = move_type_to_rust_type(this_module, &s.generic_type_params[0])?; + // let t1 = move_type_to_rust_type(this_module, &s.generic_type_params[1])?; + + // parse_quote!(SmartTable<#t0, #t1>) + // } + // MoveType::Struct(s) if is_table(&s) => { + // let t0 = move_type_to_rust_type(this_module, &s.generic_type_params[0])?; + // let t1 = move_type_to_rust_type(this_module, &s.generic_type_params[1])?; + + // parse_quote!(Table<#t0, #t1>) + // } + MoveType::Struct(MoveStructTag { + address, + module, + name, + generic_type_params, + }) => { + if address != &this_module { + return Err(format!("no clue where this is coming from ({address}::{module}::{name}<{generic_type_params:?}>)").into()); + } + + let module = format_ident!("{}", module.to_string()); + let ident = format_ident!("{}", name.to_string()); + let (param, field): (Vec<_>, Vec<_>) = generic_type_params + .iter() + .map(|m| move_type_to_rust_type(this_module, m)) + .collect::, _>>()? + .into_iter() + .unzip(); + + ( + parse_quote!(super::#module::#ident<#(#param,)*>), + parse_quote!(super::#module::#ident<#(#field,)*>), + ) + } + MoveType::GenericTypeParam { index } => { + let ident = format_ident!("T{index}"); + + (parse_quote!(#ident), parse_quote!(#ident)) + } + MoveType::Reference { mutable: _, to } => move_type_to_rust_type(this_module, to)?, + MoveType::Unparsable(_) => todo!(), + }) +} + +fn move_type_to_type_literal(typ: &MoveType) -> proc_macro2::TokenStream { + match typ { + MoveType::Bool => quote!(::aptos_rest_client::aptos_api_types::MoveType::Bool), + MoveType::U8 => quote!(::aptos_rest_client::aptos_api_types::MoveType::U8), + MoveType::U16 => quote!(::aptos_rest_client::aptos_api_types::MoveType::U16), + MoveType::U32 => quote!(::aptos_rest_client::aptos_api_types::MoveType::U32), + MoveType::U64 => quote!(::aptos_rest_client::aptos_api_types::MoveType::U64), + MoveType::U128 => quote!(::aptos_rest_client::aptos_api_types::MoveType::U128), + MoveType::U256 => quote!(::aptos_rest_client::aptos_api_types::MoveType::U256), + MoveType::Address => quote!(::aptos_rest_client::aptos_api_types::MoveType::Address), + MoveType::Signer => quote!(::aptos_rest_client::aptos_api_types::MoveType::Signer), + MoveType::Vector { items } => { + let items = move_type_to_type_literal(items); + + quote!(::aptos_rest_client::aptos_api_types::MoveType::Vector { items: #items }) + } + MoveType::Struct(MoveStructTag { + address, + module, + name, + generic_type_params, + }) => { + let address = address.to_standard_string(); + let module = module.to_string(); + let name = name.to_string(); + let generic_type_params = generic_type_params.iter().map(move_type_to_type_literal); + + quote!(::aptos_rest_client::aptos_api_types::MoveType::Struct(::aptos_rest_client::aptos_api_types::MoveStructTag { + address: #address.parse().unwrap(), + module: #module.parse().unwrap(), + name: #name.parse().unwrap(), + generic_type_params: vec![#(#generic_type_params)*], + })) + } + MoveType::GenericTypeParam { index } => { + quote!(::aptos_rest_client::aptos_api_types::MoveType::GenericTypeParam { index: #index }) + } + MoveType::Reference { mutable: _, to: _ } => todo!(), + MoveType::Unparsable(_) => todo!(), + } +} diff --git a/tools/rust-proto.nix b/tools/rust-proto.nix index 513b8de9b7..5d90cdb599 100644 --- a/tools/rust-proto.nix +++ b/tools/rust-proto.nix @@ -188,6 +188,7 @@ # serde_flatten = ''#[cfg_attr(feature = "serde", serde(flatten))]''; serde_string = ''#[cfg_attr(feature = "serde", serde(with = "::serde_utils::string"))]''; serde_base64 = ''#[cfg_attr(feature = "serde", serde(with = "::serde_utils::base64"))]''; + # serde_base64_opt = ''#[cfg_attr(feature = "serde", serde(with = "::serde_utils::base64_opt"))]''; serde_base64_opt_default = ''#[cfg_attr(feature = "serde", serde(with = "::serde_utils::base64_opt_default"))]''; serde_inner_base64 = ''#[cfg_attr(feature = "serde", serde(with = "::serde_utils::inner_base64"))]''; serde_hex_upper_unprefixed = ''#[cfg_attr(feature = "serde", serde(with = "::serde_utils::hex_upper_unprefixed"))]''; @@ -199,64 +200,84 @@ { type_attribute = { ".google.protobuf.Any" = [ serde ]; - ".google.protobuf.Timestamp" = [ serde ]; ".google.protobuf.Duration" = [ serde ]; + ".google.protobuf.Timestamp" = [ serde ]; + ".ibc.core.client.v1" = [ serde ]; ".ibc.core.client.v1.Height" = [ ]; + ".ibc.core.commitment.v1" = [ serde ]; - ".ibc.core.commitment.v1.MerkleRoot" = [ ]; ".ibc.core.commitment.v1.MerklePrefix" = [ ]; + ".ibc.core.commitment.v1.MerkleRoot" = [ ]; + ".ibc.core.channel.v1" = [ serde ]; ".ibc.core.channel.v1.Channel" = [ ]; ".ibc.core.channel.v1.Counterparty" = [ ]; + ".ibc.core.connection.v1" = [ serde ]; ".ibc.core.connection.v1.ConnectionEnd" = [ ]; ".ibc.core.connection.v1.Counterparty" = [ ]; ".ibc.core.connection.v1.Version" = [ ]; + ".ibc.core.types.v1" = [ serde ]; + + ".ibc.applications.interchain_accounts.controller.v1" = [ serde ]; + ".ibc.applications.interchain_accounts.v1" = [ serde ]; + ".ibc.applications.transfer.v1" = [ serde ]; ".ibc.applications.transfer.v2" = [ serde ]; - ".ibc.applications.interchain_accounts.v1" = [ serde ]; - ".ibc.applications.interchain_accounts.controller.v1" = [ serde ]; + ".ibc.lightclients.wasm.v1" = [ serde ]; + ".ibc.lightclients.tendermint.v1.Fraction" = [ serde ]; + ".union.ibc.lightclients.ethereum.v1" = [ serde ]; + ".cosmos.ics23.v1" = [ serde ]; - ".cosmos.ics23.v1.LeafOp" = [ ]; ".cosmos.ics23.v1.InnerOp" = [ ]; - ".cosmos.ics23.v1.ProofSpec" = [ ]; ".cosmos.ics23.v1.InnerSpec" = [ ]; + ".cosmos.ics23.v1.LeafOp" = [ ]; + ".cosmos.ics23.v1.ProofSpec" = [ ]; + ".cosmos.auth.v1beta1" = [ serde ]; + ".cosmos.upgrade.v1beta1" = [ serde ]; + ".cosmos.base.v1beta1" = [ serde ]; ".cosmos.base.query.v1beta1" = [ serde ]; + ".cosmos.bank.v1beta1" = [ serde ]; - ".tendermint.types.SignedHeader" = [ serde ]; - ".tendermint.types.Vote" = [ serde ]; - ".tendermint.types.Validator" = [ serde ]; - ".tendermint.types.ValidatorSet" = [ serde ]; - ".tendermint.types.Header" = [ serde ]; + ".tendermint.types.Block" = [ serde ]; + ".tendermint.types.BlockID" = [ serde ]; ".tendermint.types.Commit" = [ serde ]; ".tendermint.types.CommitSig" = [ serde ]; - ".tendermint.types.BlockID" = [ serde ]; - ".tendermint.types.PartSetHeader" = [ serde ]; - ".tendermint.types.Block" = [ serde ]; - ".tendermint.types.Evidence" = [ serde ]; ".tendermint.types.Data" = [ serde ]; - ".tendermint.types.EvidenceList" = [ serde ]; - ".tendermint.types.LightClientAttackEvidence" = [ serde ]; ".tendermint.types.DuplicateVoteEvidence" = [ serde ]; + ".tendermint.types.Evidence" = [ serde ]; + ".tendermint.types.EvidenceList" = [ serde ]; + ".tendermint.types.Header" = [ serde ]; ".tendermint.types.LightBlock" = [ serde ]; + ".tendermint.types.LightClientAttackEvidence" = [ serde ]; + ".tendermint.types.PartSetHeader" = [ serde ]; + ".tendermint.types.SignedHeader" = [ serde ]; + ".tendermint.types.TxProof" = [ serde ]; + ".tendermint.types.Validator" = [ serde ]; + ".tendermint.types.ValidatorSet" = [ serde ]; + ".tendermint.types.Vote" = [ serde ]; ".tendermint.version.Consensus" = [ serde ]; + ".tendermint.abci.ExecTxResult" = [ serde ]; + ".tendermint.abci.Event" = [ serde ]; + ".tendermint.abci.EventAttribute" = [ serde ]; ".tendermint.abci.ResponseQuery" = [ serde ]; ".tendermint.crypto.PublicKey" = [ serde ]; # ".tendermint.crypto.PublicKey.sum" = [ serde ]; ".tendermint.crypto.ProofOps" = [ serde ]; ".tendermint.crypto.ProofOp" = [ serde ]; + ".tendermint.crypto.Proof" = [ serde ]; ".tendermint.p2p.DefaultNodeInfo" = [ serde ]; ".tendermint.p2p.DefaultNodeInfoOther" = [ serde ]; @@ -370,6 +391,11 @@ ".tendermint.crypto.ProofOp.key" = [ serde_base64 ]; ".tendermint.crypto.ProofOp.data" = [ serde_base64 ]; + ".tendermint.crypto.Proof.total" = [ serde_string ]; + ".tendermint.crypto.Proof.index" = [ serde_string ]; + ".tendermint.crypto.Proof.leaf_hash" = [ serde_base64 ]; + ".tendermint.crypto.Proof.aunts" = [ serde_inner_base64 ]; + ".tendermint.p2p.DefaultNodeInfo.channels" = [ serde_hex_upper_unprefixed ]; ".tendermint.p2p.DefaultNodeInfo.default_node_id" = [ (serde_alias "id") ]; @@ -388,6 +414,14 @@ ".tendermint.types.Vote.signature" = [ serde_base64 ]; ".tendermint.types.Vote.extension" = [ serde_base64_opt_default ]; ".tendermint.types.Vote.extension_signature" = [ serde_base64_opt_default ]; + + ".tendermint.types.TxProof.root_hash" = [ serde_hex_upper_unprefixed ]; + ".tendermint.types.TxProof.data" = [ serde_base64 ]; + + ".tendermint.abci.ExecTxResult.data" = [ serde_base64_opt_default ]; + ".tendermint.abci.ExecTxResult.gas_wanted" = [ serde_string ]; + ".tendermint.abci.ExecTxResult.gas_used" = [ serde_string ]; + # ".tendermint.types.Vote.timestamp" = [ # ''#[cfg_attr( # feature = "serde", diff --git a/tools/rust/crane.nix b/tools/rust/crane.nix index ae7f504b11..df154e1276 100644 --- a/tools/rust/crane.nix +++ b/tools/rust/crane.nix @@ -57,14 +57,13 @@ # read the Cargo.toml from the given crate directory into a nix value. crateCargoToml = dir: - assert builtins.isString dir; + assert lib.assertMsg (builtins.isString dir) "expected string, found ${builtins.typeOf dir} while trying to read cargo.toml (stringified value: ${toString dir})"; lib.trivial.importTOML ../../${dir}/Cargo.toml; # first filter down to just the cargo source, and any additional files as specified by srcFilter mkCleanSrc = { workspaceDepsForCrate , extraIncludes - , name }: fs.toSource { root = ../../.; fileset = fs.union @@ -87,8 +86,12 @@ buildWorkspaceMember = { # the directory that contains the Cargo.toml and src/ for the crate, - # relative to the repository root. + # relative to the repository root. or a list of multiple crates. crateDirFromRoot + # the pname to use for this derivation if building multiple packages. + , pname ? null + # the version to use for this derivation if building multiple packages. + , version ? null , # extra attributes to be passed to craneLib.cargoTest. cargoTestExtraAttrs ? { } , # extra args to be passed to cargo build. @@ -113,7 +116,7 @@ pnameSuffix ? "" # extra environment variables to pass to the derivation. , extraEnv ? { } - # if true, build without -j1 nd --release. + # if true, build without -j1 and --release. , dev ? false , extraBuildInputs ? [ ] , extraNativeBuildInputs ? [ ] @@ -128,7 +131,32 @@ "cannot set both buildStdTarget (${toString buildStdTarget}) and cargoBuildRustToolchain (${toString cargoBuildRustToolchain})"; let pnameSuffix' = "${pnameSuffix}${lib.optionalString dev "-dev"}"; - cratePname = "${crateInfo.pname}${pnameSuffix'}"; + + # normalize the crate info passed in, such that we can support both single and multiple packages with the same attribute + processedCrateInfo = + if (builtins.isList crateDirFromRoot) + then + assert builtins.all builtins.isString crateDirFromRoot; + { + crateDirFromRoot' = crateDirFromRoot; + pname' = assert builtins.isString pname; pname; + version' = assert builtins.isString version; version; + } + else if (builtins.isString crateDirFromRoot) + then + let + cargoToml = ((crateCargoToml crateDirFromRoot).package); + in + { + crateDirFromRoot' = [ crateDirFromRoot ]; + version' = cargoToml.version; + pname' = cargoToml.name; + } + else + abort "expected crateDirFromRoot to be a string or a list of strings, but it was a ${builtins.typeOf crateDirFromRoot}: ${toString crateDirFromRoot}"; + + inherit (processedCrateInfo) + crateDirFromRoot' pname' version'; cargoBuildRustToolchain' = if (cargoBuildRustToolchain == null) @@ -145,7 +173,7 @@ # gets all the local (i.e. path) dependencies for a crate, recursively. # # note that to make this easier, we define all local dependencies as workspace dependencies. - getWorkspaceDeps = dir: + getWorkspaceDeps = dirs: let go = dir': foundSoFar: let @@ -172,13 +200,9 @@ unique ]; in - go dir [ ]; + unique (flatten (builtins.map (dir: go dir [ ]) dirs)); - workspaceDepsForCrate = - assert lib.assertMsg - (builtins.isString crateDirFromRoot) - "expected crateDirFromRoot to be a string, but it was a ${builtins.typeOf crateDirFromRoot}: ${crateDirFromRoot}"; - (getWorkspaceDeps crateDirFromRoot); + workspaceDepsForCrate = (getWorkspaceDeps crateDirFromRoot'); workspaceDepsForCrateCargoTomls = readMemberCargoTomls workspaceDepsForCrate; @@ -186,7 +210,6 @@ extraTestIncludePathsForCrate = getExtraIncludes workspaceDepsForCrateCargoTomls; crateSrc = mkCleanSrc { - name = cratePname; workspaceDepsForCrate = mkRootPaths workspaceDepsForCrate; extraIncludes = mkRootPaths (includePathsForCrate ++ extraTestIncludePathsForCrate); }; @@ -202,7 +225,7 @@ in # REVIEW: This can maybe be a runCommand? pkgs.stdenv.mkDerivation { - name = "${cratePname}-patched-workspace-cargo-toml"; + name = "${pname'}-patched-workspace-cargo-toml"; src = crateSrc; buildPhase = '' cp -r . $out @@ -210,19 +233,14 @@ ''; }; - crateInfo = - let - toml = crateCargoToml crateDirFromRoot; - in - { - pname = toml.package.name; - version = toml.package.version; - }; - - packageFilterArg = "-p ${crateInfo.pname}"; + packageFilterArgs = lib.concatMapStringsSep + " " + (dir: "-p ${(crateCargoToml dir).package.name}") + crateDirFromRoot'; crateAttrs = extraEnv // { - inherit (crateInfo) pname version; + pname = pname'; + version = version'; src = crateRepoSource; @@ -231,7 +249,7 @@ # defaults to "--all-targets" otherwise, which breaks some stuff cargoCheckExtraArgs = ""; - cargoExtraArgs = packageFilterArg; + cargoExtraArgs = packageFilterArgs; buildInputs = [ pkgs.pkg-config pkgs.openssl ] ++ ( lib.optionals pkgs.stdenv.isDarwin [ pkgs.darwin.apple_sdk.frameworks.Security ] @@ -256,13 +274,13 @@ cargoTestAttrs = builtins.addErrorContext - "while evaluating `cargoTestArgs` for crate `${cratePname}`" + "while evaluating `cargoTestArgs` for crate `${pname'}`" ( let crateAttrsWithArtifactsTest = crateAttrs // { doNotLinkInheritedArtifacts = true; cargoArtifacts = artifacts; - buildPhaseCargoCommand = "cargo test ${packageFilterArg} ${cargoTestExtraArgs}"; + buildPhaseCargoCommand = "cargo test ${packageFilterArgs} ${cargoTestExtraArgs}"; }; sharedAttrs = builtins.intersectAttrs crateAttrsWithArtifactsTest cargoTestExtraAttrs; in @@ -280,19 +298,20 @@ in { - packages.${cratePname} = cargoBuild.buildPackage ( + packages."${pname'}${pnameSuffix'}" = cargoBuild.buildPackage ( crateAttrs // { pnameSuffix = pnameSuffix'; - cargoExtraArgs = "${lib.optionalString (!dev) "-j1"} ${packageFilterArg} ${cargoBuildExtraArgs}" + (lib.optionalString + cargoExtraArgs = "${lib.optionalString (!dev) "-j1"} ${packageFilterArgs} ${cargoBuildExtraArgs}" + (lib.optionalString (buildStdTarget != null) # the leading space is important here! " -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort --target ${buildStdTarget}"); RUSTFLAGS = rustflags; # we don't want to run cargo check/ cargo test on this derivation since we do that in a separate package doCheck = false; - meta = { - mainProgram = crateInfo.pname; - }; + meta = + if (builtins.length (crateDirFromRoot') == 1) then { + mainProgram = pname'; + } else { }; } // (lib.optionalAttrs (cargoBuildInstallPhase != null) ({ installPhaseCommand = cargoBuildInstallPhase; })) // (lib.optionalAttrs (cargoBuildCheckPhase != null) ({ @@ -305,7 +324,7 @@ ) ); - checks = mkChecks cratePname { + checks = mkChecks pname' { # NOTE: We don't run this on individual crates, since we run clippy on the entire workspace. # Left here for reference in case we ever want to reuse this down the line. # clippy = mkCi (system == "x86_64-linux") (craneLib.cargoClippy (crateAttrs // { @@ -325,7 +344,6 @@ in mkCleanSrc { - name = "cargo-workspace-src"; workspaceDepsForCrate = mkRootPaths workspaceCargoToml.workspace.members; extraIncludes = mkRootPaths (includePaths ++ extraTestIncludePaths); }; diff --git a/uniond/proto/union/ibc/lightclients/movement/v1/movement.proto b/uniond/proto/union/ibc/lightclients/movement/v1/movement.proto index 1fae16fb6b..33b33c589d 100644 --- a/uniond/proto/union/ibc/lightclients/movement/v1/movement.proto +++ b/uniond/proto/union/ibc/lightclients/movement/v1/movement.proto @@ -97,11 +97,7 @@ message PublicKey { message AggregateSignature { bytes validator_bitmask = 1; - Signature sig = 2; -} - -message Signature { - bytes sig = 1; + bytes sig = 2; } message EpochChangeProof { diff --git a/voyager/Cargo.toml b/voyager/Cargo.toml index 8c43cd0de9..45c6fbd200 100644 --- a/voyager/Cargo.toml +++ b/voyager/Cargo.toml @@ -15,66 +15,57 @@ test-include = [] workspace = true [dependencies] -arbitrary = { workspace = true, optional = true, features = ["derive"] } -axum = { workspace = true, features = ["macros", "tokio", "json"] } -beacon-api = { workspace = true } -bech32 = "0.9.1" -bip32 = { workspace = true, features = ["secp256k1"] } -bitvec = { workspace = true } -block-message = { workspace = true } -chain-utils = { workspace = true } -clap = { workspace = true, features = ["default", "derive", "env", "error-context"] } -contracts = { workspace = true } -crossbeam-queue = { workspace = true, features = ["std"] } -derive_more = { workspace = true } -either = { workspace = true, features = ["serde"] } -enumorph = { workspace = true } -ethers = { workspace = true, features = ["rustls", "ws"] } -frame-support-procedural = { workspace = true } -frunk = { workspace = true } -futures = { workspace = true } -hex = { workspace = true } -hex-literal = { workspace = true } -itertools = "0.13.0" -num-bigint = { workspace = true } -pg-queue = { workspace = true } -pin-utils = "0.1.0" -prometheus = "0.13.4" -prost = { workspace = true } -protos = { workspace = true, features = ["proto_full", "client"] } -queue-msg = { workspace = true } -relay-message = { workspace = true } -reqwest = { workspace = true, features = ["tokio-rustls"] } -ripemd = { workspace = true } -serde = { workspace = true, features = ["derive"] } -serde-utils = { workspace = true } -serde_json = { workspace = true } -sha2 = { workspace = true } -sqlx = { workspace = true, features = ["postgres", "migrate", "tls-rustls"] } -subtle-encoding = { workspace = true, features = ["bech32-preview"] } -tendermint = { workspace = true } -tendermint-proto = { workspace = true } -tendermint-rpc = { workspace = true, features = ["http-client", "websocket-client"] } -thiserror = { workspace = true } -tikv-jemallocator = "0.5" -tokio = { workspace = true, features = ["macros"] } -tokio-stream = { workspace = true } -tokio-util = "0.7.9" -tonic = { workspace = true, features = ["transport", "tls", "tls-roots", "tls-webpki-roots"] } -tracing = { workspace = true, features = ["max_level_trace"] } -tracing-subscriber = { workspace = true, features = ["env-filter", "json"] } -typenum = { workspace = true } -unionlabs = { workspace = true, features = ["ethabi"] } -voyager-message.workspace = true +axum = { workspace = true, features = ["macros", "tokio", "json"] } +beacon-api = { workspace = true } +bech32 = "0.9.1" +bip32 = { workspace = true, features = ["secp256k1"] } +bitvec = { workspace = true } +chain-utils = { workspace = true } +clap = { workspace = true, features = ["default", "derive", "env", "error-context"] } +contracts = { workspace = true } +crossbeam-queue = { workspace = true, features = ["std"] } +derive_more = { workspace = true } +either = { workspace = true, features = ["serde"] } +enumorph = { workspace = true } +ethers = { workspace = true, features = ["rustls", "ws"] } +frame-support-procedural = { workspace = true } +frunk = { workspace = true } +futures = { workspace = true } +hex = { workspace = true } +hex-literal = { workspace = true } +itertools = "0.13.0" +jsonrpsee = { workspace = true, features = ["client", "full", "tracing"] } +num-bigint = { workspace = true } +pg-queue = { workspace = true } +pin-utils = "0.1.0" +prometheus = "0.13.4" +prost = { workspace = true } +protos = { workspace = true, features = ["proto_full", "client"] } +queue-msg = { workspace = true } +reqwest = { workspace = true, features = ["tokio-rustls"] } +ripemd = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +serde_json = { workspace = true } +sha2 = { workspace = true } +soketto = "0.8.0" +sqlx = { workspace = true, features = ["postgres", "migrate", "tls-rustls"] } +subtle-encoding = { workspace = true, features = ["bech32-preview"] } +tendermint = { workspace = true } +tendermint-proto = { workspace = true } +tendermint-rpc = { workspace = true, features = ["http-client", "websocket-client"] } +thiserror = { workspace = true } +tikv-jemallocator = "0.5" +tokio = { workspace = true, features = ["macros"] } +tokio-stream = { workspace = true } +tokio-util = "0.7.9" +tonic = { workspace = true, features = ["transport", "tls", "tls-roots", "tls-webpki-roots"] } +tracing = { workspace = true, features = ["max_level_trace"] } +tracing-futures = { version = "0.2.5", features = ["futures-03"] } +tracing-subscriber = { workspace = true, features = ["env-filter", "json"] } +typenum = { workspace = true } +unionlabs = { workspace = true, features = ["ethabi"] } +voyager-message = { workspace = true } [features] default = [] - -arbitrary = [ - "dep:arbitrary", - "relay-message/arbitrary", - "block-message/arbitrary", - "unionlabs/arbitrary", - "chain-utils/arbitrary", - "queue-msg/arbitrary", -] diff --git a/voyager/devnet-config.json b/voyager/devnet-config.json new file mode 100644 index 0000000000..1b6d4541ba --- /dev/null +++ b/voyager/devnet-config.json @@ -0,0 +1,188 @@ +{ + "plugins": [ + { + "enabled": true, + "path": "/home/ben/projects/union/union/target/debug/voyager-chain-module-cosmos-sdk", + "config": { + "chain_id": "union-devnet-1", + "ws_url": "http://localhost:26757", + "grpc_url": "http://localhost:9190" + } + }, + { + "enabled": true, + "path": "/home/ben/projects/union/union/target/debug/voyager-chain-module-ethereum", + "config": { + "chain_id": "32382", + "ibc_handler_address": "0xed2af2ad7fe0d92011b26a2e5d1b4dc7d12a47c5", + "eth_rpc_api": "ws://localhost:8546", + "eth_beacon_rpc_api": "http://localhost:9596" + } + }, + { + "enabled": true, + "path": "/home/ben/projects/union/union/target/debug/voyager-chain-module-movement", + "config": { + "chain_id": "27", + "rpc_url": "http://localhost:30731", + "ibc_handler_address": "0x9e1ceeb126ea73b3c29a6cfd1151e06a948cbc4ce06c81fc38119edc0edb5408" + } + }, + { + "enabled": true, + "path": "/home/ben/projects/union/union/target/debug/voyager-client-module-cometbls", + "config": { + "ibc_interface": "ibc-solidity" + } + }, + { + "enabled": true, + "path": "/home/ben/projects/union/union/target/debug/voyager-client-module-cometbls", + "config": { + "ibc_interface": "ibc-move/aptos" + } + }, + { + "enabled": true, + "path": "/home/ben/projects/union/union/target/debug/voyager-consensus-module-cometbls", + "config": { + "chain_id": "union-devnet-1", + "ws_url": "http://localhost:26757", + "grpc_url": "http://localhost:9190", + "prover_endpoints": ["http://localhost:9999"] + } + }, + { + "enabled": true, + "path": "/home/ben/projects/union/union/target/debug/voyager-consensus-module-ethereum", + "config": { + "chain_id": "32382", + "chain_spec": "minimal", + "ibc_handler_address": "0xed2af2ad7fe0d92011b26a2e5d1b4dc7d12a47c5", + "eth_rpc_api": "ws://localhost:8546", + "eth_beacon_rpc_api": "http://localhost:9596" + } + }, + { + "enabled": true, + "path": "/home/ben/projects/union/union/target/debug/voyager-client-module-ethereum", + "config": { + "chain_spec": "minimal" + } + }, + { + "enabled": true, + "path": "/home/ben/projects/union/union/target/debug/voyager-transaction-module-cosmos-sdk", + "config": { + "chain_id": "union-devnet-1", + "keyring": { + "name": "union-devnet", + "keys": [ + { + "type": "raw", + "name": "alice", + "key": "0xaa820fa947beb242032a41b6dc9a8b9c37d8f5fbcda0966b1ec80335b10a7d6f" + } + ] + }, + "gas_config": { + "gas_price": "1.0", + "gas_denom": "muno", + "gas_multiplier": "1.1", + "max_gas": 60000000 + }, + "ws_url": "http://localhost:26757", + "grpc_url": "http://localhost:9190" + } + }, + { + "enabled": true, + "path": "/home/ben/projects/union/union/target/debug/voyager-transaction-module-ethereum", + "config": { + "chain_id": "32382", + "ibc_handler_address": "0xed2af2ad7fe0d92011b26a2e5d1b4dc7d12a47c5", + "multicall_address": "0x9fd9D9528c8373D990a1380B9414bDE179007A35", + "keyring": { + "name": "ethereum-devnet", + "keys": [ + { + "type": "raw", + "name": "dev-key0", + "key": "0x4e9444a6efd6d42725a250b650a781da2737ea308c839eaccb0f7f3dbd2fea77" + }, + { + "type": "raw", + "name": "dev-key1", + "key": "0xd9c5dc47ed678fc3e63249953866d79e5cf48418e79d8eec1a985be7393ef3b9" + }, + { + "type": "raw", + "name": "eth-key-2", + "key": "0x0a917066d306f09670e47729bfd4384f4afcac98493c65b9733870a434d71f29" + }, + { + "type": "raw", + "name": "eth-key-3", + "key": "0xff45ae2a6c4899294e898a171e15de8a4d2557852378364f8684c6a1520ccd7d" + }, + { + "type": "raw", + "name": "eth-key-4", + "key": "0x27ae0c7b8d7c698e41b173265490a4c64b4e39ae78599166e003f868f12140fd" + } + ] + }, + "eth_rpc_api": "ws://localhost:8546" + } + }, + { + "enabled": true, + "path": "/home/ben/projects/union/union/target/debug/voyager-plugin-packet-filter", + "config": { + "connection_event_filters": [{}], + "channel_event_filters": [{}], + "packet_event_filters": [{}] + } + }, + { + "enabled": true, + "path": "/home/ben/projects/union/union/target/debug/voyager-plugin-transaction-batch", + "config": { + "chain_id": "union-devnet-1", + "client_configs": { + "*": { + "min_batch_size": 1, + "max_batch_size": 3, + "max_wait_time": { "secs": 10, "nanos": 0 } + } + } + } + }, + { + "enabled": true, + "path": "/home/ben/projects/union/union/target/debug/voyager-plugin-transaction-batch", + "config": { + "chain_id": "32382", + "client_configs": { + "*": { + "min_batch_size": 1, + "max_batch_size": 3, + "max_wait_time": { "secs": 10, "nanos": 0 } + } + } + } + } + ], + "voyager": { + "num_workers": 50, + "queue": { + "type": "pg-queue", + "database_url": "postgres://postgres:postgrespassword@127.0.0.1:5432/default", + "max_connections": 50, + "min_connections": 50, + "idle_timeout": null, + "max_lifetime": null + }, + "optimizer_delay_milliseconds": 100 + } +} diff --git a/voyager/minimal-config.json b/voyager/minimal-config.json index 6f9c0e6397..242b2b1c18 100644 --- a/voyager/minimal-config.json +++ b/voyager/minimal-config.json @@ -48,7 +48,7 @@ }, "voyager": { "num_workers": 4, - "laddr": "0.0.0.0:65534", + "laddr": "0.0.0.0:7717", "queue": { "type": "pg-queue", "database_url": "postgres://postgres:postgrespassword@127.0.0.1:5432/default", diff --git a/voyager/modules/chain/cosmos-sdk/Cargo.toml b/voyager/modules/chain/cosmos-sdk/Cargo.toml new file mode 100644 index 0000000000..e7d06b8478 --- /dev/null +++ b/voyager/modules/chain/cosmos-sdk/Cargo.toml @@ -0,0 +1,26 @@ +[package] +edition = "2021" +name = "voyager-chain-module-cosmos-sdk" +version = "0.1.0" + +[dependencies] +clap = { workspace = true, features = ["derive"] } +cometbft-rpc = { workspace = true } +dashmap = { workspace = true } +enumorph = { workspace = true } +frunk = { workspace = true } +futures = { workspace = true } +jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } +macros = { workspace = true } +prost = { workspace = true } +protos = { workspace = true } +queue-msg = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +serde_json = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +unionlabs = { workspace = true } +voyager-message = { workspace = true } diff --git a/voyager/modules/chain/cosmos-sdk/src/call.rs b/voyager/modules/chain/cosmos-sdk/src/call.rs new file mode 100644 index 0000000000..9421652f29 --- /dev/null +++ b/voyager/modules/chain/cosmos-sdk/src/call.rs @@ -0,0 +1,32 @@ +use std::num::NonZeroU32; + +use enumorph::Enumorph; +use queue_msg::queue_msg; +use unionlabs::{events::IbcEvent, hash::H256, ibc::core::client::height::Height}; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCall { + FetchBlocks(FetchBlocks), + FetchTransactions(FetchTransactions), + MakeChainEvent(MakeChainEvent), +} + +#[queue_msg] +pub struct FetchBlocks { + pub from_height: Height, + pub to_height: Height, +} + +#[queue_msg] +pub struct FetchTransactions { + pub height: Height, + pub page: NonZeroU32, +} + +#[queue_msg] +pub struct MakeChainEvent { + pub height: Height, + pub tx_hash: H256, + pub event: IbcEvent, +} diff --git a/voyager/modules/chain/cosmos-sdk/src/callback.rs b/voyager/modules/chain/cosmos-sdk/src/callback.rs new file mode 100644 index 0000000000..e3dbf95927 --- /dev/null +++ b/voyager/modules/chain/cosmos-sdk/src/callback.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCallback {} diff --git a/voyager/modules/chain/cosmos-sdk/src/data.rs b/voyager/modules/chain/cosmos-sdk/src/data.rs new file mode 100644 index 0000000000..063c8f7f1d --- /dev/null +++ b/voyager/modules/chain/cosmos-sdk/src/data.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleData {} diff --git a/voyager/modules/chain/cosmos-sdk/src/main.rs b/voyager/modules/chain/cosmos-sdk/src/main.rs new file mode 100644 index 0000000000..75c52be2a4 --- /dev/null +++ b/voyager/modules/chain/cosmos-sdk/src/main.rs @@ -0,0 +1,1461 @@ +// #![warn(clippy::unwrap_used)] + +use std::{ + collections::VecDeque, + error::Error, + fmt::{Debug, Display}, + num::{NonZeroU32, NonZeroU8, ParseIntError}, + sync::Arc, +}; + +use dashmap::DashMap; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + types::{ErrorObject, ErrorObjectOwned}, +}; +use queue_msg::{call, conc, data, BoxDynError, Op}; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; +use serde_utils::Hex; +use tracing::{debug, error, info, instrument, warn}; +use unionlabs::{ + encoding::{DecodeAs, Proto}, + events::{ + ChannelOpenAck, ChannelOpenConfirm, ChannelOpenInit, ChannelOpenTry, ClientMisbehaviour, + ConnectionOpenAck, ConnectionOpenConfirm, ConnectionOpenInit, ConnectionOpenTry, + CreateClient, IbcEvent, SubmitEvidence, UpdateClient, + }, + hash::{H256, H64}, + ibc::core::{ + channel::{self, channel::Channel}, + client::height::Height, + commitment::merkle_proof::MerkleProof, + connection::connection_end::ConnectionEnd, + }, + ics24::{ + AcknowledgementPath, ChannelEndPath, ClientConsensusStatePath, ClientStatePath, + CommitmentPath, ConnectionPath, IbcPath, NextClientSequencePath, + NextConnectionSequencePath, NextSequenceAckPath, NextSequenceRecvPath, + NextSequenceSendPath, Path, ReceiptPath, + }, + id::{ChannelId, ClientId, ConnectionId, PortId}, + option_unwrap, parse_wasm_client_type, ErrorReporter, QueryHeight, WasmClientType, +}; +use voyager_message::{ + call::Call, + data::{ChainEvent, ChannelMetadata, ClientInfo, ConnectionMetadata, Data, PacketMetadata}, + module::{ + ChainModuleInfo, ChainModuleServer, IbcGo08WasmClientMetadata, ModuleInfo, + QueueInteractionsServer, RawClientState, + }, + reconnecting_jsonrpc_ws_client, + rpc::{json_rpc_error_to_rpc_error, missing_state, VoyagerRpcClient, VoyagerRpcClientExt}, + run_module_server, ChainId, ClientType, IbcInterface, ModuleContext, ModuleServer, + VoyagerMessage, FATAL_JSONRPC_ERROR_CODE, +}; + +use crate::{ + call::{FetchBlocks, FetchTransactions, MakeChainEvent, ModuleCall}, + callback::ModuleCallback, + data::ModuleData, +}; + +pub mod call; +pub mod callback; +pub mod data; + +const PER_PAGE_LIMIT: NonZeroU8 = option_unwrap!(NonZeroU8::new(10)); + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + run_module_server::().await +} + +#[derive(clap::Subcommand)] +pub enum Cmd { + ChainId, + LatestHeight, +} + +#[derive(Debug, Clone)] +pub struct Module { + pub chain_id: ChainId<'static>, + pub chain_revision: u64, + + pub tm_client: cometbft_rpc::Client, + pub grpc_url: String, + + pub checksum_cache: Arc>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Config { + pub chain_id: ChainId<'static>, + pub ws_url: String, + pub grpc_url: String, +} + +impl ModuleContext for Module { + type Config = Config; + type Cmd = Cmd; + type Info = ChainModuleInfo; + + async fn new(config: Self::Config) -> Result { + let tm_client = cometbft_rpc::Client::new(config.ws_url).await?; + + let chain_id = tm_client.status().await?.node_info.network; + + let chain_revision = chain_id + .split('-') + .last() + .ok_or_else(|| ChainIdParseError { + found: chain_id.clone(), + source: None, + })? + .parse() + .map_err(|err| ChainIdParseError { + found: chain_id.clone(), + source: Some(err), + })?; + + Ok(Self { + tm_client, + chain_id: ChainId::new(chain_id), + chain_revision, + grpc_url: config.grpc_url, + checksum_cache: Arc::new(DashMap::default()), + }) + } + + fn info(config: Self::Config) -> ModuleInfo { + ModuleInfo { + name: plugin_name(&config.chain_id), + kind: ChainModuleInfo { + chain_id: config.chain_id, + }, + } + } + + async fn cmd(config: Self::Config, cmd: Self::Cmd) { + let module = Self::new(config).await.unwrap(); + + match cmd { + Cmd::ChainId => println!("{}", module.chain_id), + Cmd::LatestHeight => println!("{}", module.latest_height().await.unwrap()), + } + } +} + +fn plugin_name(chain_id: &ChainId<'_>) -> String { + pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); + + format!("{PLUGIN_NAME}/{}", chain_id) +} + +impl Module { + fn plugin_name(&self) -> String { + plugin_name(&self.chain_id) + } + + #[must_use] + pub fn make_height(&self, height: u64) -> Height { + Height { + revision_number: self.chain_revision, + revision_height: height, + } + } + + async fn client_type_of_checksum(&self, checksum: H256) -> RpcResult> { + if let Some(ty) = self.checksum_cache.get(&checksum) { + debug!( + checksum = %checksum.to_string_unprefixed(), + ty = ?*ty, + "cache hit for checksum" + ); + + return Ok(Some(*ty)); + }; + + info!( + checksum = %checksum.to_string_unprefixed(), + "cache miss for checksum" + ); + + let bz = protos::ibc::lightclients::wasm::v1::query_client::QueryClient::connect( + self.grpc_url.clone(), + ) + .await + .map_err(rpc_error( + "error connecting to grpc server", + Some(json!({ + "grpc_url": self.grpc_url + })), + ))? + .code(protos::ibc::lightclients::wasm::v1::QueryCodeRequest { + checksum: checksum.to_string_unprefixed(), + }) + .await + .map_err(rpc_error( + "error querying wasm code", + Some(json!({ + "checksum": checksum, + "grpc_url": self.grpc_url + })), + ))? + .into_inner() + .data; + + match parse_wasm_client_type(bz) { + Ok(Some(ty)) => { + info!( + checksum = %checksum.to_string_unprefixed(), + ?ty, + "parsed checksum" + ); + + self.checksum_cache.insert(checksum, ty); + + Ok(Some(ty)) + } + Ok(None) => Ok(None), + Err(err) => { + error!( + checksum = %checksum.to_string_unprefixed(), + %err, + "unable to parse wasm client type" + ); + + Ok(None) + } + } + } + + #[instrument(skip_all, fields(%client_id))] + async fn checksum_of_client_id(&self, client_id: ClientId) -> RpcResult { + type WasmClientState = protos::ibc::lightclients::wasm::v1::ClientState; + + let client_state = protos::ibc::core::client::v1::query_client::QueryClient::connect( + self.grpc_url.clone(), + ) + .await + .map_err(rpc_error( + "error connecting to grpc server", + Some(json!({ "client_id": client_id })), + ))? + .client_state(protos::ibc::core::client::v1::QueryClientStateRequest { + client_id: client_id.to_string(), + }) + .await + .map_err(rpc_error( + "error querying client state", + Some(json!({ "client_id": client_id })), + ))? + .into_inner() + .client_state + .ok_or_else(|| { + // lol + rpc_error( + "error fetching client state", + Some(json!({ "client_id": client_id })), + )(&*Box::::from("client state field is empty")) + })?; + + assert!( + client_state.type_url == ::type_url(), + "attempted to get the wasm blob checksum of a non-wasm \ + light client. this is a bug, please report this at \ + `https://github.com/unionlabs/union`." + ); + + // NOTE: We only need the checksum, so we don't need to decode the inner state contained in .data + ::decode(&*client_state.value) + .map_err(rpc_error( + "error decoding client state", + Some(json!({ "client_id": client_id })), + ))? + .checksum + .try_into() + .map_err(rpc_error( + "invalid checksum", + Some(json!({ "client_id": client_id })), + )) + } + + // async fn fetch_connection(&self, connection_id: ConnectionId) -> (ConnectionEnd, Height) { + // let inner = protos::ibc::core::connection::v1::query_client::QueryClient::connect( + // self.grpc_url.clone(), + // ) + // .await + // .unwrap() + // .connection(protos::ibc::core::connection::v1::QueryConnectionRequest { + // connection_id: connection_id.to_string(), + // }) + // .await + // .unwrap() + // .into_inner(); + + // ( + // inner.connection.unwrap().try_into().unwrap(), + // inner.proof_height.unwrap().into(), + // ) + // } + + // async fn fetch_client(&self, client_id: ClientId) -> (Vec, Height) { + // let inner = protos::ibc::core::client::v1::query_client::QueryClient::connect( + // self.grpc_url.clone(), + // ) + // .await + // .unwrap() + // .client_state(protos::ibc::core::client::v1::QueryClientStateRequest { + // client_id: client_id.to_string(), + // }) + // .await + // .unwrap() + // .into_inner(); + + // ( + // inner.client_state.unwrap().try_into().unwrap(), + // inner.proof_height.unwrap().into(), + // ) + // } + + async fn latest_height(&self) -> Result { + let commit_response = self.tm_client.commit(None).await?; + + let mut height = commit_response + .signed_header + .header + .height + .inner() + .try_into() + .expect("value is >= 0; qed;"); + + if !commit_response.canonical { + debug!("commit is not canonical, latest finalized height is the previous block"); + height -= 1; + } + + debug!(height, "latest height"); + + Ok(self.make_height(height)) + } + + #[allow(clippy::too_many_arguments)] // pls + async fn make_packet_metadata( + &self, + event_height: Height, + self_connection_id: ConnectionId, + self_port_id: PortId, + self_channel_id: ChannelId, + other_port_id: PortId, + other_channel_id: ChannelId, + voyager_rpc_client: &reconnecting_jsonrpc_ws_client::Client, + ) -> RpcResult<( + ChainId<'static>, + ClientInfo, + ChannelMetadata, + ChannelMetadata, + channel::order::Order, + )> { + let self_connection = voyager_rpc_client + .query_ibc_state_typed( + self.chain_id.clone(), + event_height.into(), + ConnectionPath { + connection_id: self_connection_id.clone(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("connection must exist", None))?; + + let client_info = voyager_rpc_client + .client_info(self.chain_id.clone(), self_connection.client_id.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = voyager_rpc_client + .client_meta( + self.chain_id.clone(), + event_height.into(), + self_connection.client_id.clone(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let this_channel = voyager_rpc_client + .query_ibc_state_typed( + self.chain_id.clone(), + event_height.into(), + ChannelEndPath { + port_id: self_port_id.clone(), + channel_id: self_channel_id.clone(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("channel must exist", None))?; + + let counterparty_channel = voyager_rpc_client + .query_ibc_state_typed( + client_meta.chain_id.clone(), + QueryHeight::Latest, + ChannelEndPath { + port_id: other_port_id.clone(), + channel_id: other_channel_id.clone(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("channel must exist", None))?; + + let source_channel = ChannelMetadata { + port_id: self_port_id.clone(), + channel_id: self_channel_id.clone(), + version: this_channel.version, + connection: ConnectionMetadata { + client_id: self_connection.client_id, + connection_id: self_connection_id.clone(), + }, + }; + let destination_channel = ChannelMetadata { + port_id: other_port_id.clone(), + channel_id: other_channel_id.clone(), + version: counterparty_channel.version, + connection: ConnectionMetadata { + client_id: self_connection.counterparty.client_id, + connection_id: self_connection + .counterparty + .connection_id + .expect("counterparty connection id should be set"), + }, + }; + + Ok(( + client_meta.chain_id, + client_info, + source_channel, + destination_channel, + this_channel.ordering, + )) + } +} + +#[derive(Debug, thiserror::Error)] +#[error("unable to parse chain id: expected format `-`, found `{found}`")] +pub struct ChainIdParseError { + found: String, + #[source] + source: Option, +} + +#[async_trait] +impl QueueInteractionsServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn callback( + &self, + cb: ModuleCallback, + _data: VecDeque>, + ) -> RpcResult>> { + match cb {} + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn call( + &self, + msg: ModuleCall, + ) -> RpcResult>> { + match msg { + ModuleCall::FetchTransactions(FetchTransactions { height, page }) => { + info!(%height, %page, "fetching events in block"); + + let response = self + .ctx + .tm_client + .tx_search( + format!("tx.height={}", height.revision_height), + false, + page, + PER_PAGE_LIMIT, + cometbft_rpc::types::Order::Desc, + ) + .await + .map_err(rpc_error( + format_args!("error fetching transactions at height {height}"), + Some(json!({ "height": height })), + ))?; + + Ok(conc( + response + .txs + .into_iter() + .flat_map(|txr| { + txr.tx_result.events.into_iter().filter_map(move |event| { + debug!(%event.ty, "observed event"); + IbcEvent::try_from_tendermint_event(event) + .map(|event| event.map(|event| (event, txr.hash))) + }) + }) + .collect::, _>>() + .map_err(|err| { + ErrorObject::owned( + -1, + ErrorReporter(err).to_string(), + Some(json!({ + "height": height, + "page": page + })), + ) + })? + .into_iter() + .map(|(ibc_event, tx_hash)| { + debug!(event = %ibc_event.name(), "observed IBC event"); + call(Call::plugin( + self.ctx.plugin_name(), + MakeChainEvent { + height, + tx_hash, + event: ibc_event, + }, + )) + }) + .chain( + ((page.get() * PER_PAGE_LIMIT.get() as u32) < response.total_count) + .then(|| { + call(Call::plugin( + self.ctx.plugin_name(), + FetchTransactions { + height, + page: page.checked_add(1).expect("too many pages?"), + }, + )) + }), + ), + )) + } + ModuleCall::FetchBlocks(FetchBlocks { + from_height, + to_height, + }) => { + assert!(from_height.revision_height < to_height.revision_height); + + if to_height.revision_height - from_height.revision_height == 1 { + Ok(call(Call::plugin( + self.ctx.plugin_name(), + FetchTransactions { + height: from_height, + page: const { option_unwrap!(NonZeroU32::new(1_u32)) }, + }, + ))) + } else { + // this is exclusive on `to`, so fetch the `from` block and "discard" the `to` block + // the assumption is that another message with `to..N` will be queued, which then following + // this logic will fetch `to`. + + let new_from_height = from_height.increment(); + + Ok(conc( + [call(Call::plugin( + self.ctx.plugin_name(), + FetchTransactions { + height: from_height, + page: const { option_unwrap!(NonZeroU32::new(1_u32)) }, + }, + ))] + .into_iter() + .chain((new_from_height != to_height).then(|| { + debug!("range not completed, requeueing fetch from {new_from_height} to {to_height}"); + + call(Call::plugin( + self.ctx.plugin_name(), + FetchBlocks { + from_height: new_from_height, + to_height, + }, + )) + })), + )) + } + } + ModuleCall::MakeChainEvent(MakeChainEvent { + height, + tx_hash, + event, + }) => { + // events at height N are provable at height N+k where k<0 + let provable_height = height.increment(); + + match event { + IbcEvent::SubmitEvidence(SubmitEvidence { .. }) => { + // TODO: Not sure how to handle this one, since it only contains the hash + panic!() + } + IbcEvent::CreateClient(CreateClient { ref client_id, .. }) + | IbcEvent::UpdateClient(UpdateClient { ref client_id, .. }) + | IbcEvent::ClientMisbehaviour(ClientMisbehaviour { ref client_id, .. }) + | IbcEvent::ConnectionOpenInit(ConnectionOpenInit { ref client_id, .. }) + | IbcEvent::ConnectionOpenTry(ConnectionOpenTry { ref client_id, .. }) + | IbcEvent::ConnectionOpenAck(ConnectionOpenAck { ref client_id, .. }) + | IbcEvent::ConnectionOpenConfirm(ConnectionOpenConfirm { + ref client_id, + .. + }) => { + let client_info = self + .voyager_rpc_client + .client_info(self.ctx.chain_id.clone(), client_id.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + height.into(), + client_id.clone(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id: client_meta.chain_id, + tx_hash, + provable_height, + event: match event { + IbcEvent::CreateClient(event) => { + voyager_message::data::CreateClient { + client_id: event.client_id, + client_type: ClientType::new(event.client_type), + consensus_height: event.consensus_height, + } + .into() + } + IbcEvent::UpdateClient(event) => { + voyager_message::data::UpdateClient { + client_id: event.client_id, + client_type: ClientType::new(event.client_type), + consensus_heights: event.consensus_heights, + } + .into() + } + IbcEvent::ConnectionOpenInit(event) => { + voyager_message::data::ConnectionOpenInit { + client_id: event.client_id, + connection_id: event.connection_id, + counterparty_client_id: event.counterparty_client_id, + } + } + .into(), + IbcEvent::ConnectionOpenTry(event) => { + voyager_message::data::ConnectionOpenTry { + client_id: event.client_id, + connection_id: event.connection_id, + counterparty_client_id: event.counterparty_client_id, + counterparty_connection_id: event + .counterparty_connection_id, + } + } + .into(), + IbcEvent::ConnectionOpenAck(event) => { + voyager_message::data::ConnectionOpenAck { + client_id: event.client_id, + connection_id: event.connection_id, + counterparty_client_id: event.counterparty_client_id, + counterparty_connection_id: event + .counterparty_connection_id, + } + } + .into(), + IbcEvent::ConnectionOpenConfirm(event) => { + voyager_message::data::ConnectionOpenConfirm { + client_id: event.client_id, + connection_id: event.connection_id, + counterparty_client_id: event.counterparty_client_id, + counterparty_connection_id: event + .counterparty_connection_id, + } + } + .into(), + _ => unreachable!("who needs flow typing"), + }, + })) + } + IbcEvent::ChannelOpenInit(ChannelOpenInit { + ref connection_id, .. + }) + | IbcEvent::ChannelOpenTry(ChannelOpenTry { + ref connection_id, .. + }) => { + let connection = self + .voyager_rpc_client + .query_ibc_state_typed( + self.ctx.chain_id.clone(), + height.into(), + ConnectionPath { + connection_id: connection_id.clone(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("connection must exist", None))?; + + let client_info = self + .voyager_rpc_client + .client_info(self.ctx.chain_id.clone(), connection.client_id.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + height.into(), + connection.client_id.clone(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id: client_meta.chain_id, + tx_hash, + provable_height, + event: match event { + IbcEvent::ChannelOpenInit(event) => { + voyager_message::data::ChannelOpenInit { + port_id: event.port_id, + channel_id: event.channel_id, + counterparty_port_id: event.counterparty_port_id, + connection, + version: event.version, + } + } + .into(), + IbcEvent::ChannelOpenTry(event) => { + voyager_message::data::ChannelOpenTry { + port_id: event.port_id, + channel_id: event.channel_id, + counterparty_port_id: event.counterparty_port_id, + counterparty_channel_id: event.counterparty_channel_id, + connection, + version: event.version, + } + .into() + } + _ => unreachable!("who needs flow typing"), + }, + })) + } + IbcEvent::ChannelOpenAck(ChannelOpenAck { + ref connection_id, + ref port_id, + ref channel_id, + .. + }) + | IbcEvent::ChannelOpenConfirm(ChannelOpenConfirm { + ref connection_id, + ref port_id, + ref channel_id, + .. + }) => { + let connection = self + .voyager_rpc_client + .query_ibc_state_typed( + self.ctx.chain_id.clone(), + height.into(), + ConnectionPath { + connection_id: connection_id.clone(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("connection must exist", None))?; + + let client_info = self + .voyager_rpc_client + .client_info(self.ctx.chain_id.clone(), connection.client_id.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + height.into(), + connection.client_id.clone(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let channel = self + .voyager_rpc_client + .query_ibc_state_typed( + self.ctx.chain_id.clone(), + height.into(), + ChannelEndPath { + port_id: port_id.to_owned(), + channel_id: channel_id.to_owned(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("channel must exist", None))?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id: client_meta.chain_id, + tx_hash, + provable_height, + event: match event { + IbcEvent::ChannelOpenAck(event) => { + voyager_message::data::ChannelOpenAck { + port_id: event.port_id, + channel_id: event.channel_id, + counterparty_port_id: event.counterparty_port_id, + counterparty_channel_id: event.counterparty_channel_id, + connection, + version: channel.version, + } + } + .into(), + IbcEvent::ChannelOpenConfirm(event) => { + voyager_message::data::ChannelOpenConfirm { + port_id: event.port_id, + channel_id: event.channel_id, + counterparty_port_id: event.counterparty_port_id, + counterparty_channel_id: event.counterparty_channel_id, + connection, + version: channel.version, + } + .into() + } + _ => unreachable!("who needs flow typing"), + }, + })) + } + // packet origin is this chain + IbcEvent::SendPacket(event) => { + let ( + counterparty_chain_id, + client_info, + source_channel, + destination_channel, + channel_ordering, + ) = self + .ctx + .make_packet_metadata( + height, + event.connection_id.to_owned(), + event.packet_src_port.to_owned(), + event.packet_src_channel.to_owned(), + event.packet_dst_port.to_owned(), + event.packet_dst_channel.to_owned(), + &self.voyager_rpc_client, + ) + .await?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id, + tx_hash, + provable_height, + event: voyager_message::data::SendPacket { + packet_data: event.packet_data_hex, + packet: PacketMetadata { + sequence: event.packet_sequence, + source_channel, + destination_channel, + channel_ordering, + timeout_height: event.packet_timeout_height, + timeout_timestamp: event.packet_timeout_timestamp, + }, + } + .into(), + })) + } + IbcEvent::TimeoutPacket(event) => { + let ( + counterparty_chain_id, + client_info, + source_channel, + destination_channel, + channel_ordering, + ) = self + .ctx + .make_packet_metadata( + height, + event.connection_id.to_owned(), + event.packet_src_port.to_owned(), + event.packet_src_channel.to_owned(), + event.packet_dst_port.to_owned(), + event.packet_dst_channel.to_owned(), + &self.voyager_rpc_client, + ) + .await?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id, + tx_hash, + provable_height, + event: voyager_message::data::TimeoutPacket { + packet: PacketMetadata { + sequence: event.packet_sequence, + source_channel, + destination_channel, + channel_ordering, + timeout_height: event.packet_timeout_height, + timeout_timestamp: event.packet_timeout_timestamp, + }, + } + .into(), + })) + } + IbcEvent::AcknowledgePacket(event) => { + let ( + counterparty_chain_id, + client_info, + source_channel, + destination_channel, + channel_ordering, + ) = self + .ctx + .make_packet_metadata( + height, + event.connection_id.to_owned(), + event.packet_src_port.to_owned(), + event.packet_src_channel.to_owned(), + event.packet_dst_port.to_owned(), + event.packet_dst_channel.to_owned(), + &self.voyager_rpc_client, + ) + .await?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id, + tx_hash, + provable_height, + event: voyager_message::data::AcknowledgePacket { + packet: PacketMetadata { + sequence: event.packet_sequence, + source_channel, + destination_channel, + channel_ordering, + timeout_height: event.packet_timeout_height, + timeout_timestamp: event.packet_timeout_timestamp, + }, + } + .into(), + })) + } + // packet origin is the counterparty chain (if i put this comment above this pattern rustfmt explodes) + IbcEvent::WriteAcknowledgement(event) => { + let ( + counterparty_chain_id, + client_info, + destination_channel, + source_channel, + channel_ordering, + ) = self + .ctx + .make_packet_metadata( + height, + event.connection_id.to_owned(), + event.packet_dst_port.to_owned(), + event.packet_dst_channel.to_owned(), + event.packet_src_port.to_owned(), + event.packet_src_channel.to_owned(), + &self.voyager_rpc_client, + ) + .await?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id, + tx_hash, + provable_height, + event: voyager_message::data::WriteAcknowledgement { + packet_data: event.packet_data_hex, + packet_ack: event.packet_ack_hex, + packet: PacketMetadata { + sequence: event.packet_sequence, + source_channel, + destination_channel, + channel_ordering, + timeout_height: event.packet_timeout_height, + timeout_timestamp: event.packet_timeout_timestamp, + }, + } + .into(), + })) + } + IbcEvent::RecvPacket(event) => { + let ( + counterparty_chain_id, + client_info, + destination_channel, + source_channel, + channel_ordering, + ) = self + .ctx + .make_packet_metadata( + height, + event.connection_id.to_owned(), + event.packet_dst_port.to_owned(), + event.packet_dst_channel.to_owned(), + event.packet_src_port.to_owned(), + event.packet_src_channel.to_owned(), + &self.voyager_rpc_client, + ) + .await?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id, + tx_hash, + provable_height, + event: voyager_message::data::RecvPacket { + packet_data: event.packet_data_hex, + packet: PacketMetadata { + sequence: event.packet_sequence, + source_channel, + destination_channel, + channel_ordering, + timeout_height: event.packet_timeout_height, + timeout_timestamp: event.packet_timeout_timestamp, + }, + } + .into(), + })) + } + } + } + } + } +} + +#[async_trait] +impl ChainModuleServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + fn chain_id(&self) -> RpcResult> { + Ok(self.ctx.chain_id.clone()) + } + + /// Query the latest finalized height of this chain. + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_latest_height(&self) -> RpcResult { + self.ctx + .latest_height() + .await + // TODO: Add more context here + .map_err(|err| ErrorObject::owned(-1, ErrorReporter(err).to_string(), None::<()>)) + } + + /// Query the latest (non-finalized) height of this chain. + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_latest_height_as_destination(&self) -> RpcResult { + self.ctx + .latest_height() + .await + // TODO: Add more context here + .map_err(|err| ErrorObject::owned(-1, ErrorReporter(err).to_string(), None::<()>)) + } + + /// Query the latest finalized timestamp of this chain. + // TODO: Use a better timestamp type here + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_latest_timestamp(&self) -> RpcResult { + let mut commit_response = + self.ctx.tm_client.commit(None).await.map_err(|err| { + ErrorObject::owned(-1, ErrorReporter(err).to_string(), None::<()>) + })?; + + if commit_response.canonical { + debug!("commit is not canonical, fetching commit at previous block"); + commit_response = self + .ctx + .tm_client + .commit(Some( + (u64::try_from(commit_response.signed_header.header.height.inner() - 1) + .expect("should be fine")) + .try_into() + .expect("should be fine"), + )) + .await + .map_err(|err| { + ErrorObject::owned(-1, ErrorReporter(err).to_string(), None::<()>) + })?; + + if !commit_response.canonical { + error!( + ?commit_response, + "commit for previous height is not canonical? continuing \ + anyways, but this may cause issues downstream" + ); + } + } + + Ok(commit_response + .signed_header + .header + .time + .as_unix_nanos() + .try_into() + .expect("should be fine")) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn fetch_block_range( + &self, + from_height: Height, + to_height: Height, + ) -> RpcResult>> { + Ok(call(Call::plugin( + self.ctx.plugin_name(), + FetchBlocks { + from_height, + to_height, + }, + ))) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn client_info(&self, client_id: ClientId) -> RpcResult { + match client_id.to_string().rsplit_once('-') { + Some(("07-tendermint", _)) => Ok(ClientInfo { + client_type: ClientType::new(ClientType::TENDERMINT), + ibc_interface: IbcInterface::new(IbcInterface::IBC_GO_V8_NATIVE), + metadata: Default::default(), + }), + Some(("08-wasm", _)) => { + let checksum = self.ctx.checksum_of_client_id(client_id.clone()).await?; + + Ok(ClientInfo { + client_type: match self.ctx.client_type_of_checksum(checksum).await? { + Some(ty) => match ty { + WasmClientType::EthereumMinimal => { + ClientType::new(ClientType::ETHEREUM_MINIMAL) + } + WasmClientType::EthereumMainnet => { + ClientType::new(ClientType::ETHEREUM_MAINNET) + } + WasmClientType::Cometbls => ClientType::new(ClientType::COMETBLS), + WasmClientType::Tendermint => ClientType::new(ClientType::TENDERMINT), + WasmClientType::Scroll => ClientType::new(ClientType::SCROLL), + WasmClientType::Arbitrum => ClientType::new(ClientType::ARBITRUM), + WasmClientType::Linea => todo!(), + WasmClientType::Berachain => ClientType::new(ClientType::BEACON_KIT), + WasmClientType::Movement => ClientType::new(ClientType::MOVEMENT), + WasmClientType::EvmInCosmos => todo!(), + }, + None => { + warn!(%client_id, "unknown client type for 08-wasm client"); + // this early return is kind of dirty but it works + return Err(ErrorObject::owned( + -1, + "unknown client type for 08-wasm client", + Some(json!({ + "client_id": client_id.to_string() + })), + )); + } + }, + ibc_interface: IbcInterface::new(IbcInterface::IBC_GO_V8_08_WASM), + metadata: into_value(IbcGo08WasmClientMetadata { checksum }), + }) + } + _ => Err(ErrorObject::owned( + -1, + format!("unknown client type (client id `{client_id}`)"), + Some(json!({ + "client_id": client_id.to_string() + })), + )), + } + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_ibc_state(&self, at: Height, path: Path) -> RpcResult { + const IBC_STORE_PATH: &str = "store/ibc/key"; + + let path_string = path.to_string(); + + let error_data = || Some(json!({ "height": at, "path": path })); + + let query_result = self + .ctx + .tm_client + .abci_query( + IBC_STORE_PATH, + &path_string, + Some( + i64::try_from(at.revision_height) + .expect("should be fine") + .try_into() + .expect("invalid height"), + ), + false, + ) + .await + .map_err(rpc_error( + format_args!("error fetching abci query"), + error_data(), + ))? + .response; + + // NOTE: At this point, we assume that if the node has given us a response that the data contained within said response is fully reflective of the actual state on-chain, and as such it is a fatal error if we fail to decode it + type ValueOf = ::Value; + + Ok(match path { + Path::ClientState(_) => into_value::>(Hex(query_result.value)), + Path::ClientConsensusState(_) => { + into_value::>(Hex(query_result.value)) + } + Path::Connection(_) => { + into_value::>(if query_result.value.is_empty() { + None + } else { + Some( + ConnectionEnd::decode_as::(&query_result.value).map_err( + fatal_rpc_error("error decoding connection end", error_data()), + )?, + ) + }) + } + Path::ChannelEnd(_) => { + into_value::>(if query_result.value.is_empty() { + None + } else { + Some( + Channel::decode_as::(&query_result.value) + .map_err(fatal_rpc_error("error decoding channel end", error_data()))?, + ) + }) + } + Path::Commitment(_) => { + into_value::>(if query_result.value.is_empty() { + None + } else { + Some( + H256::try_from(query_result.value) + .map_err(fatal_rpc_error("error decoding commitment", error_data()))?, + ) + }) + } + Path::Acknowledgement(_) => { + into_value::>(if query_result.value.is_empty() { + None + } else { + Some(H256::try_from(query_result.value).map_err(fatal_rpc_error( + "error decoding acknowledgement commitment", + error_data(), + ))?) + }) + } + Path::Receipt(_) => into_value::>(match query_result.value[..] { + [] => false, + [1] => true, + ref invalid => { + return Err(fatal_rpc_error("error decoding receipt", error_data())( + format!( + "value is neither empty nor the single byte 0x01, found {}", + serde_utils::to_hex(invalid) + ), + )) + } + }), + // NOTE: For these branches, we use H64 as a mildly hacky way to have a better error message (since `<[T; N] as TryFrom>>::Error = Vec`) + Path::NextSequenceSend(_) => { + into_value::>(u64::from_be_bytes( + H64::try_from(query_result.value) + .map_err(fatal_rpc_error( + "error decoding next_sequence_send", + error_data(), + ))? + .0, + )) + } + Path::NextSequenceRecv(_) => { + into_value::>(u64::from_be_bytes( + H64::try_from(query_result.value) + .map_err(fatal_rpc_error( + "error decoding next_sequence_recv", + error_data(), + ))? + .0, + )) + } + Path::NextSequenceAck(_) => { + into_value::>(u64::from_be_bytes( + H64::try_from(query_result.value) + .map_err(fatal_rpc_error( + "error decoding next_sequence_ack", + error_data(), + ))? + .0, + )) + } + Path::NextConnectionSequence(_) => { + into_value::>(u64::from_be_bytes( + H64::try_from(query_result.value) + .map_err(fatal_rpc_error( + "error decoding next_connection_sequence", + error_data(), + ))? + .0, + )) + } + Path::NextClientSequence(_) => { + into_value::>(u64::from_be_bytes( + H64::try_from(query_result.value) + .map_err(fatal_rpc_error( + "error decoding next_client_sequence", + error_data(), + ))? + .0, + )) + } + }) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_ibc_proof(&self, at: Height, path: Path) -> RpcResult { + // TODO: This is also in the fn above, move this to somewhere more appropriate (chain-utils perhaps?) + + const IBC_STORE_PATH: &str = "store/ibc/key"; + + let path_string = path.to_string(); + + let query_result = self + .ctx + .tm_client + .abci_query( + IBC_STORE_PATH, + &path_string, + // a proof at height H is provable at height H + 1 + // we assume that the height passed in to this function is the intended height to prove against, thus we have to query the height - 1 + Some( + (i64::try_from(at.revision_height).expect("should be fine") - 1) + .try_into() + .expect("invalid height"), + ), + true, + ) + .await + .map_err(rpc_error( + format_args!("error fetching abci query"), + Some(json!({ "height": at, "path": path })), + ))?; + + Ok(into_value( + MerkleProof::try_from(protos::ibc::core::commitment::v1::MerkleProof { + proofs: query_result + .response + .proof_ops + .unwrap() + .ops + .into_iter() + .map(|op| { + ::decode( + op.data.as_slice(), + ) + .unwrap() + }) + .collect::>(), + }) + .unwrap(), + )) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_raw_unfinalized_trusted_client_state( + &self, + client_id: ClientId, + ) -> RpcResult> { + let height = self.query_latest_height().await?; + + let client_state = serde_json::from_value::>>( + self.query_ibc_state( + height, + ClientStatePath { + client_id: client_id.clone(), + } + .into(), + ) + .await?, + ) + .expect("infallible"); + + let ClientInfo { + client_type, + ibc_interface, + metadata: _, + } = self.client_info(client_id.clone()).await?; + + Ok(RawClientState { + client_type, + ibc_interface, + bytes: client_state.0.into(), + }) + } +} + +// NOTE: For both of the below functions, `message` as a field will override any actual message put in (i.e. `error!("foo", message = "bar")` will print as "bar", not "foo" with an extra field `message = "bar"`. + +fn rpc_error( + message: impl Display, + data: Option, +) -> impl FnOnce(E) -> ErrorObjectOwned { + move |e| { + let message = format!("{message}: {}", ErrorReporter(e)); + error!(%message, data = %data.as_ref().unwrap_or(&serde_json::Value::Null)); + ErrorObject::owned(-1, message, data) + } +} + +fn fatal_rpc_error>>( + message: impl Display, + data: Option, +) -> impl FnOnce(E) -> ErrorObjectOwned { + move |e| { + let e = e.into(); + let message = format!("{message}: {}", ErrorReporter(&*e)); + error!(%message, data = %data.as_ref().unwrap_or(&serde_json::Value::Null)); + ErrorObject::owned(FATAL_JSONRPC_ERROR_CODE, message, data) + } +} + +#[track_caller] +fn into_value(t: T) -> Value { + match serde_json::to_value(t) { + Ok(ok) => ok, + Err(err) => { + error!( + error = %ErrorReporter(err), + "error serializing value of type {}", + std::any::type_name::() + ); + + panic!( + "error serializing value of type {}", + std::any::type_name::() + ); + } + } +} diff --git a/voyager/modules/chain/ethereum/Cargo.toml b/voyager/modules/chain/ethereum/Cargo.toml new file mode 100644 index 0000000000..61ca1fdf02 --- /dev/null +++ b/voyager/modules/chain/ethereum/Cargo.toml @@ -0,0 +1,26 @@ +[package] +edition = "2021" +name = "voyager-chain-module-ethereum" +version = "0.1.0" + +[dependencies] +beacon-api = { workspace = true } +chain-utils = { workspace = true } +contracts = { workspace = true, features = ["providers"] } +enumorph = { workspace = true } +ethers = { workspace = true, features = ["rustls", "ws"] } +frunk = { workspace = true } +futures = { workspace = true } +jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } +macros = { workspace = true } +queue-msg = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +serde_json = { workspace = true } +static_assertions = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +unionlabs = { workspace = true } +voyager-message = { workspace = true } diff --git a/voyager/modules/chain/ethereum/src/call.rs b/voyager/modules/chain/ethereum/src/call.rs new file mode 100644 index 0000000000..57bbe7e2b1 --- /dev/null +++ b/voyager/modules/chain/ethereum/src/call.rs @@ -0,0 +1,41 @@ +use chain_utils::ethereum::IBCHandlerEvents; +use enumorph::Enumorph; +use queue_msg::{queue_msg, SubsetOf}; +use unionlabs::{hash::H256, ibc::core::client::height::Height}; + +#[queue_msg] +#[derive(Enumorph, SubsetOf)] +pub enum ModuleCall { + MakeFullEvent(MakeFullEvent), + + FetchEvents(FetchEvents), + FetchGetLogs(FetchGetLogs), + FetchBeaconBlockRange(FetchBeaconBlockRange), +} + +#[queue_msg] +pub struct MakeFullEvent { + pub slot: u64, + pub tx_hash: H256, + pub event: IBCHandlerEvents, +} + +#[queue_msg] +pub struct FetchEvents { + pub from_height: Height, + pub to_height: Height, +} + +#[queue_msg] +pub struct FetchGetLogs { + pub from_slot: u64, + pub to_slot: u64, +} + +/// NOTE: This isn't just fetching one block because sometimes beacon slots are missed. We need to be able to fetch a range of slots to account for this. +/// The range is `[from_slot..to_slot)`, so to fetch a single block `N`, the range would be `N..N+1`. +#[queue_msg] +pub struct FetchBeaconBlockRange { + pub from_slot: u64, + pub to_slot: u64, +} diff --git a/voyager/modules/chain/ethereum/src/callback.rs b/voyager/modules/chain/ethereum/src/callback.rs new file mode 100644 index 0000000000..a783fb9049 --- /dev/null +++ b/voyager/modules/chain/ethereum/src/callback.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::{queue_msg, SubsetOf}; + +#[queue_msg] +#[derive(Enumorph, SubsetOf)] +pub enum ModuleCallback {} diff --git a/voyager/modules/chain/ethereum/src/data.rs b/voyager/modules/chain/ethereum/src/data.rs new file mode 100644 index 0000000000..063c8f7f1d --- /dev/null +++ b/voyager/modules/chain/ethereum/src/data.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleData {} diff --git a/voyager/modules/chain/ethereum/src/main.rs b/voyager/modules/chain/ethereum/src/main.rs new file mode 100644 index 0000000000..9461d22225 --- /dev/null +++ b/voyager/modules/chain/ethereum/src/main.rs @@ -0,0 +1,1494 @@ +// #![warn(clippy::unwrap_used)] // oh boy this will be a lot of work + +use std::{collections::VecDeque, sync::Arc}; + +use beacon_api::client::BeaconApiClient; +use chain_utils::ethereum::{IBCHandlerEvents, IbcHandlerExt}; +use contracts::{ + ibc_channel_handshake::IBCChannelHandshakeEvents, ibc_client::IBCClientEvents, + ibc_connection::IBCConnectionEvents, ibc_handler::IBCHandler, ibc_packet::IBCPacketEvents, +}; +use ethers::{ + contract::EthLogDecode, + providers::{Middleware, Provider, Ws}, + types::Filter, +}; +use futures::{stream::FuturesUnordered, TryStreamExt}; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + types::ErrorObject, +}; +use queue_msg::{call, conc, data, noop, BoxDynError, Op}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use tracing::{debug, info, instrument, warn}; +use unionlabs::{ + ethereum::{ibc_commitment_key, IBC_HANDLER_COMMITMENTS_SLOT}, + hash::H160, + ibc::{ + core::{channel, client::height::Height}, + lightclients::ethereum::storage_proof::StorageProof, + }, + ics24::{ChannelEndPath, ClientStatePath, ConnectionPath, Path}, + id::{ChannelId, ClientId, PortId}, + uint::U256, + ErrorReporter, QueryHeight, +}; +use voyager_message::{ + call::Call, + data::{ + ChainEvent, ChannelMetadata, ChannelOpenAck, ChannelOpenConfirm, ChannelOpenInit, + ChannelOpenTry, ClientInfo, ConnectionMetadata, ConnectionOpenAck, ConnectionOpenConfirm, + ConnectionOpenInit, ConnectionOpenTry, CreateClient, Data, PacketMetadata, UpdateClient, + }, + module::{ + ChainModuleInfo, ChainModuleServer, ModuleInfo, QueueInteractionsServer, RawClientState, + }, + reconnecting_jsonrpc_ws_client, + rpc::{json_rpc_error_to_rpc_error, missing_state, VoyagerRpcClient, VoyagerRpcClientExt}, + run_module_server, ChainId, ClientType, DefaultCmd, IbcInterface, ModuleContext, ModuleServer, + VoyagerMessage, +}; + +use crate::{ + call::{FetchBeaconBlockRange, FetchEvents, FetchGetLogs, MakeFullEvent, ModuleCall}, + callback::ModuleCallback, + data::ModuleData, +}; + +pub mod call; +pub mod callback; +pub mod data; + +const ETHEREUM_REVISION_NUMBER: u64 = 0; + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + run_module_server::().await +} + +#[derive(Debug, Clone)] +pub struct Module { + pub chain_id: ChainId<'static>, + + pub ibc_handler_address: H160, + + pub provider: Provider, + pub beacon_api_client: BeaconApiClient, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Config { + /// The expected chain id of this ethereum-like chain. + pub chain_id: ChainId<'static>, + + /// The address of the `IBCHandler` smart contract. + pub ibc_handler_address: H160, + + /// The RPC endpoint for the execution chain. + pub eth_rpc_api: String, + /// The RPC endpoint for the beacon chain. + pub eth_beacon_rpc_api: String, +} + +impl ModuleContext for Module { + type Config = Config; + type Cmd = DefaultCmd; + type Info = ChainModuleInfo; + + async fn new(config: Self::Config) -> Result { + Module::new(config).await + } + + fn info(config: Self::Config) -> ModuleInfo { + ModuleInfo { + name: plugin_name(&config.chain_id), + kind: ChainModuleInfo { + chain_id: config.chain_id, + }, + } + } + + async fn cmd(_config: Self::Config, cmd: Self::Cmd) { + match cmd {} + } +} + +fn plugin_name(chain_id: &ChainId<'_>) -> String { + pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); + + format!("{PLUGIN_NAME}/{}", chain_id) +} + +impl Module { + pub fn plugin_name(&self) -> String { + plugin_name(&self.chain_id) + } + + pub async fn new(config: Config) -> Result { + let provider = Provider::new(Ws::connect(config.eth_rpc_api).await?); + + let chain_id = provider.get_chainid().await?; + + Ok(Self { + chain_id: ChainId::new(U256(chain_id).to_string()), + ibc_handler_address: config.ibc_handler_address, + provider, + beacon_api_client: BeaconApiClient::new(config.eth_beacon_rpc_api).await?, + }) + } + + #[must_use] + pub fn make_height(&self, height: u64) -> Height { + Height { + revision_number: ETHEREUM_REVISION_NUMBER, + revision_height: height, + } + } + + fn ibc_handler(&self) -> IBCHandler> { + IBCHandler::new(self.ibc_handler_address, Arc::new(self.provider.clone())) + } + + #[instrument(skip(self))] + pub async fn execution_height_of_beacon_slot(&self, slot: u64) -> u64 { + let execution_height = self + .beacon_api_client + .execution_height(beacon_api::client::BlockId::Slot(slot)) + .await + .unwrap(); + + debug!("beacon slot {slot} is execution height {execution_height}"); + + execution_height + } + + #[instrument(skip_all, fields(%path, %height))] + pub async fn fetch_ibc_state(&self, path: Path, height: Height) -> Result { + let execution_height = self + .execution_height_of_beacon_slot(height.revision_height) + .await; + + Ok(match path { + Path::ClientState(path) => serde_json::to_value( + self.ibc_handler() + .ibc_state_read(execution_height, path.clone()) + .await + .unwrap(), + ) + .unwrap(), + Path::ClientConsensusState(path) => serde_json::to_value( + self.ibc_handler() + .ibc_state_read(execution_height, path.clone()) + .await + .unwrap(), + ) + .unwrap(), + Path::Connection(path) => serde_json::to_value( + self.ibc_handler() + .ibc_state_read(execution_height, path.clone()) + .await + .unwrap(), + ) + .unwrap(), + Path::ChannelEnd(path) => serde_json::to_value( + self.ibc_handler() + .ibc_state_read(execution_height, path.clone()) + .await + .unwrap(), + ) + .unwrap(), + Path::Commitment(path) => serde_json::to_value( + self.ibc_handler() + .ibc_state_read(execution_height, path.clone()) + .await + .unwrap(), + ) + .unwrap(), + Path::Acknowledgement(path) => serde_json::to_value( + self.ibc_handler() + .ibc_state_read(execution_height, path.clone()) + .await + .unwrap(), + ) + .unwrap(), + Path::Receipt(path) => serde_json::to_value( + self.ibc_handler() + .ibc_state_read(execution_height, path.clone()) + .await + .unwrap(), + ) + .unwrap(), + Path::NextSequenceSend(path) => serde_json::to_value( + self.ibc_handler() + .ibc_state_read(execution_height, path.clone()) + .await + .unwrap(), + ) + .unwrap(), + Path::NextSequenceRecv(path) => serde_json::to_value( + self.ibc_handler() + .ibc_state_read(execution_height, path.clone()) + .await + .unwrap(), + ) + .unwrap(), + Path::NextSequenceAck(path) => serde_json::to_value( + self.ibc_handler() + .ibc_state_read(execution_height, path.clone()) + .await + .unwrap(), + ) + .unwrap(), + Path::NextConnectionSequence(path) => serde_json::to_value( + self.ibc_handler() + .ibc_state_read(execution_height, path.clone()) + .await + .unwrap(), + ) + .unwrap(), + Path::NextClientSequence(path) => serde_json::to_value( + self.ibc_handler() + .ibc_state_read(execution_height, path.clone()) + .await + .unwrap(), + ) + .unwrap(), + }) + } + + async fn make_packet_metadata( + &self, + event_height: Height, + self_port_id: PortId, + self_channel_id: ChannelId, + voyager_rpc_client: &reconnecting_jsonrpc_ws_client::Client, + ) -> RpcResult<( + ChainId<'static>, + ClientInfo, + ChannelMetadata, + ChannelMetadata, + channel::order::Order, + )> { + let self_channel = voyager_rpc_client + .query_ibc_state_typed( + self.chain_id.clone(), + event_height.into(), + ChannelEndPath { + port_id: self_port_id.clone(), + channel_id: self_channel_id.clone(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("connection must exist", None))?; + + let self_connection = voyager_rpc_client + .query_ibc_state_typed( + self.chain_id.clone(), + event_height.into(), + ConnectionPath { + connection_id: self_channel.connection_hops[0].clone(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let self_connection_state = self_connection + .state + .ok_or_else(missing_state("connection must exist", None))?; + + let client_info = voyager_rpc_client + .client_info( + self.chain_id.clone(), + self_connection_state.client_id.clone(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = voyager_rpc_client + .client_meta( + self.chain_id.clone(), + event_height.into(), + self_connection_state.client_id.clone(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let other_channel = voyager_rpc_client + .query_ibc_state_typed( + client_meta.chain_id.clone(), + QueryHeight::Latest, + ChannelEndPath { + port_id: self_channel.counterparty.port_id.clone(), + channel_id: self_channel.counterparty.channel_id.parse().unwrap(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let other_channel_state = other_channel + .state + .ok_or_else(missing_state("channel must exist", None))?; + + let source_channel = ChannelMetadata { + port_id: self_port_id.clone(), + channel_id: self_channel_id.clone(), + version: self_channel.version, + connection: ConnectionMetadata { + client_id: self_connection_state.client_id, + connection_id: self_connection.path.connection_id.clone(), + }, + }; + let destination_channel = ChannelMetadata { + port_id: other_channel.path.port_id.clone(), + channel_id: other_channel.path.channel_id.clone(), + version: other_channel_state.version, + connection: ConnectionMetadata { + client_id: self_connection_state.counterparty.client_id, + connection_id: self_connection_state.counterparty.connection_id.unwrap(), + }, + }; + + Ok(( + client_meta.chain_id, + client_info, + source_channel, + destination_channel, + self_channel.ordering, + )) + } +} + +#[async_trait] +impl QueueInteractionsServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn callback( + &self, + cb: ModuleCallback, + _data: VecDeque>, + ) -> RpcResult>> { + match cb {} + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn call( + &self, + msg: ModuleCall, + ) -> RpcResult>> { + match msg { + ModuleCall::MakeFullEvent(MakeFullEvent { + slot, + tx_hash, + event, + }) => { + let height = self.ctx.make_height(slot); + + match event { + IBCHandlerEvents::ChannelEvent( + IBCChannelHandshakeEvents::ChannelCloseConfirmFilter(_), + ) + | IBCHandlerEvents::ChannelEvent( + IBCChannelHandshakeEvents::ChannelCloseInitFilter(_), + ) => { + todo!() + } + + IBCHandlerEvents::ChannelEvent( + IBCChannelHandshakeEvents::ChannelOpenInitFilter(raw_event), + ) => { + let connection = self + .voyager_rpc_client + .query_ibc_state_typed( + self.ctx.chain_id.clone(), + height.into(), + ConnectionPath { + connection_id: raw_event.connection_id.parse().unwrap(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("connection must exist", None))?; + + let client_info = self + .voyager_rpc_client + .client_info(self.ctx.chain_id.clone(), connection.client_id.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + height.into(), + connection.client_id.clone(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let channel = self + .voyager_rpc_client + .query_ibc_state_typed( + self.ctx.chain_id.clone(), + height.into(), + ChannelEndPath { + port_id: raw_event.port_id.parse().unwrap(), + channel_id: raw_event.channel_id.parse().unwrap(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("connection must exist", None))?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id: client_meta.chain_id, + tx_hash, + provable_height: height, + event: ChannelOpenInit { + port_id: raw_event.port_id.parse().unwrap(), + channel_id: raw_event.channel_id.parse().unwrap(), + counterparty_port_id: raw_event + .counterparty_port_id + .parse() + .unwrap(), + connection, + version: channel.version, + } + .into(), + })) + } + IBCHandlerEvents::ChannelEvent( + IBCChannelHandshakeEvents::ChannelOpenTryFilter(raw_event), + ) => { + let connection = self + .voyager_rpc_client + .query_ibc_state_typed( + self.ctx.chain_id.clone(), + height.into(), + ConnectionPath { + connection_id: raw_event.connection_id.parse().unwrap(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("connection must exist", None))?; + + let client_info = self + .voyager_rpc_client + .client_info(self.ctx.chain_id.clone(), connection.client_id.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + height.into(), + connection.client_id.clone(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let channel = self + .voyager_rpc_client + .query_ibc_state_typed( + self.ctx.chain_id.clone(), + height.into(), + ChannelEndPath { + port_id: raw_event.port_id.parse().unwrap(), + channel_id: raw_event.channel_id.parse().unwrap(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("channel must exist", None))?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id: client_meta.chain_id, + tx_hash, + provable_height: height, + event: ChannelOpenTry { + port_id: raw_event.port_id.parse().unwrap(), + channel_id: raw_event.channel_id.parse().unwrap(), + counterparty_port_id: raw_event + .counterparty_port_id + .parse() + .unwrap(), + counterparty_channel_id: raw_event + .counterparty_channel_id + .parse() + .unwrap(), + connection, + version: channel.version, + } + .into(), + })) + } + IBCHandlerEvents::ChannelEvent( + IBCChannelHandshakeEvents::ChannelOpenAckFilter(raw_event), + ) => { + let connection = self + .voyager_rpc_client + .query_ibc_state_typed( + self.ctx.chain_id.clone(), + height.into(), + ConnectionPath { + connection_id: raw_event.connection_id.parse().unwrap(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("connection must exist", None))?; + + let client_info = self + .voyager_rpc_client + .client_info(self.ctx.chain_id.clone(), connection.client_id.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + height.into(), + connection.client_id.clone(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let channel = self + .voyager_rpc_client + .query_ibc_state_typed( + self.ctx.chain_id.clone(), + height.into(), + ChannelEndPath { + port_id: raw_event.port_id.parse().unwrap(), + channel_id: raw_event.channel_id.parse().unwrap(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("channel must exist", None))?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id: client_meta.chain_id, + tx_hash, + provable_height: height, + event: ChannelOpenAck { + port_id: raw_event.port_id.parse().unwrap(), + channel_id: raw_event.channel_id.parse().unwrap(), + counterparty_port_id: raw_event + .counterparty_port_id + .parse() + .unwrap(), + counterparty_channel_id: raw_event + .counterparty_channel_id + .parse() + .unwrap(), + connection, + version: channel.version, + } + .into(), + })) + } + IBCHandlerEvents::ChannelEvent( + IBCChannelHandshakeEvents::ChannelOpenConfirmFilter(raw_event), + ) => { + let connection = self + .voyager_rpc_client + .query_ibc_state_typed( + self.ctx.chain_id.clone(), + height.into(), + ConnectionPath { + connection_id: raw_event.connection_id.parse().unwrap(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("connection must exist", None))?; + + let client_info = self + .voyager_rpc_client + .client_info(self.ctx.chain_id.clone(), connection.client_id.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + height.into(), + connection.client_id.clone(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let channel = self + .voyager_rpc_client + .query_ibc_state_typed( + self.ctx.chain_id.clone(), + height.into(), + ChannelEndPath { + port_id: raw_event.port_id.parse().unwrap(), + channel_id: raw_event.channel_id.parse().unwrap(), + }, + ) + .await + .map_err(json_rpc_error_to_rpc_error)? + .state + .ok_or_else(missing_state("channel must exist", None))?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id: client_meta.chain_id, + tx_hash, + provable_height: height, + event: ChannelOpenConfirm { + port_id: raw_event.port_id.parse().unwrap(), + channel_id: raw_event.channel_id.parse().unwrap(), + counterparty_port_id: raw_event + .counterparty_port_id + .parse() + .unwrap(), + counterparty_channel_id: raw_event + .counterparty_channel_id + .parse() + .unwrap(), + connection, + version: channel.version, + } + .into(), + })) + } + + IBCHandlerEvents::ConnectionEvent( + IBCConnectionEvents::ConnectionOpenInitFilter(raw_event), + ) => { + let client_info = self + .voyager_rpc_client + .client_info( + self.ctx.chain_id.clone(), + raw_event.client_id.parse().unwrap(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + height.into(), + raw_event.client_id.parse().unwrap(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id: client_meta.chain_id, + tx_hash, + provable_height: height, + event: ConnectionOpenInit { + client_id: raw_event.client_id.parse().unwrap(), + connection_id: raw_event.connection_id.parse().unwrap(), + counterparty_client_id: raw_event + .counterparty_client_id + .parse() + .unwrap(), + } + .into(), + })) + } + IBCHandlerEvents::ConnectionEvent( + IBCConnectionEvents::ConnectionOpenTryFilter(raw_event), + ) => { + let client_info = self + .voyager_rpc_client + .client_info( + self.ctx.chain_id.clone(), + raw_event.client_id.parse().unwrap(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + height.into(), + raw_event.client_id.parse().unwrap(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id: client_meta.chain_id, + tx_hash, + provable_height: height, + event: ConnectionOpenTry { + client_id: raw_event.client_id.parse().unwrap(), + connection_id: raw_event.connection_id.parse().unwrap(), + counterparty_client_id: raw_event + .counterparty_client_id + .parse() + .unwrap(), + counterparty_connection_id: raw_event + .counterparty_connection_id + .parse() + .unwrap(), + } + .into(), + })) + } + IBCHandlerEvents::ConnectionEvent( + IBCConnectionEvents::ConnectionOpenAckFilter(raw_event), + ) => { + let client_info = self + .voyager_rpc_client + .client_info( + self.ctx.chain_id.clone(), + raw_event.client_id.parse().unwrap(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + height.into(), + raw_event.client_id.parse().unwrap(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id: client_meta.chain_id, + tx_hash, + provable_height: height, + event: ConnectionOpenAck { + client_id: raw_event.client_id.parse().unwrap(), + connection_id: raw_event.connection_id.parse().unwrap(), + counterparty_client_id: raw_event + .counterparty_client_id + .parse() + .unwrap(), + counterparty_connection_id: raw_event + .counterparty_connection_id + .parse() + .unwrap(), + } + .into(), + })) + } + IBCHandlerEvents::ConnectionEvent( + IBCConnectionEvents::ConnectionOpenConfirmFilter(raw_event), + ) => { + let client_info = self + .voyager_rpc_client + .client_info( + self.ctx.chain_id.clone(), + raw_event.client_id.parse().unwrap(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + height.into(), + raw_event.client_id.parse().unwrap(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id: client_meta.chain_id, + tx_hash, + provable_height: height, + event: ConnectionOpenConfirm { + client_id: raw_event.client_id.parse().unwrap(), + connection_id: raw_event.connection_id.parse().unwrap(), + counterparty_client_id: raw_event + .counterparty_client_id + .parse() + .unwrap(), + counterparty_connection_id: raw_event + .counterparty_connection_id + .parse() + .unwrap(), + } + .into(), + })) + } + + IBCHandlerEvents::ClientEvent(IBCClientEvents::ClientCreatedFilter( + raw_event, + )) => { + let client_id = raw_event.client_id.parse::().unwrap(); + + let client_info = self + .voyager_rpc_client + .client_info(self.ctx.chain_id.clone(), client_id.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + height.into(), + raw_event.client_id.parse().unwrap(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info: client_info.clone(), + counterparty_chain_id: client_meta.chain_id, + tx_hash, + provable_height: height, + event: CreateClient { + client_id, + client_type: client_info.client_type, + consensus_height: client_meta.height, + } + .into(), + })) + } + IBCHandlerEvents::ClientEvent(IBCClientEvents::ClientRegisteredFilter( + raw_event, + )) => { + info!(?raw_event, "observed ClientRegistered event"); + + Ok(noop()) + } + IBCHandlerEvents::ClientEvent(IBCClientEvents::ClientUpdatedFilter( + raw_event, + )) => { + let client_id = raw_event.client_id.parse::().unwrap(); + + let client_info = self + .voyager_rpc_client + .client_info(self.ctx.chain_id.clone(), client_id.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + height.into(), + raw_event.client_id.parse().unwrap(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info: client_info.clone(), + counterparty_chain_id: client_meta.chain_id, + tx_hash, + provable_height: height, + event: UpdateClient { + client_id, + client_type: client_info.client_type, + consensus_heights: vec![raw_event.height.into()], + } + .into(), + })) + } + IBCHandlerEvents::PacketEvent(event) => { + match event { + // packet origin is this chain + IBCPacketEvents::SendPacketFilter(event) => { + let ( + counterparty_chain_id, + client_info, + source_channel, + destination_channel, + channel_ordering, + ) = self + .ctx + .make_packet_metadata( + height, + event.source_port.parse().unwrap(), + event.source_channel.parse().unwrap(), + &self.voyager_rpc_client, + ) + .await?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id, + tx_hash, + provable_height: height, + event: voyager_message::data::SendPacket { + packet_data: event.data.to_vec(), + packet: PacketMetadata { + sequence: event.sequence.try_into().unwrap(), + source_channel, + destination_channel, + channel_ordering, + timeout_height: event.timeout_height.into(), + timeout_timestamp: event.timeout_timestamp, + }, + } + .into(), + })) + } + IBCPacketEvents::TimeoutPacketFilter(event) => { + let ( + counterparty_chain_id, + client_info, + source_channel, + destination_channel, + channel_ordering, + ) = self + .ctx + .make_packet_metadata( + height, + event.packet.source_port.parse().unwrap(), + event.packet.source_channel.parse().unwrap(), + &self.voyager_rpc_client, + ) + .await?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id, + tx_hash, + provable_height: height, + event: voyager_message::data::TimeoutPacket { + packet: PacketMetadata { + sequence: event.packet.sequence.try_into().unwrap(), + source_channel, + destination_channel, + channel_ordering, + timeout_height: event.packet.timeout_height.into(), + timeout_timestamp: event.packet.timeout_timestamp, + }, + } + .into(), + })) + } + IBCPacketEvents::AcknowledgePacketFilter(event) => { + let ( + counterparty_chain_id, + client_info, + source_channel, + destination_channel, + channel_ordering, + ) = self + .ctx + .make_packet_metadata( + height, + event.packet.source_port.parse().unwrap(), + event.packet.source_channel.parse().unwrap(), + &self.voyager_rpc_client, + ) + .await?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id, + tx_hash, + provable_height: height, + event: voyager_message::data::AcknowledgePacket { + packet: PacketMetadata { + sequence: event.packet.sequence.try_into().unwrap(), + source_channel, + destination_channel, + channel_ordering, + timeout_height: event.packet.timeout_height.into(), + timeout_timestamp: event.packet.timeout_timestamp, + }, + } + .into(), + })) + } + // packet origin is the counterparty chain + IBCPacketEvents::WriteAcknowledgementFilter(event) => { + let ( + counterparty_chain_id, + client_info, + destination_channel, + source_channel, + channel_ordering, + ) = self + .ctx + .make_packet_metadata( + height, + event.packet.destination_port.parse().unwrap(), + event.packet.destination_channel.parse().unwrap(), + &self.voyager_rpc_client, + ) + .await?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id, + tx_hash, + provable_height: height, + event: voyager_message::data::WriteAcknowledgement { + packet_data: event.packet.data.to_vec(), + packet_ack: event.acknowledgement.to_vec(), + packet: PacketMetadata { + sequence: event.packet.sequence.try_into().unwrap(), + source_channel, + destination_channel, + channel_ordering, + timeout_height: event.packet.timeout_height.into(), + timeout_timestamp: event.packet.timeout_timestamp, + }, + } + .into(), + })) + } + IBCPacketEvents::RecvPacketFilter(event) => { + let ( + counterparty_chain_id, + client_info, + destination_channel, + source_channel, + channel_ordering, + ) = self + .ctx + .make_packet_metadata( + height, + event.packet.destination_port.parse().unwrap(), + event.packet.destination_channel.parse().unwrap(), + &self.voyager_rpc_client, + ) + .await?; + + Ok(data(ChainEvent { + chain_id: self.ctx.chain_id.clone(), + client_info, + counterparty_chain_id, + tx_hash, + provable_height: height, + event: voyager_message::data::RecvPacket { + packet_data: event.packet.data.to_vec(), + packet: PacketMetadata { + sequence: event.packet.sequence.try_into().unwrap(), + source_channel, + destination_channel, + channel_ordering, + timeout_height: event.packet.timeout_height.into(), + timeout_timestamp: event.packet.timeout_timestamp, + }, + } + .into(), + })) + } + } + } + IBCHandlerEvents::OwnableEvent(_) => Ok(noop()), + } + } + ModuleCall::FetchEvents(FetchEvents { + from_height, + to_height, + }) => Ok(call(Call::plugin( + self.ctx.plugin_name(), + FetchBeaconBlockRange { + from_slot: from_height.revision_height, + to_slot: to_height.revision_height, + }, + ))), + ModuleCall::FetchBeaconBlockRange(FetchBeaconBlockRange { from_slot, to_slot }) => { + debug!(%from_slot, %to_slot, "fetching beacon block range"); + + assert!(from_slot < to_slot); + + if to_slot - from_slot == 1 { + Ok(call(Call::plugin( + self.ctx.plugin_name(), + FetchGetLogs { from_slot, to_slot }, + ))) + } else { + // attempt to shrink from..to + // note that this is *exclusive* on `to` + for slot in (from_slot + 1)..to_slot { + info!(%slot, "querying slot"); + + match self + .ctx + .beacon_api_client + .block(beacon_api::client::BlockId::Slot(slot)) + .await + { + Err(beacon_api::errors::Error::NotFound( + beacon_api::errors::NotFoundError { + message, + error, + status_code, + }, + )) => { + info!(%slot, %message, %error, %status_code, "beacon block not found for slot"); + continue; + } + Err(err) => { + panic!("error fetching beacon block for slot {slot}: {err}") + } + Ok(_) => { + return Ok(conc([ + call(Call::plugin( + self.ctx.plugin_name(), + FetchGetLogs { + from_slot, + to_slot: slot, + }, + )), + call(Call::plugin( + self.ctx.plugin_name(), + FetchBeaconBlockRange { + from_slot: slot, + to_slot, + }, + )), + ])); + } + } + } + + // if the range is not shrinkable (i.e. all blocks between `from` and `to` are missing, but `from` and `to` both exist), fetch logs between `from` and `to` + Ok(call(Call::plugin( + self.ctx.plugin_name(), + FetchGetLogs { from_slot, to_slot }, + ))) + } + } + ModuleCall::FetchGetLogs(FetchGetLogs { from_slot, to_slot }) => { + debug!(%from_slot, %to_slot, "fetching logs in beacon block range"); + + let from_block = self.ctx.execution_height_of_beacon_slot(from_slot).await; + let to_block = self.ctx.execution_height_of_beacon_slot(to_slot).await; + + if from_block == to_block { + info!(%from_block, %to_block, %from_slot, %to_slot, "beacon block range is empty"); + Ok(noop()) + } else { + const ETH_GET_LOGS_BATCH_SIZE: u64 = 100; + + info!(%from_block, %to_block, "fetching block range"); + + let mut from_block = from_block; + + let mut msgs = vec![]; + let join_set = FuturesUnordered::new(); + + for (from_block, to_block) in std::iter::from_fn(move || { + if from_block < to_block { + // NOTE: These -1s are very important, else events will be double fetched + if to_block - from_block < ETH_GET_LOGS_BATCH_SIZE { + Some((from_block, { + from_block = to_block; + from_block - 1 + })) + } else { + Some((from_block, { + from_block += ETH_GET_LOGS_BATCH_SIZE; + from_block - 1 + })) + } + } else { + None + } + }) { + info!(%from_block, %to_block, %from_slot, %to_slot, "fetching logs in range"); + + join_set.push(async move { + self.ctx + .provider + .get_logs( + &Filter::new() + .address(ethers::types::H160::from( + self.ctx.ibc_handler_address, + )) + .from_block(from_block) + .to_block(to_block), + ) + .await + }); + } + + for logs in join_set + .try_collect::>() + .await + .expect("unable to fetch logs") + { + for log in logs { + let tx_hash = log + .transaction_hash + .expect("log should have transaction_hash") + .into(); + + debug!(?log, "raw log"); + + match IBCHandlerEvents::decode_log(&log.into()) { + Ok(event) => { + debug!(?event, "found IBCHandler event"); + msgs.push(call(Call::plugin( + self.ctx.plugin_name(), + MakeFullEvent { + slot: to_slot, + tx_hash, + event, + }, + ))) + } + Err(e) => { + warn!("could not decode evm event {}", e); + } + } + } + } + + info!( + %from_block, + %to_block, + + %from_slot, + %to_slot, + + slot_range_len = %(to_slot - from_slot), + block_range_len = %(to_block - from_block), + + total = %msgs.len(), + + "fetched logs in block range" + ); + + Ok(conc(msgs)) + } + } + } + } +} + +#[async_trait] +impl ChainModuleServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + fn chain_id(&self) -> RpcResult> { + Ok(self.ctx.chain_id.clone()) + } + + /// Query the latest finalized height of this chain. + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_latest_height(&self) -> RpcResult { + self.ctx + .beacon_api_client + .finality_update() + .await + .map(|response| { + self.ctx + .make_height(response.data.attested_header.beacon.slot) + }) + .map_err(|err| ErrorObject::owned(-1, ErrorReporter(err).to_string(), None::<()>)) + } + + /// Query the latest (non-finalized) height of this chain. + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_latest_height_as_destination(&self) -> RpcResult { + let height = self + .ctx + .beacon_api_client + .block(beacon_api::client::BlockId::Head) + .await + .map_err(|err| ErrorObject::owned(-1, ErrorReporter(err).to_string(), None::<()>))? + .data + .message + .slot; + + // // HACK: we introduced this because we were using alchemy for the + // // execution endpoint and our custom beacon endpoint that rely on + // // its own execution chain. Alchemy was a bit delayed and the + // // execution height for the beacon head wasn't existing for few + // // secs. We wait for an extra beacon head to let alchemy catch up. + // // We should be able to remove that once we rely on an execution + // // endpoint that is itself used by the beacon endpoint (no different + // // POV). + // loop { + // let next_height = self + // .beacon_api_client + // .block(beacon_api::client::BlockId::Head) + // .await? + // .data + // .message + // .slot; + // if next_height > height { + // break; + // } + + // tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; + // } + + Ok(self.ctx.make_height(height)) + } + + /// Query the latest finalized timestamp of this chain. + // TODO: Use a better timestamp type here + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_latest_timestamp(&self) -> RpcResult { + Ok(self + .ctx + .beacon_api_client + .finality_update() + .await + .map_err(|err| ErrorObject::owned(-1, ErrorReporter(err).to_string(), None::<()>))? + .data + .attested_header + .execution + .timestamp + .try_into() + .unwrap()) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn fetch_block_range( + &self, + from_height: Height, + to_height: Height, + ) -> RpcResult>> { + Ok(call(Call::plugin( + self.ctx.plugin_name(), + FetchEvents { + from_height, + to_height, + }, + ))) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn client_info(&self, client_id: ClientId) -> RpcResult { + Ok(ClientInfo { + client_type: ClientType::new( + self.ctx + .ibc_handler() + .client_types(client_id.to_string()) + .await + .unwrap(), + ), + ibc_interface: IbcInterface::new(IbcInterface::IBC_SOLIDITY), + metadata: Default::default(), + }) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_ibc_state(&self, at: Height, path: Path) -> RpcResult { + self.ctx.fetch_ibc_state(path, at).await.map_err(|err| { + ErrorObject::owned( + -1, + format!("error fetching ibc state: {}", ErrorReporter(&*err)), + None::<()>, + ) + }) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_ibc_proof(&self, at: Height, path: Path) -> RpcResult { + let location = ibc_commitment_key(&path.to_string(), IBC_HANDLER_COMMITMENTS_SLOT); + + let execution_height = self + .ctx + .execution_height_of_beacon_slot(at.revision_height) + .await; + + let proof = self + .ctx + .provider + .get_proof( + ethers::types::H160::from(self.ctx.ibc_handler_address), + vec![location.to_be_bytes().into()], + Some(execution_height.into()), + ) + .await + .unwrap(); + + let proof = match <[_; 1]>::try_from(proof.storage_proof) { + Ok([proof]) => proof, + Err(invalid) => { + panic!("received invalid response from eth_getProof, expected length of 1 but got `{invalid:#?}`"); + } + }; + + let proof = StorageProof { + key: U256::from_be_bytes(proof.key.to_fixed_bytes()), + value: proof.value.into(), + proof: proof + .proof + .into_iter() + .map(|bytes| bytes.to_vec()) + .collect(), + }; + + Ok(serde_json::to_value(proof).expect("serialization is infallible; qed;")) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_raw_unfinalized_trusted_client_state( + &self, + client_id: ClientId, + ) -> RpcResult> { + let latest_execution_height = self.ctx.provider.get_block_number().await.unwrap().as_u64(); + + let ClientInfo { + client_type, + ibc_interface, + metadata: _, + } = self.client_info(client_id.clone()).await?; + + Ok(RawClientState { + client_type, + ibc_interface, + bytes: self + .ctx + .ibc_handler() + .ibc_state_read(latest_execution_height, ClientStatePath { client_id }) + .await + .unwrap() + .0 + .into(), + }) + } +} + +// type Pls = <(::Info, Module) as voyager_message::module::IntoRpc< +// ModuleData, +// ModuleCall, +// ModuleCallback, +// // RpcModule = ModuleServer, +// >>::RpcModule; + +// static_assertions::assert_type_eq_all!(Pls, ModuleServer); diff --git a/voyager/modules/chain/movement/Cargo.toml b/voyager/modules/chain/movement/Cargo.toml new file mode 100644 index 0000000000..5e22562bc4 --- /dev/null +++ b/voyager/modules/chain/movement/Cargo.toml @@ -0,0 +1,33 @@ +[package] +edition = "2021" +name = "voyager-chain-module-movement" +version = "0.1.0" + +[dependencies] +aptos-crypto = { workspace = true } +aptos-rest-client = { workspace = true } +aptos-types = { workspace = true } +bcs = "0.1.6" +clap = { workspace = true, features = ["derive"] } +enumorph = { workspace = true } +frunk = { workspace = true } +futures = { workspace = true } +hex = { workspace = true } +hex-literal = { workspace = true } +jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } +macros = { workspace = true } +move-bindgen = { workspace = true } +move-core-types = { workspace = true } +prost = { workspace = true } +protos = { workspace = true } +queue-msg = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +serde_json = { workspace = true } +sha3 = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +unionlabs = { workspace = true } +voyager-message = { workspace = true } diff --git a/voyager/modules/chain/movement/src/call.rs b/voyager/modules/chain/movement/src/call.rs new file mode 100644 index 0000000000..378115ed4f --- /dev/null +++ b/voyager/modules/chain/movement/src/call.rs @@ -0,0 +1,21 @@ +use enumorph::Enumorph; +use macros::model; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCall { + FetchBlock(FetchBlock), + FetchBlocks(FetchBlocks), +} + +#[model] +pub struct FetchBlocks { + pub from_height: u64, + pub to_height: u64, +} + +#[model] +pub struct FetchBlock { + pub height: u64, +} diff --git a/voyager/modules/chain/movement/src/callback.rs b/voyager/modules/chain/movement/src/callback.rs new file mode 100644 index 0000000000..e3dbf95927 --- /dev/null +++ b/voyager/modules/chain/movement/src/callback.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCallback {} diff --git a/voyager/modules/chain/movement/src/client.rs b/voyager/modules/chain/movement/src/client.rs new file mode 100644 index 0000000000..b7173b8bd7 --- /dev/null +++ b/voyager/modules/chain/movement/src/client.rs @@ -0,0 +1,648 @@ +#![allow( + async_fn_in_trait, + non_snake_case, + clippy::useless_conversion, + clippy::unused_unit, + clippy::too_many_arguments +)] + +pub mod packet { + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = packet)] + pub struct Packet { + pub sequence: ::aptos_rest_client::aptos_api_types::U64, + pub source_port: String, + pub source_channel: String, + pub destination_port: String, + pub destination_channel: String, + pub data: Vec, + pub timeout_height: super::height::Height, + pub timeout_timestamp: ::aptos_rest_client::aptos_api_types::U64, + } +} + +pub mod height { + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = height)] + pub struct Height { + pub revision_number: ::aptos_rest_client::aptos_api_types::U64, + pub revision_height: ::aptos_rest_client::aptos_api_types::U64, + } +} + +pub mod connection_end { + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = connection_end)] + pub struct ConnectionEnd { + pub client_id: String, + pub versions: Vec, + pub state: ::aptos_rest_client::aptos_api_types::U64, + pub delay_period: ::aptos_rest_client::aptos_api_types::U64, + pub counterparty: super::connection_end::Counterparty, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = connection_end)] + pub struct Counterparty { + pub client_id: String, + pub connection_id: String, + pub prefix: super::connection_end::MerklePrefix, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = connection_end)] + pub struct MerklePrefix { + pub key_prefix: Vec, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = connection_end)] + pub struct Version { + pub identifier: String, + pub features: Vec, + } +} + +pub mod Core { + pub trait ClientExt { + fn client(&self) -> &::aptos_rest_client::Client; + fn module_address(&self) -> ::aptos_types::account_address::AccountAddress; + async fn client_state( + &self, + (_0,): (String,), + ledger_version: Option, + ) -> ::core::result::Result, ::aptos_rest_client::error::RestError> { + let response = self + .client() + .view( + &::aptos_rest_client::aptos_api_types::ViewRequest { + function: ::aptos_rest_client::aptos_api_types::EntryFunctionId { + module: ::aptos_rest_client::aptos_api_types::MoveModuleId { + address: self.module_address().into(), + name: stringify!(Core).parse().unwrap(), + }, + name: stringify!(client_state).parse().unwrap(), + }, + type_arguments: vec![ + ::aptos_rest_client::aptos_api_types::MoveType::Struct( + ::aptos_rest_client::aptos_api_types::MoveStructTag { + address: "0x1".parse().unwrap(), + module: "string".parse().unwrap(), + name: "String".parse().unwrap(), + generic_type_params: vec![], + }, + ), + ], + arguments: vec![serde_json::to_value(String::from(_0)).unwrap()], + }, + ledger_version, + ) + .await? + .into_inner(); + let ret = ::serde_json::from_value::<(Vec,)>(::serde_json::Value::from(response))?; + Ok(ret.0) + } + fn connection_open_init( + &self, + (_0, _1, _2, _3, _4, _5, _6): ( + impl ::move_bindgen::IntoTypeTagged, + impl ::move_bindgen::IntoTypeTagged, + impl ::move_bindgen::IntoTypeTagged>, + impl ::move_bindgen::IntoTypeTagged, + impl ::move_bindgen::IntoTypeTagged, + impl ::move_bindgen::IntoTypeTagged>, + impl ::move_bindgen::IntoTypeTagged, + ), + ) -> ::aptos_types::transaction::EntryFunction { + let (values, type_args): (Vec<_>, Vec<_>) = vec![ + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_0); + ( + bcs::to_bytes(&t).unwrap(), + ::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_1); + ( + bcs::to_bytes(&t).unwrap(), + ::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_2); + ( + bcs::to_bytes(&t).unwrap(), + as ::move_bindgen::TypeTagged>::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_3); + ( + bcs::to_bytes(&t).unwrap(), + ::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_4); + ( + bcs::to_bytes(&t).unwrap(), + ::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_5); + ( + bcs::to_bytes(&t).unwrap(), + as ::move_bindgen::TypeTagged>::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_6); + ( + bcs::to_bytes(&t).unwrap(), + ::type_tag(ctx), + ) + }, + ] + .into_iter() + .unzip(); + ::aptos_types::transaction::EntryFunction::new( + ::aptos_rest_client::aptos_api_types::MoveModuleId { + address: self.module_address().into(), + name: stringify!(Core).parse().unwrap(), + } + .into(), + stringify!(connection_open_init).parse().unwrap(), + type_args, + values, + ) + } + fn connection_open_try( + &self, + (_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11): ( + impl ::move_bindgen::IntoTypeTagged, + impl ::move_bindgen::IntoTypeTagged, + impl ::move_bindgen::IntoTypeTagged>, + impl ::move_bindgen::IntoTypeTagged, + impl ::move_bindgen::IntoTypeTagged, + impl ::move_bindgen::IntoTypeTagged>, + impl ::move_bindgen::IntoTypeTagged>, + impl ::move_bindgen::IntoTypeTagged>>, + impl ::move_bindgen::IntoTypeTagged>, + impl ::move_bindgen::IntoTypeTagged>, + impl ::move_bindgen::IntoTypeTagged, + impl ::move_bindgen::IntoTypeTagged, + ), + ) -> ::aptos_types::transaction::EntryFunction { + let (values, type_args): (Vec<_>, Vec<_>) = vec![ + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_0); + ( + bcs::to_bytes(&t).unwrap(), + ::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_1); + ( + bcs::to_bytes(&t).unwrap(), + ::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_2); + ( + bcs::to_bytes(&t).unwrap(), + as ::move_bindgen::TypeTagged>::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_3); + ( + bcs::to_bytes(&t).unwrap(), + ::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_4); + ( + bcs::to_bytes(&t).unwrap(), + ::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_5); + ( + bcs::to_bytes(&t).unwrap(), + as ::move_bindgen::TypeTagged>::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_6); + ( + bcs::to_bytes(&t).unwrap(), + as ::move_bindgen::TypeTagged>::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_7); + ( + bcs::to_bytes(&t).unwrap(), + > as ::move_bindgen::TypeTagged>::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_8); + ( + bcs::to_bytes(&t).unwrap(), + as ::move_bindgen::TypeTagged>::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_9); + ( + bcs::to_bytes(&t).unwrap(), + as ::move_bindgen::TypeTagged>::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_10); + ( + bcs::to_bytes(&t).unwrap(), + ::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_11); + ( + bcs::to_bytes(&t).unwrap(), + ::type_tag(ctx), + ) + }, + ] + .into_iter() + .unzip(); + ::aptos_types::transaction::EntryFunction::new( + ::aptos_rest_client::aptos_api_types::MoveModuleId { + address: self.module_address().into(), + name: stringify!(Core).parse().unwrap(), + } + .into(), + stringify!(connection_open_try).parse().unwrap(), + type_args, + values, + ) + } + async fn consensus_state( + &self, + (_0, _1, _2): (String, u64, u64), + ledger_version: Option, + ) -> ::core::result::Result, ::aptos_rest_client::error::RestError> { + let response = self + .client() + .view( + &::aptos_rest_client::aptos_api_types::ViewRequest { + function: ::aptos_rest_client::aptos_api_types::EntryFunctionId { + module: ::aptos_rest_client::aptos_api_types::MoveModuleId { + address: self.module_address().into(), + name: stringify!(Core).parse().unwrap(), + }, + name: stringify!(consensus_state).parse().unwrap(), + }, + type_arguments: vec![ + ::aptos_rest_client::aptos_api_types::MoveType::Struct( + ::aptos_rest_client::aptos_api_types::MoveStructTag { + address: "0x1".parse().unwrap(), + module: "string".parse().unwrap(), + name: "String".parse().unwrap(), + generic_type_params: vec![], + }, + ), + ::aptos_rest_client::aptos_api_types::MoveType::U64, + ::aptos_rest_client::aptos_api_types::MoveType::U64, + ], + arguments: vec![ + serde_json::to_value(String::from(_0)).unwrap(), + serde_json::to_value(::aptos_rest_client::aptos_api_types::U64::from( + _1, + )) + .unwrap(), + serde_json::to_value(::aptos_rest_client::aptos_api_types::U64::from( + _2, + )) + .unwrap(), + ], + }, + ledger_version, + ) + .await? + .into_inner(); + let ret = ::serde_json::from_value::<(Vec,)>(::serde_json::Value::from(response))?; + Ok(ret.0) + } + fn create_client( + &self, + (_0, _1, _2): ( + impl ::move_bindgen::IntoTypeTagged, + impl ::move_bindgen::IntoTypeTagged>, + impl ::move_bindgen::IntoTypeTagged>, + ), + ) -> ::aptos_types::transaction::EntryFunction { + let (values, type_args): (Vec<_>, Vec<_>) = vec![ + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_0); + ( + bcs::to_bytes(&t).unwrap(), + ::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_1); + ( + bcs::to_bytes(&t).unwrap(), + as ::move_bindgen::TypeTagged>::type_tag(ctx), + ) + }, + { + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_2); + ( + bcs::to_bytes(&t).unwrap(), + as ::move_bindgen::TypeTagged>::type_tag(ctx), + ) + }, + ] + .into_iter() + .unzip(); + ::aptos_types::transaction::EntryFunction::new( + ::aptos_rest_client::aptos_api_types::MoveModuleId { + address: self.module_address().into(), + name: stringify!(Core).parse().unwrap(), + } + .into(), + stringify!(create_client).parse().unwrap(), + type_args, + values, + ) + } + async fn get_connection( + &self, + (_0,): (String,), + ledger_version: Option, + ) -> ::core::result::Result< + super::connection_end::ConnectionEnd, + ::aptos_rest_client::error::RestError, + > { + let response = self + .client() + .view( + &::aptos_rest_client::aptos_api_types::ViewRequest { + function: ::aptos_rest_client::aptos_api_types::EntryFunctionId { + module: ::aptos_rest_client::aptos_api_types::MoveModuleId { + address: self.module_address().into(), + name: stringify!(Core).parse().unwrap(), + }, + name: stringify!(get_connection).parse().unwrap(), + }, + type_arguments: vec![ + ::aptos_rest_client::aptos_api_types::MoveType::Struct( + ::aptos_rest_client::aptos_api_types::MoveStructTag { + address: "0x1".parse().unwrap(), + module: "string".parse().unwrap(), + name: "String".parse().unwrap(), + generic_type_params: vec![], + }, + ), + ], + arguments: vec![serde_json::to_value(String::from(_0)).unwrap()], + }, + ledger_version, + ) + .await? + .into_inner(); + let ret = ::serde_json::from_value::<(super::connection_end::ConnectionEnd,)>( + ::serde_json::Value::from(response), + )?; + Ok(ret.0) + } + async fn get_connection_commitment( + &self, + (_0,): (String,), + ledger_version: Option, + ) -> ::core::result::Result, ::aptos_rest_client::error::RestError> { + let response = self + .client() + .view( + &::aptos_rest_client::aptos_api_types::ViewRequest { + function: ::aptos_rest_client::aptos_api_types::EntryFunctionId { + module: ::aptos_rest_client::aptos_api_types::MoveModuleId { + address: self.module_address().into(), + name: stringify!(Core).parse().unwrap(), + }, + name: stringify!(get_connection_commitment).parse().unwrap(), + }, + type_arguments: vec![ + ::aptos_rest_client::aptos_api_types::MoveType::Struct( + ::aptos_rest_client::aptos_api_types::MoveStructTag { + address: "0x1".parse().unwrap(), + module: "string".parse().unwrap(), + name: "String".parse().unwrap(), + generic_type_params: vec![], + }, + ), + ], + arguments: vec![serde_json::to_value(String::from(_0)).unwrap()], + }, + ledger_version, + ) + .await? + .into_inner(); + let ret = ::serde_json::from_value::<(Vec,)>(::serde_json::Value::from(response))?; + Ok(ret.0) + } + async fn get_vault_addr( + &self, + ledger_version: Option, + ) -> ::core::result::Result< + ::aptos_rest_client::aptos_api_types::Address, + ::aptos_rest_client::error::RestError, + > { + let response = self + .client() + .view( + &::aptos_rest_client::aptos_api_types::ViewRequest { + function: ::aptos_rest_client::aptos_api_types::EntryFunctionId { + module: ::aptos_rest_client::aptos_api_types::MoveModuleId { + address: self.module_address().into(), + name: stringify!(Core).parse().unwrap(), + }, + name: stringify!(get_vault_addr).parse().unwrap(), + }, + type_arguments: vec![], + arguments: vec![], + }, + ledger_version, + ) + .await? + .into_inner(); + let ret = ::serde_json::from_value::<(::aptos_rest_client::aptos_api_types::Address,)>( + ::serde_json::Value::from(response), + )?; + Ok(ret.0) + } + fn hackerman( + &self, + (_0,): (impl ::move_bindgen::IntoTypeTagged,), + ) -> ::aptos_types::transaction::EntryFunction { + let (values, type_args): (Vec<_>, Vec<_>) = vec![{ + let (t, ctx) = ::move_bindgen::IntoTypeTagged::into_type_tagged(_0); + ( + bcs::to_bytes(&t).unwrap(), + ::type_tag(ctx), + ) + }] + .into_iter() + .unzip(); + ::aptos_types::transaction::EntryFunction::new( + ::aptos_rest_client::aptos_api_types::MoveModuleId { + address: self.module_address().into(), + name: stringify!(Core).parse().unwrap(), + } + .into(), + stringify!(hackerman).parse().unwrap(), + type_args, + values, + ) + } + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct ChannelOpenAck { + pub port_id: String, + pub channel_id: String, + pub counterparty_port_id: String, + pub counterparty_channel_id: String, + pub connection_id: String, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct WriteAcknowledgement { + pub packet: super::packet::Packet, + pub acknowledgement: Vec, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct Hackerman { + pub t: T0, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct ChannelOpenTry { + pub port_id: String, + pub channel_id: String, + pub counterparty_port_id: String, + pub counterparty_channel_id: String, + pub connection_id: String, + pub version: String, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct ConnectionOpenTry { + pub connection_id: String, + pub client_id: String, + pub counterparty_client_id: String, + pub counterparty_connection_id: String, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct ConnectionOpenAck { + pub connection_id: String, + pub client_id: String, + pub counterparty_client_id: String, + pub counterparty_connection_id: String, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct ChannelOpenInit { + pub port_id: String, + pub channel_id: String, + pub counterparty_port_id: String, + pub connection_id: String, + pub version: String, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct RecvPacket { + pub packet: super::packet::Packet, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct SendPacket { + pub sequence: ::aptos_rest_client::aptos_api_types::U64, + pub source_port: String, + pub source_channel: String, + pub timeout_height: super::height::Height, + pub timeout_timestamp: ::aptos_rest_client::aptos_api_types::U64, + pub data: Vec, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct ConnectionOpenConfirm { + pub connection_id: String, + pub client_id: String, + pub counterparty_client_id: String, + pub counterparty_connection_id: String, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct ClientCreatedEvent { + pub client_id: String, + pub client_type: String, + pub consensus_height: super::height::Height, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct ConnectionOpenInit { + pub connection_id: String, + pub client_id: String, + pub counterparty_client_id: String, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct AcknowledgePacket { + pub packet: super::packet::Packet, + pub acknowledgement: Vec, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct ChannelOpenConfirm { + pub port_id: String, + pub channel_id: String, + pub counterparty_port_id: String, + pub counterparty_channel_id: String, + pub connection_id: String, + } + #[macros::model] + #[derive(::move_bindgen::TypeTagged)] + #[type_tag(module = Core)] + pub struct TimeoutPacket { + pub packet: super::packet::Packet, + } +} diff --git a/voyager/modules/chain/movement/src/data.rs b/voyager/modules/chain/movement/src/data.rs new file mode 100644 index 0000000000..063c8f7f1d --- /dev/null +++ b/voyager/modules/chain/movement/src/data.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleData {} diff --git a/voyager/modules/chain/movement/src/events.rs b/voyager/modules/chain/movement/src/events.rs new file mode 100644 index 0000000000..16fd85eba2 --- /dev/null +++ b/voyager/modules/chain/movement/src/events.rs @@ -0,0 +1,167 @@ +use serde::{Deserialize, Serialize}; +use unionlabs::id::ClientId; + +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged, deny_unknown_fields)] +pub enum IbcEvent { + CreateClient { + client_id: ClientId, + // TODO: Figure out if there's a better type we can use than string + client_type: String, + consensus_height: Height, + }, + + UpdateClient { + client_id: ClientId, + client_type: String, + consensus_heights: Vec, + }, + // ConnectionOpenInit { + // connection_id: ConnectionId, + // client_id: ClientId, + // counterparty_client_id: ClientId, + // }, + + // ConnectionOpenTry { + // connection_id: ConnectionId, + // client_id: ClientId, + // counterparty_client_id: ClientId, + // counterparty_connection_id: ConnectionId, + // }, + + // ConnectionOpenAck { + // connection_id: ConnectionId, + // client_id: ClientId, + // counterparty_client_id: ClientId, + // counterparty_connection_id: ConnectionId, + // }, + + // ConnectionOpenConfirm { + // connection_id: ConnectionId, + // client_id: ClientId, + // counterparty_client_id: ClientId, + // counterparty_connection_id: ConnectionId, + // }, + + // ChannelOpenInit { + // port_id: PortId, + // channel_id: ChannelId, + // counterparty_port_id: PortId, + // connection_id: ConnectionId, + // version: String, + // }, + + // ChannelOpenTry { + // port_id: PortId, + // channel_id: ChannelId, + // counterparty_port_id: PortId, + // counterparty_channel_id: ChannelId, + // connection_id: ConnectionId, + // version: String, + // }, + + // ChannelOpenAck { + // port_id: PortId, + // channel_id: ChannelId, + // counterparty_port_id: PortId, + // counterparty_channel_id: ChannelId, + // connection_id: ConnectionId, + // }, + + // ChannelOpenConfirm { + // port_id: PortId, + // channel_id: ChannelId, + // counterparty_port_id: PortId, + // counterparty_channel_id: ChannelId, + // connection_id: ConnectionId, + // }, + + // WriteAcknowledgement { + // #[serde(with = "::serde_utils::hex_string")] + // #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + // packet_data_hex: Vec, + // packet_timeout_height: Height, + // packet_timeout_timestamp: u64, + // packet_sequence: NonZeroU64, + // packet_src_port: PortId, + // packet_src_channel: ChannelId, + // packet_dst_port: PortId, + // packet_dst_channel: ChannelId, + // #[serde(with = "::serde_utils::hex_string")] + // #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + // packet_ack_hex: Vec, + // connection_id: ConnectionId, + // }, + + // RecvPacket { + // #[serde(with = "::serde_utils::hex_string")] + // #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + // packet_data_hex: Vec, + // packet_timeout_height: Height, + // packet_timeout_timestamp: u64, + // packet_sequence: NonZeroU64, + // packet_src_port: PortId, + // packet_src_channel: ChannelId, + // packet_dst_port: PortId, + // packet_dst_channel: ChannelId, + // packet_channel_ordering: Order, + // connection_id: ConnectionId, + // }, + + // SendPacket { + // #[serde(with = "::serde_utils::hex_string")] + // #[debug(wrap = ::serde_utils::fmt::DebugAsHex)] + // packet_data_hex: Vec, + // // TODO: Make this generic height instead of concrete + // packet_timeout_height: Height, + // packet_timeout_timestamp: u64, + // packet_sequence: NonZeroU64, + // packet_src_port: PortId, + // packet_src_channel: ChannelId, + // packet_dst_port: PortId, + // packet_dst_channel: ChannelId, + // packet_channel_ordering: Order, + // connection_id: ConnectionId, + // }, + + // AcknowledgePacket { + // packet_timeout_height: Height, + // packet_timeout_timestamp: u64, + // packet_sequence: NonZeroU64, + // packet_src_port: PortId, + // packet_src_channel: ChannelId, + // packet_dst_port: PortId, + // packet_dst_channel: ChannelId, + // packet_channel_ordering: Order, + // connection_id: ConnectionId, + // }, + + // TimeoutPacket { + // packet_timeout_height: Height, + // packet_timeout_timestamp: u64, + // packet_sequence: NonZeroU64, + // packet_src_port: PortId, + // packet_src_channel: ChannelId, + // packet_dst_port: PortId, + // packet_dst_channel: ChannelId, + // packet_channel_ordering: Order, + // connection_id: ConnectionId, + // }, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Height { + #[serde(with = "::serde_utils::string")] + revision_height: u64, + #[serde(with = "::serde_utils::string")] + revision_number: u64, +} + +impl From for unionlabs::ibc::core::client::height::Height { + fn from(value: Height) -> Self { + Self { + revision_number: value.revision_number, + revision_height: value.revision_height, + } + } +} diff --git a/voyager/modules/chain/movement/src/main.rs b/voyager/modules/chain/movement/src/main.rs new file mode 100644 index 0000000000..c62ff565f8 --- /dev/null +++ b/voyager/modules/chain/movement/src/main.rs @@ -0,0 +1,615 @@ +use std::collections::VecDeque; + +use aptos_crypto::PrivateKey; +use aptos_rest_client::{ + aptos_api_types::{Address, MoveType}, + Transaction, +}; +use aptos_types::transaction::RawTransaction; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + types::ErrorObject, +}; +use queue_msg::{call, noop, BoxDynError, Op}; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; +use serde_utils::Hex; +use sha3::Digest; +use tracing::{debug, instrument, warn}; +use unionlabs::{ + events::{CreateClient, IbcEvent, UpdateClient}, + hash::H256, + ibc::core::client::height::Height, + ics24::{ClientStatePath, Path}, + id::ClientId, + ErrorReporter, +}; +use voyager_message::{ + call::Call, + data::{ClientInfo, Data}, + module::{ + ChainModuleInfo, ChainModuleServer, ModuleInfo, QueueInteractionsServer, RawClientState, + }, + run_module_server, ChainId, ClientType, IbcInterface, ModuleContext, ModuleServer, + VoyagerMessage, +}; + +use crate::{ + call::{FetchBlock, FetchBlocks, ModuleCall}, + callback::ModuleCallback, + client::Core::ClientExt, + data::ModuleData, +}; + +pub mod call; +pub mod callback; +pub mod data; + +pub mod client; +pub mod events; + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + run_module_server::().await +} + +#[derive(clap::Subcommand)] +pub enum Cmd { + ChainId, + LatestHeight, + VaultAddress, + SubmitTx, + FetchAbi, +} + +#[derive(Debug, Clone)] +pub struct Module { + pub chain_id: ChainId<'static>, + + pub aptos_client: aptos_rest_client::Client, + + pub ibc_handler_address: Address, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Config { + pub chain_id: ChainId<'static>, + pub rpc_url: String, + pub ibc_handler_address: Address, +} + +impl ModuleContext for Module { + type Config = Config; + type Cmd = Cmd; + type Info = ChainModuleInfo; + + async fn new(config: Self::Config) -> Result { + let aptos_client = aptos_rest_client::Client::new(config.rpc_url.parse()?); + + let chain_id = aptos_client.get_index().await?.inner().chain_id; + + Ok(Self { + chain_id: ChainId::new(chain_id.to_string()), + aptos_client, + ibc_handler_address: config.ibc_handler_address, + }) + } + + fn info(config: Self::Config) -> ModuleInfo { + ModuleInfo { + name: plugin_name(&config.chain_id), + kind: ChainModuleInfo { + chain_id: config.chain_id, + }, + } + } + + async fn cmd(config: Self::Config, cmd: Self::Cmd) { + let module = Module::new(config).await.unwrap(); + + match cmd { + Cmd::ChainId => println!("{}", module.chain_id), + Cmd::LatestHeight => println!("{}", module.latest_height().await.unwrap()), + Cmd::VaultAddress => { + let addr = module.get_vault_addr(None).await.unwrap(); + + println!("{addr}"); + } + Cmd::SubmitTx => { + let pk = aptos_crypto::ed25519::Ed25519PrivateKey::try_from( + hex_literal::hex!( + "f90391c81027f03cdea491ed8b36ffaced26b6df208a9b569e5baf2590eb9b16" + ) + .as_slice(), + ) + .unwrap(); + + let sender = H256::from( + sha3::Sha3_256::new() + .chain_update(pk.public_key().to_bytes()) + .chain_update([0]) + .finalize(), + ) + .0 + .into(); + + dbg!(&sender); + + let account = module + .aptos_client + .get_account(sender) + .await + .unwrap() + .into_inner(); + + dbg!(&account); + + let raw = RawTransaction::new_entry_function( + sender, + account.sequence_number, + module.hackerman( + // client::height::Height { + // revision_number: 1.into(), + // revision_height: 1.into(), + // } + // .with_address(module.ibc_handler_address.into()), + // ("hi".to_owned(),), + (69_420_u64,), + ), + 400000, + 100, + queue_msg::now() + 10, + aptos_types::chain_id::ChainId::new(27), + ); + + let sig = raw.sign(&pk, pk.public_key()).unwrap(); + + dbg!(&sig); + + let res = module.aptos_client.submit_and_wait(&sig).await.unwrap(); + + dbg!(&res); + + let tx_events = match res.into_inner() { + Transaction::UserTransaction(tx) => tx.events, + e => panic!("{e:?}"), + }; + + let (typ, data) = tx_events + .into_iter() + .find_map(|e| match e.typ { + MoveType::Struct(s) => { + (s.address == module.ibc_handler_address).then_some((s, e.data)) + } + _ => None, + }) + .unwrap(); + + dbg!(&typ, &data); + + // let event = serde_json::from_value::(data).unwrap(); + // let event: unionlabs::events::IbcEvent = match typ.name.as_str() { + // "ClientCreatedEvent" => { + // serde_json::from_value::(data) + // .unwrap() + // .into() + // } + // unknown => panic!("unknown event {unknown}"), + // }; + + // println!("{:.unwrap()}", event); + } + Cmd::FetchAbi => { + let abis = module + .aptos_client + .get_account_modules(module.ibc_handler_address.into()) + .await + .unwrap() + .into_inner() + .into_iter() + .flat_map(|x| x.try_parse_abi().unwrap().abi) + .collect::>(); + + dbg!(abis); + } + } + } +} + +impl client::Core::ClientExt for Module { + fn client(&self) -> &aptos_rest_client::Client { + &self.aptos_client + } + + fn module_address(&self) -> aptos_types::account_address::AccountAddress { + self.ibc_handler_address.into() + } +} + +fn plugin_name(chain_id: &ChainId<'_>) -> String { + pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); + + format!("{PLUGIN_NAME}/{}", chain_id) +} + +impl Module { + fn plugin_name(&self) -> String { + plugin_name(&self.chain_id) + } + + pub async fn latest_height(&self) -> Result { + let ledger_info = self.aptos_client.get_index().await?; + let height = ledger_info.inner().block_height.0; + + debug!(height, "latest height"); + + Ok(self.make_height(height)) + } + + #[must_use] + pub fn make_height(&self, height: u64) -> Height { + Height { + // TODO: Make this a constant + revision_number: 0, + revision_height: height, + } + } +} + +#[async_trait] +impl QueueInteractionsServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn callback( + &self, + cb: ModuleCallback, + _data: VecDeque>, + ) -> RpcResult>> { + match cb {} + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn call( + &self, + msg: ModuleCall, + ) -> RpcResult>> { + match msg { + ModuleCall::FetchBlock(FetchBlock { height }) => { + let events = self + .ctx + .aptos_client + .get_block_by_height(height, true) + .await + .map_err(|e| { + ErrorObject::owned( + -1, + format!("error fetching height: {}", ErrorReporter(e)), + None::<()>, + ) + })? + .into_inner() + .transactions + .unwrap_or_default() + .into_iter() + .filter_map(|tx| match tx { + Transaction::UserTransaction(tx) => Some(tx), + _ => None, + }) + .flat_map(|tx| tx.events) + .filter_map(|e| match e.typ { + MoveType::Struct(s) => { + (s.address == self.ctx.ibc_handler_address).then_some((s, e.data)) + } + _ => None, + }) + .map(|(_typ, data)| { + // TODO: Check the type before deserializing + serde_json::from_value::(data).unwrap() + }) + // .map(|e| ChainEvent { + // chain_id: todo!(), + // client_info: todo!(), + // counterparty_chain_id: todo!(), + // tx_hash: todo!(), + // provable_height: todo!(), + // event: match e { + // events::IbcEvent::CreateClient { + // client_id, + // client_type, + // consensus_height, + // } => CreateClient { + // client_id, + // client_type, + // consensus_height: consensus_height.into(), + // } + // .into(), + // events::IbcEvent::UpdateClient { + // client_id, + // client_type, + // consensus_heights, + // } => UpdateClient { + // client_id, + // client_type, + // consensus_heights: consensus_heights + // .into_iter() + // .map(Into::into) + // .collect(), + // } + // .into(), + // }, + // }); + .map(|e| match e { + events::IbcEvent::CreateClient { + client_id, + client_type, + consensus_height, + } => CreateClient { + client_id, + client_type, + consensus_height: consensus_height.into(), + } + .into(), + events::IbcEvent::UpdateClient { + client_id, + client_type, + consensus_heights, + } => UpdateClient { + client_id, + client_type, + consensus_heights: consensus_heights + .into_iter() + .map(Into::into) + .collect(), + } + .into(), + }) + .collect::>(); + + dbg!(events); + + Ok(noop()) + } + ModuleCall::FetchBlocks(_) => todo!(), + } + } +} + +#[async_trait] +impl ChainModuleServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + fn chain_id(&self) -> RpcResult> { + Ok(self.ctx.chain_id.clone()) + } + + /// Query the latest finalized height of this chain. + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_latest_height(&self) -> RpcResult { + self.ctx + .latest_height() + .await + // TODO: Add more context here + .map_err(|err| ErrorObject::owned(-1, ErrorReporter(err).to_string(), None::<()>)) + } + + /// Query the latest (non-finalized) height of this chain. + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_latest_height_as_destination(&self) -> RpcResult { + self.query_latest_height() + .await + // TODO: Add more context here + .map_err(|err| ErrorObject::owned(-1, ErrorReporter(err).to_string(), None::<()>)) + } + + /// Query the latest finalized timestamp of this chain. + // TODO: Use a better timestamp type here + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_latest_timestamp(&self) -> RpcResult { + let latest_height = self.query_latest_height().await?; + + match self + .ctx + .aptos_client + .get_block_by_height(latest_height.revision_height, false) + .await + { + Ok(block) => { + let timestamp = block.inner().block_timestamp.0; + + debug!(%timestamp, %latest_height, "latest timestamp"); + + Ok(timestamp.try_into().unwrap()) + } + Err(err) => Err(ErrorObject::owned( + -1, + ErrorReporter(err).to_string(), + None::<()>, + )), + } + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn fetch_block_range( + &self, + from_height: Height, + to_height: Height, + ) -> RpcResult>> { + Ok(call(Call::plugin( + self.ctx.plugin_name(), + FetchBlocks { + from_height: from_height.revision_height, + to_height: to_height.revision_height, + }, + ))) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn client_info(&self, client_id: ClientId) -> RpcResult { + match client_id.to_string().rsplit_once('-') { + Some(("cometbls", _)) => Ok(ClientInfo { + client_type: ClientType::new(ClientType::COMETBLS), + ibc_interface: IbcInterface::new(IbcInterface::IBC_MOVE_APTOS), + metadata: Default::default(), + }), + _ => Err(ErrorObject::owned( + -1, + format!("unknown client type (client id `{client_id}`)"), + Some(json!({ + "client_id": client_id.to_string() + })), + )), + } + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_ibc_state(&self, at: Height, path: Path) -> RpcResult { + let _ = (at, path); + + // const IBC_STORE_PATH: &str = "store/ibc/key"; + + // let path_string = path.to_string(); + + // let query_result = self + // .tm_client + // .abci_query( + // IBC_STORE_PATH, + // &path_string, + // Some( + // i64::try_from(at.revision_height) + // .unwrap() + // .try_into() + // .expect("invalid height"), + // ), + // false, + // ) + // .await + // .unwrap() + // .response; + + // Ok(match path { + // Path::ClientState(_) => serde_json::to_value(Hex(query_result.value)).unwrap(), + // Path::ClientConsensusState(_) => serde_json::to_value(Hex(query_result.value)).unwrap(), + // Path::Connection(_) => serde_json::to_value( + // ConnectionEnd::decode_as::(&query_result.value).unwrap(), + // ) + // .unwrap(), + // Path::ChannelEnd(_) => { + // serde_json::to_value(Channel::decode_as::(&query_result.value).unwrap()) + // .unwrap() + // } + // Path::Commitment(_) => { + // serde_json::to_value(H256::try_from(query_result.value).unwrap()).unwrap() + // } + // Path::Acknowledgement(_) => { + // serde_json::to_value(H256::try_from(query_result.value).unwrap()).unwrap() + // } + // Path::Receipt(_) => serde_json::to_value(match query_result.value[..] { + // [] => false, + // [1] => true, + // ref invalid => panic!("not a bool??? {invalid:?}"), + // }) + // .unwrap(), + // Path::NextSequenceSend(_) => { + // serde_json::to_value(u64::from_be_bytes(query_result.value.try_into().unwrap())) + // .unwrap() + // } + // Path::NextSequenceRecv(_) => { + // serde_json::to_value(u64::from_be_bytes(query_result.value.try_into().unwrap())) + // .unwrap() + // } + // Path::NextSequenceAck(_) => { + // serde_json::to_value(u64::from_be_bytes(query_result.value.try_into().unwrap())) + // .unwrap() + // } + // Path::NextConnectionSequence(_) => { + // serde_json::to_value(u64::from_be_bytes(query_result.value.try_into().unwrap())) + // .unwrap() + // } + // Path::NextClientSequence(_) => { + // serde_json::to_value(u64::from_be_bytes(query_result.value.try_into().unwrap())) + // .unwrap() + // } + // }) + + todo!() + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_ibc_proof(&self, at: Height, path: Path) -> RpcResult { + let _ = (at, path); + + // const IBC_STORE_PATH: &str = "store/ibc/key"; + + // let path_string = path.to_string(); + + // let query_result = self + // .tm_client + // .abci_query( + // IBC_STORE_PATH, + // &path_string, + // // a proof at height H is provable at height H + 1 + // // we assume that the height passed in to this function is the intended height to prove against, thus we have to query the height - 1 + // Some( + // (i64::try_from(at.revision_height).unwrap() - 1) + // .try_into() + // .expect("invalid height"), + // ), + // true, + // ) + // .await + // .unwrap(); + + // Ok(serde_json::to_value( + // MerkleProof::try_from(protos::ibc::core::commitment::v1::MerkleProof { + // proofs: query_result + // .response + // .proof_ops + // .unwrap() + // .ops + // .into_iter() + // .map(|op| { + // ::decode( + // op.data.as_slice(), + // ) + // .unwrap() + // }) + // .collect::>(), + // }) + // .unwrap(), + // ) + // .unwrap()) + + todo!() + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn query_raw_unfinalized_trusted_client_state( + &self, + client_id: ClientId, + ) -> RpcResult> { + let height = self.query_latest_height().await?; + + let client_state = serde_json::from_value::>>( + self.query_ibc_state( + height, + ClientStatePath { + client_id: client_id.clone(), + } + .into(), + ) + .await?, + ) + .unwrap(); + + let ClientInfo { + client_type, + ibc_interface, + metadata: _, + } = self.client_info(client_id.clone()).await?; + + Ok(RawClientState { + client_type, + ibc_interface, + bytes: client_state.0.into(), + }) + } +} diff --git a/voyager/modules/client/cometbls/Cargo.toml b/voyager/modules/client/cometbls/Cargo.toml new file mode 100644 index 0000000000..a883c17eea --- /dev/null +++ b/voyager/modules/client/cometbls/Cargo.toml @@ -0,0 +1,26 @@ +[package] +edition = "2021" +name = "voyager-client-module-cometbls" +version = "0.1.0" + +[dependencies] +clap = { workspace = true, features = ["default", "derive", "env", "error-context"] } +cometbft-rpc = { workspace = true } +dashmap = { workspace = true } +enumorph = { workspace = true } +frunk = { workspace = true } +futures = { workspace = true } +jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } +macros = { workspace = true } +prost = { workspace = true } +protos = { workspace = true } +queue-msg = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +serde_json = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +unionlabs = { workspace = true } +voyager-message = { workspace = true } diff --git a/voyager/modules/client/cometbls/src/call.rs b/voyager/modules/client/cometbls/src/call.rs new file mode 100644 index 0000000000..9bb6889adc --- /dev/null +++ b/voyager/modules/client/cometbls/src/call.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCall {} diff --git a/voyager/modules/client/cometbls/src/callback.rs b/voyager/modules/client/cometbls/src/callback.rs new file mode 100644 index 0000000000..e3dbf95927 --- /dev/null +++ b/voyager/modules/client/cometbls/src/callback.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCallback {} diff --git a/voyager/modules/client/cometbls/src/data.rs b/voyager/modules/client/cometbls/src/data.rs new file mode 100644 index 0000000000..063c8f7f1d --- /dev/null +++ b/voyager/modules/client/cometbls/src/data.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleData {} diff --git a/voyager/modules/client/cometbls/src/main.rs b/voyager/modules/client/cometbls/src/main.rs new file mode 100644 index 0000000000..8ba47a09e1 --- /dev/null +++ b/voyager/modules/client/cometbls/src/main.rs @@ -0,0 +1,349 @@ +use std::collections::VecDeque; + +use jsonrpsee::{ + core::{async_trait, RpcResult}, + types::ErrorObject, +}; +use macros::model; +use queue_msg::{BoxDynError, Op}; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; +use serde_utils::Hex; +use tracing::{debug, instrument}; +use unionlabs::{ + self, + encoding::{Bcs, DecodeAs, EncodeAs, EthAbi}, + ibc::lightclients::cometbls::{ + client_state::ClientState, consensus_state::ConsensusState, header::Header, + }, + ErrorReporter, +}; +use voyager_message::{ + data::Data, + module::{ + ClientModuleInfo, ClientModuleServer, ClientStateMeta, ConsensusStateMeta, ModuleInfo, + QueueInteractionsServer, + }, + run_module_server, ChainId, ClientType, DefaultCmd, IbcInterface, ModuleContext, ModuleServer, + VoyagerMessage, FATAL_JSONRPC_ERROR_CODE, +}; + +use crate::{call::ModuleCall, callback::ModuleCallback, data::ModuleData}; + +pub mod call; +pub mod callback; +pub mod data; + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + run_module_server::().await +} + +#[model(no_serde)] +#[derive(Copy, Serialize, Deserialize)] +#[serde(try_from = "String", into = "String")] +pub enum SupportedIbcInterface { + IbcSolidity, + IbcMoveAptos, +} + +impl TryFrom for SupportedIbcInterface { + // TODO: Better error type here + type Error = String; + + fn try_from(value: String) -> Result { + match &*value { + IbcInterface::IBC_SOLIDITY => Ok(SupportedIbcInterface::IbcSolidity), + IbcInterface::IBC_MOVE_APTOS => Ok(SupportedIbcInterface::IbcMoveAptos), + _ => Err(format!("unsupported IBC interface: `{value}`")), + } + } +} + +impl SupportedIbcInterface { + fn as_str(&self) -> &'static str { + match self { + SupportedIbcInterface::IbcSolidity => IbcInterface::IBC_SOLIDITY, + SupportedIbcInterface::IbcMoveAptos => IbcInterface::IBC_MOVE_APTOS, + } + } +} + +impl From for String { + fn from(value: SupportedIbcInterface) -> Self { + value.as_str().to_owned() + } +} + +#[derive(Debug, Clone)] +pub struct Module { + pub ibc_interface: SupportedIbcInterface, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Config { + pub ibc_interface: SupportedIbcInterface, +} + +impl ModuleContext for Module { + type Config = Config; + type Cmd = DefaultCmd; + type Info = ClientModuleInfo; + + async fn new(config: Self::Config) -> Result { + Ok(dbg!(Self { + ibc_interface: config.ibc_interface, + })) + } + + fn info(config: Self::Config) -> ModuleInfo { + ModuleInfo { + name: plugin_name(config.ibc_interface), + kind: ClientModuleInfo { + client_type: ClientType::new(ClientType::COMETBLS), + ibc_interface: IbcInterface::new(config.ibc_interface.as_str()), + }, + } + } + + async fn cmd(_config: Self::Config, cmd: Self::Cmd) { + match cmd {} + } +} + +fn plugin_name(ibc_interface: SupportedIbcInterface) -> String { + pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); + + format!("{PLUGIN_NAME}/{}", ibc_interface.as_str()) +} + +impl Module { + pub fn decode_consensus_state(&self, consensus_state: &[u8]) -> RpcResult { + match self.ibc_interface { + SupportedIbcInterface::IbcSolidity => { + ConsensusState::decode_as::(consensus_state).map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to decode consensus state: {}", ErrorReporter(err)), + None::<()>, + ) + }) + } + SupportedIbcInterface::IbcMoveAptos => { + ConsensusState::decode_as::(consensus_state).map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to decode consensus state: {}", ErrorReporter(err)), + None::<()>, + ) + }) + } + } + } + + pub fn decode_client_state(&self, client_state: &[u8]) -> RpcResult { + match self.ibc_interface { + SupportedIbcInterface::IbcSolidity => ClientState::decode_as::(client_state) + .map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to decode client state: {}", ErrorReporter(err)), + None::<()>, + ) + }), + SupportedIbcInterface::IbcMoveAptos => ClientState::decode_as::(client_state) + .map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to decode client state: {}", ErrorReporter(err)), + None::<()>, + ) + }), + } + } +} + +#[async_trait] +impl QueueInteractionsServer for ModuleServer { + #[instrument(skip_all)] + async fn call( + &self, + msg: ModuleCall, + ) -> RpcResult>> { + match msg {} + } + + #[instrument(skip_all)] + async fn callback( + &self, + cb: ModuleCallback, + _data: VecDeque>, + ) -> RpcResult>> { + match cb {} + } +} + +#[async_trait] +impl ClientModuleServer for ModuleServer { + #[instrument(skip_all)] + async fn supported_interface(&self) -> RpcResult { + Ok(ClientModuleInfo { + client_type: ClientType::new(ClientType::COMETBLS), + ibc_interface: IbcInterface::new(self.ctx.ibc_interface.as_str()), + }) + } + + #[instrument(skip_all)] + async fn decode_client_state_meta( + &self, + client_state: Hex>, + ) -> RpcResult { + let cs = self.ctx.decode_client_state(&client_state.0)?; + + Ok(ClientStateMeta { + chain_id: ChainId::new(cs.chain_id), + height: cs.latest_height, + }) + } + + #[instrument(skip_all)] + async fn decode_consensus_state_meta( + &self, + consensus_state: Hex>, + ) -> RpcResult { + let cs = self.ctx.decode_consensus_state(&consensus_state.0)?; + + Ok(ConsensusStateMeta { + timestamp_nanos: cs.timestamp, + }) + } + + #[instrument(skip_all)] + async fn decode_client_state(&self, client_state: Hex>) -> RpcResult { + Ok(serde_json::to_value(self.ctx.decode_client_state(&client_state.0)?).unwrap()) + } + + #[instrument(skip_all)] + async fn decode_consensus_state(&self, consensus_state: Hex>) -> RpcResult { + Ok(serde_json::to_value(self.ctx.decode_consensus_state(&consensus_state.0)?).unwrap()) + } + + #[instrument(skip_all)] + async fn encode_client_state( + &self, + client_state: Value, + metadata: Value, + ) -> RpcResult>> { + if !metadata.is_null() { + return Err(ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + "metadata was provided, but this client type does not require metadata for client \ + state encoding", + Some(json!({ + "provided_metadata": metadata, + })), + )); + } + + serde_json::from_value::(client_state) + .map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to deserialize client state: {}", ErrorReporter(err)), + None::<()>, + ) + }) + .map(|cs| match self.ctx.ibc_interface { + SupportedIbcInterface::IbcSolidity => cs.encode_as::(), + SupportedIbcInterface::IbcMoveAptos => cs.encode_as::(), + }) + .map(Hex) + } + + #[instrument(skip_all)] + async fn encode_consensus_state(&self, consensus_state: Value) -> RpcResult>> { + serde_json::from_value::(consensus_state) + .map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!( + "unable to deserialize consensus state: {}", + ErrorReporter(err) + ), + None::<()>, + ) + }) + .map(|cs| match self.ctx.ibc_interface { + SupportedIbcInterface::IbcSolidity => cs.encode_as::(), + SupportedIbcInterface::IbcMoveAptos => cs.encode_as::(), + }) + .map(Hex) + } + + #[instrument(skip_all)] + async fn reencode_counterparty_client_state( + &self, + client_state: Hex>, + _client_type: ClientType<'static>, + ) -> RpcResult>> { + Ok(client_state) + } + + #[instrument(skip_all)] + async fn reencode_counterparty_consensus_state( + &self, + consensus_state: Hex>, + _client_type: ClientType<'static>, + ) -> RpcResult>> { + Ok(consensus_state) + } + + #[instrument(skip_all)] + async fn encode_header(&self, header: Value) -> RpcResult>> { + serde_json::from_value::
(header) + .map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to deserialize header: {}", ErrorReporter(err)), + None::<()>, + ) + }) + .map(|header| match self.ctx.ibc_interface { + SupportedIbcInterface::IbcSolidity => header.encode_as::(), + SupportedIbcInterface::IbcMoveAptos => header.encode_as::(), + }) + .map(Hex) + } + + #[instrument(skip_all)] + async fn encode_proof(&self, proof: Value) -> RpcResult>> { + debug!(%proof, "encoding proof"); + + serde_json::from_value::(proof) + .map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to deserialize proof: {}", ErrorReporter(err)), + None::<()>, + ) + }) + .map(|cs| match self.ctx.ibc_interface { + SupportedIbcInterface::IbcSolidity => { + unionlabs::union::ics23::merkle_proof::MerkleProof::try_from( + protos::ibc::core::commitment::v1::MerkleProof::from(cs), + ) + .unwrap() + .encode_as::() + } + SupportedIbcInterface::IbcMoveAptos => { + // TODO: Currently disabled, test this later + unionlabs::union::ics23::merkle_proof::MerkleProof::try_from( + protos::ibc::core::commitment::v1::MerkleProof::from(cs), + ) + .unwrap() + .encode_as::() + } + }) + .map(Hex) + } +} diff --git a/voyager/modules/client/ethereum/Cargo.toml b/voyager/modules/client/ethereum/Cargo.toml new file mode 100644 index 0000000000..a4e1e09067 --- /dev/null +++ b/voyager/modules/client/ethereum/Cargo.toml @@ -0,0 +1,24 @@ +[package] +edition = "2021" +name = "voyager-client-module-ethereum" +version = "0.1.0" + +[dependencies] +chain-utils = { workspace = true } +enumorph = { workspace = true } +frunk = { workspace = true } +futures = { workspace = true } +jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } +macros = { workspace = true } +prost = { workspace = true } +protos = { workspace = true } +queue-msg = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +serde_json = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +unionlabs = { workspace = true } +voyager-message = { workspace = true } diff --git a/voyager/modules/client/ethereum/src/call.rs b/voyager/modules/client/ethereum/src/call.rs new file mode 100644 index 0000000000..9bb6889adc --- /dev/null +++ b/voyager/modules/client/ethereum/src/call.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCall {} diff --git a/voyager/modules/client/ethereum/src/callback.rs b/voyager/modules/client/ethereum/src/callback.rs new file mode 100644 index 0000000000..e3dbf95927 --- /dev/null +++ b/voyager/modules/client/ethereum/src/callback.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCallback {} diff --git a/voyager/modules/client/ethereum/src/data.rs b/voyager/modules/client/ethereum/src/data.rs new file mode 100644 index 0000000000..063c8f7f1d --- /dev/null +++ b/voyager/modules/client/ethereum/src/data.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleData {} diff --git a/voyager/modules/client/ethereum/src/main.rs b/voyager/modules/client/ethereum/src/main.rs new file mode 100644 index 0000000000..c83386db58 --- /dev/null +++ b/voyager/modules/client/ethereum/src/main.rs @@ -0,0 +1,331 @@ +use std::collections::VecDeque; + +use chain_utils::ethereum::ETHEREUM_REVISION_NUMBER; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + types::ErrorObject, +}; +use queue_msg::Op; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; +use serde_utils::Hex; +use tracing::instrument; +use unionlabs::{ + self, + encoding::{DecodeAs, EncodeAs, EthAbi, Proto}, + ethereum::config::PresetBaseKind, + google::protobuf::any::Any, + ibc::{ + core::client::height::Height, + lightclients::{ + cometbls, + ethereum::{self, header::UnboundedHeader, storage_proof::StorageProof}, + wasm, + }, + }, + ErrorReporter, +}; +use voyager_message::{ + data::Data, + module::{ + ClientModuleInfo, ClientModuleServer, ClientStateMeta, ConsensusStateMeta, + IbcGo08WasmClientMetadata, ModuleInfo, QueueInteractionsServer, + }, + run_module_server, ChainId, ClientType, DefaultCmd, IbcInterface, ModuleContext, ModuleServer, + VoyagerMessage, FATAL_JSONRPC_ERROR_CODE, +}; + +use crate::{call::ModuleCall, callback::ModuleCallback, data::ModuleData}; + +pub mod call; +pub mod callback; +pub mod data; + +const SUPPORTED_IBC_INTERFACE: IbcInterface<'static> = + IbcInterface::new_static(IbcInterface::IBC_GO_V8_08_WASM); + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + run_module_server::().await +} + +#[derive(Debug, Clone)] +pub struct Module { + pub chain_spec: PresetBaseKind, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Config { + pub chain_spec: PresetBaseKind, +} + +impl ModuleContext for Module { + type Config = Config; + type Cmd = DefaultCmd; + type Info = ClientModuleInfo; + + async fn new(config: Self::Config) -> Result { + Ok(Self { + chain_spec: config.chain_spec, + }) + } + + fn info(config: Self::Config) -> ModuleInfo { + ModuleInfo { + name: plugin_name(config.chain_spec), + kind: ClientModuleInfo { + client_type: ClientType::new_static(match config.chain_spec { + PresetBaseKind::Minimal => ClientType::ETHEREUM_MINIMAL, + PresetBaseKind::Mainnet => ClientType::ETHEREUM_MAINNET, + }), + ibc_interface: SUPPORTED_IBC_INTERFACE, + }, + } + } + + async fn cmd(_config: Self::Config, cmd: Self::Cmd) { + match cmd {} + } +} + +fn plugin_name(chain_spec: PresetBaseKind) -> String { + pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); + + format!("{PLUGIN_NAME}/{chain_spec}/{SUPPORTED_IBC_INTERFACE}",) +} + +type SelfConsensusState = + Any>; +type SelfClientState = Any>; + +impl Module { + pub fn decode_consensus_state(consensus_state: &[u8]) -> RpcResult { + SelfConsensusState::decode_as::(consensus_state).map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to decode consensus state: {}", ErrorReporter(err)), + None::<()>, + ) + }) + } + + pub fn decode_client_state(client_state: &[u8]) -> RpcResult { + ::decode_as::(client_state).map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to decode client state: {}", ErrorReporter(err)), + None::<()>, + ) + }) + } + + pub fn make_height(revision_height: u64) -> Height { + Height { + revision_number: ETHEREUM_REVISION_NUMBER, + revision_height, + } + } +} + +#[derive(Debug, thiserror::Error)] +pub enum ModuleInitError {} + +#[async_trait] +impl QueueInteractionsServer for ModuleServer { + #[instrument] + async fn call( + &self, + msg: ModuleCall, + ) -> RpcResult>> { + match msg {} + } + + #[instrument] + async fn callback( + &self, + callback: ModuleCallback, + _data: VecDeque>, + ) -> RpcResult>> { + match callback {} + } +} + +#[async_trait] +impl ClientModuleServer for ModuleServer { + #[instrument] + async fn supported_interface(&self) -> RpcResult { + Ok(ClientModuleInfo { + client_type: ClientType::new_static(match self.ctx.chain_spec { + PresetBaseKind::Minimal => ClientType::ETHEREUM_MINIMAL, + PresetBaseKind::Mainnet => ClientType::ETHEREUM_MAINNET, + }), + ibc_interface: SUPPORTED_IBC_INTERFACE, + }) + } + + #[instrument] + async fn decode_client_state_meta( + &self, + client_state: Hex>, + ) -> RpcResult { + let cs = Module::decode_client_state(&client_state.0)?; + + Ok(ClientStateMeta { + chain_id: ChainId::new(cs.0.data.chain_id.to_string()), + height: Module::make_height(cs.0.data.latest_slot), + }) + } + + #[instrument] + async fn decode_consensus_state_meta( + &self, + consensus_state: Hex>, + ) -> RpcResult { + let cs = Module::decode_consensus_state(&consensus_state.0)?; + + Ok(ConsensusStateMeta { + timestamp_nanos: cs.0.data.timestamp, + }) + } + + #[instrument] + async fn decode_client_state(&self, client_state: Hex>) -> RpcResult { + Ok(serde_json::to_value(Module::decode_client_state(&client_state.0)?).unwrap()) + } + + #[instrument] + async fn decode_consensus_state(&self, consensus_state: Hex>) -> RpcResult { + Ok(serde_json::to_value(Module::decode_consensus_state(&consensus_state.0)?).unwrap()) + } + + #[instrument] + async fn encode_client_state( + &self, + client_state: Value, + metadata: Value, + ) -> RpcResult>> { + let IbcGo08WasmClientMetadata { checksum } = + serde_json::from_value(metadata).map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to deserialize metadata: {}", ErrorReporter(err)), + None::<()>, + ) + })?; + + serde_json::from_value::(client_state) + .map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to deserialize client state: {}", ErrorReporter(err)), + None::<()>, + ) + }) + .map(|cs| { + Any(wasm::client_state::ClientState { + latest_height: Module::make_height(cs.latest_slot), + data: cs, + checksum, + }) + .encode_as::() + }) + .map(Hex) + } + + #[instrument] + async fn encode_consensus_state(&self, consensus_state: Value) -> RpcResult>> { + serde_json::from_value::(consensus_state) + .map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!( + "unable to deserialize consensus state: {}", + ErrorReporter(err) + ), + None::<()>, + ) + }) + .map(|cs| Any(wasm::consensus_state::ConsensusState { data: cs }).encode_as::()) + .map(Hex) + } + + #[instrument(skip_all)] + async fn reencode_counterparty_client_state( + &self, + client_state: Hex>, + client_type: ClientType<'static>, + ) -> RpcResult>> { + match client_type.as_str() { + ClientType::COMETBLS => Ok(Hex(Any(cometbls::client_state::ClientState::decode_as::< + EthAbi, + >(&client_state.0) + .map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to decode client state: {}", ErrorReporter(err)), + Some(json!({ + "client_type": client_type, + })), + ) + })?) + .encode_as::())), + _ => Ok(client_state), + } + } + + #[instrument(skip_all)] + async fn reencode_counterparty_consensus_state( + &self, + consensus_state: Hex>, + client_type: ClientType<'static>, + ) -> RpcResult>> { + match client_type.as_str() { + ClientType::COMETBLS => Ok(Hex(Any(wasm::consensus_state::ConsensusState { + data: cometbls::consensus_state::ConsensusState::decode_as::( + &consensus_state.0, + ) + .map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to decode client state: {}", ErrorReporter(err)), + Some(json!({ + "client_type": client_type, + })), + ) + })?, + }) + .encode_as::())), + _ => Ok(consensus_state), + } + } + + #[instrument] + async fn encode_header(&self, header: Value) -> RpcResult>> { + serde_json::from_value::(header) + .map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to deserialize header: {}", ErrorReporter(err)), + None::<()>, + ) + }) + .map(|header| { + Any(wasm::client_message::ClientMessage { data: header }).encode_as::() + }) + .map(Hex) + } + + #[instrument] + async fn encode_proof(&self, proof: Value) -> RpcResult>> { + serde_json::from_value::(proof) + .map_err(|err| { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!("unable to deserialize proof: {}", ErrorReporter(err)), + None::<()>, + ) + }) + .map(|cs| cs.encode_as::()) + .map(Hex) + } +} diff --git a/voyager/modules/consensus/cometbls/Cargo.toml b/voyager/modules/consensus/cometbls/Cargo.toml new file mode 100644 index 0000000000..6db692b6a2 --- /dev/null +++ b/voyager/modules/consensus/cometbls/Cargo.toml @@ -0,0 +1,25 @@ +[package] +edition = "2021" +name = "voyager-consensus-module-cometbls" +version = "0.1.0" + +[dependencies] +cometbft-rpc = { workspace = true } +dashmap = { workspace = true } +enumorph = { workspace = true } +frunk = { workspace = true } +futures = { workspace = true } +jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } +macros = { workspace = true } +num-bigint = { workspace = true } +prost = { workspace = true } +protos = { workspace = true } +queue-msg = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +unionlabs = { workspace = true } +voyager-message = { workspace = true } diff --git a/voyager/modules/consensus/cometbls/src/call.rs b/voyager/modules/consensus/cometbls/src/call.rs new file mode 100644 index 0000000000..ec9f023ef8 --- /dev/null +++ b/voyager/modules/consensus/cometbls/src/call.rs @@ -0,0 +1,37 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; +use unionlabs::{ibc::core::client::height::Height, union::galois::prove_request::ProveRequest}; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCall { + FetchUntrustedCommit(FetchUntrustedCommit), + FetchTrustedValidators(FetchTrustedValidators), + FetchUntrustedValidators(FetchUntrustedValidators), + FetchProveRequest(FetchProveRequest), +} + +#[queue_msg] +pub struct FetchTrustedCommit { + pub height: Height, +} + +#[queue_msg] +pub struct FetchUntrustedCommit { + pub height: Height, +} + +#[queue_msg] +pub struct FetchTrustedValidators { + pub height: Height, +} + +#[queue_msg] +pub struct FetchUntrustedValidators { + pub height: Height, +} + +#[queue_msg] +pub struct FetchProveRequest { + pub request: ProveRequest, +} diff --git a/voyager/modules/consensus/cometbls/src/callback.rs b/voyager/modules/consensus/cometbls/src/callback.rs new file mode 100644 index 0000000000..af6f01168d --- /dev/null +++ b/voyager/modules/consensus/cometbls/src/callback.rs @@ -0,0 +1,284 @@ +use std::collections::HashMap; + +use enumorph::Enumorph; +use frunk::{hlist_pat, HList}; +use num_bigint::BigUint; +use queue_msg::{aggregation::DoCallback, call, data, promise, queue_msg, Op}; +use tracing::{debug, trace}; +use unionlabs::{ + bounded::BoundedI64, + cometbls::types::canonical_vote::CanonicalVote, + ibc::{ + core::client::height::Height, + lightclients::cometbls::{header::Header, light_header::LightHeader}, + }, + tendermint::{ + crypto::public_key::PublicKey, + types::{ + canonical_block_header::CanonicalPartSetHeader, canonical_block_id::CanonicalBlockId, + commit_sig::CommitSig, signed_header::SignedHeader, signed_msg_type::SignedMsgType, + simple_validator::SimpleValidator, + }, + }, + union::galois::{prove_request::ProveRequest, validator_set_commit::ValidatorSetCommit}, +}; +use voyager_message::{ + call::Call, + callback::Callback, + data::{DecodedHeaderMeta, OrderedHeaders}, + ChainId, PluginMessage, VoyagerMessage, +}; + +use crate::{ + call::{FetchProveRequest, ModuleCall}, + data::{ModuleData, ProveResponse, TrustedValidators, UntrustedCommit, UntrustedValidators}, +}; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCallback { + AggregateProveRequest(AggregateProveRequest), + AggregateHeader(AggregateHeader), +} + +#[queue_msg] +pub struct AggregateProveRequest { + pub chain_id: ChainId<'static>, + + pub update_from: Height, + pub update_to: Height, +} + +#[queue_msg] +pub struct AggregateHeader { + pub chain_id: ChainId<'static>, + + pub signed_header: SignedHeader, + + pub update_from: Height, + pub update_to: Height, +} + +impl DoCallback> for AggregateProveRequest { + type Params = HList![ + PluginMessage, + PluginMessage, + PluginMessage + ]; + + fn call( + AggregateProveRequest { + chain_id, + update_from, + update_to, + }: Self, + hlist_pat![ + PluginMessage { + plugin: plugin_name, + message: UntrustedCommit { + height: _untrusted_commit_height, + signed_header, + } + }, + PluginMessage { + plugin: _, + message: TrustedValidators { + height: _trusted_validators_height, + validators: trusted_validators, + } + }, + PluginMessage { + plugin: _, + message: UntrustedValidators { + height: _untrusted_validators_height, + validators: untrusted_validators, + } + }, + ]: Self::Params, + ) -> Op> { + let make_validators_commit = + |mut validators: Vec| { + // Validators must be sorted to match the root, by token then address + validators.sort_by(|a, b| { + // TODO: Double check how these comparisons are supposed to work + #[allow(clippy::collapsible_else_if)] + if a.voting_power == b.voting_power { + if a.address < b.address { + std::cmp::Ordering::Less + } else { + std::cmp::Ordering::Greater + } + } else { + if a.voting_power > b.voting_power { + std::cmp::Ordering::Less + } else { + std::cmp::Ordering::Greater + } + } + }); + + // The bitmap is a public input of the circuit, it must fit in Fr (scalar field) bn254 + let mut bitmap = BigUint::default(); + // REVIEW: This will over-allocate for the trusted validators; should be benchmarked + let mut signatures = Vec::>::with_capacity(validators.len()); + + let validators_map = validators + .iter() + .enumerate() + .map(|(i, v)| (v.address, i)) + .collect::>(); + + // For each validator signature, we search for the actual validator + // in the set and set it's signed bit to 1. We then push the + // signature only if the validator signed. It's possible that we + // don't find a validator for a given signature as the validator set + // may have drifted (trusted validator set). + for sig in signed_header.commit.signatures.iter() { + match sig { + CommitSig::Absent => { + debug!("validator did not sign"); + } + CommitSig::Commit { + validator_address, + timestamp: _, + signature, + } => { + if let Some(validator_index) = validators_map.get(validator_address) { + bitmap.set_bit(*validator_index as u64, true); + signatures.push(signature.clone()); + trace!( + %validator_address, + %validator_index, + "validator signed" + ); + } else { + trace!( + %validator_address, + "validator set drifted, could not find validator signature" + ); + } + } + CommitSig::Nil { + validator_address, .. + } => { + trace!( + %validator_address, + "validator commit is nil" + ); + } + } + } + + let simple_validators = validators + .iter() + .map(|v| { + let PublicKey::Bn254(ref key) = v.pub_key else { + panic!("must be bn254") + }; + SimpleValidator { + pub_key: PublicKey::Bn254(key.to_vec()), + voting_power: v.voting_power.into(), + } + }) + .collect::>(); + + ValidatorSetCommit { + validators: simple_validators, + signatures, + bitmap: bitmap.to_bytes_be(), + } + }; + + let trusted_validators_commit = make_validators_commit(trusted_validators); + let untrusted_validators_commit = make_validators_commit(untrusted_validators); + + promise( + [call(Call::plugin( + &plugin_name, + FetchProveRequest { + request: ProveRequest { + vote: CanonicalVote { + // REVIEW: Should this be hardcoded to precommit? + ty: SignedMsgType::Precommit, + height: signed_header.commit.height, + round: BoundedI64::new(signed_header.commit.round.inner().into()) + .expect("0..=i32::MAX can be converted to 0..=i64::MAX safely"), + block_id: CanonicalBlockId { + hash: signed_header.commit.block_id.hash.unwrap_or_default(), + part_set_header: CanonicalPartSetHeader { + total: signed_header.commit.block_id.part_set_header.total, + hash: signed_header + .commit + .block_id + .part_set_header + .hash + .unwrap_or_default(), + }, + }, + chain_id: signed_header.header.chain_id.clone(), + }, + untrusted_header: signed_header.header.clone(), + trusted_commit: trusted_validators_commit, + untrusted_commit: untrusted_validators_commit, + }, + }, + ))], + [], + Callback::plugin( + &plugin_name, + AggregateHeader { + chain_id, + signed_header, + update_from, + update_to, + }, + ), + ) + } +} + +impl DoCallback> for AggregateHeader { + type Params = HList![PluginMessage]; + + fn call( + AggregateHeader { + mut signed_header, + chain_id: _, + update_from, + update_to: _, + }: Self, + hlist_pat![PluginMessage { + plugin: _, + message: ProveResponse { + prove_response: response, + } + }]: Self::Params, + ) -> Op> { + // TODO: maybe introduce a new commit for union signed header as we don't need the signatures but the ZKP only + // Keeping this signatures significantly increase the size of the structure and the associated gas cost in EVM (calldata). + signed_header.commit.signatures.clear(); + + data(OrderedHeaders { + headers: vec![( + DecodedHeaderMeta { + height: Height { + revision_number: update_from.revision_number, + revision_height: signed_header.header.height.inner().try_into().unwrap(), + }, + }, + serde_json::to_value(Header { + signed_header: LightHeader { + height: signed_header.header.height, + time: signed_header.header.time, + validators_hash: signed_header.header.validators_hash, + next_validators_hash: signed_header.header.next_validators_hash, + app_hash: signed_header.header.app_hash, + }, + trusted_height: update_from, + zero_knowledge_proof: response.proof.evm_proof, + }) + .unwrap(), + )], + }) + } +} diff --git a/voyager/modules/consensus/cometbls/src/data.rs b/voyager/modules/consensus/cometbls/src/data.rs new file mode 100644 index 0000000000..774651e5cd --- /dev/null +++ b/voyager/modules/consensus/cometbls/src/data.rs @@ -0,0 +1,45 @@ +use enumorph::Enumorph; +use queue_msg::{queue_msg, SubsetOf}; +use unionlabs::{ + ibc::core::client::height::Height, + tendermint::types::{signed_header::SignedHeader, validator::Validator}, + union::galois::prove_response, +}; + +#[queue_msg] +#[derive(Enumorph, SubsetOf)] +pub enum ModuleData { + UntrustedCommit(UntrustedCommit), + TrustedValidators(TrustedValidators), + UntrustedValidators(UntrustedValidators), + ProveResponse(ProveResponse), +} + +#[queue_msg] +pub struct UntrustedCommit { + pub height: Height, + pub signed_header: SignedHeader, +} + +#[queue_msg] +pub struct TrustedCommit { + pub height: Height, + pub signed_header: SignedHeader, +} + +#[queue_msg] +pub struct TrustedValidators { + pub height: Height, + pub validators: Vec, +} + +#[queue_msg] +pub struct UntrustedValidators { + pub height: Height, + pub validators: Vec, +} + +#[queue_msg] +pub struct ProveResponse { + pub prove_response: prove_response::ProveResponse, +} diff --git a/voyager/modules/consensus/cometbls/src/main.rs b/voyager/modules/consensus/cometbls/src/main.rs new file mode 100644 index 0000000000..0947a02339 --- /dev/null +++ b/voyager/modules/consensus/cometbls/src/main.rs @@ -0,0 +1,397 @@ +use std::{ + collections::VecDeque, + fmt::Debug, + num::{NonZeroU64, ParseIntError}, +}; + +use jsonrpsee::core::{async_trait, RpcResult}; +use protos::union::galois::api::v3::union_prover_api_client; +use queue_msg::{call, data, defer, now, promise, seq, void, BoxDynError, Op}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use tracing::{debug, error, info, instrument}; +use unionlabs::{ + ibc::{ + core::{client::height::Height, commitment::merkle_root::MerkleRoot}, + lightclients::cometbls::{client_state::ClientState, consensus_state::ConsensusState}, + }, + traits::Member, + union::galois::{ + poll_request::PollRequest, + poll_response::{PollResponse, ProveRequestDone, ProveRequestFailed}, + }, +}; +use voyager_message::{ + call::{Call, WaitForHeight}, + callback::Callback, + data::Data, + module::{ConsensusModuleInfo, ConsensusModuleServer, ModuleInfo, QueueInteractionsServer}, + run_module_server, ChainId, ClientType, DefaultCmd, ModuleContext, ModuleServer, + VoyagerMessage, +}; + +use crate::{ + call::{ + FetchProveRequest, FetchTrustedValidators, FetchUntrustedCommit, FetchUntrustedValidators, + ModuleCall, + }, + callback::{AggregateProveRequest, ModuleCallback}, + data::{ModuleData, ProveResponse, TrustedValidators, UntrustedCommit, UntrustedValidators}, +}; + +pub mod call; +pub mod callback; +pub mod data; + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + run_module_server::().await +} + +#[derive(Debug, Clone)] +pub struct Module { + pub chain_id: ChainId<'static>, + + pub tm_client: cometbft_rpc::Client, + pub chain_revision: u64, + pub grpc_url: String, + + pub prover_endpoints: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Config { + pub chain_id: ChainId<'static>, + + pub ws_url: String, + pub grpc_url: String, + + pub prover_endpoints: Vec, +} + +impl ModuleContext for Module { + type Config = Config; + type Cmd = DefaultCmd; + type Info = ConsensusModuleInfo; + + async fn new(config: Self::Config) -> Result { + let tm_client = cometbft_rpc::Client::new(config.ws_url).await?; + + let chain_id = tm_client.status().await?.node_info.network.to_string(); + + if chain_id != config.chain_id.as_str() { + return Err(format!( + "incorrect chain id: expected `{}`, but found `{}`", + config.chain_id, chain_id + ) + .into()); + } + + let chain_revision = chain_id + .split('-') + .last() + .ok_or_else(|| ChainIdParseError { + found: chain_id.clone(), + source: None, + })? + .parse() + .map_err(|err| ChainIdParseError { + found: chain_id.clone(), + source: Some(err), + })?; + + Ok(Self { + tm_client, + chain_id: ChainId::new(chain_id), + chain_revision, + prover_endpoints: config.prover_endpoints, + grpc_url: config.grpc_url, + }) + } + + fn info(config: Self::Config) -> ModuleInfo { + ModuleInfo { + name: plugin_name(&config.chain_id), + kind: ConsensusModuleInfo { + chain_id: config.chain_id, + client_type: ClientType::new(ClientType::COMETBLS), + }, + } + } + + async fn cmd(_config: Self::Config, cmd: Self::Cmd) { + match cmd {} + } +} + +fn plugin_name(chain_id: &ChainId<'_>) -> String { + pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); + + format!("{PLUGIN_NAME}/{}", chain_id) +} + +impl Module { + fn plugin_name(&self) -> String { + plugin_name(&self.chain_id) + } +} + +#[derive(Debug, thiserror::Error)] +#[error("unable to parse chain id: expected format `-`, found `{found}`")] +pub struct ChainIdParseError { + found: String, + #[source] + source: Option, +} + +#[async_trait] +impl QueueInteractionsServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn call( + &self, + msg: ModuleCall, + ) -> RpcResult>> { + match msg { + ModuleCall::FetchUntrustedCommit(FetchUntrustedCommit { height }) => { + let commit = self + .ctx + .tm_client + .commit(Some(height.revision_height.try_into().unwrap())) + .await + .unwrap(); + + Ok(data(Data::plugin( + self.ctx.plugin_name(), + UntrustedCommit { + height, + signed_header: commit.signed_header, + }, + ))) + } + ModuleCall::FetchTrustedValidators(FetchTrustedValidators { height }) => { + let validators = self + .ctx + .tm_client + .all_validators(Some(height.revision_height.try_into().unwrap())) + .await + .unwrap() + .validators; + + Ok(data(Data::plugin( + self.ctx.plugin_name(), + TrustedValidators { height, validators }, + ))) + } + ModuleCall::FetchUntrustedValidators(FetchUntrustedValidators { height }) => { + let validators = self + .ctx + .tm_client + .all_validators(Some(height.revision_height.try_into().unwrap())) + .await + .unwrap() + .validators; + + Ok(data(Data::plugin( + self.ctx.plugin_name(), + UntrustedValidators { height, validators }, + ))) + } + ModuleCall::FetchProveRequest(FetchProveRequest { request }) => { + debug!("submitting prove request"); + + let prover_endpoint = &self.ctx.prover_endpoints[usize::try_from( + request.untrusted_header.height.inner(), + ) + .expect("never going to happen bro") + % self.ctx.prover_endpoints.len()]; + + let response = + union_prover_api_client::UnionProverApiClient::connect(prover_endpoint.clone()) + .await + .unwrap() + .poll(protos::union::galois::api::v3::PollRequest::from( + PollRequest { + request: request.clone(), + }, + )) + .await + .map(|x| x.into_inner().try_into().unwrap()); + + debug!("submitted prove request"); + + let retry = || { + debug!("proof pending"); + + seq([ + // REVIEW: How long should we wait between polls? + defer(now() + 1), + call(Call::plugin( + self.ctx.plugin_name(), + FetchProveRequest { request }, + )), + ]) + }; + match response { + Ok(PollResponse::Pending) => Ok(retry()), + Err(status) if status.message() == "busy_building" => Ok(retry()), + Err(err) => panic!("prove request failed: {:?}", err), + Ok(PollResponse::Failed(ProveRequestFailed { message })) => { + error!(%message, "prove request failed"); + panic!() + } + Ok(PollResponse::Done(ProveRequestDone { response })) => { + info!(prover = %prover_endpoint, "proof generated"); + + Ok(data(Data::plugin( + self.ctx.plugin_name(), + ProveResponse { + prove_response: response, + }, + ))) + } + } + } + } + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn callback( + &self, + callback: ModuleCallback, + data: VecDeque>, + ) -> RpcResult>> { + Ok(match callback { + ModuleCallback::AggregateProveRequest(aggregate) => { + queue_msg::aggregation::do_callback(aggregate, data) + } + ModuleCallback::AggregateHeader(aggregate) => { + queue_msg::aggregation::do_callback(aggregate, data) + } + }) + } +} + +#[async_trait] +impl ConsensusModuleServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn consensus_info(&self) -> RpcResult { + Ok(ConsensusModuleInfo { + chain_id: self.ctx.chain_id.clone(), + client_type: ClientType::new(ClientType::COMETBLS), + }) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn self_client_state(&self, height: Height) -> RpcResult { + let params = protos::cosmos::staking::v1beta1::query_client::QueryClient::connect( + self.ctx.grpc_url.clone(), + ) + .await + .unwrap() + .params(protos::cosmos::staking::v1beta1::QueryParamsRequest {}) + .await + .unwrap() + .into_inner() + .params + .unwrap(); + + let commit = self + .ctx + .tm_client + .commit(Some(NonZeroU64::new(height.revision_height).unwrap())) + .await + .unwrap(); + + let height = commit.signed_header.header.height; + + // Expected to be nanos + let unbonding_period = + u64::try_from(params.unbonding_time.clone().unwrap().seconds).unwrap() * 1_000_000_000; + + Ok(serde_json::to_value(ClientState { + chain_id: self.ctx.chain_id.to_string(), + trusting_period: unbonding_period * 85 / 100, + unbonding_period, + max_clock_drift: (60 * 20) * 1_000_000_000, + frozen_height: Height { + revision_number: 0, + revision_height: 0, + }, + latest_height: Height { + revision_number: self + .ctx + .chain_id + .as_str() + .split('-') + .last() + .unwrap() + .parse() + .unwrap(), + revision_height: height.inner().try_into().expect("value is >= 0; qed;"), + }, + }) + .unwrap()) + } + + /// The consensus state on this chain at the specified `Height`. + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn self_consensus_state(&self, height: Height) -> RpcResult { + let commit = self + .ctx + .tm_client + .commit(Some(NonZeroU64::new(height.revision_height).unwrap())) + .await + .unwrap(); + + Ok(serde_json::to_value(ConsensusState { + timestamp: commit.signed_header.header.time.as_unix_nanos(), + app_hash: MerkleRoot { + hash: commit.signed_header.header.app_hash, + }, + next_validators_hash: commit.signed_header.header.next_validators_hash, + }) + .unwrap()) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn fetch_update_headers( + &self, + update_from: Height, + update_to: Height, + _counterparty_chain_id: ChainId<'static>, + ) -> RpcResult>> { + Ok(seq([ + void(call(WaitForHeight { + chain_id: self.ctx.chain_id.clone(), + height: update_to, + })), + promise( + [ + call(Call::plugin( + self.ctx.plugin_name(), + FetchUntrustedCommit { height: update_to }, + )), + call(Call::plugin( + self.ctx.plugin_name(), + FetchUntrustedValidators { height: update_to }, + )), + call(Call::plugin( + self.ctx.plugin_name(), + FetchTrustedValidators { + height: update_from.increment(), + }, + )), + ], + [], + Callback::plugin( + self.ctx.plugin_name(), + AggregateProveRequest { + chain_id: self.ctx.chain_id.clone(), + update_from, + update_to, + }, + ), + ), + ])) + } +} diff --git a/voyager/modules/consensus/ethereum/Cargo.toml b/voyager/modules/consensus/ethereum/Cargo.toml new file mode 100644 index 0000000000..b33d78b62a --- /dev/null +++ b/voyager/modules/consensus/ethereum/Cargo.toml @@ -0,0 +1,28 @@ +[package] +edition = "2021" +name = "voyager-consensus-module-ethereum" +version = "0.1.0" + +[dependencies] +beacon-api = { workspace = true } +bitvec = { workspace = true } +chain-utils = { workspace = true } +enumorph = { workspace = true } +ethereum-verifier = { workspace = true } +ethers = { workspace = true, features = ["rustls", "ws"] } +frunk = { workspace = true } +futures = { workspace = true } +jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } +macros = { workspace = true } +num-bigint = { workspace = true } +prost = { workspace = true } +protos = { workspace = true } +queue-msg = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +unionlabs = { workspace = true } +voyager-message = { workspace = true } diff --git a/voyager/modules/consensus/ethereum/src/call.rs b/voyager/modules/consensus/ethereum/src/call.rs new file mode 100644 index 0000000000..c1039c6c98 --- /dev/null +++ b/voyager/modules/consensus/ethereum/src/call.rs @@ -0,0 +1,44 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCall { + FetchLightClientUpdate(FetchLightClientUpdate), + FetchFinalityUpdate(FetchFinalityUpdate), + FetchLightClientUpdates(FetchLightClientUpdates), + FetchBootstrap(FetchBootstrap), + FetchAccountUpdate(FetchAccountUpdate), + FetchBeaconGenesis(FetchBeaconGenesis), + FetchBeaconSpec(FetchBeaconSpec), +} + +#[queue_msg] +pub struct FetchLightClientUpdate { + pub period: u64, +} + +#[queue_msg] +pub struct FetchFinalityUpdate {} + +#[queue_msg] +pub struct FetchLightClientUpdates { + pub trusted_period: u64, + pub target_period: u64, +} + +#[queue_msg] +pub struct FetchBootstrap { + pub slot: u64, +} + +#[queue_msg] +pub struct FetchAccountUpdate { + pub slot: u64, +} + +#[queue_msg] +pub struct FetchBeaconGenesis {} + +#[queue_msg] +pub struct FetchBeaconSpec {} diff --git a/voyager/modules/consensus/ethereum/src/callback.rs b/voyager/modules/consensus/ethereum/src/callback.rs new file mode 100644 index 0000000000..e3dbf95927 --- /dev/null +++ b/voyager/modules/consensus/ethereum/src/callback.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCallback {} diff --git a/voyager/modules/consensus/ethereum/src/data.rs b/voyager/modules/consensus/ethereum/src/data.rs new file mode 100644 index 0000000000..71b956a167 --- /dev/null +++ b/voyager/modules/consensus/ethereum/src/data.rs @@ -0,0 +1,68 @@ +use beacon_api::types::Spec; +use enumorph::Enumorph; +use queue_msg::{queue_msg, SubsetOf}; +use unionlabs::{ + ethereum::beacon::{ + genesis_data::GenesisData, light_client_bootstrap::UnboundedLightClientBootstrap, + light_client_finality_update::UnboundedLightClientFinalityUpdate, + }, + ibc::lightclients::ethereum::{ + account_update::AccountUpdate, header::UnboundedHeader, + light_client_update::UnboundedLightClientUpdate, + }, +}; + +#[queue_msg] +#[derive(Enumorph, SubsetOf)] +pub enum ModuleData { + FinalityUpdate(FinalityUpdate), + LightClientUpdates(LightClientUpdates), + LightClientUpdate(LightClientUpdate), + Bootstrap(BootstrapData), + AccountUpdate(AccountUpdateData), + BeaconGenesis(BeaconGenesis), + BeaconSpec(BeaconSpec), + Header(Header), +} + +#[queue_msg] +pub struct BootstrapData { + pub slot: u64, + pub bootstrap: UnboundedLightClientBootstrap, +} + +#[queue_msg] +pub struct AccountUpdateData { + pub slot: u64, + pub update: AccountUpdate, +} + +#[queue_msg] +pub struct BeaconGenesis { + pub genesis: GenesisData, +} + +#[queue_msg] +pub struct FinalityUpdate { + pub finality_update: UnboundedLightClientFinalityUpdate, +} + +#[queue_msg] +pub struct LightClientUpdates { + pub light_client_updates: Vec, +} + +#[queue_msg] +pub struct LightClientUpdate { + pub update: UnboundedLightClientUpdate, +} + +#[queue_msg] +pub struct Header { + pub header: UnboundedHeader, +} + +#[queue_msg] +pub struct BeaconSpec { + pub spec: Spec, +} diff --git a/voyager/modules/consensus/ethereum/src/main.rs b/voyager/modules/consensus/ethereum/src/main.rs new file mode 100644 index 0000000000..44765c2628 --- /dev/null +++ b/voyager/modules/consensus/ethereum/src/main.rs @@ -0,0 +1,795 @@ +use std::{collections::VecDeque, ops::Div}; + +use beacon_api::{client::BeaconApiClient, types::Spec}; +use bitvec::{order::Msb0, vec::BitVec}; +use chain_utils::{ethereum::ETHEREUM_REVISION_NUMBER, BoxDynError}; +use ethers::providers::{Middleware, Provider, ProviderError, Ws, WsClientError}; +use futures::{stream, StreamExt}; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + types::ErrorObject, +}; +use queue_msg::{call, data, defer, now, seq, Op}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use tracing::{debug, info, instrument}; +use unionlabs::{ + constants::metric::NANOS_PER_SECOND, + ethereum::{config::PresetBaseKind, IBC_HANDLER_COMMITMENTS_SLOT}, + hash::H160, + ibc::{ + core::client::height::Height, + lightclients::ethereum::{ + self, + account_proof::AccountProof, + account_update::AccountUpdate, + header::UnboundedHeader, + light_client_update::UnboundedLightClientUpdate, + trusted_sync_committee::{UnboundedActiveSyncCommittee, UnboundedTrustedSyncCommittee}, + }, + }, + ErrorReporter, +}; +use voyager_message::{ + call::{Call, FetchUpdateHeaders, WaitForTimestamp}, + data::{Data, DecodedHeaderMeta, OrderedHeaders}, + module::{ConsensusModuleInfo, ConsensusModuleServer, ModuleInfo, QueueInteractionsServer}, + run_module_server, ChainId, ClientType, DefaultCmd, ModuleContext, ModuleServer, + VoyagerMessage, +}; + +use crate::{ + call::{ + FetchAccountUpdate, FetchBeaconGenesis, FetchBeaconSpec, FetchBootstrap, + FetchFinalityUpdate, FetchLightClientUpdate, FetchLightClientUpdates, ModuleCall, + }, + callback::ModuleCallback, + data::{ + AccountUpdateData, BeaconGenesis, BeaconSpec, BootstrapData, FinalityUpdate, + LightClientUpdates, ModuleData, + }, +}; + +pub mod call; +pub mod callback; +pub mod data; + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + run_module_server::().await +} + +#[derive(Debug, Clone)] +pub struct Module { + pub chain_id: ChainId<'static>, + + pub chain_spec: PresetBaseKind, + + /// The address of the `IBCHandler` smart contract. + pub ibc_handler_address: H160, + + pub provider: Provider, + pub beacon_api_client: BeaconApiClient, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Config { + pub chain_id: ChainId<'static>, + + pub chain_spec: PresetBaseKind, + + /// The address of the `IBCHandler` smart contract. + pub ibc_handler_address: H160, + + /// The RPC endpoint for the execution chain. + pub eth_rpc_api: String, + /// The RPC endpoint for the beacon chain. + pub eth_beacon_rpc_api: String, +} + +fn plugin_name(chain_id: &ChainId<'_>) -> String { + pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); + + format!("{PLUGIN_NAME}/{}", chain_id) +} + +impl Module { + fn plugin_name(&self) -> String { + plugin_name(&self.chain_id) + } + + pub async fn fetch_account_update(&self, slot: u64) -> AccountUpdate { + let execution_height = self + .beacon_api_client + .execution_height(beacon_api::client::BlockId::Slot(slot)) + .await + .unwrap(); + + let account_update = self + .provider + .get_proof( + ethers::types::H160::from(self.ibc_handler_address), + vec![], + // NOTE: Proofs are from the execution layer, so we use execution height, not beacon slot. + Some(execution_height.into()), + ) + .await + .unwrap(); + + AccountUpdate { + account_proof: AccountProof { + storage_root: account_update.storage_hash.into(), + proof: account_update + .account_proof + .into_iter() + .map(|x| x.to_vec()) + .collect(), + }, + } + } +} + +impl ModuleContext for Module { + type Config = Config; + type Cmd = DefaultCmd; + type Info = ConsensusModuleInfo; + + async fn new(config: Self::Config) -> Result { + let provider = Provider::new(Ws::connect(config.eth_rpc_api).await?); + + let chain_id = ChainId::new(provider.get_chainid().await?.to_string()); + + if chain_id != config.chain_id { + return Err(format!( + "incorrect chain id: expected `{}`, but found `{}`", + config.chain_id, chain_id + ) + .into()); + } + + let beacon_api_client = BeaconApiClient::new(config.eth_beacon_rpc_api).await?; + + let spec = beacon_api_client.spec().await.unwrap().data; + + if spec.preset_base != config.chain_spec { + return Err(format!( + "incorrect chain spec: expected `{}`, but found `{}`", + config.chain_spec, spec.preset_base + ) + .into()); + } + + Ok(Self { + chain_id, + chain_spec: spec.preset_base, + ibc_handler_address: config.ibc_handler_address, + provider, + beacon_api_client, + }) + } + + fn info(config: Self::Config) -> ModuleInfo { + ModuleInfo { + name: plugin_name(&config.chain_id), + kind: ConsensusModuleInfo { + chain_id: config.chain_id, + client_type: ClientType::new(match config.chain_spec { + PresetBaseKind::Minimal => ClientType::ETHEREUM_MINIMAL, + PresetBaseKind::Mainnet => ClientType::ETHEREUM_MAINNET, + }), + }, + } + } + + async fn cmd(_config: Self::Config, cmd: Self::Cmd) { + match cmd {} + } +} + +#[derive(Debug, thiserror::Error)] +pub enum ModuleInitError { + #[error("unable to connect to websocket")] + Ws(#[from] WsClientError), + #[error("provider error")] + Provider(#[from] ProviderError), + #[error("beacon error")] + Beacon(#[from] beacon_api::client::NewError), +} + +#[async_trait] +impl QueueInteractionsServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn call( + &self, + msg: ModuleCall, + ) -> RpcResult>> { + let beacon_api_client = &self.ctx.beacon_api_client; + + match msg { + ModuleCall::FetchFinalityUpdate(FetchFinalityUpdate {}) => { + let finality_update = beacon_api_client.finality_update().await.unwrap().data; + + let has_supermajority = { + let scb = BitVec::::try_from( + finality_update.sync_aggregate.sync_committee_bits.clone(), + ) + .unwrap(); + + let sync_committee_size = self + .ctx + .beacon_api_client + .spec() + .await + .unwrap() + .data + .sync_committee_size; + + assert_eq!(scb.len() as u64, sync_committee_size); + + scb.count_ones() * 3 < scb.len() * 2 + }; + + if has_supermajority { + info!( + signature_slot = finality_update.signature_slot, + "signature supermajority not hit" + ); + + Ok(seq([ + defer(now() + 1), + call(Call::plugin(self.ctx.plugin_name(), FetchFinalityUpdate {})), + ])) + } else { + Ok(data(Data::plugin( + self.ctx.plugin_name(), + FinalityUpdate { finality_update }, + ))) + } + } + ModuleCall::FetchLightClientUpdates(FetchLightClientUpdates { + trusted_period, + target_period, + }) => Ok(data(Data::plugin( + self.ctx.plugin_name(), + LightClientUpdates { + light_client_updates: beacon_api_client + .light_client_updates(trusted_period + 1, target_period - trusted_period) + .await + .unwrap() + .0 + .into_iter() + .map(|x| x.data) + .collect(), + }, + ))), + ModuleCall::FetchLightClientUpdate(FetchLightClientUpdate { period }) => { + Ok(data(Data::plugin( + self.ctx.plugin_name(), + crate::data::LightClientUpdate { + update: beacon_api_client + .light_client_updates(period, 1) + .await + .unwrap() + .0 + .into_iter() + .map(|x| x.data) + .collect::>() + .pop() + .unwrap(), + }, + ))) + } + ModuleCall::FetchBootstrap(FetchBootstrap { slot }) => Ok(data(Data::plugin( + self.ctx.plugin_name(), + BootstrapData { + slot, + bootstrap: beacon_api_client + .bootstrap_for_slot(slot) + .await + .unwrap() + .data, + }, + ))), + ModuleCall::FetchAccountUpdate(FetchAccountUpdate { slot }) => { + let execution_height = beacon_api_client + .execution_height(beacon_api::client::BlockId::Slot(slot)) + .await + .unwrap(); + + let account_update = self + .ctx + .provider + .get_proof( + ethers::types::H160::from(self.ctx.ibc_handler_address), + vec![], + // NOTE: Proofs are from the execution layer, so we use execution height, not beacon slot. + Some(execution_height.into()), + ) + .await + .unwrap(); + + Ok(data(Data::plugin( + self.ctx.plugin_name(), + AccountUpdateData { + slot, + update: AccountUpdate { + account_proof: AccountProof { + storage_root: account_update.storage_hash.into(), + proof: account_update + .account_proof + .into_iter() + .map(|x| x.to_vec()) + .collect(), + }, + }, + }, + ))) + } + ModuleCall::FetchBeaconGenesis(FetchBeaconGenesis {}) => Ok(data(Data::plugin( + self.ctx.plugin_name(), + BeaconGenesis { + genesis: beacon_api_client.genesis().await.unwrap().data, + }, + ))), + ModuleCall::FetchBeaconSpec(FetchBeaconSpec {}) => Ok(data(Data::plugin( + self.ctx.plugin_name(), + BeaconSpec { + spec: beacon_api_client.spec().await.unwrap().data, + }, + ))), + } + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn callback( + &self, + cb: ModuleCallback, + _data: VecDeque>, + ) -> RpcResult>> { + match cb { + // ModuleCallback::CreateUpdate(aggregate) => do_callback(aggregate, data), + // ModuleCallback::MakeCreateUpdates(aggregate) => do_callback(aggregate, data), + // ModuleCallback::MakeCreateUpdatesFromLightClientUpdates(aggregate) => { + // do_callback(aggregate, data) + // } + // ModuleCallback::AggregateHeaders(cb) => { + // cb.aggregate(&self.ctx.beacon_api_client, data).await? + // } + } + } +} + +#[async_trait] +impl ConsensusModuleServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn consensus_info(&self) -> RpcResult { + Ok(ConsensusModuleInfo { + chain_id: self.ctx.chain_id.clone(), + client_type: ClientType::new(match self.ctx.chain_spec { + PresetBaseKind::Minimal => ClientType::ETHEREUM_MINIMAL, + PresetBaseKind::Mainnet => ClientType::ETHEREUM_MAINNET, + }), + }) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn self_client_state(&self, height: Height) -> RpcResult { + let genesis = self.ctx.beacon_api_client.genesis().await.unwrap().data; + + let spec = self.ctx.beacon_api_client.spec().await.unwrap().data; + + Ok(serde_json::to_value(ethereum::client_state::ClientState { + chain_id: self + .ctx + .chain_id + .as_str() + .parse() + .expect("self.chain_id is a valid u256"), + genesis_validators_root: genesis.genesis_validators_root, + genesis_time: genesis.genesis_time, + fork_parameters: spec.to_fork_parameters(), + seconds_per_slot: spec.seconds_per_slot, + slots_per_epoch: spec.slots_per_epoch, + epochs_per_sync_committee_period: spec.epochs_per_sync_committee_period, + latest_slot: height.revision_height, + min_sync_committee_participants: 0, + frozen_height: Height { + revision_number: 0, + revision_height: 0, + }, + ibc_commitment_slot: IBC_HANDLER_COMMITMENTS_SLOT, + ibc_contract_address: self.ctx.ibc_handler_address, + }) + .expect("infallible")) + } + + /// The consensus state on this chain at the specified `Height`. + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn self_consensus_state(&self, height: Height) -> RpcResult { + let beacon_api_client = &self.ctx.beacon_api_client; + + let trusted_header = beacon_api_client + .header(beacon_api::client::BlockId::Slot(height.revision_height)) + .await + .unwrap() + .data; + + let bootstrap = beacon_api_client + .bootstrap(trusted_header.root) + .await + .unwrap() + .data; + + let spec = self.ctx.beacon_api_client.spec().await.unwrap().data; + + assert!(bootstrap.header.beacon.slot == height.revision_height); + + let light_client_update = { + let current_period = height.revision_height.div(spec.period()); + + debug!(%current_period); + + let light_client_updates = beacon_api_client + .light_client_updates(current_period, 1) + .await + .unwrap(); + + let [light_client_update] = &*light_client_updates.0 else { + panic!() + }; + + light_client_update.data.clone() + }; + + // Normalize to nanos in order to be compliant with cosmos + let timestamp = bootstrap.header.execution.timestamp * 1_000_000_000; + + Ok( + serde_json::to_value(ethereum::consensus_state::ConsensusState { + slot: bootstrap.header.beacon.slot, + state_root: bootstrap.header.execution.state_root, + storage_root: self + .ctx + .provider + .get_proof( + ethers::types::H160::from(self.ctx.ibc_handler_address.0), + vec![], + Some(bootstrap.header.execution.block_number.into()), + ) + .await + .unwrap() + .storage_hash + .0 + .into(), + timestamp, + current_sync_committee: bootstrap.current_sync_committee.aggregate_pubkey, + next_sync_committee: light_client_update + .next_sync_committee + .map(|nsc| nsc.aggregate_pubkey), + }) + .expect("infallible"), + ) + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn fetch_update_headers( + &self, + update_from: Height, + update_to: Height, + counterparty_chain_id: ChainId<'static>, + ) -> RpcResult>> { + // Ok(promise( + // [ + // call(Call::plugin(self.ctx.plugin_name(), FetchFinalityUpdate {})), + // call(Call::plugin(self.ctx.plugin_name(), FetchBeaconSpec {})), + // ], + // [], + // Callback::plugin( + // self.ctx.plugin_name(), + // MakeCreateUpdates { + // update_from, + // update_to, + // counterparty_chain_id, + // }, + // ), + // )) + + self.ctx + .fetch_update(update_from, update_to, counterparty_chain_id) + .await + .map_err(|e| { + ErrorObject::owned( + -1, + format!("error fetching update: {}", ErrorReporter(&*e)), + None::<()>, + ) + }) + } +} + +impl Module { + /// Fetch a client update from the provided trusted height (`update_from`) to at least the desired new height (`update_to`). + /// + /// Note that this will generate updates as close to the tip of the chain as possible, as long as that height is > `update_to`. Due to the nature of ethereum finality, it is not possible to update to a *specific* height in the same way as is possible in chains with single slot finality (such as tendermint or cometbls). While it would be possible to update to a height *closer* to `update_to`, the extra complexity brought by that is unlikely to be worth the slightly smaller update generated, especially since in practice the light client will likely always be up to date with the tip of the (finalized) chain. + #[instrument( + skip_all, + fields( + chain_id = %self.chain_id, + %counterparty_chain_id, + %update_from, + %update_to + ) + )] + async fn fetch_update( + &self, + update_from: Height, + update_to: Height, + counterparty_chain_id: ChainId<'static>, + ) -> Result>, BoxDynError> { + let finality_update = self.beacon_api_client.finality_update().await.unwrap().data; + + // === FETCH VALID FINALITY UPDATE + + // TODO: This is named poorly? + let has_supermajority = { + let scb = BitVec::::try_from( + finality_update.sync_aggregate.sync_committee_bits.clone(), + ) + .unwrap(); + + let sync_committee_size = self + .beacon_api_client + .spec() + .await + .unwrap() + .data + .sync_committee_size; + + assert_eq!(scb.len() as u64, sync_committee_size); + + scb.count_ones() * 3 < scb.len() * 2 + }; + + if has_supermajority { + info!( + signature_slot = finality_update.signature_slot, + "signature supermajority not hit" + ); + + return Ok(seq([ + defer(now() + 1), + call(FetchUpdateHeaders { + chain_id: self.chain_id.clone(), + counterparty_chain_id, + update_from, + update_to, + }), + ])); + }; + + // === FETCH LIGHT CLIENT UPDATES + + let spec = self.beacon_api_client.spec().await.unwrap().data; + + let target_period = + sync_committee_period(finality_update.attested_header.beacon.slot, spec.period()); + + let trusted_period = sync_committee_period(update_from.revision_height, spec.period()); + + info!("target period: {target_period}, trusted period: {trusted_period}"); + + assert!( + trusted_period <= target_period, + "trusted period {trusted_period} is behind target \ + period {target_period}, something is wrong!", + ); + + // Eth chain is more than 1 signature period ahead of us. We need to do sync committee + // updates until we reach the `target_period - 1`. + + // let target_period = sync_committee_period(finality_update.signature_slot, spec.period()); + + let light_client_updates = self + .beacon_api_client + .light_client_updates(trusted_period + 1, target_period - trusted_period) + .await + .unwrap() + .0 + .into_iter() + .map(|x| x.data) + .collect::>(); + + info!( + "fetched {} light client updates", + light_client_updates.len() + ); + + let (updates, last_update_block_number) = stream::iter(light_client_updates) + .fold((VecDeque::new(), update_from.revision_height), { + |(mut vec, mut trusted_slot), update| { + let self_ = self.clone(); + let spec = spec.clone(); + + async move { + let old_trusted_slot = trusted_slot; + + // REVIEW: Assert that this is greater (i.e. increasing)? + trusted_slot = update.attested_header.beacon.slot; + + vec.push_back( + self_ + .make_header(old_trusted_slot, update, true, &spec) + .await, + ); + + (vec, trusted_slot) + } + } + }) + .await; + + let lc_updates = if trusted_period < target_period { + updates + } else { + [].into() + }; + + let does_not_have_finality_update = last_update_block_number >= update_to.revision_height; + + debug!(last_update_block_number, update_to.revision_height); + + let finality_update_msg = if does_not_have_finality_update { + info!("does not have finality update"); + // do nothing + None + } else { + info!("has finality update"); + // do finality update + Some( + self.make_header( + last_update_block_number, + UnboundedLightClientUpdate { + attested_header: finality_update.attested_header, + next_sync_committee: None, + next_sync_committee_branch: None, + finalized_header: finality_update.finalized_header, + finality_branch: finality_update.finality_branch, + sync_aggregate: finality_update.sync_aggregate, + signature_slot: finality_update.signature_slot, + }, + false, + &spec, + ) + .await, + ) + }; + + let headers = lc_updates + .into_iter() + .chain(finality_update_msg) + .collect::>(); + + // header.sort_by_key(|header| header.consensus_update.attested_header.beacon.slot); + + let genesis = self + .beacon_api_client + .genesis() + .await + .map_err(|e| { + ErrorObject::owned( + -1, + format!("error fetching beacon genesis: {}", ErrorReporter(e)), + None::<()>, + ) + })? + .data; + + let last_update_signature_slot = headers + .iter() + .map(|h| h.consensus_update.signature_slot) + .max() + .expect("expected at least one update"); + + Ok(seq([ + call(WaitForTimestamp { + chain_id: counterparty_chain_id.clone(), + // we wait for one more block just to be sure the counterparty's block time has caught up + timestamp: i64::try_from( + (genesis.genesis_time + (last_update_signature_slot * spec.seconds_per_slot)) + + spec.seconds_per_slot, + ) + .unwrap() + * NANOS_PER_SECOND as i64, + }), + queue_msg::data(OrderedHeaders { + headers: headers + .into_iter() + .map(|header| { + ( + DecodedHeaderMeta { + height: Height { + revision_number: ETHEREUM_REVISION_NUMBER, + revision_height: header + .consensus_update + .attested_header + .beacon + .slot, + }, + }, + serde_json::to_value(header).unwrap(), + ) + }) + .collect(), + }), + ])) + } + + #[instrument( + skip_all, + fields( + chain_id = %self.chain_id, + %currently_trusted_slot, + signature_slot = %light_client_update.signature_slot, + %is_next, + ) + )] + async fn make_header( + &self, + currently_trusted_slot: u64, + light_client_update: UnboundedLightClientUpdate, + is_next: bool, + spec: &Spec, + ) -> UnboundedHeader { + // When we fetch the update at this height, the `next_sync_committee` will + // be the current sync committee of the period that we want to update to. + let previous_period = u64::max( + 1, + light_client_update.attested_header.beacon.slot / spec.period(), + ) - 1; + + let account_update = self + .fetch_account_update(light_client_update.attested_header.beacon.slot) + .await; + + let previous_period_light_client_update = self + .beacon_api_client + .light_client_updates(previous_period, 1) + .await + .unwrap() + .0 + .into_iter() + .map(|x| x.data) + .collect::>() + .pop() + .unwrap(); + + UnboundedHeader { + consensus_update: light_client_update, + trusted_sync_committee: UnboundedTrustedSyncCommittee { + trusted_height: Height { + revision_number: ETHEREUM_REVISION_NUMBER, + revision_height: currently_trusted_slot, + }, + sync_committee: if is_next { + UnboundedActiveSyncCommittee::Next( + previous_period_light_client_update + .next_sync_committee + .unwrap(), + ) + } else { + UnboundedActiveSyncCommittee::Current( + previous_period_light_client_update + .next_sync_committee + .unwrap(), + ) + }, + }, + account_update, + } + } +} + +// REVIEW: Does this function exist anywhere else? +fn sync_committee_period(height: u64, period: u64) -> u64 { + height.div(period) +} diff --git a/voyager/modules/transaction/aptos/Cargo.toml b/voyager/modules/transaction/aptos/Cargo.toml new file mode 100644 index 0000000000..8186bbfd46 --- /dev/null +++ b/voyager/modules/transaction/aptos/Cargo.toml @@ -0,0 +1,29 @@ +[package] +edition = "2021" +name = "voyager-transaction-module-aptos" +version = "0.1.0" + +[dependencies] +aptos-crypto = { workspace = true } +aptos-rest-client = { workspace = true } +aptos-types = { workspace = true } +move-core-types = { workspace = true } + +bip32 = { workspace = true } +chain-utils = { workspace = true } +enumorph = { workspace = true } +frunk = { workspace = true } +futures = { workspace = true } +jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } +macros = { workspace = true } +queue-msg = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +serde_json = { workspace = true } +sha3 = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +unionlabs = { workspace = true } +voyager-message = { workspace = true } diff --git a/voyager/modules/transaction/aptos/src/call.rs b/voyager/modules/transaction/aptos/src/call.rs new file mode 100644 index 0000000000..7f25b808d9 --- /dev/null +++ b/voyager/modules/transaction/aptos/src/call.rs @@ -0,0 +1,9 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; +use voyager_message::data::IbcMessage; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCall { + SubmitTransaction(Vec), +} diff --git a/voyager/modules/transaction/aptos/src/callback.rs b/voyager/modules/transaction/aptos/src/callback.rs new file mode 100644 index 0000000000..a783fb9049 --- /dev/null +++ b/voyager/modules/transaction/aptos/src/callback.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::{queue_msg, SubsetOf}; + +#[queue_msg] +#[derive(Enumorph, SubsetOf)] +pub enum ModuleCallback {} diff --git a/voyager/modules/transaction/aptos/src/data.rs b/voyager/modules/transaction/aptos/src/data.rs new file mode 100644 index 0000000000..063c8f7f1d --- /dev/null +++ b/voyager/modules/transaction/aptos/src/data.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleData {} diff --git a/voyager/modules/transaction/aptos/src/main.rs b/voyager/modules/transaction/aptos/src/main.rs new file mode 100644 index 0000000000..cb1990eb8b --- /dev/null +++ b/voyager/modules/transaction/aptos/src/main.rs @@ -0,0 +1,311 @@ +use std::{collections::VecDeque, sync::Arc}; + +use aptos_crypto::{ed25519::Ed25519PrivateKey, PrivateKey}; +use aptos_rest_client::aptos_api_types::{Address, MoveModuleId}; +use aptos_types::{ + account_address::AccountAddress, + transaction::{EntryFunction, RawTransaction}, +}; +use chain_utils::{ + keyring::{ConcurrentKeyring, KeyringConfig, KeyringEntry}, + BoxDynError, +}; +use jsonrpsee::core::{async_trait, RpcResult}; +use queue_msg::{call, noop, optimize::OptimizationResult, Op}; +use serde::{Deserialize, Serialize}; +use sha3::Digest; +use tracing::instrument; +use unionlabs::hash::H256; +use voyager_message::{ + call::Call, + data::{Data, WithChainId}, + module::{ModuleInfo, PluginModuleInfo, PluginModuleServer, QueueInteractionsServer}, + run_module_server, ChainId, DefaultCmd, ModuleContext, ModuleServer, VoyagerMessage, +}; + +use crate::{call::ModuleCall, callback::ModuleCallback, data::ModuleData}; + +pub mod call; +pub mod callback; +pub mod data; + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + run_module_server::().await +} + +#[derive(Debug, Clone)] +pub struct Module { + pub chain_id: ChainId<'static>, + + pub ibc_handler_address: Address, + + pub aptos_client: aptos_rest_client::Client, + + pub keyring: ConcurrentKeyring>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Config { + pub chain_id: ChainId<'static>, + + pub rpc_url: String, + pub ibc_handler_address: Address, + + pub keyring: KeyringConfig, +} + +impl ModuleContext for Module { + type Config = Config; + type Cmd = DefaultCmd; + type Info = PluginModuleInfo; + + async fn new(config: Self::Config) -> Result { + let aptos_client = aptos_rest_client::Client::new(config.rpc_url.parse().unwrap()); + + let chain_id = aptos_client.get_index().await?.inner().chain_id; + + Ok(Self { + chain_id: ChainId::new(chain_id.to_string()), + ibc_handler_address: config.ibc_handler_address, + aptos_client, + keyring: ConcurrentKeyring::new( + config.keyring.name, + config.keyring.keys.into_iter().map(|config| { + let pk = aptos_crypto::ed25519::Ed25519PrivateKey::try_from(&*config.value()) + .unwrap(); + + let address = H256::from( + sha3::Sha3_256::new() + .chain_update(pk.public_key().to_bytes()) + .chain_update([0]) + .finalize(), + ) + .0 + .into(); + + KeyringEntry { + name: config.name(), + address, + signer: Arc::new(pk), + } + }), + ), + }) + } + + fn info(config: Self::Config) -> ModuleInfo { + ModuleInfo { + name: plugin_name(&config.chain_id), + kind: PluginModuleInfo { + interest_filter: format!( + r#" +if ."@type" == "data" then + ."@value" as $data | + + # pull all transaction data messages + ($data."@type" == "identified_ibc_message_batch" or $data."@type" == "identified_ibc_message") + and $data."@value".chain_id == "{chain_id}" +else + false +end +"#, + chain_id = config.chain_id, + ), + }, + } + } + + async fn cmd(_config: Self::Config, cmd: Self::Cmd) { + match cmd {} + } +} + +fn plugin_name(chain_id: &ChainId<'_>) -> String { + pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); + + format!("{PLUGIN_NAME}/{}", chain_id) +} + +impl Module { + fn plugin_name(&self) -> String { + pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); + + format!("{PLUGIN_NAME}/{}", self.chain_id) + } +} + +#[async_trait] +impl QueueInteractionsServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn call( + &self, + msg: ModuleCall, + ) -> RpcResult>> { + match msg { + ModuleCall::SubmitTransaction(msgs) => { + self.ctx + .keyring + .with(|pk| async move { + let sender = H256::from( + sha3::Sha3_256::new() + .chain_update(pk.public_key().to_bytes()) + .chain_update([0]) + .finalize(), + ) + .0 + .into(); + + let account = self + .ctx + .aptos_client + .get_account(sender) + .await + .unwrap() + .into_inner(); + + dbg!(&account); + + let raw = RawTransaction::new_entry_function( + sender, + account.sequence_number, + EntryFunction::new( + MoveModuleId { + address: self.ctx.ibc_handler_address, + name: "Core".parse().unwrap(), + } + .into(), + "hackerman".parse().unwrap(), + vec![], + vec![], + ), + 400000, + 100, + queue_msg::now() + 10, + self.ctx.chain_id.as_str().parse().unwrap(), + ); + + // let hash = raw.test_only_hash() + + let sig = raw.sign(pk, pk.public_key()).unwrap(); + + dbg!(&sig); + + let res = self.ctx.aptos_client.submit_and_wait(&sig).await.unwrap(); + + dbg!(&res); + + Ok(noop()) + }) + .await + .unwrap_or_else(|| { + Ok(call(Call::plugin( + self.ctx.plugin_name(), + ModuleCall::SubmitTransaction(msgs), + ))) + }) + } + } + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn callback( + &self, + cb: ModuleCallback, + _data: VecDeque>, + ) -> RpcResult>> { + match cb {} + } +} + +#[async_trait] +impl PluginModuleServer for ModuleServer { + async fn run_pass( + &self, + msgs: Vec>>, + ) -> RpcResult>> { + Ok(OptimizationResult { + optimize_further: vec![], + ready: msgs + .into_iter() + .enumerate() + .map(|(idx, msg)| { + ( + vec![idx], + match msg { + Op::Data(Data::IdentifiedIbcMessage(WithChainId { + chain_id, + message, + })) => { + assert_eq!(chain_id, self.ctx.chain_id); + + call(Call::plugin( + self.ctx.plugin_name(), + ModuleCall::SubmitTransaction(vec![message]), + )) + } + Op::Data(Data::IdentifiedIbcMessageBatch(WithChainId { + chain_id, + message, + })) => { + assert_eq!(chain_id, self.ctx.chain_id); + + call(Call::plugin( + self.ctx.plugin_name(), + ModuleCall::SubmitTransaction(message), + )) + } + _ => panic!("unexpected message: {msg:?}"), + }, + ) + }) + .collect(), + }) + } +} + +// #[allow(clippy::type_complexity)] +// fn process_msgs( +// msgs: Vec, +// sender: AccountAddress, +// relayer: H160, +// ) -> Vec<(IbcMessage, EntryFunction)> { +// let _ = (msgs, sender, relayer); + +// // msgs.clone() +// // .into_iter() +// // .map(|msg| match msg.clone() { +// // IbcMessage::CreateClient(MsgCreateClientData { +// // msg: data, +// // client_type, +// // }) => ( +// // msg, +// // EntryFunction::new( +// // MoveModuleId { +// // address: (), +// // name: (), +// // } +// // .into(), +// // "create_client".parse().unwrap(), +// // vec![], +// // vec![client_type, data.client_state, data.consensus_state], +// // ), +// // ), +// // IbcMessage::UpdateClient(data) => ( +// // msg, +// // mk_function_call( +// // ibc_handler, +// // UpdateClientCall(contracts::shared_types::MsgUpdateClient { +// // client_id: data.client_id.to_string(), +// // client_message: data.client_message.into(), +// // relayer: relayer.into(), +// // }), +// // ), +// // ), +// // _ => todo!(), +// // }) +// // .collect() + +// todo!() +// } diff --git a/voyager/modules/transaction/cosmos-sdk/Cargo.toml b/voyager/modules/transaction/cosmos-sdk/Cargo.toml new file mode 100644 index 0000000000..7ed2cb3205 --- /dev/null +++ b/voyager/modules/transaction/cosmos-sdk/Cargo.toml @@ -0,0 +1,30 @@ +[package] +edition = "2021" +name = "voyager-transaction-module-cosmos-sdk" +version = "0.1.0" + +[dependencies] +bip32 = { workspace = true } +chain-utils = { workspace = true } +cometbft-rpc = { workspace = true } +dashmap = { workspace = true } +enumorph = { workspace = true } +frunk = { workspace = true } +futures = { workspace = true } +hex = { workspace = true } +jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } +macros = { workspace = true } +prost = { workspace = true } +protos = { workspace = true } +queue-msg = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +serde_json = { workspace = true } +sha2 = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tonic = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +unionlabs = { workspace = true } +voyager-message = { workspace = true } diff --git a/voyager/modules/transaction/cosmos-sdk/src/call.rs b/voyager/modules/transaction/cosmos-sdk/src/call.rs new file mode 100644 index 0000000000..7f25b808d9 --- /dev/null +++ b/voyager/modules/transaction/cosmos-sdk/src/call.rs @@ -0,0 +1,9 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; +use voyager_message::data::IbcMessage; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCall { + SubmitTransaction(Vec), +} diff --git a/voyager/modules/transaction/cosmos-sdk/src/callback.rs b/voyager/modules/transaction/cosmos-sdk/src/callback.rs new file mode 100644 index 0000000000..e3dbf95927 --- /dev/null +++ b/voyager/modules/transaction/cosmos-sdk/src/callback.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCallback {} diff --git a/voyager/modules/transaction/cosmos-sdk/src/data.rs b/voyager/modules/transaction/cosmos-sdk/src/data.rs new file mode 100644 index 0000000000..063c8f7f1d --- /dev/null +++ b/voyager/modules/transaction/cosmos-sdk/src/data.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleData {} diff --git a/voyager/modules/transaction/cosmos-sdk/src/main.rs b/voyager/modules/transaction/cosmos-sdk/src/main.rs new file mode 100644 index 0000000000..622dd28de6 --- /dev/null +++ b/voyager/modules/transaction/cosmos-sdk/src/main.rs @@ -0,0 +1,851 @@ +use std::collections::VecDeque; + +use chain_utils::{ + cosmos_sdk::{ + cosmos_sdk_error::{ChannelError, CosmosSdkError, IbcWasmError, SdkError}, + CosmosKeyring, GasConfig, + }, + keyring::{KeyringConfig, KeyringEntry}, + BoxDynError, +}; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + types::ErrorObject, +}; +use prost::Message; +use queue_msg::{call, noop, optimize::OptimizationResult, Op}; +use serde::{Deserialize, Serialize}; +use sha2::Digest; +use tracing::{debug, error, info, instrument, warn}; +use unionlabs::{ + self, + bounded::BoundedI64, + cosmos::{ + auth::base_account::BaseAccount, + base::abci::gas_info::GasInfo, + crypto::{secp256k1, AnyPubKey}, + tx::{ + auth_info::AuthInfo, mode_info::ModeInfo, sign_doc::SignDoc, signer_info::SignerInfo, + signing::sign_info::SignMode, tx::Tx, tx_body::TxBody, tx_raw::TxRaw, + }, + }, + encoding::{EncodeAs, Proto}, + google::protobuf::any::{mk_any, Any}, + hash::H256, + signer::CosmosSigner, + ErrorReporter, +}; +use voyager_message::{ + call::Call, + data::{Data, IbcMessage, WithChainId}, + module::{ModuleInfo, PluginModuleInfo, PluginModuleServer, QueueInteractionsServer}, + run_module_server, ChainId, DefaultCmd, ModuleContext, ModuleServer, VoyagerMessage, + FATAL_JSONRPC_ERROR_CODE, +}; + +use crate::{call::ModuleCall, callback::ModuleCallback, data::ModuleData}; + +pub mod call; +pub mod callback; +pub mod data; + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + run_module_server::().await +} + +#[derive(Debug, Clone)] +pub struct Module { + pub chain_id: ChainId<'static>, + pub keyring: CosmosKeyring, + pub tm_client: cometbft_rpc::Client, + pub grpc_url: String, + pub gas_config: GasConfig, + pub bech32_prefix: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Config { + pub chain_id: ChainId<'static>, + pub keyring: KeyringConfig, + pub ws_url: String, + pub grpc_url: String, + pub gas_config: GasConfig, +} + +impl ModuleContext for Module { + type Config = Config; + type Cmd = DefaultCmd; + type Info = PluginModuleInfo; + + async fn new(config: Self::Config) -> Result { + let tm_client = cometbft_rpc::Client::new(config.ws_url).await?; + + let chain_id = tm_client.status().await?.node_info.network.to_string(); + + let bech32_prefix = protos::cosmos::auth::v1beta1::query_client::QueryClient::connect( + config.grpc_url.clone(), + ) + .await + .unwrap() + .bech32_prefix(protos::cosmos::auth::v1beta1::Bech32PrefixRequest {}) + .await + .unwrap() + .into_inner() + .bech32_prefix; + + Ok(Self { + keyring: CosmosKeyring::new( + config.keyring.name, + config.keyring.keys.into_iter().map(|entry| { + let signer = CosmosSigner::new( + bip32::secp256k1::ecdsa::SigningKey::from_bytes( + entry.value().as_slice().into(), + ) + .expect("invalid private key"), + bech32_prefix.clone(), + ); + + KeyringEntry { + name: entry.name(), + address: signer.to_string(), + signer, + } + }), + ), + tm_client, + chain_id: ChainId::new(chain_id), + grpc_url: config.grpc_url, + gas_config: config.gas_config, + bech32_prefix, + }) + } + + fn info(config: Self::Config) -> ModuleInfo { + ModuleInfo { + name: plugin_name(&config.chain_id), + kind: PluginModuleInfo { + interest_filter: format!( + r#" +if ."@type" == "data" then + ."@value" as $data | + + # pull all transaction data messages + ($data."@type" == "identified_ibc_message_batch" or $data."@type" == "identified_ibc_message") + and $data."@value".chain_id == "{chain_id}" +else + false +end +"#, + chain_id = config.chain_id, + ), + }, + } + } + + async fn cmd(_config: Self::Config, cmd: Self::Cmd) { + match cmd {} + } +} + +fn plugin_name(chain_id: &ChainId<'_>) -> String { + pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); + + format!("{PLUGIN_NAME}/{}", chain_id) +} + +impl Module { + fn plugin_name(&self) -> String { + plugin_name(&self.chain_id) + } + + pub async fn do_send_transaction( + &self, + msgs: Vec, + ) -> Result>, BroadcastTxCommitError> + { + let res = self + .keyring + .with(|signer| { + let msg = msgs.clone(); + + async move { + // TODO: Figure out a way to thread this value through + let memo = format!("Voyager {}", env!("CARGO_PKG_VERSION")); + + let msgs = process_msgs(msg, signer); + + // let simulation_results = stream::iter(msgs.clone().into_iter().enumerate()) + // .then(move |(idx, (effect, msg))| async move { + // let type_url = msg.type_url.clone(); + + // self.simulate_tx( + // signer, + // [msg], + // format!("Voyager {}", env!("CARGO_PKG_VERSION")) + // ) + // .map(move |res| (idx, type_url, effect, res)) + // .await + // }) + // .collect::)>>() + // .await; + + // // iterate backwards such that when we remove items from msgs, we don't shift the relative indices + // for (idx, type_url, msg, simulation_result) in simulation_results.into_iter().rev() { + // let _span = info_span!( + // "simulation result", + // msg = type_url, + // idx, + // ) + // .entered(); + + // match simulation_result { + // Ok((_, _, gas_info)) => { + // info!( + // gas_wanted = %gas_info.gas_wanted, + // gas_used = %gas_info.gas_used, + // "individual message simulation successful", + // ); + + // log_msg(&self.chain_id, msg); + // } + // Err(error) => { + // if error.message().contains("account sequence mismatch") { + // warn!("account sequence mismatch on individual message simulation, treating this message as successful"); + // log_msg(&self.chain_id, msg); + // } else { + // error!( + // %error, + // "individual message simulation failed" + // ); + + // log_msg(&self.chain_id, msg); + + // msgs.remove(idx); + // } + // } + // } + // } + + // if msgs.is_empty() { + // info!( + // "no messages remaining to submit after filtering out failed transactions" + // ); + // return Ok(()); + // } + + let batch_size = msgs.len(); + let msg_names = msgs.iter().map(move |x| x.1.type_url.clone()).collect::>(); + + match self.broadcast_tx_commit( + signer, + msgs.iter().map(move |x| x.1.clone()).collect::>(), + memo + ).await { + Ok((tx_hash, gas_used)) => { + info!( + %tx_hash, + %gas_used, + batch.size = %batch_size, + "submitted cosmos transaction" + ); + + for msg in msg_names { + info!(%tx_hash, %msg, "cosmos tx"); + } + + Ok(()) + } + Err(err) => match err { + BroadcastTxCommitError::Tx(CosmosSdkError::ChannelError( + ChannelError::ErrRedundantTx, + )) => { + info!("packet messages are redundant"); + Ok(()) + } + // BroadcastTxCommitError::Tx(CosmosSdkError::SdkError( + // SdkError::ErrOutOfGas + // )) => { + // error!("out of gas"); + // Err(BroadcastTxCommitError::OutOfGas) + // } + BroadcastTxCommitError::Tx(CosmosSdkError::SdkError( + SdkError::ErrWrongSequence + )) => { + warn!("account sequence mismatch on tx submission, message will be requeued and retried"); + Err(BroadcastTxCommitError::AccountSequenceMismatch(None)) + } + BroadcastTxCommitError::SimulateTx(err) if err.message().contains("account sequence mismatch") => { + warn!("account sequence mismatch on simulation, message will be requeued and retried"); + Err(BroadcastTxCommitError::AccountSequenceMismatch(Some(err))) + } + err => Err(err), + }, + } + } + }) + .await; + + let rewrap_msg = || Call::plugin(self.plugin_name(), ModuleCall::SubmitTransaction(msgs)); + + match res { + Some(Err(BroadcastTxCommitError::AccountSequenceMismatch(_))) => Ok(call(rewrap_msg())), + Some(Err(BroadcastTxCommitError::OutOfGas)) => Ok(call(rewrap_msg())), + Some(Err(BroadcastTxCommitError::SimulateTx(err))) => { + error!( + error = %ErrorReporter(err), + "transaction simulation failed, message will be requeued and retried" + ); + + Ok(call(rewrap_msg())) + } + Some(Err(BroadcastTxCommitError::QueryLatestHeight(err))) => { + error!(error = %ErrorReporter(err), "error querying latest height"); + + Ok(call(rewrap_msg())) + } + Some(res) => res.map(|()| noop()), + // None => Ok(seq([defer_relative(1), effect(WithChainId{chain_id: self.chain_id.clone(), message: msg})])), + None => Ok(call(rewrap_msg())), + } + } + + /// - simulate tx + /// - submit tx + /// - wait for inclusion + /// - return (tx_hash, gas_used) + pub async fn broadcast_tx_commit( + &self, + signer: &CosmosSigner, + messages: impl IntoIterator + Clone, + memo: String, + ) -> Result<(H256, BoundedI64<0, { i64::MAX }>), BroadcastTxCommitError> { + let account = self.account_info(&signer.to_string()).await; + + let (tx_body, mut auth_info, simulation_gas_info) = + match self.simulate_tx(signer, messages, memo).await { + Ok((tx_body, auth_info, simulation_gas_info)) => { + (tx_body, auth_info, simulation_gas_info) + } + Err((tx_body, auth_info, _err)) => ( + tx_body, + auth_info, + GasInfo { + gas_wanted: u64::MAX, + gas_used: u64::MAX, + }, + ), + }; + // .map_err(BroadcastTxCommitError::SimulateTx)?; + + info!( + gas_used = %simulation_gas_info.gas_used, + gas_wanted = %simulation_gas_info.gas_wanted, + "tx simulation successful" + ); + + auth_info.fee = self.gas_config.mk_fee(simulation_gas_info.gas_used); + + // dbg!(&auth_info.fee); + + info!( + fee = %auth_info.fee.amount[0].amount, + gas_multiplier = %self.gas_config.gas_multiplier, + "submitting transaction with gas" + ); + + // re-sign the new auth info with the simulated gas + let signature = signer + .try_sign( + &SignDoc { + body_bytes: tx_body.clone().encode_as::(), + auth_info_bytes: auth_info.clone().encode_as::(), + chain_id: self.chain_id.to_string(), + account_number: account.account_number, + } + .encode_as::(), + ) + .expect("signing failed") + .to_vec(); + + let tx_raw_bytes = TxRaw { + body_bytes: tx_body.clone().encode_as::(), + auth_info_bytes: auth_info.clone().encode_as::(), + signatures: [signature].to_vec(), + } + .encode_as::(); + + let tx_hash: H256 = sha2::Sha256::new() + .chain_update(&tx_raw_bytes) + .finalize() + .into(); + + if let Ok(tx) = self.tm_client.tx(tx_hash, false).await { + debug!(%tx_hash, "tx already included"); + return Ok((tx_hash, tx.tx_result.gas_used)); + } + + let response = self + .tm_client + .broadcast_tx_sync(&tx_raw_bytes) + .await + .map_err(BroadcastTxCommitError::BroadcastTxSync) + .unwrap(); + + assert_eq!(tx_hash, response.hash, "tx hash calculated incorrectly"); + + info!( + check_tx_code = %response.code, + codespace = %response.codespace, + check_tx_log = %response.log + ); + + if response.code > 0 { + let error = CosmosSdkError::from_code_and_codespace(&response.codespace, response.code); + + error!(%error, "cosmos tx failed"); + + return Err(BroadcastTxCommitError::Tx(error)); + }; + + let mut target_height = self + .tm_client + .block(None) + .await + .map_err(BroadcastTxCommitError::QueryLatestHeight)? + .block + .header + .height; + + // TODO: Do this in the queue + let mut i = 0; + loop { + let reached_height = 'l: loop { + let current_height = self + .tm_client + .block(None) + .await + .map_err(BroadcastTxCommitError::QueryLatestHeight)? + .block + .header + .height; + + if current_height >= target_height { + break 'l current_height; + } + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + }; + + let tx_inclusion = self.tm_client.tx(tx_hash, false).await; + + debug!(?tx_inclusion); + + match tx_inclusion { + Ok(tx) => { + if tx.tx_result.code == 0 { + break Ok((tx_hash, tx.tx_result.gas_used)); + } else { + let error = CosmosSdkError::from_code_and_codespace( + &tx.tx_result.codespace, + tx.tx_result.code, + ); + warn!( + %error, + %tx_hash, + + %tx.tx_result.code, + tx.tx_result.data = %::serde_utils::to_hex(&tx.tx_result.data), + %tx.tx_result.log, + %tx.tx_result.info, + %tx.tx_result.gas_wanted, + %tx.tx_result.gas_used, + ?tx.tx_result.events, + %tx.tx_result.codespace, + + "cosmos transaction failed" + ); + break Err(BroadcastTxCommitError::Tx(error)); + } + } + Err(err) if i > 5 => { + warn!("tx inclusion couldn't be retrieved after {} try", i); + break Err(BroadcastTxCommitError::Inclusion(err)); + } + Err(_) => { + target_height = reached_height.add(&1); + i += 1; + continue; + } + } + } + } + + pub async fn simulate_tx( + &self, + signer: &CosmosSigner, + messages: impl IntoIterator + Clone, + memo: String, + ) -> Result<(TxBody, AuthInfo, GasInfo), (TxBody, AuthInfo, tonic::Status)> { + use protos::cosmos::tx; + + let account = self.account_info(&signer.to_string()).await; + + let mut client = tx::v1beta1::service_client::ServiceClient::connect(self.grpc_url.clone()) + .await + .unwrap(); + + let tx_body = TxBody { + // TODO: Use RawAny here + messages: messages.clone().into_iter().map(Into::into).collect(), + memo, + timeout_height: 0, + extension_options: vec![], + non_critical_extension_options: vec![], + }; + + let auth_info = AuthInfo { + signer_infos: [SignerInfo { + public_key: Some(AnyPubKey::Secp256k1(secp256k1::PubKey { + key: signer.public_key(), + })), + mode_info: ModeInfo::Single { + mode: SignMode::Direct, + }, + sequence: account.sequence, + }] + .to_vec(), + fee: self.gas_config.mk_fee(self.gas_config.max_gas).clone(), + }; + + let simulation_signature = signer + .try_sign( + &SignDoc { + body_bytes: tx_body.clone().encode_as::(), + auth_info_bytes: auth_info.clone().encode_as::(), + chain_id: self.chain_id.to_string(), + account_number: account.account_number, + } + .encode_as::(), + ) + .expect("signing failed") + .to_vec(); + + let result = client + .simulate(tx::v1beta1::SimulateRequest { + tx_bytes: Tx { + body: tx_body.clone(), + auth_info: auth_info.clone(), + signatures: [simulation_signature.clone()].to_vec(), + } + .encode_as::(), + ..Default::default() + }) + .await; + + match result { + Ok(ok) => Ok(( + tx_body, + auth_info, + ok.into_inner() + .gas_info + .expect("gas info is present on successful simulation result") + .into(), + )), + Err(err) => { + info!(error = %ErrorReporter(&err), "tx simulation failed"); + Err((tx_body, auth_info, err)) + } + } + } + + async fn account_info(&self, account: &str) -> BaseAccount { + debug!(%account, "fetching account"); + + let Any(account) = protos::cosmos::auth::v1beta1::query_client::QueryClient::connect( + self.grpc_url.clone(), + ) + .await + .unwrap() + .account(protos::cosmos::auth::v1beta1::QueryAccountRequest { + address: account.to_string(), + }) + .await + .unwrap() + .into_inner() + .account + .unwrap() + .try_into() + .unwrap(); + + account + } +} + +#[derive(Debug, thiserror::Error)] +pub enum BroadcastTxCommitError { + #[error("error querying latest height")] + QueryLatestHeight(#[source] cometbft_rpc::JsonRpcError), + #[error("error sending broadcast_tx_sync")] + BroadcastTxSync(#[source] cometbft_rpc::JsonRpcError), + #[error("tx was not included")] + Inclusion(#[source] cometbft_rpc::JsonRpcError), + #[error("tx failed: {0:?}")] + Tx(CosmosSdkError), + #[error("tx simulation failed")] + SimulateTx(#[source] tonic::Status), + #[error("account sequence mismatch")] + AccountSequenceMismatch(#[source] Option), + #[error("out of gas")] + OutOfGas, +} + +#[async_trait] +impl QueueInteractionsServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + #[allow(clippy::collapsible_match)] + async fn call( + &self, + msg: ModuleCall, + ) -> RpcResult>> { + match msg { + ModuleCall::SubmitTransaction(msgs) => self + .ctx + .do_send_transaction(msgs) + .await + .map_err(|err| match &err { + BroadcastTxCommitError::Tx(tx_err) => match tx_err { + CosmosSdkError::Capability(capability_error) => ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + ErrorReporter(capability_error).to_string(), + None::<()>, + ), + CosmosSdkError::IbcWasmError(IbcWasmError::ErrInvalidChecksum) => { + ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + ErrorReporter(err).to_string(), + None::<()>, + ) + } + _ => ErrorObject::owned(-1, ErrorReporter(err).to_string(), None::<()>), + }, + _ => ErrorObject::owned(-1, ErrorReporter(err).to_string(), None::<()>), + }), + } + } + + #[instrument(skip_all)] + async fn callback( + &self, + cb: ModuleCallback, + _data: VecDeque>, + ) -> RpcResult>> { + match cb {} + } +} + +#[async_trait] +impl PluginModuleServer for ModuleServer { + #[instrument(skip_all)] + async fn run_pass( + &self, + msgs: Vec>>, + ) -> RpcResult>> { + Ok(OptimizationResult { + optimize_further: vec![], + ready: msgs + .into_iter() + .enumerate() + .map(|(idx, msg)| { + ( + vec![idx], + match msg { + Op::Data(Data::IdentifiedIbcMessage(WithChainId { + chain_id, + message, + })) => { + assert_eq!(chain_id, self.ctx.chain_id); + + call(Call::plugin( + self.ctx.plugin_name(), + ModuleCall::SubmitTransaction(vec![message]), + )) + } + Op::Data(Data::IdentifiedIbcMessageBatch(WithChainId { + chain_id, + message, + })) => { + assert_eq!(chain_id, self.ctx.chain_id); + + call(Call::plugin( + self.ctx.plugin_name(), + ModuleCall::SubmitTransaction(message), + )) + } + _ => panic!("unexpected message: {msg:?}"), + }, + ) + }) + .collect(), + }) + } +} + +fn process_msgs( + msgs: Vec, + signer: &CosmosSigner, +) -> Vec<(IbcMessage, protos::google::protobuf::Any)> { + msgs.into_iter() + .map(|msg| { + let encoded = match msg.clone() { + IbcMessage::ConnectionOpenInit(message) => { + mk_any(&protos::ibc::core::connection::v1::MsgConnectionOpenInit { + client_id: message.client_id.to_string(), + counterparty: Some(message.counterparty.into()), + version: Some(message.version.into()), + signer: signer.to_string(), + delay_period: message.delay_period, + }) + } + IbcMessage::ConnectionOpenTry(message) => { + mk_any(&protos::ibc::core::connection::v1::MsgConnectionOpenTry { + client_id: message.client_id.to_string(), + client_state: Some( + protos::google::protobuf::Any::decode(&*message.client_state) + .expect("value should be encoded as an `Any`"), + ), + counterparty: Some(message.counterparty.into()), + delay_period: message.delay_period, + counterparty_versions: message + .counterparty_versions + .into_iter() + .map(Into::into) + .collect(), + proof_height: Some(message.proof_height.into()), + proof_init: message.proof_init, + proof_client: message.proof_client, + proof_consensus: message.proof_consensus, + consensus_height: Some(message.consensus_height.into()), + signer: signer.to_string(), + host_consensus_state_proof: vec![], + ..Default::default() + }) + } + IbcMessage::ConnectionOpenAck(message) => { + mk_any(&protos::ibc::core::connection::v1::MsgConnectionOpenAck { + client_state: Some( + protos::google::protobuf::Any::decode(&*message.client_state) + .expect("value should be encoded as an `Any`"), + ), + proof_height: Some(message.proof_height.into()), + proof_client: message.proof_client, + proof_consensus: message.proof_consensus, + consensus_height: Some(message.consensus_height.into()), + signer: signer.to_string(), + host_consensus_state_proof: vec![], + connection_id: message.connection_id.to_string(), + counterparty_connection_id: message.counterparty_connection_id.to_string(), + version: Some(message.version.into()), + proof_try: message.proof_try, + }) + } + IbcMessage::ConnectionOpenConfirm(message) => mk_any( + &protos::ibc::core::connection::v1::MsgConnectionOpenConfirm { + connection_id: message.connection_id.to_string(), + proof_ack: message.proof_ack, + proof_height: Some(message.proof_height.into()), + signer: signer.to_string(), + }, + ), + IbcMessage::ChannelOpenInit(message) => { + mk_any(&protos::ibc::core::channel::v1::MsgChannelOpenInit { + port_id: message.port_id.to_string(), + channel: Some(message.channel.into()), + signer: signer.to_string(), + }) + } + IbcMessage::ChannelOpenTry(message) => { + mk_any(&protos::ibc::core::channel::v1::MsgChannelOpenTry { + port_id: message.port_id.to_string(), + channel: Some(message.channel.into()), + counterparty_version: message.counterparty_version, + proof_init: message.proof_init, + proof_height: Some(message.proof_height.into()), + signer: signer.to_string(), + ..Default::default() + }) + } + IbcMessage::ChannelOpenAck(message) => { + mk_any(&protos::ibc::core::channel::v1::MsgChannelOpenAck { + port_id: message.port_id.to_string(), + channel_id: message.channel_id.to_string(), + counterparty_version: message.counterparty_version, + counterparty_channel_id: message.counterparty_channel_id.to_string(), + proof_try: message.proof_try, + proof_height: Some(message.proof_height.into()), + signer: signer.to_string(), + }) + } + IbcMessage::ChannelOpenConfirm(message) => { + mk_any(&protos::ibc::core::channel::v1::MsgChannelOpenConfirm { + port_id: message.port_id.to_string(), + channel_id: message.channel_id.to_string(), + proof_height: Some(message.proof_height.into()), + signer: signer.to_string(), + proof_ack: message.proof_ack, + }) + } + IbcMessage::RecvPacket(message) => { + mk_any(&protos::ibc::core::channel::v1::MsgRecvPacket { + packet: Some(message.packet.into()), + proof_height: Some(message.proof_height.into()), + signer: signer.to_string(), + proof_commitment: message.proof_commitment, + }) + } + IbcMessage::AcknowledgePacket(message) => { + mk_any(&protos::ibc::core::channel::v1::MsgAcknowledgement { + packet: Some(message.packet.into()), + acknowledgement: message.acknowledgement, + proof_acked: message.proof_acked, + proof_height: Some(message.proof_height.into()), + signer: signer.to_string(), + }) + } + IbcMessage::TimeoutPacket(message) => { + mk_any(&protos::ibc::core::channel::v1::MsgTimeout { + packet: Some(message.packet.into()), + proof_unreceived: message.proof_unreceived, + proof_height: Some(message.proof_height.into()), + next_sequence_recv: message.next_sequence_recv.get(), + signer: signer.to_string(), + }) + } + IbcMessage::CreateClient(message) => { + mk_any(&protos::ibc::core::client::v1::MsgCreateClient { + client_state: Some( + protos::google::protobuf::Any::decode(&*message.msg.client_state) + .expect("value should be encoded as an `Any`"), + ), + consensus_state: Some( + protos::google::protobuf::Any::decode(&*message.msg.consensus_state) + .expect("value should be encoded as an `Any`"), + ), + signer: signer.to_string(), + }) + } + IbcMessage::UpdateClient(message) => { + mk_any(&protos::ibc::core::client::v1::MsgUpdateClient { + signer: signer.to_string(), + client_id: message.client_id.to_string(), + client_message: Some( + protos::google::protobuf::Any::decode(&*message.client_message) + .expect("value should be encoded as an `Any`"), + ), + }) + } + }; + + (msg, encoded) + }) + .collect() +} diff --git a/voyager/modules/transaction/ethereum/Cargo.toml b/voyager/modules/transaction/ethereum/Cargo.toml new file mode 100644 index 0000000000..ee8d846447 --- /dev/null +++ b/voyager/modules/transaction/ethereum/Cargo.toml @@ -0,0 +1,26 @@ +[package] +edition = "2021" +name = "voyager-transaction-module-ethereum" +version = "0.1.0" + +[dependencies] +beacon-api = { workspace = true } +bip32 = { workspace = true } +chain-utils = { workspace = true } +contracts = { workspace = true, features = ["providers"] } +enumorph = { workspace = true } +ethers = { workspace = true, features = ["rustls", "ws"] } +frunk = { workspace = true } +futures = { workspace = true } +jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } +macros = { workspace = true } +queue-msg = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-utils = { workspace = true } +serde_json = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +unionlabs = { workspace = true } +voyager-message = { workspace = true } diff --git a/voyager/modules/transaction/ethereum/src/call.rs b/voyager/modules/transaction/ethereum/src/call.rs new file mode 100644 index 0000000000..37720ce69a --- /dev/null +++ b/voyager/modules/transaction/ethereum/src/call.rs @@ -0,0 +1,9 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; +use voyager_message::data::IbcMessage; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCall { + SubmitMulticall(Vec), +} diff --git a/voyager/modules/transaction/ethereum/src/callback.rs b/voyager/modules/transaction/ethereum/src/callback.rs new file mode 100644 index 0000000000..a783fb9049 --- /dev/null +++ b/voyager/modules/transaction/ethereum/src/callback.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::{queue_msg, SubsetOf}; + +#[queue_msg] +#[derive(Enumorph, SubsetOf)] +pub enum ModuleCallback {} diff --git a/voyager/modules/transaction/ethereum/src/data.rs b/voyager/modules/transaction/ethereum/src/data.rs new file mode 100644 index 0000000000..063c8f7f1d --- /dev/null +++ b/voyager/modules/transaction/ethereum/src/data.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleData {} diff --git a/voyager/modules/transaction/ethereum/src/main.rs b/voyager/modules/transaction/ethereum/src/main.rs new file mode 100644 index 0000000000..5fbe20f943 --- /dev/null +++ b/voyager/modules/transaction/ethereum/src/main.rs @@ -0,0 +1,727 @@ +use std::{collections::VecDeque, sync::Arc}; + +use chain_utils::{ + ethereum::{EthereumSignerMiddleware, IbcHandlerErrors}, + keyring::{ConcurrentKeyring, KeyringConfig, KeyringEntry}, + BoxDynError, +}; +use contracts::{ + ibc_handler::{ + AcknowledgePacketCall, ChannelOpenAckCall, ChannelOpenConfirmCall, ChannelOpenInitCall, + ChannelOpenTryCall, ConnectionOpenAckCall, ConnectionOpenConfirmCall, + ConnectionOpenInitCall, ConnectionOpenTryCall, CreateClientCall, IBCHandler, + RecvPacketCall, TimeoutPacketCall, UpdateClientCall, + }, + multicall::{Call3, Multicall, MulticallResultFilter}, +}; +use ethers::{ + abi::AbiDecode, + contract::{ContractError, EthCall, EthLogDecode, FunctionCall}, + core::k256::ecdsa, + middleware::{ + nonce_manager::NonceManagerError, signer::SignerMiddlewareError, NonceManagerMiddleware, + SignerMiddleware, + }, + providers::{Middleware, Provider, ProviderError, Ws}, + signers::{LocalWallet, Signer}, + types::TransactionReceipt, + utils::secret_key_to_address, +}; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + types::ErrorObject, +}; +use queue_msg::{call, defer, now, optimize::OptimizationResult, seq, Op}; +use serde::{Deserialize, Serialize}; +use tracing::{debug, error, error_span, info, info_span, instrument, warn, Instrument}; +use unionlabs::{ + hash::{H160, H256}, + uint::U256, + ErrorReporter, +}; +use voyager_message::{ + call::Call, + data::{log_msg, Data, IbcMessage, MsgCreateClientData, WithChainId}, + module::{ModuleInfo, PluginModuleInfo, PluginModuleServer, QueueInteractionsServer}, + run_module_server, ChainId, DefaultCmd, ModuleContext, ModuleServer, VoyagerMessage, +}; + +use crate::{call::ModuleCall, callback::ModuleCallback, data::ModuleData}; + +pub mod call; +pub mod callback; +pub mod data; + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + run_module_server::().await +} + +#[derive(Debug, Clone)] +pub struct Module { + pub chain_id: ChainId<'static>, + + /// The address of the `IBCHandler` smart contract. + pub ibc_handler_address: H160, + pub multicall_address: H160, + + pub provider: Provider, + + pub keyring: ConcurrentKeyring, + + pub max_gas_price: Option, + pub legacy: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Config { + pub chain_id: ChainId<'static>, + + /// The address of the `IBCHandler` smart contract. + pub ibc_handler_address: H160, + pub multicall_address: H160, + + /// The RPC endpoint for the execution chain. + pub eth_rpc_api: String, + + pub keyring: KeyringConfig, + + #[serde(default)] + pub max_gas_price: Option, + + #[serde(default)] + pub legacy: bool, +} + +impl ModuleContext for Module { + type Config = Config; + type Cmd = DefaultCmd; + type Info = PluginModuleInfo; + + async fn new(config: Self::Config) -> Result { + let provider = Provider::new(Ws::connect(config.eth_rpc_api).await?); + + let raw_chain_id = provider.get_chainid().await?; + let chain_id = ChainId::new(U256(raw_chain_id).to_string()); + + if chain_id != config.chain_id { + return Err(format!( + "incorrect chain id: expected `{}`, but found `{}`", + config.chain_id, chain_id + ) + .into()); + } + + Ok(Self { + chain_id, + ibc_handler_address: config.ibc_handler_address, + multicall_address: config.multicall_address, + provider, + keyring: ConcurrentKeyring::new( + config.keyring.name, + config.keyring.keys.into_iter().map(|config| { + let signing_key = ::from_bytes( + &config.value().as_slice().try_into().unwrap(), + ) + .unwrap(); + + let address = secret_key_to_address(&signing_key); + + let wallet = + LocalWallet::new_with_signer(signing_key, address, raw_chain_id.as_u64()); + + KeyringEntry { + name: config.name(), + address: address.into(), + signer: wallet, + } + }), + ), + max_gas_price: config.max_gas_price, + legacy: config.legacy, + }) + } + + fn info(config: Self::Config) -> ModuleInfo { + ModuleInfo { + name: plugin_name(&config.chain_id), + kind: PluginModuleInfo { + interest_filter: format!( + r#" +if ."@type" == "data" then + ."@value" as $data | + + # pull all transaction data messages + ($data."@type" == "identified_ibc_message_batch" or $data."@type" == "identified_ibc_message") + and $data."@value".chain_id == "{chain_id}" +else + false +end +"#, + chain_id = config.chain_id, + ), + }, + } + } + + async fn cmd(_config: Self::Config, cmd: Self::Cmd) { + match cmd {} + } +} + +fn plugin_name(chain_id: &ChainId<'_>) -> String { + pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); + + format!("{PLUGIN_NAME}/{}", chain_id) +} + +impl Module { + fn plugin_name(&self) -> String { + plugin_name(&self.chain_id) + } +} + +#[async_trait] +impl QueueInteractionsServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn call( + &self, + msg: ModuleCall, + ) -> RpcResult>> { + match msg { + ModuleCall::SubmitMulticall(msgs) => { + let res = self.ctx.keyring + .with({ + let msgs = msgs.clone(); + move |wallet| -> _ { + let signer = Arc::new(SignerMiddleware::new( + NonceManagerMiddleware::new(self.ctx.provider.clone(), wallet.address()), + wallet.clone(), + )); + + async move { + if let Some(max_gas_price) = self.ctx.max_gas_price { + let gas_price = U256::from(self.ctx.provider + .get_gas_price() + .await + .expect("unable to fetch gas price")); + + if gas_price > max_gas_price { + warn!(%max_gas_price, %gas_price, "gas price is too high"); + return Err(TxSubmitError::GasPriceTooHigh { + max: max_gas_price, + price: gas_price + }) + } + } + + let multicall = Multicall::new(ethers::types::H160::from(self.ctx.multicall_address), signer.clone()); + + let msgs = process_msgs( + msgs, + &IBCHandler::new(self.ctx.ibc_handler_address, signer), + wallet.address().into(), + ); + + let msg_names = msgs + .iter() + .map(|x| (x.0.clone(), x.1.function.name.clone())) + .collect::>(); + + let call = multicall.multicall( + msgs.into_iter() + .map(|(_, x): (_, FunctionCall<_, _, _>)| Call3 { + target: self.ctx.ibc_handler_address.into(), + allow_failure: true, + call_data: x.calldata().expect("is a contract call"), + }) + .collect(), + ); + + let call = if self.ctx.legacy { call.legacy() } else { call }; + + let msg_name = call.function.name.clone(); + + info!("submitting evm tx"); + + match call.estimate_gas().await { + Ok(estimated_gas) => { + debug!( + %estimated_gas, + "gas estimation" + ); + + // TODO: config + match call.gas(estimated_gas + (estimated_gas / 10)).send().await { + Ok(ok) => { + let tx_hash = ok.tx_hash(); + async move { + let tx_rcp: TransactionReceipt = ok.await?.ok_or(TxSubmitError::NoTxReceipt)?; + + let result = MulticallResultFilter::decode_log( + ðers::abi::RawLog::from( + tx_rcp + .logs + .last() + .expect("multicall event should be last log") + .clone(), + ), + ) + .expect("unable to decode multicall result log"); + + info!( + gas_used = %tx_rcp.gas_used.unwrap_or_default(), + batch.size = msg_names.len(), + "submitted batched evm messages" + ); + + let mut retry_msgs = vec![]; + + for (idx, (result, (msg, msg_name))) in result.0.into_iter().zip(msg_names).enumerate() { + if result.success { + info_span!( + "evm tx", + msg = msg_name, + %idx, + ) + .in_scope(|| log_msg(&self.ctx.chain_id.to_string(), &msg)); + } else if let Ok(known_revert) = + IbcHandlerErrors::decode(&*result.return_data.clone()) + { + error_span!( + "evm message failed", + msg = %msg_name, + %idx, + revert = ?known_revert, + well_known = true, + ) + .in_scope(|| log_msg(&self.ctx.chain_id.to_string(), &msg)); + } else if result.return_data.is_empty() { + error_span!( + "evm message failed", + msg = %msg_name, + %idx, + revert = %serde_utils::to_hex(result.return_data), + well_known = false, + ) + .in_scope(|| log_msg(&self.ctx.chain_id.to_string(), &msg)); + + retry_msgs.push((true, msg)); + // return Err(TxSubmitError::EmptyRevert) + } else { + error_span!( + "evm message failed", + msg = %msg_name, + %idx, + revert = %serde_utils::to_hex(result.return_data), + well_known = false, + ) + .in_scope(|| log_msg(&self.ctx.chain_id.to_string(), &msg)); + + retry_msgs.push((false, msg)); + } + } + + // empty iterator returns false + if retry_msgs.iter().any(|(is_empty_revert, _)| *is_empty_revert) { + Err(TxSubmitError::EmptyRevert(retry_msgs.into_iter().map(|(_, msg)| msg).collect())) + } else { + Ok(()) + } + } + .instrument(info_span!( + "evm tx", + tx_hash = %H256::from(tx_hash), + )).await + } + // Err(ContractError::Revert(revert)) => { + // error!(?revert, "evm transaction failed"); + // let err = ::decode( + // revert.clone(), + // ) + // .map_err(|_| TxSubmitError::InvalidRevert(revert.clone()))?; + // error!( + // msg = %msg_name, + // ?revert, + // ?err, + // "evm transaction failed" + // ); + + // Ok(()) + // } + Err(ContractError::ProviderError { + e: ProviderError::JsonRpcClientError(e), + }) + | Err(ContractError::MiddlewareError { + e: + SignerMiddlewareError::MiddlewareError(NonceManagerError::MiddlewareError( + ProviderError::JsonRpcClientError(e), + )), + }) if e.as_error_response().is_some_and(|e| { + e.message + .contains("insufficient funds for gas * price + value") + }) => + { + error!("out of gas"); + Err(TxSubmitError::OutOfGas) + } + err => { + panic!("evm transaction non-recoverable failure: {err:?}") + } + } + } + Err(err) => { + let _span = error_span!( + "tx error", + msg = %msg_name, + err = %ErrorReporter(&err) + ); + + match err { + ContractError::Revert(revert) => { + error!(?revert, "evm gas estimation failed"); + + match ::decode( + &revert, + ) { + Ok(known_err) => { + // REVIEW: Are any of these recoverable? + // match known_err { + // IbcHandlerErrors::PacketErrors(_) => todo!(), + // IbcHandlerErrors::ConnectionErrors(_) => todo!(), + // IbcHandlerErrors::ChannelErrors(_) => todo!(), + // IbcHandlerErrors::ClientErrors(_) => todo!(), + // IbcHandlerErrors::CometblsClientErrors(_) => todo!(), + // } + + error!(?revert, ?known_err, "evm estimation failed"); + } + Err(_) => { + error!( + "evm estimation failed with unknown revert code" + ); + } + } + + Ok(()) + } + _ => { + error!("evm tx recoverable error"); + panic!(); + } + } + } + } + } + } + }) + .await; + + let rewrap_msg = + || Call::plugin(self.ctx.plugin_name(), ModuleCall::SubmitMulticall(msgs)); + + match res { + Some(Ok(())) => Ok(Op::Noop), + Some(Err(TxSubmitError::GasPriceTooHigh { .. })) => { + Ok(seq([defer(now() + 6), call(rewrap_msg())])) + } + Some(Err(TxSubmitError::OutOfGas)) => { + Ok(seq([defer(now() + 12), call(rewrap_msg())])) + } + Some(Err(TxSubmitError::EmptyRevert(msgs))) => Ok(seq([ + defer(now() + 12), + call(Call::plugin( + self.ctx.plugin_name(), + ModuleCall::SubmitMulticall(msgs), + )), + ])), + Some(Err(err)) => Err(ErrorObject::owned( + -1, + ErrorReporter(err).to_string(), + None::<()>, + )), + None => Ok(call(rewrap_msg())), + } + } + } + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn callback( + &self, + cb: ModuleCallback, + _data: VecDeque>, + ) -> RpcResult>> { + match cb {} + } +} + +#[derive(Debug, thiserror::Error)] +pub enum TxSubmitError { + #[error(transparent)] + Contract(#[from] ContractError), + #[error(transparent)] + Provider(#[from] ProviderError), + #[error("no tx receipt from tx")] + NoTxReceipt, + #[error("invalid revert code: {0}")] + InvalidRevert(ethers::types::Bytes), + #[error("out of gas")] + OutOfGas, + #[error("0x revert")] + EmptyRevert(Vec), + #[error("gas price is too high: max {max}, price {price}")] + GasPriceTooHigh { max: U256, price: U256 }, +} + +#[async_trait] +impl PluginModuleServer for ModuleServer { + async fn run_pass( + &self, + msgs: Vec>>, + ) -> RpcResult>> { + Ok(OptimizationResult { + optimize_further: vec![], + ready: msgs + .into_iter() + .enumerate() + .map(|(idx, msg)| { + ( + vec![idx], + match msg { + Op::Data(Data::IdentifiedIbcMessage(WithChainId { + chain_id, + message, + })) => { + assert_eq!(chain_id, self.ctx.chain_id); + + call(Call::plugin( + self.ctx.plugin_name(), + ModuleCall::SubmitMulticall(vec![message]), + )) + } + Op::Data(Data::IdentifiedIbcMessageBatch(WithChainId { + chain_id, + message, + })) => { + assert_eq!(chain_id, self.ctx.chain_id); + + call(Call::plugin( + self.ctx.plugin_name(), + ModuleCall::SubmitMulticall(message), + )) + } + _ => panic!("unexpected message: {msg:?}"), + }, + ) + }) + .collect(), + }) + } +} + +#[allow(clippy::type_complexity)] +fn process_msgs( + msgs: Vec, + ibc_handler: &IBCHandler, + relayer: H160, +) -> Vec<(IbcMessage, FunctionCall, M, ()>)> { + pub fn mk_function_call( + ibc_handler: &IBCHandler, + data: Call, + ) -> ethers::contract::FunctionCall, M, ()> { + ibc_handler + .method_hash(::selector(), data) + .expect("method selector is generated; qed;") + } + + msgs.clone() + .into_iter() + .map(|msg| match msg.clone() { + IbcMessage::ConnectionOpenInit(data) => ( + msg, + mk_function_call( + ibc_handler, + ConnectionOpenInitCall(contracts::ibc_handler::MsgConnectionOpenInit { + client_id: data.client_id.to_string(), + version: data.version.into(), + counterparty: data.counterparty.into(), + delay_period: data.delay_period, + relayer: relayer.into(), + }), + ), + ), + IbcMessage::ConnectionOpenTry(data) => ( + msg, + mk_function_call( + ibc_handler, + ConnectionOpenTryCall(contracts::ibc_handler::MsgConnectionOpenTry { + counterparty: data.counterparty.into(), + delay_period: data.delay_period, + client_id: data.client_id.to_string(), + client_state_bytes: data.client_state.into(), + counterparty_versions: data + .counterparty_versions + .into_iter() + .map(Into::into) + .collect(), + proof_init: data.proof_init.into(), + proof_client: data.proof_client.into(), + proof_consensus: data.proof_consensus.into(), + proof_height: data.proof_height.into(), + consensus_height: data.consensus_height.into(), + relayer: relayer.into(), + }), + ), + ), + IbcMessage::ConnectionOpenAck(data) => ( + msg, + mk_function_call( + ibc_handler, + ConnectionOpenAckCall(contracts::ibc_handler::MsgConnectionOpenAck { + connection_id: data.connection_id.to_string(), + counterparty_connection_id: data.counterparty_connection_id.to_string(), + version: data.version.into(), + client_state_bytes: data.client_state.into(), + proof_height: data.proof_height.into(), + proof_try: data.proof_try.into(), + proof_client: data.proof_client.into(), + proof_consensus: data.proof_consensus.into(), + consensus_height: data.consensus_height.into(), + relayer: relayer.into(), + }), + ), + ), + IbcMessage::ConnectionOpenConfirm(data) => ( + msg, + mk_function_call( + ibc_handler, + ConnectionOpenConfirmCall(contracts::ibc_handler::MsgConnectionOpenConfirm { + connection_id: data.connection_id.to_string(), + proof_ack: data.proof_ack.into(), + proof_height: data.proof_height.into(), + relayer: relayer.into(), + }), + ), + ), + IbcMessage::ChannelOpenInit(data) => ( + msg, + mk_function_call( + ibc_handler, + ChannelOpenInitCall(contracts::ibc_handler::MsgChannelOpenInit { + port_id: data.port_id.to_string(), + channel: data.channel.into(), + relayer: relayer.into(), + }), + ), + ), + IbcMessage::ChannelOpenTry(data) => ( + msg, + mk_function_call( + ibc_handler, + ChannelOpenTryCall(contracts::ibc_handler::MsgChannelOpenTry { + port_id: data.port_id.to_string(), + channel: data.channel.into(), + counterparty_version: data.counterparty_version, + proof_init: data.proof_init.into(), + proof_height: data.proof_height.into(), + relayer: relayer.into(), + }), + ), + ), + IbcMessage::ChannelOpenAck(data) => ( + msg, + mk_function_call( + ibc_handler, + ChannelOpenAckCall(contracts::ibc_handler::MsgChannelOpenAck { + port_id: data.port_id.to_string(), + channel_id: data.channel_id.to_string(), + counterparty_version: data.counterparty_version, + counterparty_channel_id: data.counterparty_channel_id.to_string(), + proof_try: data.proof_try.into(), + proof_height: data.proof_height.into(), + relayer: relayer.into(), + }), + ), + ), + IbcMessage::ChannelOpenConfirm(data) => ( + msg, + mk_function_call( + ibc_handler, + ChannelOpenConfirmCall(contracts::ibc_handler::MsgChannelOpenConfirm { + port_id: data.port_id.to_string(), + channel_id: data.channel_id.to_string(), + proof_ack: data.proof_ack.into(), + proof_height: data.proof_height.into(), + relayer: relayer.into(), + }), + ), + ), + IbcMessage::RecvPacket(data) => ( + msg, + mk_function_call( + ibc_handler, + RecvPacketCall(contracts::ibc_handler::MsgPacketRecv { + packet: data.packet.into(), + proof: data.proof_commitment.into(), + proof_height: data.proof_height.into(), + relayer: relayer.into(), + }), + ), + ), + IbcMessage::AcknowledgePacket(data) => ( + msg, + mk_function_call( + ibc_handler, + AcknowledgePacketCall(contracts::ibc_handler::MsgPacketAcknowledgement { + packet: data.packet.into(), + acknowledgement: data.acknowledgement.into(), + proof: data.proof_acked.into(), + proof_height: data.proof_height.into(), + relayer: relayer.into(), + }), + ), + ), + IbcMessage::TimeoutPacket(data) => ( + msg, + mk_function_call( + ibc_handler, + TimeoutPacketCall(contracts::ibc_handler::MsgPacketTimeout { + packet: data.packet.into(), + proof: data.proof_unreceived.into(), + proof_height: data.proof_height.into(), + next_sequence_recv: data.next_sequence_recv.get(), + relayer: relayer.into(), + }), + ), + ), + IbcMessage::CreateClient(MsgCreateClientData { + msg: data, + client_type, + }) => ( + msg, + mk_function_call( + ibc_handler, + CreateClientCall(contracts::shared_types::MsgCreateClient { + client_type: client_type.to_string(), + client_state_bytes: data.client_state.into(), + consensus_state_bytes: data.consensus_state.into(), + relayer: relayer.into(), + }), + ), + ), + IbcMessage::UpdateClient(data) => ( + msg, + mk_function_call( + ibc_handler, + UpdateClientCall(contracts::shared_types::MsgUpdateClient { + client_id: data.client_id.to_string(), + client_message: data.client_message.into(), + relayer: relayer.into(), + }), + ), + ), + }) + .collect() +} diff --git a/voyager/plugins/packet-filter/Cargo.toml b/voyager/plugins/packet-filter/Cargo.toml new file mode 100644 index 0000000000..6d62d08d44 --- /dev/null +++ b/voyager/plugins/packet-filter/Cargo.toml @@ -0,0 +1,22 @@ +[package] +edition = "2021" +name = "voyager-plugin-packet-filter" +version = "0.1.0" + +[dependencies] +enumorph = { workspace = true } +frunk = { workspace = true } +futures = { workspace = true } +jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } +macros = { workspace = true } +queue-msg = { workspace = true } +regex = "1.10.6" +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +serde_with = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +unionlabs = { workspace = true } +voyager-message = { workspace = true } diff --git a/voyager/plugins/packet-filter/src/call.rs b/voyager/plugins/packet-filter/src/call.rs new file mode 100644 index 0000000000..9bb6889adc --- /dev/null +++ b/voyager/plugins/packet-filter/src/call.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCall {} diff --git a/voyager/plugins/packet-filter/src/callback.rs b/voyager/plugins/packet-filter/src/callback.rs new file mode 100644 index 0000000000..e3dbf95927 --- /dev/null +++ b/voyager/plugins/packet-filter/src/callback.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCallback {} diff --git a/voyager/plugins/packet-filter/src/data.rs b/voyager/plugins/packet-filter/src/data.rs new file mode 100644 index 0000000000..063c8f7f1d --- /dev/null +++ b/voyager/plugins/packet-filter/src/data.rs @@ -0,0 +1,6 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleData {} diff --git a/voyager/plugins/packet-filter/src/main.rs b/voyager/plugins/packet-filter/src/main.rs new file mode 100644 index 0000000000..d392cd4d0e --- /dev/null +++ b/voyager/plugins/packet-filter/src/main.rs @@ -0,0 +1,329 @@ +use std::collections::VecDeque; + +use jsonrpsee::core::{async_trait, RpcResult}; +use queue_msg::{optimize::OptimizationResult, BoxDynError, Op}; +use regex::Regex; +use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, DisplayFromStr}; +use tracing::{instrument, trace}; +use voyager_message::{ + data::Data, + module::{ModuleInfo, PluginModuleInfo, PluginModuleServer, QueueInteractionsServer}, + run_module_server, DefaultCmd, ModuleContext, ModuleServer, VoyagerMessage, +}; + +use crate::{call::ModuleCall, callback::ModuleCallback, data::ModuleData}; + +pub mod call; +pub mod callback; +pub mod data; + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + run_module_server::().await +} + +#[derive(Debug, Clone)] +pub struct Module { + pub connection_event_filters: Vec, + pub channel_event_filters: Vec, + pub packet_event_filters: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Config { + pub connection_event_filters: Vec, + pub channel_event_filters: Vec, + pub packet_event_filters: Vec, +} + +impl ModuleContext for Module { + type Config = Config; + type Cmd = DefaultCmd; + type Info = PluginModuleInfo; + + async fn new(config: Self::Config) -> Result { + Ok(Module::new(config)) + } + + fn info(config: Self::Config) -> ModuleInfo { + let module = Module::new(config); + + ModuleInfo { + name: module.plugin_name(), + kind: PluginModuleInfo { + interest_filter: module.make_filter(), + }, + } + } + + async fn cmd(_config: Self::Config, cmd: Self::Cmd) { + match cmd {} + } +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ConnectionEventFilter { + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub chain_id: Regex, + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub client_id: Regex, + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub counterparty_client_id: Regex, +} + +impl ConnectionEventFilter { + fn to_jaq(&self) -> String { + let Self { + chain_id, + client_id, + counterparty_client_id, + } = self; + + format!( + r#"( + ($chain_id | test("{chain_id}")) + and ($event.client_id | test("{client_id}")) + and ($event.counterparty_client_id | test("{counterparty_client_id}")) + )"# + ) + } +} + +fn match_any() -> Regex { + Regex::new(".*").unwrap() +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ChannelEventFilter { + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub chain_id: Regex, + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub connection_id: Regex, + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub port_id: Regex, + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub counterparty_port_id: Regex, + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub channel_version: Regex, +} + +impl ChannelEventFilter { + fn to_jaq(&self) -> String { + let Self { + chain_id, + connection_id, + port_id, + counterparty_port_id, + channel_version, + } = self; + + format!( + r#"( + ($chain_id | test("{chain_id}")) + and ($event.port_id | test("{port_id}")) + and ($event.counterparty_port_id | test("{counterparty_port_id }")) + and ($event.connection_id | test("{connection_id}")) + and ($event.version | test("{channel_version}")) + )"# + ) + } +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PacketEventFilter { + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub chain_id: Regex, + + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub source_connection_id: Regex, + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub source_port_id: Regex, + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub source_channel_id: Regex, + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub source_channel_version: Regex, + + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub destination_port_id: Regex, + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub destination_channel_id: Regex, + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub destination_connection_id: Regex, + #[serde_as(as = "DisplayFromStr")] + #[serde(default = "match_any")] + pub destination_channel_version: Regex, +} + +impl PacketEventFilter { + fn to_jaq(&self) -> String { + let Self { + chain_id, + source_connection_id, + source_port_id, + source_channel_id, + source_channel_version, + destination_port_id, + destination_channel_id, + destination_connection_id, + destination_channel_version, + } = self; + + format!( + r#"( + ($chain_id | test("{chain_id}")) + and ($event.packet.source_channel.port_id | test("{source_port_id}")) + and ($event.packet.source_channel.channel_id | test("{source_channel_id}")) + and ($event.packet.source_channel.version | test("{source_channel_version}")) + and ($event.packet.source_channel.connection.connection_id | test("{source_connection_id}")) + + and ($event.packet.destination_channel.port_id | test("{destination_port_id}")) + and ($event.packet.destination_channel.channel_id | test("{destination_channel_id}")) + and ($event.packet.destination_channel.version | test("{destination_channel_version}")) + and ($event.packet.destination_channel.connection.connection_id | test("{destination_connection_id}")) + )"# + ) + } +} + +impl Module { + fn plugin_name(&self) -> String { + pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); + + PLUGIN_NAME.to_owned() + } + + pub fn new(config: Config) -> Self { + Self { + connection_event_filters: config.connection_event_filters, + channel_event_filters: config.channel_event_filters, + packet_event_filters: config.packet_event_filters, + } + } + + /// Construct the filter that will run on every event. If this returns true, then this plugin will receive the event in it's optimization queue and drop it. + /// To accomplish this, the filter expresses "inverted interest" - since the regex filters filter *in* what we want to keep, this filter must return false for all messages that match the regex filters, the regex filters and true for everything else. + pub fn make_filter(&self) -> String { + // let filter = Term::<&str>::IfThenElse(vec![], Some(Box::new(Term::Call("false", vec![])))); + + // Filter::from(&filter) + + // if no filters are provided, then none all events for that specific IBC message type will be filtered out (i.e we express interest here). to do this, we return `false`, since in the context that this will be called in expresses whether or not the event matched one of the "filter in" regex filters. + let packet_filter = ["false".to_owned()] + .into_iter() + .chain(self.packet_event_filters.iter().map(|x| x.to_jaq())) + .collect::>() + .join(" or "); + let channel_filter = ["false".to_owned()] + .into_iter() + .chain(self.channel_event_filters.iter().map(|x| x.to_jaq())) + .collect::>() + .join(" or "); + let connection_filter = ["false".to_owned()] + .into_iter() + .chain(self.connection_event_filters.iter().map(|x| x.to_jaq())) + .collect::>() + .join(" or "); + + format!( + r#" +if ."@type" == "data" then + ."@value" as $data | + + if $data."@type" == "ibc_event" then + $data."@value".chain_id as $chain_id | + $data."@value".event."@type" as $event_type | + $data."@value".event."@value" as $event | + + (if $event_type == "send_packet" then + ({packet_filter}) + elif $event_type == "recv_packet" then + ({packet_filter}) + elif $event_type == "write_acknowledgement" then + ({packet_filter}) + + elif $event_type == "channel_open_init" then + ({channel_filter}) + elif $event_type == "channel_open_try" then + ({channel_filter}) + elif $event_type == "channel_open_ack" then + ({channel_filter}) + + elif $event_type == "connection_open_init" then + ({connection_filter}) + elif $event_type == "connection_open_try" then + ({connection_filter}) + elif $event_type == "connection_open_ack" then + ({connection_filter}) + else + true + end) + # the bool returned from the above expression denotes whether or not + # an IBC event matched the inclusion filters - invert the result to + # only express interest in messages that didn't match such that they + # can be dropped in our optimization pass + | not + else + # don't filter out data messages that aren't IBC events + false + end +else + # don't filter out non-data messages + false +end + "# + ) + } +} + +#[async_trait] +impl QueueInteractionsServer for ModuleServer { + #[instrument] + async fn call( + &self, + msg: ModuleCall, + ) -> RpcResult>> { + match msg {} + } + + #[instrument] + async fn callback( + &self, + cb: ModuleCallback, + _data: VecDeque>, + ) -> RpcResult>> { + match cb {} + } +} + +#[async_trait] +impl PluginModuleServer for ModuleServer { + #[instrument] + async fn run_pass( + &self, + msgs: Vec>>, + ) -> RpcResult>> { + trace!("dropping {} messages", msgs.len()); + + Ok(OptimizationResult::default()) + } +} diff --git a/voyager/plugins/transaction-batch/Cargo.toml b/voyager/plugins/transaction-batch/Cargo.toml new file mode 100644 index 0000000000..4eec7bb750 --- /dev/null +++ b/voyager/plugins/transaction-batch/Cargo.toml @@ -0,0 +1,27 @@ +[package] +edition = "2021" +name = "voyager-plugin-transaction-batch" +version = "0.1.0" + +[dependencies] +cometbft-rpc = { workspace = true } +dashmap = { workspace = true } +either = { workspace = true } +enumorph = { workspace = true } +frunk = { workspace = true } +futures = { workspace = true } +itertools = "0.13.0" +jsonrpsee = { workspace = true, features = ["macros", "server", "tracing"] } +macros = { workspace = true } +prost = { workspace = true } +protos = { workspace = true } +queue-msg = { workspace = true } +reconnecting-jsonrpc-ws-client = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } +unionlabs = { workspace = true } +voyager-message = { workspace = true } diff --git a/voyager/plugins/transaction-batch/src/call.rs b/voyager/plugins/transaction-batch/src/call.rs new file mode 100644 index 0000000000..2b41327c99 --- /dev/null +++ b/voyager/plugins/transaction-batch/src/call.rs @@ -0,0 +1,18 @@ +use enumorph::Enumorph; +use queue_msg::queue_msg; +use unionlabs::id::ClientId; + +use crate::data::BatchableEvent; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCall { + MakeTransactionBatchesWithUpdate(MakeTransactionBatchesWithUpdate), +} + +/// Constructs multiple batch transactions, where all of the batches are provable at the new consensus height. +#[queue_msg] +pub struct MakeTransactionBatchesWithUpdate { + pub client_id: ClientId, + pub batches: Vec>, +} diff --git a/voyager/plugins/transaction-batch/src/callback.rs b/voyager/plugins/transaction-batch/src/callback.rs new file mode 100644 index 0000000000..96a6272d30 --- /dev/null +++ b/voyager/plugins/transaction-batch/src/callback.rs @@ -0,0 +1,348 @@ +use std::collections::VecDeque; + +use enumorph::Enumorph; +use frunk::hlist_pat; +use jsonrpsee::core::RpcResult; +use queue_msg::{ + aggregation::{HListTryFromIterator, SubsetOf}, + call, conc, data, noop, promise, queue_msg, seq, Op, +}; +use tracing::warn; +use unionlabs::{ibc::core::client::height::Height, id::ClientId, QueryHeight}; +use voyager_message::{ + call::{ + MakeMsgAcknowledgement, MakeMsgChannelOpenAck, MakeMsgChannelOpenConfirm, + MakeMsgChannelOpenTry, MakeMsgConnectionOpenAck, MakeMsgConnectionOpenConfirm, + MakeMsgConnectionOpenTry, MakeMsgRecvPacket, WaitForTrustedHeight, + }, + callback::Callback, + data::{Data, IbcMessage, OrderedMsgUpdateClients, WithChainId}, + module::ClientStateMeta, + rpc::{json_rpc_error_to_rpc_error, VoyagerRpcClient}, + ChainId, ModuleServer, VoyagerMessage, +}; + +use crate::{ + call::ModuleCall, + data::{BatchableEvent, Event, ModuleData}, + Module, +}; + +#[queue_msg] +#[derive(Enumorph)] +pub enum ModuleCallback { + MakeIbcMessagesFromUpdate(MakeIbcMessagesFromUpdate), + MakeBatchTransaction(MakeBatchTransaction), +} + +/// Given an [`OrderedMsgUpdateClients`], returns [`Op`]s that generate [`IbcMessage`]s with proofs at the highest height of the updates. +#[queue_msg] +pub struct MakeIbcMessagesFromUpdate { + pub client_id: ClientId, + pub batches: Vec>, +} + +impl MakeIbcMessagesFromUpdate { + pub async fn call( + self, + module_server: &ModuleServer, + datas: VecDeque>, + ) -> RpcResult>> { + let Ok( + hlist_pat![ + updates @ OrderedMsgUpdateClients { .. }, + ], + ) = HListTryFromIterator::try_from_iter(datas) + else { + panic!("bad data") + }; + + let client_meta = module_server + .voyager_rpc_client + .client_meta( + module_server.ctx.chain_id.clone(), + QueryHeight::Latest, + self.client_id.clone(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let new_trusted_height = updates + .updates + .last() + .expect("must have at least one update") + .0 + .height; + + make_msgs( + module_server, + self.client_id, + self.batches, + Some(updates), + client_meta, + new_trusted_height, + ) + } +} + +pub fn make_msgs( + module_server: &ModuleServer, + + client_id: ClientId, + batches: Vec>, + + updates: Option, + + client_meta: ClientStateMeta, + new_trusted_height: Height, +) -> RpcResult>> { + Ok(conc(batches.into_iter().enumerate().map(|(i, batch)| { + promise( + batch.into_iter().map(|batchable_event| { + assert!(batchable_event.provable_height <= new_trusted_height); + + let origin_chain_id = client_meta.chain_id.clone(); + let target_chain_id = module_server.ctx.chain_id.clone(); + + // in this context, we are the destination - the counterparty of the source is the destination + match batchable_event.event { + Event::ConnectionOpenInit(connection_open_init_event) => { + call(MakeMsgConnectionOpenTry { + origin_chain_id, + origin_chain_proof_height: new_trusted_height, + target_chain_id, + connection_open_init_event, + }) + } + Event::ConnectionOpenTry(connection_open_try_event) => { + call(MakeMsgConnectionOpenAck { + origin_chain_id, + origin_chain_proof_height: new_trusted_height, + target_chain_id, + connection_open_try_event, + }) + } + Event::ConnectionOpenAck(connection_open_ack_event) => { + call(MakeMsgConnectionOpenConfirm { + origin_chain_id, + origin_chain_proof_height: new_trusted_height, + target_chain_id, + connection_open_ack_event, + }) + } + Event::ChannelOpenInit(channel_open_init_event) => { + call(MakeMsgChannelOpenTry { + origin_chain_id, + origin_chain_proof_height: new_trusted_height, + target_chain_id, + channel_open_init_event, + }) + } + Event::ChannelOpenTry(channel_open_try_event) => call(MakeMsgChannelOpenAck { + origin_chain_id, + origin_chain_proof_height: new_trusted_height, + target_chain_id, + channel_open_try_event, + }), + Event::ChannelOpenAck(channel_open_ack_event) => { + call(MakeMsgChannelOpenConfirm { + origin_chain_id, + origin_chain_proof_height: new_trusted_height, + target_chain_id, + channel_open_ack_event, + }) + } + Event::SendPacket(send_packet_event) => call(MakeMsgRecvPacket { + origin_chain_id, + origin_chain_proof_height: new_trusted_height, + target_chain_id, + send_packet_event, + }), + Event::WriteAcknowledgement(write_acknowledgement_event) => { + call(MakeMsgAcknowledgement { + origin_chain_id, + origin_chain_proof_height: new_trusted_height, + target_chain_id, + write_acknowledgement_event, + }) + } + } + }), + [], + Callback::plugin( + module_server.ctx.plugin_name(), + MakeBatchTransaction { + client_id: client_id.clone(), + // if updates are provided and this is the first batch using this update height, provide the updates along with the messages + updates: (i == 0).then(|| updates.clone()).flatten(), + }, + ), + ) + }))) +} + +#[queue_msg] +pub struct MakeBatchTransaction { + // NOTE: We could technically fetch this from the information in the callback data messages, but this is just so much easier + pub client_id: ClientId, + /// Updates to send before the messages in this message's callback data. If this is `None`, then that means the updates have been included in a previous batch, and this will instead be enqueued with a WaitForTrustedHeight in front of it. + pub updates: Option, +} + +impl MakeBatchTransaction { + pub fn call( + self, + chain_id: ChainId<'static>, + datas: VecDeque>, + ) -> Op> { + if datas.is_empty() { + warn!("no IBC messages in queue! this likely means that all of the IBC messages that were queued to be sent were already sent to the destination chain"); + } + + let msgs = datas + .into_iter() + .map(|d| IbcMessage::try_from_super(d).unwrap()); + + // TODO: We may need to sort packet messages when we support ordered channels + // msgs.sort_unstable_by(|a, b| match (a, b) { + // (IbcMessage::RecvPacket(_), IbcMessage::RecvPacket(_)) => todo!(), + // (IbcMessage::RecvPacket(_), IbcMessage::AcknowledgePacket(_)) => todo!(), + // (IbcMessage::RecvPacket(_), IbcMessage::TimeoutPacket(_)) => todo!(), + // (IbcMessage::AcknowledgePacket(_), IbcMessage::RecvPacket(_)) => todo!(), + // (IbcMessage::AcknowledgePacket(_), IbcMessage::AcknowledgePacket(_)) => todo!(), + // (IbcMessage::AcknowledgePacket(_), IbcMessage::TimeoutPacket(_)) => todo!(), + // (IbcMessage::TimeoutPacket(_), IbcMessage::RecvPacket(_)) => todo!(), + // (IbcMessage::TimeoutPacket(_), IbcMessage::AcknowledgePacket(_)) => todo!(), + // (IbcMessage::TimeoutPacket(_), IbcMessage::TimeoutPacket(_)) => todo!(), + // }); + + match self.updates { + Some(updates) => data(WithChainId { + chain_id, + message: updates + .updates + .into_iter() + .map(|(_, msg)| IbcMessage::from(msg)) + .chain(msgs) + .collect::>(), + }), + None => { + let msgs = msgs.collect::>(); + + if msgs.is_empty() { + noop() + } else { + // TODO: We can probably relax this in the future if we want to reuse this module to work with all IBC messages + // NOTE: We assume that all of the IBC messages were generated against the same consensus height + let required_consensus_height = msgs[0] + .proof_height() + .expect("all batchable messages have a proof height"); + + seq([ + call(WaitForTrustedHeight { + chain_id: chain_id.clone(), + client_id: self.client_id, + height: required_consensus_height, + }), + data(WithChainId { + chain_id, + message: msgs, + }), + ]) + } + } + } + } +} + +// #[derive(PartialEq, Eq)] +// pub struct OrderedIbcMessage(IbcMessage); + +// impl PartialOrd for OrderedIbcMessage { +// fn partial_cmp(&self, other: &Self) -> Option { +// Some(self.cmp(other)) +// } +// } + +// impl Ord for OrderedIbcMessage { +// fn cmp(&self, other: &Self) -> Ordering { +// use IbcMessage::*; +// use Ordering::*; + +// match (self.0, other.0) { +// (ConnectionOpenTry(lhs), ConnectionOpenTry(rhs)) => lhs, +// (ConnectionOpenTry(_), _) => Ordering::Less, +// (ConnectionOpenAck(_), ConnectionOpenAck(_)) => Ordering::Equal, +// (ConnectionOpenAck(_), ConnectionOpenConfirm(_)) => todo!(), +// (ConnectionOpenAck(_), ChannelOpenTry(_)) => todo!(), +// (ConnectionOpenAck(_), ChannelOpenAck(_)) => todo!(), +// (ConnectionOpenAck(_), ChannelOpenConfirm(_)) => todo!(), +// (ConnectionOpenAck(_), RecvPacket(_)) => todo!(), +// (ConnectionOpenAck(_), AcknowledgePacket(_)) => todo!(), +// (ConnectionOpenAck(_), TimeoutPacket(_)) => todo!(), +// (ConnectionOpenConfirm(_), ConnectionOpenTry(_)) => todo!(), +// (ConnectionOpenConfirm(_), ConnectionOpenAck(_)) => todo!(), +// (ConnectionOpenConfirm(_), ConnectionOpenConfirm(_)) => todo!(), +// (ConnectionOpenConfirm(_), ChannelOpenTry(_)) => todo!(), +// (ConnectionOpenConfirm(_), ChannelOpenAck(_)) => todo!(), +// (ConnectionOpenConfirm(_), ChannelOpenConfirm(_)) => todo!(), +// (ConnectionOpenConfirm(_), RecvPacket(_)) => todo!(), +// (ConnectionOpenConfirm(_), AcknowledgePacket(_)) => todo!(), +// (ConnectionOpenConfirm(_), TimeoutPacket(_)) => todo!(), +// (ChannelOpenTry(_), ConnectionOpenTry(_)) => todo!(), +// (ChannelOpenTry(_), ConnectionOpenAck(_)) => todo!(), +// (ChannelOpenTry(_), ConnectionOpenConfirm(_)) => todo!(), +// (ChannelOpenTry(_), ChannelOpenTry(_)) => todo!(), +// (ChannelOpenTry(_), ChannelOpenAck(_)) => todo!(), +// (ChannelOpenTry(_), ChannelOpenConfirm(_)) => todo!(), +// (ChannelOpenTry(_), RecvPacket(_)) => todo!(), +// (ChannelOpenTry(_), AcknowledgePacket(_)) => todo!(), +// (ChannelOpenTry(_), TimeoutPacket(_)) => todo!(), +// (ChannelOpenAck(_), ConnectionOpenTry(_)) => todo!(), +// (ChannelOpenAck(_), ConnectionOpenAck(_)) => todo!(), +// (ChannelOpenAck(_), ConnectionOpenConfirm(_)) => todo!(), +// (ChannelOpenAck(_), ChannelOpenTry(_)) => todo!(), +// (ChannelOpenAck(_), ChannelOpenAck(_)) => todo!(), +// (ChannelOpenAck(_), ChannelOpenConfirm(_)) => todo!(), +// (ChannelOpenAck(_), RecvPacket(_)) => todo!(), +// (ChannelOpenAck(_), AcknowledgePacket(_)) => todo!(), +// (ChannelOpenAck(_), TimeoutPacket(_)) => todo!(), +// (ChannelOpenConfirm(_), ConnectionOpenTry(_)) => todo!(), +// (ChannelOpenConfirm(_), ConnectionOpenAck(_)) => todo!(), +// (ChannelOpenConfirm(_), ConnectionOpenConfirm(_)) => todo!(), +// (ChannelOpenConfirm(_), ChannelOpenTry(_)) => todo!(), +// (ChannelOpenConfirm(_), ChannelOpenAck(_)) => todo!(), +// (ChannelOpenConfirm(_), ChannelOpenConfirm(_)) => todo!(), +// (ChannelOpenConfirm(_), RecvPacket(_)) => todo!(), +// (ChannelOpenConfirm(_), AcknowledgePacket(_)) => todo!(), +// (ChannelOpenConfirm(_), TimeoutPacket(_)) => todo!(), +// (RecvPacket(_), ConnectionOpenTry(_)) => todo!(), +// (RecvPacket(_), ConnectionOpenAck(_)) => todo!(), +// (RecvPacket(_), ConnectionOpenConfirm(_)) => todo!(), +// (RecvPacket(_), ChannelOpenTry(_)) => todo!(), +// (RecvPacket(_), ChannelOpenAck(_)) => todo!(), +// (RecvPacket(_), ChannelOpenConfirm(_)) => todo!(), +// (RecvPacket(_), RecvPacket(_)) => todo!(), +// (RecvPacket(_), AcknowledgePacket(_)) => todo!(), +// (RecvPacket(_), TimeoutPacket(_)) => todo!(), +// (AcknowledgePacket(_), ConnectionOpenTry(_)) => todo!(), +// (AcknowledgePacket(_), ConnectionOpenAck(_)) => todo!(), +// (AcknowledgePacket(_), ConnectionOpenConfirm(_)) => todo!(), +// (AcknowledgePacket(_), ChannelOpenTry(_)) => todo!(), +// (AcknowledgePacket(_), ChannelOpenAck(_)) => todo!(), +// (AcknowledgePacket(_), ChannelOpenConfirm(_)) => todo!(), +// (AcknowledgePacket(_), RecvPacket(_)) => todo!(), +// (AcknowledgePacket(_), AcknowledgePacket(_)) => todo!(), +// (AcknowledgePacket(_), TimeoutPacket(_)) => todo!(), +// (TimeoutPacket(_), ConnectionOpenTry(_)) => todo!(), +// (TimeoutPacket(_), ConnectionOpenAck(_)) => todo!(), +// (TimeoutPacket(_), ConnectionOpenConfirm(_)) => todo!(), +// (TimeoutPacket(_), ChannelOpenTry(_)) => todo!(), +// (TimeoutPacket(_), ChannelOpenAck(_)) => todo!(), +// (TimeoutPacket(_), ChannelOpenConfirm(_)) => todo!(), +// (TimeoutPacket(_), RecvPacket(_)) => todo!(), +// (TimeoutPacket(_), AcknowledgePacket(_)) => todo!(), +// (TimeoutPacket(_), TimeoutPacket(_)) => todo!(), +// } +// } +// } diff --git a/voyager/plugins/transaction-batch/src/data.rs b/voyager/plugins/transaction-batch/src/data.rs new file mode 100644 index 0000000000..daffe5c242 --- /dev/null +++ b/voyager/plugins/transaction-batch/src/data.rs @@ -0,0 +1,47 @@ +use enumorph::Enumorph; +use queue_msg::{queue_msg, SubsetOf}; +use unionlabs::{ibc::core::client::height::Height, id::ClientId}; +use voyager_message::data::{ + ChannelOpenAck, ChannelOpenInit, ChannelOpenTry, ConnectionOpenAck, ConnectionOpenInit, + ConnectionOpenTry, SendPacket, WriteAcknowledgement, +}; + +#[queue_msg] +#[derive(Enumorph, SubsetOf)] +pub enum ModuleData { + BatchEvents(EventBatch), +} + +#[queue_msg] +pub struct EventBatch { + /// The client that will need an update to send these messages through. + pub client_id: ClientId, + /// The on-chain events that will need to be turned into messages to send to this chain. + pub events: Vec, +} + +#[queue_msg] +pub struct BatchableEvent { + /// unix timestamp (in ms) of when this event was first seen by this plugin. + pub first_seen_at: u64, + // the 'provable height' of the event + pub provable_height: Height, + pub event: Event, +} + +// REVIEW: We probably want to add a way to have "a packet timed out" be a variant here as well +/// A subset of [`FullIbcEvent`], containing only events that cause an action on the counterparty chain. +#[queue_msg] +#[derive(Enumorph)] +pub enum Event { + ConnectionOpenInit(ConnectionOpenInit), + ConnectionOpenTry(ConnectionOpenTry), + ConnectionOpenAck(ConnectionOpenAck), + + ChannelOpenInit(ChannelOpenInit), + ChannelOpenTry(ChannelOpenTry), + ChannelOpenAck(ChannelOpenAck), + + SendPacket(SendPacket), + WriteAcknowledgement(WriteAcknowledgement), +} diff --git a/voyager/plugins/transaction-batch/src/main.rs b/voyager/plugins/transaction-batch/src/main.rs new file mode 100644 index 0000000000..d37463eee6 --- /dev/null +++ b/voyager/plugins/transaction-batch/src/main.rs @@ -0,0 +1,591 @@ +use std::{ + collections::{BTreeMap, HashMap, VecDeque}, + convert, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; + +use either::Either; +use futures::{stream::FuturesOrdered, StreamExt, TryFutureExt, TryStreamExt}; +use itertools::Itertools; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + types::ErrorObject, +}; +use queue_msg::{ + aggregation::SubsetOf, call, data, now, optimize::OptimizationResult, promise, seq, + BoxDynError, Op, +}; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use tracing::{debug, error, info, instrument, trace, warn}; +use unionlabs::{id::ClientId, QueryHeight}; +use voyager_message::{ + call::{Call, FetchUpdateHeaders, WaitForHeight}, + callback::{AggregateMsgUpdateClientsFromOrderedHeaders, Callback}, + data::{ChainEvent, Data, FullIbcEvent}, + module::{ModuleInfo, PluginModuleInfo, PluginModuleServer, QueueInteractionsServer}, + rpc::{json_rpc_error_to_rpc_error, VoyagerRpcClient}, + run_module_server, ChainId, DefaultCmd, ModuleContext, ModuleServer, PluginMessage, + VoyagerMessage, FATAL_JSONRPC_ERROR_CODE, +}; + +use crate::{ + call::{MakeTransactionBatchesWithUpdate, ModuleCall}, + callback::{make_msgs, MakeIbcMessagesFromUpdate, ModuleCallback}, + data::{BatchableEvent, EventBatch, ModuleData}, +}; + +pub mod call; +pub mod callback; +pub mod data; + +#[tokio::main(flavor = "multi_thread")] +async fn main() { + run_module_server::().await +} + +#[derive(Debug, Clone)] +pub struct Module { + pub chain_id: ChainId<'static>, + pub client_configs: ClientConfigs, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Config { + pub chain_id: ChainId<'static>, + pub client_configs: BTreeMap, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ClientConfig { + pub min_batch_size: usize, + pub max_batch_size: usize, + pub max_wait_time: Duration, +} + +#[derive(Debug, Clone)] +pub enum ClientConfigs { + Any(ClientConfig), + Many(BTreeMap), +} + +impl ClientConfigs { + fn new(mut configs: BTreeMap) -> Self { + // if-let chains one day + if configs.len() == 1 && configs.contains_key("*") { + Self::Any(configs.remove("*").unwrap()) + } else { + Self::Many( + configs + .into_iter() + .map(|x| (x.0.parse().unwrap(), x.1)) + .collect(), + ) + } + } + + fn config_for_client(&self, client_id: &ClientId) -> &ClientConfig { + match &self { + ClientConfigs::Any(any) => any, + ClientConfigs::Many(many) => &many[client_id], + } + } + + fn jaq_filter(&self) -> String { + match self { + ClientConfigs::Any(_) => "true".to_owned(), + ClientConfigs::Many(many) => { + let clients_json = serde_json::to_string( + &many.keys().map(|k| (k, ())).collect::>(), + ) + .unwrap(); + + format!("{clients_json} | has($client_id)") + } + } + } +} + +impl ModuleContext for Module { + type Config = Config; + type Cmd = DefaultCmd; + type Info = PluginModuleInfo; + + async fn new(config: Self::Config) -> Result { + Ok(Module::new(config)) + } + + fn info(config: Self::Config) -> ModuleInfo { + let module = Module::new(config); + + ModuleInfo { + name: module.plugin_name(), + kind: PluginModuleInfo { + interest_filter: format!( + r#" +if ."@type" == "data" then + ."@value" as $data | + + # pull all ibc events that cause an action on this chain (i.e. where we are the destination) + # the counterparty of the event origin is the destination + if $data."@type" == "ibc_event" and $data."@value".counterparty_chain_id == "{chain_id}" then + $data."@value".event."@type" as $event_type | + $data."@value".event."@value" as $event_data | + + ( + $event_type == "connection_open_init" + and ($event_data.counterparty_client_id as $client_id | {clients_filter}) + ) or ( + $event_type == "connection_open_try" + and ($event_data.counterparty_client_id as $client_id | {clients_filter}) + ) or ( + $event_type == "connection_open_ack" + and ($event_data.counterparty_client_id as $client_id | {clients_filter}) + ) or ( + $event_type == "channel_open_init" + and ($event_data.connection.counterparty.client_id as $client_id | {clients_filter}) + ) or ( + $event_type == "channel_open_try" + and ($event_data.connection.counterparty.client_id as $client_id | {clients_filter}) + ) or ( + $event_type == "channel_open_ack" + and ($event_data.connection.counterparty.client_id as $client_id | {clients_filter}) + ) or ( + $event_type == "send_packet" + and ($event_data.packet.destination_channel.connection.client_id as $client_id | {clients_filter}) + ) or ( + $event_type == "write_acknowledgement" + and ($event_data.packet.source_channel.connection.client_id as $client_id | {clients_filter}) + ) or ($data."@type" == "plugin" + and $data."@value".plugin == "{plugin_name}" + and $data."@value".message."@type" == "event_batch") + else + false + end +else + false +end +"#, + chain_id = module.chain_id, + plugin_name = module.plugin_name(), + clients_filter = module.client_configs.jaq_filter() + ), + }, + } + } + + async fn cmd(_config: Self::Config, cmd: Self::Cmd) { + match cmd {} + } +} + +pub const PLUGIN_NAME: &str = env!("CARGO_PKG_NAME"); + +impl Module { + fn plugin_name(&self) -> String { + format!("{PLUGIN_NAME}/{}", self.chain_id) + } + + pub fn new(config: Config) -> Self { + // // TODO: Make this a better error + // assert!(config.min_batch_size <= config.max_batch_size); + + Self { + chain_id: config.chain_id, + client_configs: ClientConfigs::new(config.client_configs), + } + } +} + +#[async_trait] +impl QueueInteractionsServer for ModuleServer { + #[instrument(skip_all)] + async fn call( + &self, + msg: ModuleCall, + ) -> RpcResult>> { + match msg { + ModuleCall::MakeTransactionBatchesWithUpdate(MakeTransactionBatchesWithUpdate { + client_id, + batches, + }) => { + let client_meta = self + .voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + QueryHeight::Latest, + client_id.clone(), + ) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + // let client_info = self + // .client + // .client_info(self.chain_id.clone(), client_id.clone()) + // .await + // .map_err(json_rpc_error_to_rpc_error)?; + + let latest_height = self + .voyager_rpc_client + .query_latest_height(client_meta.chain_id.clone()) + .await + .map_err(json_rpc_error_to_rpc_error)?; + + let target_height = batches + .iter() + .flatten() + .map(|e| e.provable_height) + .max() + .expect("batch has at least one event; qed;"); + + // at this point we assume that a valid update exists - we only ever enqueue this message behind the relevant WaitForHeight on the counterparty chain. to prevent explosions, we do a sanity check here. + if latest_height < target_height { + return Err(ErrorObject::owned( + FATAL_JSONRPC_ERROR_CODE, + format!( + "the latest height of the counterparty chain ({counterparty_chain_id}) \ + is {latest_height} and the latest trusted height on the client tracking \ + it ({client_id}) on this chain ({self_chain_id}) is {trusted_height}. \ + in order to create an update for this client, we need to wait for the \ + counterparty chain to progress to the next consensus checkpoint greater \ + than the required target height {target_height}", + counterparty_chain_id = client_meta.chain_id, + trusted_height = client_meta.height, + client_id = client_id, + self_chain_id = self.ctx.chain_id, + ), + Some(json!({ + "current_timestamp": now(), + })), + )); + } + + if client_meta.height >= target_height { + info!( + "client {client_id} has already been updated to a height \ + >= the desired target height ({} >= {target_height})", + client_meta.height, + ); + + make_msgs( + self, + client_id, + batches, + None, + client_meta.clone(), + client_meta.height, + ) + } else { + Ok(promise( + [promise( + [call(FetchUpdateHeaders { + counterparty_chain_id: self.ctx.chain_id.clone(), + chain_id: client_meta.chain_id, + update_from: client_meta.height, + update_to: latest_height, + })], + [], + AggregateMsgUpdateClientsFromOrderedHeaders { + chain_id: self.ctx.chain_id.clone(), + counterparty_client_id: client_id.clone(), + }, + )], + [], + Callback::plugin( + self.ctx.plugin_name(), + MakeIbcMessagesFromUpdate { + client_id: client_id.clone(), + batches, + }, + ), + )) + } + } + } + } + + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn callback( + &self, + cb: ModuleCallback, + datas: VecDeque>, + ) -> RpcResult>> { + match cb { + ModuleCallback::MakeIbcMessagesFromUpdate(cb) => cb.call(self, datas).await, + ModuleCallback::MakeBatchTransaction(cb) => { + Ok(cb.call(self.ctx.chain_id.clone(), datas)) + } + } + } +} + +#[async_trait] +impl PluginModuleServer for ModuleServer { + #[instrument(skip_all, fields(chain_id = %self.ctx.chain_id))] + async fn run_pass( + &self, + msgs: Vec>>, + ) -> RpcResult>> { + let mut batchers = HashMap::>::new(); + + for (idx, msg) in msgs.into_iter().enumerate() { + let Op::Data(msg) = msg else { + error!("unexpected message: {msg:?}"); + + continue; + }; + + match ChainEvent::try_from_super(msg) { + Ok(chain_event) => { + // the client id of the client on this chain (we are the counterparty from the perspective of the chain where the event was emitted) + // this is the client that will need to be updated before this ibc message can be sent + let client_id = chain_event + .counterparty_client_id() + .expect("all batchable messages have a counterparty"); + + trace!(%client_id, "batching event"); + + let first_seen_at: u64 = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_millis() + .try_into() + .expect("how many milliseconds can there be man"); + + batchers.entry(client_id.clone()).or_default().push(( + idx, + match chain_event.event { + FullIbcEvent::ConnectionOpenInit(event) => BatchableEvent { + first_seen_at, + provable_height: chain_event.provable_height, + event: event.into(), + }, + FullIbcEvent::ConnectionOpenTry(event) => BatchableEvent { + first_seen_at, + provable_height: chain_event.provable_height, + event: event.into(), + }, + FullIbcEvent::ConnectionOpenAck(event) => BatchableEvent { + first_seen_at, + provable_height: chain_event.provable_height, + event: event.into(), + }, + + FullIbcEvent::ChannelOpenInit(event) => BatchableEvent { + first_seen_at, + provable_height: chain_event.provable_height, + event: event.into(), + }, + FullIbcEvent::ChannelOpenTry(event) => BatchableEvent { + first_seen_at, + provable_height: chain_event.provable_height, + event: event.into(), + }, + FullIbcEvent::ChannelOpenAck(event) => BatchableEvent { + first_seen_at, + provable_height: chain_event.provable_height, + event: event.into(), + }, + + FullIbcEvent::SendPacket(event) => BatchableEvent { + first_seen_at, + provable_height: chain_event.provable_height, + event: event.into(), + }, + FullIbcEvent::WriteAcknowledgement(event) => BatchableEvent { + first_seen_at, + provable_height: chain_event.provable_height, + event: event.into(), + }, + + event => panic!("unexpected event: {event:?}"), + }, + )); + } + Err(msg) => { + match >::try_from_super(msg) { + Ok(PluginMessage { plugin: _, message }) => { + trace!( + client_id = %message.client_id, + events.len = %message.events.len(), + "batching event" + ); + + batchers + .entry(message.client_id) + .or_default() + .extend(message.events.into_iter().map(|event| (idx, event))); + } + Err(msg) => { + error!("unexpected message: {msg:?}"); + } + }; + } + }; + } + + let (ready, optimize_further) = batchers + .into_iter() + .flat_map(|(client_id, mut events)| { + let client_config = &self.ctx.client_configs.config_for_client(&client_id); + + events.sort_by_key(|e| e.1.first_seen_at); + + let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + let is_overdue = |first_seen_at| { + Duration::from_millis(first_seen_at) + client_config.max_wait_time < now + }; + + let (mut overdue_events, mut events): (Vec<_>, Vec<_>) = + events.into_iter().partition_map(|e| { + if is_overdue(e.1.first_seen_at) { + Either::Left(e) + } else { + Either::Right(e) + } + }); + + events.sort_by_key(|e| e.1.provable_height); + overdue_events.sort_by_key(|e| e.1.provable_height); + + if !overdue_events.is_empty() + && overdue_events.len() + events.len() < client_config.min_batch_size + { + warn!( + "found {} overdue events and {} non-overdue events, but the min batch \ + size for this client ({client_id}) is {}", + overdue_events.len(), + events.len(), + client_config.min_batch_size + ); + } + + // [...overdue_events_sorted_by_provable_height, ...events_sorted_by_provable_height] + overdue_events + .into_iter() + .chain(events) + .chunks(client_config.max_batch_size) + .into_iter() + .map(move |chunk| { + let (idxs, events): (Vec<_>, Vec<_>) = chunk.into_iter().unzip(); + + if events.len() == client_config.max_batch_size + || events.iter().any(|e| is_overdue(e.first_seen_at)) + { + // this batch is ready to send out, we need to fetch an update for the client on our chain and turn the events into `IbcMessage`s. + // + // in order to do this, we first need to figure out what height the client is at, and request an update from that height to a height >= the highest height of all of the messages in this batch. + // note that we can't request a *specific* height to update to, since not all chains provide this functionality (ethereum being a notable one) - we instead need to wait for the update to be constructed, and then use the new trusted height of the update to fetch our proofs from. + // + // this will be done in a multi-step aggregation, where first we fetch the update, then construct the messages, and then turn that into a batch transaction. + + // // the height on the counterparty chain that all of the events are provable at + // let target_height = events + // .iter() + // .map(|e| e.provable_height) + // .max() + // .expect("batch has at least one event; qed;"); + + Either::Left((client_id.clone(), (idxs, events))) + // self.client + // .client_meta( + // self.chain_id.clone(), + // QueryHeight::Latest, + // client_id.clone(), + // ) + // .map_ok({ + // let client_id = client_id.clone(); + // move |client_meta| { + // ( + // idxs, + // seq([ + // call(WaitForHeight { + // chain_id: client_meta.chain_id, + // height: target_height, + // }), + // call(Call::plugin( + // self.ctx.plugin_name(), + // MakeTransactionBatchWithUpdate { + // batch: EventBatch { client_id, events }, + // }, + // )), + // ]), + // ) + // } + // }), + } else { + Either::Right(( + idxs, + data(Data::plugin( + self.ctx.plugin_name(), + EventBatch { + client_id: client_id.clone(), + events, + }, + )), + self.ctx.plugin_name(), + )) + } + }) + .collect::>() + }) + .partition_map::, Vec<_>, _, _, _>(convert::identity); + + let ready = ready + .into_iter() + .into_group_map() + .into_iter() + .map(|(client_id, events)| { + // the height on the counterparty chain that all of the events in these batches are provable at + // we only want to generate one update for all of these batches + let target_height = events + .iter() + .flat_map(|x| &x.1) + .map(|e| e.provable_height) + .max() + .expect("batch has at least one event; qed;"); + + debug!(%client_id, "querying client meta for client"); + + self.voyager_rpc_client + .client_meta( + self.ctx.chain_id.clone(), + QueryHeight::Latest, + client_id.clone(), + ) + .map_ok({ + let client_id = client_id.clone(); + move |client_meta| { + let (idxs, events): (Vec<_>, Vec<_>) = events.into_iter().unzip(); + + ( + idxs.into_iter().flatten().collect::>(), + seq([ + call(WaitForHeight { + chain_id: client_meta.chain_id, + height: target_height, + }), + call(Call::plugin( + self.ctx.plugin_name(), + MakeTransactionBatchesWithUpdate { + client_id, + batches: events, + }, + )), + ]), + ) + } + }) + }) + .collect::>(); + + Ok(OptimizationResult { + optimize_further, + ready: ready + .map(|x| x) + .try_collect() + .await + .map_err(json_rpc_error_to_rpc_error)?, + }) + } +} diff --git a/voyager/prometheus.yml b/voyager/prometheus.yml index d991b91f12..f2f48f47e0 100644 --- a/voyager/prometheus.yml +++ b/voyager/prometheus.yml @@ -3,7 +3,7 @@ scrape_configs: metrics_path: /metrics static_configs: # Replace the port with the port your /metrics endpoint is running on - - targets: ['localhost:65534'] + - targets: ['localhost:7717'] # For a real deployment, you would want the scrape interval to be # longer but for testing, you want the data to show up quickly scrape_interval: 200ms diff --git a/voyager/src/cli.rs b/voyager/src/cli.rs index 94a8877204..887ccbad94 100644 --- a/voyager/src/cli.rs +++ b/voyager/src/cli.rs @@ -1,36 +1,20 @@ -use std::{ffi::OsString, marker::PhantomData, str::FromStr, sync::Arc}; +use std::ffi::OsString; -use chain_utils::Chains; -use clap::{ - error::{ContextKind, ContextValue, ErrorKind}, - Args, FromArgMatches, Parser, Subcommand, -}; -use frunk::{hlist_pat, HList}; -use queue_msg::{ - aggregation::UseAggregate, - optimize::{passes::NormalizeFinal, Pure}, - run_to_completion, InMemoryQueue, -}; -use relay_message::{ - data::{IbcProof, IbcState}, - use_aggregate::IsAggregateData, - ChainExt, DoFetchProof, DoFetchState, Identified, RelayMessage, -}; -use tracing::info; +use chain_utils::BoxDynError; +use clap::{self, Parser, Subcommand}; use unionlabs::{ + self, bounded::BoundedI64, - ibc::core::{channel, client::height::Height}, - ics24::{ - self, AcknowledgementPath, ChannelEndPath, ClientConsensusStatePath, ClientStatePath, - CommitmentPath, ConnectionPath, IbcPath, NextClientSequencePath, - NextConnectionSequencePath, NextSequenceAckPath, NextSequenceRecvPath, - NextSequenceSendPath, ReceiptPath, - }, - id::{ClientId, ConnectionId, PortId}, + ics24::{self, Path}, result_unwrap, - traits::HeightOf, + uint::U256, QueryHeight, }; +use voyager_message::ChainId; + +use crate::cli::handshake::HandshakeCmd; + +pub mod handshake; #[derive(Debug, Parser)] #[command(arg_required_else_help = true)] @@ -40,7 +24,7 @@ pub struct AppArgs { short = 'c', env, global = true, - default_value = "~/.config/voyager/config.json" + default_value = "voyager/devnet-config.json" )] pub config_file_path: OsString, #[arg(long, short = 'l', env, global = true, default_value_t = LogFormat::default())] @@ -60,619 +44,37 @@ pub enum LogFormat { Json, } -#[derive(Debug)] -pub struct HandshakeCmd { - pub chain_a: String, - pub chain_b: String, - - pub ty: HandshakeType, -} - -impl Args for HandshakeCmd { - fn augment_args(cmd: clap::Command) -> clap::Command { - HandshakeRaw::augment_args(cmd) - } - - fn augment_args_for_update(cmd: clap::Command) -> clap::Command { - HandshakeRaw::augment_args_for_update(cmd) - } -} - -impl HandshakeCmd { - pub fn from_raw(mut raw: HandshakeRaw) -> Result { - use HandshakeType::*; - - let msg = |arg: &str| { - let mut err = clap::Error::new(ErrorKind::MissingRequiredArgument); - err.insert( - ContextKind::InvalidArg, - ContextValue::Strings(vec![format!("--{}", arg.replace('_', "-"))]), - ); - err - }; - - macro_rules! fields { - ($Ty:ident { $($field:ident,)+ }) => { - $Ty { - $( - $field: raw.$field.take().ok_or_else(|| msg(stringify!($field)))?, - )+ - } - }; - } - - let ty = match (raw.create_clients, raw.open_connection, raw.open_channel) { - (true, true, true) => fields!(ClientConnectionChannel { - client_a_config, - client_b_config, - port_a, - port_b, - channel_version, - connection_ordering, - channel_ordering, - }), - (true, true, false) => fields!(ClientConnection { - client_a_config, - client_b_config, - connection_ordering, - }), - (true, false, true) => { - let mut err = clap::Error::new(ErrorKind::MissingRequiredArgument); - err.insert( - ContextKind::Usage, - ContextValue::StyledStr( - "--open-connection is required when passing --create-clients and --open-channel".into() - ), - ); - return Err(err); - } - (true, false, false) => fields!(Client { - client_a_config, - client_b_config, - }), - (false, true, true) => fields!(ConnectionChannel { - client_a, - client_b, - port_a, - port_b, - channel_version, - connection_ordering, - channel_ordering, - }), - (false, true, false) => fields!(Connection { - client_a, - client_b, - connection_ordering, - }), - (false, false, true) => fields!(Channel { - connection_a, - port_a, - port_b, - channel_version, - channel_ordering, - }), - (false, false, false) => { - let mut err = clap::Error::new(ErrorKind::MissingRequiredArgument); - err.insert( - ContextKind::Usage, - ContextValue::StyledStr( - "One of --create-clients, --open-connection, or --open-channel is required" - .into(), - ), - ); - return Err(err); - } - }; - - raw.assert_empty()?; - - Ok(Self { - chain_a: raw.chain_a, - chain_b: raw.chain_b, - ty, - }) - } -} - -#[derive(Debug)] -pub enum HandshakeType { - Client { - client_a_config: serde_json::Value, - client_b_config: serde_json::Value, - }, - ClientConnection { - client_a_config: serde_json::Value, - client_b_config: serde_json::Value, - connection_ordering: Vec, - }, - ClientConnectionChannel { - client_a_config: serde_json::Value, - client_b_config: serde_json::Value, - port_a: PortId, - port_b: PortId, - channel_version: String, - connection_ordering: Vec, - channel_ordering: channel::order::Order, - }, - ConnectionChannel { - client_a: ClientId, - client_b: ClientId, - port_a: PortId, - port_b: PortId, - channel_version: String, - connection_ordering: Vec, - channel_ordering: channel::order::Order, - }, - Connection { - client_a: ClientId, - client_b: ClientId, - connection_ordering: Vec, - }, - Channel { - connection_a: ConnectionId, - port_a: PortId, - port_b: PortId, - channel_version: String, - channel_ordering: channel::order::Order, - }, -} - -impl FromArgMatches for HandshakeCmd { - fn from_arg_matches(matches: &clap::ArgMatches) -> Result { - HandshakeRaw::from_arg_matches(matches).and_then(Self::from_raw) - } - - fn update_from_arg_matches(&mut self, _matches: &clap::ArgMatches) -> Result<(), clap::Error> { - todo!() - } -} - -#[derive(Debug, Args)] -pub struct HandshakeRaw { - #[arg(required = true)] - pub chain_a: String, - #[arg(required = true)] - pub chain_b: String, - - #[arg(long)] - pub create_clients: bool, - #[arg( - long, - value_parser(::from_str), - )] - pub client_a_config: Option, - #[arg( - long, - value_parser(::from_str), - )] - pub client_b_config: Option, - - #[arg(long)] - pub client_a: Option, - #[arg(long)] - pub client_b: Option, - - #[arg(long)] - pub open_connection: bool, - - #[arg(long)] - pub connection_a: Option, - // #[arg(long, conflicts_with = "open_connection")] - // connection_b: Option, - #[arg(long)] - pub open_channel: bool, - #[arg(long)] - pub port_a: Option, - #[arg(long)] - pub port_b: Option, - #[arg(long)] - pub channel_version: Option, - #[arg( - long, - value_parser( - // don't ask questions you don't want the answer to - |s: &str| serde_json::from_value::(>::from(s)) - ), - )] - pub channel_ordering: Option, - #[arg( - long, - value_parser( - // don't ask questions you don't want the answer to - |s: &str| serde_json::from_value::(>::from(s)) - ), - )] - pub connection_ordering: Option>, -} - -impl HandshakeRaw { - fn assert_empty(&self) -> clap::error::Result<()> { - macro_rules! none_or_err { - ($($field:ident,)+) => { - $( - if self.$field.is_some() { - let mut err = clap::Error::new(ErrorKind::UnknownArgument); - err.insert( - ContextKind::InvalidArg, - ContextValue::String(format!("--{}", stringify!($field).replace('_', "-"))), - ); - return Err(err) - } - )+ - }; - } - - none_or_err! { - client_a_config, - client_b_config, - - client_a, - client_b, - - connection_a, - port_a, - port_b, - channel_version, - channel_ordering, - connection_ordering, - } - - Ok(()) - } -} - #[derive(Debug, Subcommand)] #[allow(clippy::large_enum_variant)] pub enum Command { - RunMigrations, PrintConfig, Handshake(HandshakeCmd), + /// Construct a `FetchBlocks` message to send to the specified chain. The message will start at the current latest height of the chain. InitFetch { - on: String, + chain_id: String, }, + /// Run Voyager. Relay, #[command(subcommand)] Queue(QueueCmd), #[command(subcommand)] Util(UtilCmd), - #[command(subcommand)] - Signer(SignerCmd), + Module { + plugin_name: Option, + #[arg(trailing_var_arg = true, allow_hyphen_values = true, hide = true)] + args: Vec, + }, Query { - #[arg(long)] - on: String, - #[arg(long)] - tracking: String, - #[arg(long, default_value_t = QueryHeight::::Latest)] - at: QueryHeight, + #[arg(value_parser(|s: &str| Ok::<_, BoxDynError>(ChainId::new(s.to_owned()))))] + on: ChainId<'static>, + #[arg(long, default_value_t = QueryHeight::Latest)] + height: QueryHeight, #[command(subcommand)] - cmd: QueryCmd, + path: ics24::Path, }, } -#[derive(Debug, Subcommand)] -pub enum QueryCmd { - #[command(subcommand)] - IbcPath(ics24::Path), -} - -pub async fn any_state_proof_to_json( - chains: Arc, - path: ics24::Path, - c: Hc, - height: QueryHeight>, -) -> serde_json::Value -where - Hc: ChainExt + DoFetchState + DoFetchProof, - Tr: ChainExt, - - Identified, Hc, Tr>>: IsAggregateData, - Identified, Hc, Tr>>: IsAggregateData, - - Identified, Hc, Tr>>: - IsAggregateData, - Identified, Hc, Tr>>: - IsAggregateData, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, - - Identified>: IsAggregateData, - Identified>: IsAggregateData, -{ - use serde_json::to_value as json; - - let height = match height { - QueryHeight::Latest => c.query_latest_height().await.unwrap(), - QueryHeight::Specific(height) => height, - }; - - info!("latest height is {height}"); - - let msgs = [ - Hc::state(&c, height, path.clone()), - Hc::proof(&c, height, path.clone()), - ]; - - match path { - ics24::Path::ClientState(path) => json( - &run_to_completion::<_, _, _, InMemoryQueue<_>, _, _>( - FetchStateProof { - path, - height, - __marker: PhantomData, - }, - chains, - (), - msgs, - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await, - ), - ics24::Path::ClientConsensusState(path) => json( - &run_to_completion::<_, _, _, InMemoryQueue<_>, _, _>( - FetchStateProof { - path, - height, - __marker: PhantomData, - }, - chains, - (), - msgs, - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await, - ), - ics24::Path::Connection(path) => json( - &run_to_completion::<_, _, _, InMemoryQueue<_>, _, _>( - FetchStateProof { - path, - height, - __marker: PhantomData, - }, - chains, - (), - msgs, - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await, - ), - ics24::Path::ChannelEnd(path) => json( - &run_to_completion::<_, _, _, InMemoryQueue<_>, _, _>( - FetchStateProof { - path, - height, - __marker: PhantomData, - }, - chains, - (), - msgs, - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await, - ), - ics24::Path::Commitment(path) => json( - &run_to_completion::<_, _, _, InMemoryQueue<_>, _, _>( - FetchStateProof { - path, - height, - __marker: PhantomData, - }, - chains, - (), - msgs, - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await, - ), - ics24::Path::Acknowledgement(path) => json( - &run_to_completion::<_, _, _, InMemoryQueue<_>, _, _>( - FetchStateProof { - path, - height, - __marker: PhantomData, - }, - chains, - (), - msgs, - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await, - ), - ics24::Path::Receipt(path) => json( - &run_to_completion::<_, _, _, InMemoryQueue<_>, _, _>( - FetchStateProof { - path, - height, - __marker: PhantomData, - }, - chains, - (), - msgs, - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await, - ), - ics24::Path::NextSequenceSend(path) => json( - &run_to_completion::<_, _, _, InMemoryQueue<_>, _, _>( - FetchStateProof { - path, - height, - __marker: PhantomData, - }, - chains, - (), - msgs, - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await, - ), - ics24::Path::NextSequenceRecv(path) => json( - &run_to_completion::<_, _, _, InMemoryQueue<_>, _, _>( - FetchStateProof { - path, - height, - __marker: PhantomData, - }, - chains, - (), - msgs, - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await, - ), - ics24::Path::NextSequenceAck(path) => json( - &run_to_completion::<_, _, _, InMemoryQueue<_>, _, _>( - FetchStateProof { - path, - height, - __marker: PhantomData, - }, - chains, - (), - msgs, - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await, - ), - ics24::Path::NextConnectionSequence(path) => json( - &run_to_completion::<_, _, _, InMemoryQueue<_>, _, _>( - FetchStateProof { - path, - height, - __marker: PhantomData, - }, - chains, - (), - msgs, - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await, - ), - ics24::Path::NextClientSequence(path) => json( - &run_to_completion::<_, _, _, InMemoryQueue<_>, _, _>( - FetchStateProof { - path, - height, - __marker: PhantomData, - }, - chains, - (), - msgs, - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await, - ), - } - .unwrap() -} - -#[derive(Debug, serde::Serialize)] -#[serde(bound(serialize = ""))] -struct StateProof> { - #[serde(with = "::serde_utils::string")] - path: P, - state: P::Value, - proof: Hc::StateProof, - height: HeightOf, -} - -#[derive(Debug, serde::Serialize)] -#[serde(bound(serialize = ""))] -// TODO: Replace with TupleAggregator -struct FetchStateProof> { - #[serde(with = "::serde_utils::string")] - path: P, - height: HeightOf, - #[serde(skip)] - pub __marker: PhantomData Tr>, -} - -impl> - UseAggregate> for FetchStateProof -where - Identified>: IsAggregateData, - Identified>: IsAggregateData, -{ - type AggregatedData = - HList![Identified>, Identified>]; - - fn aggregate( - this: Self, - hlist_pat![ - Identified { - chain_id: _state_chain_id, - t: IbcState { - path: state_path, - height: state_height, - state, - }, - __marker: _, - }, - Identified { - chain_id: _proof_chain_id, - t: IbcProof { - path: proof_path, - height: proof_height, - proof, - __marker: _, - }, - __marker: _, - }, - ]: Self::AggregatedData, - ) -> StateProof { - assert_eq!(state_path, proof_path); - assert_eq!(this.path, proof_path); - assert_eq!(state_height, proof_height); - assert_eq!(this.height, proof_height); - - StateProof { - path: this.path, - state, - proof, - height: this.height, - } - } -} - -// type PgId = BoundedI64<1, { i64::MAX }>; type Pg64 = BoundedI64<0, { i64::MAX }>; -// type Pg32 = BoundedI32<1, { i32::MAX }>; #[derive(Debug, Subcommand)] pub enum QueueCmd { @@ -691,25 +93,13 @@ pub enum QueueCmd { #[derive(Debug, Subcommand)] pub enum UtilCmd { - QueryLatestHeight { - on: String, - }, - QuerySelfConsensusState { - on: String, - #[arg(long, default_value_t = QueryHeight::Latest)] - height: QueryHeight, - }, - QuerySelfClientState { - on: String, - #[arg(long, default_value_t = QueryHeight::Latest)] - height: QueryHeight, + /// Compute the EVM IBC commitment key for the given IBC commitment path. + IbcCommitmentKey { + #[command(subcommand)] + path: Path, + #[arg(long, default_value_t = U256::ZERO)] + commitment_slot: U256, }, - #[command(subcommand)] - Ethereum(EthereumCmd), - #[command(subcommand)] - Arbitrum(ArbitrumCmd), - #[command(subcommand)] - Berachain(BerachainCmd), } #[derive(Debug, Subcommand)] @@ -720,39 +110,3 @@ pub enum SignerCmd { on: Option, }, } - -#[derive(Debug, Subcommand)] -pub enum ArbitrumCmd { - NextNodeNumAtBeaconSlot { on: String, slot: u64 }, - ExecutionHeightOfBeaconSlot { on: String, slot: u64 }, -} - -#[derive(Debug, Subcommand)] -pub enum BerachainCmd { - ExecutionHeightOfBeaconSlot { on: String, slot: u64 }, - ExecutionHeaderAtBeaconSlot { on: String, slot: u64 }, - BeaconHeaderAtBeaconSlot { on: String, slot: u64 }, -} - -#[derive(Debug, Subcommand)] -pub enum EthereumCmd { - ExecutionHeightOfBeaconSlot { on: String, slot: u64 }, -} - -#[derive(Debug, Subcommand)] -pub enum SubmitPacketCmd { - Transfer { - #[arg(long)] - on: String, - #[arg(long)] - denom: String, - #[arg(long)] - amount: u64, - #[arg(long)] - receiver: String, - #[arg(long)] - source_port: String, - #[arg(long)] - source_channel: String, - }, -} diff --git a/voyager/src/cli/handshake.rs b/voyager/src/cli/handshake.rs new file mode 100644 index 0000000000..107b1623bf --- /dev/null +++ b/voyager/src/cli/handshake.rs @@ -0,0 +1,272 @@ +use std::str::FromStr; + +use clap::{ + error::{ContextKind, ContextValue, ErrorKind}, + Args, FromArgMatches, +}; +use unionlabs::{ + ibc::core::channel, + id::{ClientId, ConnectionId, PortId}, +}; +use voyager_message::ChainId; + +#[derive(Debug)] +pub struct HandshakeCmd { + pub chain_a: ChainId<'static>, + pub chain_b: ChainId<'static>, + + pub ty: HandshakeType, +} + +impl Args for HandshakeCmd { + fn augment_args(cmd: clap::Command) -> clap::Command { + HandshakeRaw::augment_args(cmd) + } + + fn augment_args_for_update(cmd: clap::Command) -> clap::Command { + HandshakeRaw::augment_args_for_update(cmd) + } +} + +impl HandshakeCmd { + pub fn from_raw(mut raw: HandshakeRaw) -> Result { + use HandshakeType::*; + + let msg = |arg: &str| { + let mut err = clap::Error::new(ErrorKind::MissingRequiredArgument); + err.insert( + ContextKind::InvalidArg, + ContextValue::Strings(vec![format!("--{}", arg.replace('_', "-"))]), + ); + err + }; + + macro_rules! fields { + ($Ty:ident { $($field:ident,)+ }) => { + $Ty { + $( + $field: raw.$field.take().ok_or_else(|| msg(stringify!($field)))?, + )+ + } + }; + } + + let ty = match (raw.create_clients, raw.open_connection, raw.open_channel) { + (true, true, true) => fields!(ClientConnectionChannel { + client_a_config, + client_b_config, + port_a, + port_b, + channel_version, + connection_ordering, + channel_ordering, + }), + (true, true, false) => fields!(ClientConnection { + client_a_config, + client_b_config, + connection_ordering, + }), + (true, false, true) => { + let mut err = clap::Error::new(ErrorKind::MissingRequiredArgument); + err.insert( + ContextKind::Usage, + ContextValue::StyledStr( + "--open-connection is required when passing --create-clients and --open-channel".into() + ), + ); + return Err(err); + } + (true, false, false) => fields!(Client { + client_a_config, + client_b_config, + }), + (false, true, true) => fields!(ConnectionChannel { + client_a, + client_b, + port_a, + port_b, + channel_version, + connection_ordering, + channel_ordering, + }), + (false, true, false) => fields!(Connection { + client_a, + client_b, + connection_ordering, + }), + (false, false, true) => fields!(Channel { + connection_a, + port_a, + port_b, + channel_version, + channel_ordering, + }), + (false, false, false) => { + let mut err = clap::Error::new(ErrorKind::MissingRequiredArgument); + err.insert( + ContextKind::Usage, + ContextValue::StyledStr( + "One of --create-clients, --open-connection, or --open-channel is required" + .into(), + ), + ); + return Err(err); + } + }; + + raw.assert_empty()?; + + Ok(Self { + chain_a: ChainId::new(raw.chain_a), + chain_b: ChainId::new(raw.chain_b), + ty, + }) + } +} + +#[derive(Debug)] +pub enum HandshakeType { + Client { + client_a_config: serde_json::Value, + client_b_config: serde_json::Value, + }, + ClientConnection { + client_a_config: serde_json::Value, + client_b_config: serde_json::Value, + connection_ordering: Vec, + }, + ClientConnectionChannel { + client_a_config: serde_json::Value, + client_b_config: serde_json::Value, + port_a: PortId, + port_b: PortId, + channel_version: String, + connection_ordering: Vec, + channel_ordering: channel::order::Order, + }, + ConnectionChannel { + client_a: ClientId, + client_b: ClientId, + port_a: PortId, + port_b: PortId, + channel_version: String, + connection_ordering: Vec, + channel_ordering: channel::order::Order, + }, + Connection { + client_a: ClientId, + client_b: ClientId, + connection_ordering: Vec, + }, + Channel { + connection_a: ConnectionId, + port_a: PortId, + port_b: PortId, + channel_version: String, + channel_ordering: channel::order::Order, + }, +} + +impl FromArgMatches for HandshakeCmd { + fn from_arg_matches(matches: &clap::ArgMatches) -> Result { + HandshakeRaw::from_arg_matches(matches).and_then(Self::from_raw) + } + + fn update_from_arg_matches(&mut self, _matches: &clap::ArgMatches) -> Result<(), clap::Error> { + todo!() + } +} + +#[derive(Debug, Args)] +pub struct HandshakeRaw { + #[arg(required = true)] + pub chain_a: String, + #[arg(required = true)] + pub chain_b: String, + + #[arg(long)] + pub create_clients: bool, + #[arg( + long, + value_parser(::from_str), + )] + pub client_a_config: Option, + #[arg( + long, + value_parser(::from_str), + )] + pub client_b_config: Option, + + #[arg(long)] + pub client_a: Option, + #[arg(long)] + pub client_b: Option, + + #[arg(long)] + pub open_connection: bool, + + #[arg(long)] + pub connection_a: Option, + // #[arg(long, conflicts_with = "open_connection")] + // connection_b: Option, + #[arg(long)] + pub open_channel: bool, + #[arg(long)] + pub port_a: Option, + #[arg(long)] + pub port_b: Option, + #[arg(long)] + pub channel_version: Option, + #[arg( + long, + value_parser( + // don't ask questions you don't want the answer to + |s: &str| serde_json::from_value::(>::from(s)) + ), + )] + pub channel_ordering: Option, + #[arg( + long, + value_parser( + // don't ask questions you don't want the answer to + |s: &str| serde_json::from_value::(>::from(s)) + ), + )] + pub connection_ordering: Option>, +} + +impl HandshakeRaw { + pub(crate) fn assert_empty(&self) -> clap::error::Result<()> { + macro_rules! none_or_err { + ($($field:ident,)+) => { + $( + if self.$field.is_some() { + let mut err = clap::Error::new(ErrorKind::UnknownArgument); + err.insert( + ContextKind::InvalidArg, + ContextValue::String(format!("--{}", stringify!($field).replace('_', "-"))), + ); + return Err(err) + } + )+ + }; + } + + none_or_err! { + client_a_config, + client_b_config, + + client_a, + client_b, + + connection_a, + port_a, + port_b, + channel_version, + channel_ordering, + connection_ordering, + } + + Ok(()) + } +} diff --git a/voyager/src/config.rs b/voyager/src/config.rs index a59434b9be..48e759d1ca 100644 --- a/voyager/src/config.rs +++ b/voyager/src/config.rs @@ -1,50 +1,35 @@ -use std::{collections::BTreeMap, net::SocketAddr}; +use std::net::SocketAddr; -use chain_utils::{AnyChain, AnyChainTryFromConfigError, ChainConfigType}; use serde::{Deserialize, Serialize}; +use voyager_message::context::ModuleConfig; -use crate::{passes::tx_batch::TxBatch, queue::AnyQueueConfig}; +use crate::queue::AnyQueueConfig; #[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(bound(serialize = "", deserialize = ""), deny_unknown_fields)] +#[serde(deny_unknown_fields)] pub struct Config { - /// Map of chain name to it's respective config. - pub chain: BTreeMap, + pub plugins: Vec, pub voyager: VoyagerConfig, } #[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] pub struct VoyagerConfig { pub num_workers: u16, - pub laddr: SocketAddr, + #[serde(default = "default_rest_laddr")] + pub rest_laddr: SocketAddr, + #[serde(default = "default_rpc_laddr")] + pub rpc_laddr: SocketAddr, pub queue: AnyQueueConfig, - pub tx_batch: TxBatch, + // pub tx_batch: TxBatch, #[serde(default)] pub optimizer_delay_milliseconds: u64, } -impl Config { - pub async fn get_chain(&self, name: &str) -> Result { - match self.chain.get(name) { - Some(config) => Ok(AnyChain::try_from_config(config.ty.clone()).await?), - None => Err(GetChainError::ChainNotFound { - name: name.to_string(), - }), - } - } +pub fn default_rest_laddr() -> SocketAddr { + "0.0.0.0:7177".parse().unwrap() } -#[derive(Debug, thiserror::Error)] -pub enum GetChainError { - #[error("chain `{name}` not found in config")] - ChainNotFound { name: String }, - #[error("error initializing chain")] - AnyChainTryFromConfig(#[from] AnyChainTryFromConfigError), -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ChainConfig { - pub enabled: bool, - #[serde(flatten)] - pub ty: ChainConfigType, +pub fn default_rpc_laddr() -> SocketAddr { + "0.0.0.0:7178".parse().unwrap() } diff --git a/voyager/src/main.rs b/voyager/src/main.rs index 27b3722c99..342d063275 100644 --- a/voyager/src/main.rs +++ b/voyager/src/main.rs @@ -8,74 +8,33 @@ )] use std::{ - collections::HashMap, - error::Error, ffi::OsString, fmt::{Debug, Write}, fs::read_to_string, iter, - marker::PhantomData, process::ExitCode, - sync::Arc, }; -use chain_utils::{ - any_chain, - arbitrum::Arbitrum, - berachain::Berachain, - cosmos::Cosmos, - ethereum::{Ethereum, EthereumConsensusChain}, - keyring::ChainKeyring, - scroll::Scroll, - union::Union, - wasm::Wasm, - AnyChain, ChainConfigType, Chains, EthereumChainConfig, IncorrectChainTypeError, - LightClientType, -}; +use chain_utils::BoxDynError; use clap::Parser; -use queue_msg::{ - aggregate, - aggregation::TupleAggregator, - conc, defer_relative, effect, event, fetch, - optimize::{passes::NormalizeFinal, Pure}, - repeat, run_to_completion, seq, InMemoryQueue, Op, -}; -use relay_message::{ - aggregate::{ - AggregateWaitForConnectionOpen, AggregateWaitForNextClientSequence, - AggregateWaitForNextConnectionSequence, - }, - data::IbcState, - RelayMessage, -}; +use queue_msg::call; use serde::Serialize; -use sqlx::query_as; +use serde_json::{json, Value}; +use serde_utils::Hex; use tikv_jemallocator::Jemalloc; use tracing_subscriber::EnvFilter; -use unionlabs::{ - ethereum::config::{Mainnet, Minimal, PresetBaseKind}, - ibc::core::{ - channel::{self, channel::Channel, msg_channel_open_init::MsgChannelOpenInit}, - commitment::merkle_prefix::MerklePrefix, - connection::{self, msg_connection_open_init::MsgConnectionOpenInit, version::Version}, - }, - ics24::{ConnectionPath, NextClientSequencePath, NextConnectionSequencePath}, - id::ClientId, - traits::{Chain, ClientIdOf}, - QueryHeight, +use unionlabs::{ethereum::ibc_commitment_key, ics24}; +use voyager_message::{ + call::FetchBlock, context::get_module_info, module::ChainModuleClient, ChainId, VoyagerMessage, }; -use voyager_message::{FromOp, VoyagerFetch, VoyagerMessage}; #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; use crate::{ - cli::{ - any_state_proof_to_json, AppArgs, ArbitrumCmd, BerachainCmd, Command, EthereumCmd, - HandshakeCmd, HandshakeType, QueryCmd, SignerCmd, UtilCmd, - }, - config::{Config, GetChainError}, - queue::{chains_from_config, AnyQueueConfig, RunError, Voyager, VoyagerInitError}, + cli::{AppArgs, Command, UtilCmd}, + config::Config, + queue::{AnyQueueConfig, Voyager, VoyagerInitError}, }; pub mod cli; @@ -83,8 +42,6 @@ pub mod config; pub mod queue; -pub mod passes; - fn main() -> ExitCode { let args = AppArgs::parse(); @@ -92,11 +49,13 @@ fn main() -> ExitCode { cli::LogFormat::Text => { tracing_subscriber::fmt() .with_env_filter(EnvFilter::from_default_env()) + // .with_span_events(FmtSpan::CLOSE) .init(); } cli::LogFormat::Json => { tracing_subscriber::fmt() .with_env_filter(EnvFilter::from_default_env()) + // .with_span_events(FmtSpan::CLOSE) .json() .init(); } @@ -140,33 +99,17 @@ pub enum VoyagerError { #[source] source: serde_json::Error, }, - #[error("error retrieving a chain from the config")] - GetChain(#[from] GetChainError), #[error("error initializing voyager")] Init(#[from] VoyagerInitError), - #[error("error while running migrations")] - Migrations(#[from] MigrationsError), #[error("fatal error encountered")] - Run(#[from] RunError), + Run(#[from] BoxDynError), #[error("unable to run command")] - Command(#[source] Box), - #[error("chain was not of expected type")] - IncorrectChainType(#[from] IncorrectChainTypeError), -} - -#[derive(Debug, thiserror::Error)] -pub enum MigrationsError { - #[error("running migrations requires the `pg-queue` queue config")] - IncorrectQueueConfig, - #[error(transparent)] - Sqlx(#[from] sqlx::Error), - #[error(transparent)] - Migrate(#[from] sqlx::migrate::MigrateError), + Command(#[source] BoxDynError), } #[allow(clippy::too_many_lines)] // NOTE: This function is a mess, will be cleaned up -async fn do_main(args: cli::AppArgs) -> Result<(), VoyagerError> { +async fn do_main(args: cli::AppArgs) -> Result<(), BoxDynError> { let mut voyager_config = read_to_string(&args.config_file_path) .map_err(|err| VoyagerError::ConfigFileNotFound { path: args.config_file_path.clone(), @@ -180,1025 +123,258 @@ async fn do_main(args: cli::AppArgs) -> Result<(), VoyagerError> { })?; match args.command { - Command::RunMigrations => { - run_migrations(voyager_config).await?; - } Command::PrintConfig => { print_json(&voyager_config); } Command::Relay => { - let queue = Voyager::new(voyager_config.clone()).await?; + let voyager = Voyager::new(voyager_config.clone()).await?; - queue.run().await?; - } - Command::Query { - on: on_name, - at, - cmd, - tracking, - } => { - query(&mut voyager_config, on_name, tracking, cmd, at).await?; + voyager.run().await?; } - Command::Queue(cli_msg) => { - let db = match voyager_config.voyager.queue { - AnyQueueConfig::PgQueue(cfg) => cfg.into_pg_pool().await.unwrap(), - _ => panic!("no database set in config"), - }; - - type Item = sqlx::types::Json>; - - match cli_msg { - // NOTE: Temporarily disabled until i figure out a better way to implement this with the new queue design - // cli::QueueCmd::History { id, max_depth } => { - // // let results = query_as!( - // // Record, - // // r#"SELECT id as "id!", parent, item as "item!: Item" FROM get_list($1, $2) ORDER BY id ASC"#, - // // id.inner(), - // // max_depth.inner() - // // ) - // // .fetch_all(&db) - // // .await - // // .unwrap(); - - // // println!("{}", serde_json::to_string_pretty(&results).unwrap()); - - // todo!(); - // } - cli::QueueCmd::Failed { page, per_page } => { - #[derive(Debug, serde::Serialize)] - struct Record { - id: i64, - message: String, - item: Item, - } - - let results = query_as!( - Record, - r#"SELECT id, item as "item: Item", message as "message!" FROM queue WHERE status = 'failed' ORDER BY id ASC LIMIT $1 OFFSET $2"#, - per_page.inner(), - ((page.inner() - 1) * per_page.inner()), - ) - .fetch_all(&db) - .await - .unwrap(); - - print_json(&results); - } + Command::Module { plugin_name, args } => match plugin_name { + Some(module_name) => { + let module_config = voyager_config + .plugins + .into_iter() + .find(|module_config| { + module_name == get_module_info(module_config).unwrap().name + }) + .expect("module not found"); + + tokio::process::Command::new(&module_config.path) + .arg("cmd") + .arg("--config") + .arg(module_config.config.to_string()) + .args(args) + .spawn()? + .wait() + .await?; } - } - Command::Handshake(HandshakeCmd { - chain_a, - chain_b, - ty, - }) => { - let chain_a = voyager_config.get_chain(&chain_a).await?; - let chain_b = voyager_config.get_chain(&chain_b).await?; - - let chains = Arc::new(chains_from_config(voyager_config.chain).await.unwrap()); - - let all_msgs = match (chain_a, chain_b) { - (AnyChain::Union(union), AnyChain::Cosmos(cosmos)) => { - mk_handshake::>(&union, &Wasm(cosmos), ty, chains).await - } - (AnyChain::Union(union), AnyChain::EthereumMainnet(ethereum)) => { - mk_handshake::, Ethereum>( - &Wasm(union), - ðereum, - ty, - chains, - ) - .await - } - (AnyChain::Union(union), AnyChain::EthereumMinimal(ethereum)) => { - mk_handshake::, Ethereum>( - &Wasm(union), - ðereum, - ty, - chains, - ) - .await - } - (AnyChain::Union(union), AnyChain::Scroll(scroll)) => { - mk_handshake::, Scroll>(&Wasm(union), &scroll, ty, chains).await + None => { + for module_config in voyager_config.plugins { + println!("{}", get_module_info(&module_config).unwrap().name); } - (AnyChain::Union(union), AnyChain::Arbitrum(scroll)) => { - mk_handshake::, Arbitrum>(&Wasm(union), &scroll, ty, chains).await - } - (AnyChain::Union(union), AnyChain::Berachain(berachain)) => { - mk_handshake::, Berachain>(&Wasm(union), &berachain, ty, chains) - .await - } - (AnyChain::Cosmos(cosmos), AnyChain::Union(union)) => { - mk_handshake::, Union>(&Wasm(cosmos), &union, ty, chains).await - } - (AnyChain::Cosmos(cosmos_a), AnyChain::Cosmos(cosmos_b)) => { - mk_handshake::(&cosmos_a, &cosmos_b, ty, chains).await - } - (AnyChain::EthereumMainnet(ethereum), AnyChain::Union(union)) => { - mk_handshake::, Wasm>( - ðereum, - &Wasm(union), - ty, - chains, - ) - .await - } - (AnyChain::EthereumMinimal(ethereum), AnyChain::Union(union)) => { - mk_handshake::, Wasm>( - ðereum, - &Wasm(union), - ty, - chains, - ) - .await - } - (AnyChain::Scroll(scroll), AnyChain::Union(union)) => { - mk_handshake::>(&scroll, &Wasm(union), ty, chains).await - } - (AnyChain::Arbitrum(scroll), AnyChain::Union(union)) => { - mk_handshake::>(&scroll, &Wasm(union), ty, chains).await + } + }, + Command::Query { on, height, path } => { + let voyager = Voyager::new(voyager_config.clone()).await?; + + let height = voyager.context.rpc_server.query_height(&on, height).await?; + + let state = voyager + .context + .rpc_server + .query_ibc_state(&on, height, path.clone()) + .await? + .state; + + let state = match &path { + ics24::Path::ClientState(path) => { + let client_info = voyager + .context + .rpc_server + .client_info(&on, path.client_id.clone()) + .await?; + + voyager + .context + .rpc_server + .decode_client_state( + &client_info.client_type, + &client_info.ibc_interface, + serde_json::from_value::>>(state).unwrap().0, + ) + .await? } - (AnyChain::Berachain(berachain), AnyChain::Union(union)) => { - mk_handshake::>(&berachain, &Wasm(union), ty, chains) - .await + ics24::Path::ClientConsensusState(path) => { + let client_info = voyager + .context + .rpc_server + .client_info(&on, path.client_id.clone()) + .await?; + + voyager + .context + .rpc_server + .decode_consensus_state( + &client_info.client_type, + &client_info.ibc_interface, + serde_json::from_value::>>(state).unwrap().0, + ) + .await? } - _ => panic!("invalid"), + _ => state, }; - print_json(&all_msgs); - } - Command::InitFetch { on } => { - let on = voyager_config.get_chain(&on).await?; - - let msg = any_chain!(|on| mk_init_fetch::(&on).await); + voyager.shutdown().await; - print_json(&msg); + print_json(&json!({ + "path": path.to_string(), + "state": state, + })); } - Command::Util(util) => match util { - UtilCmd::QueryLatestHeight { on } => { - let on = voyager_config.get_chain(&on).await?; - - // TODO: Figure out how to use `any_chain!` here - let height = match on { - AnyChain::Union(on) => on - .query_latest_height() - .await - .map_err(|e| VoyagerError::Command(Box::new(e)))?, - AnyChain::Cosmos(on) => on - .query_latest_height() - .await - .map_err(|e| VoyagerError::Command(Box::new(e)))?, - AnyChain::EthereumMainnet(on) => on - .query_latest_height() - .await - .map_err(|e| VoyagerError::Command(Box::new(e)))?, - AnyChain::EthereumMinimal(on) => on - .query_latest_height() - .await - .map_err(|e| VoyagerError::Command(Box::new(e)))?, - AnyChain::Scroll(on) => on - .query_latest_height() - .await - .map_err(|e| VoyagerError::Command(e))?, - AnyChain::Arbitrum(on) => on - .query_latest_height() - .await - .map_err(|e| VoyagerError::Command(e))?, - AnyChain::Berachain(on) => on - .query_latest_height() - .await - .map_err(|e| VoyagerError::Command(Box::new(e)))?, - }; - - print_json(&height); - } - UtilCmd::QuerySelfConsensusState { on, height } => { - let on = voyager_config.get_chain(&on).await?; - - any_chain!(|on| { - let height = match height { - QueryHeight::Latest => on.query_latest_height().await.unwrap(), - QueryHeight::Specific(height) => height, - }; - - print_json(&on.self_consensus_state(height).await) - }); - } - UtilCmd::QuerySelfClientState { on, height } => { - let on = voyager_config.get_chain(&on).await?; - - any_chain!(|on| { - let height = match height { - QueryHeight::Latest => on.query_latest_height().await.unwrap(), - QueryHeight::Specific(height) => height, - }; - - print_json(&on.self_client_state(height).await) - }); - } - UtilCmd::Arbitrum(cmd) => match cmd { - ArbitrumCmd::NextNodeNumAtBeaconSlot { on, slot } => print_json( - &voyager_config - .get_chain(&on.to_string()) - .await? - .downcast::()? - .next_node_num_at_beacon_slot(slot) - .await, - ), - ArbitrumCmd::ExecutionHeightOfBeaconSlot { on, slot } => print_json( - &voyager_config - .get_chain(&on.to_string()) - .await? - .downcast::()? - .execution_height_of_beacon_slot(slot) - .await, - ), - }, - UtilCmd::Berachain(cmd) => match cmd { - BerachainCmd::ExecutionHeightOfBeaconSlot { on, slot } => print_json( - &voyager_config - .get_chain(&on.to_string()) - .await? - .downcast::()? - .execution_height_of_beacon_slot(slot) - .await, - ), - BerachainCmd::ExecutionHeaderAtBeaconSlot { on, slot } => print_json( - &voyager_config - .get_chain(&on.to_string()) - .await? - .downcast::()? - .execution_header_at_beacon_slot(slot) - .await, - ), - BerachainCmd::BeaconHeaderAtBeaconSlot { on, slot } => print_json( - &voyager_config - .get_chain(&on.to_string()) - .await? - .downcast::()? - .beacon_block_header_at_beacon_slot(slot) - .await, - ), - }, - UtilCmd::Ethereum(cmd) => match cmd { - EthereumCmd::ExecutionHeightOfBeaconSlot { on, slot } => { - print_json(&match voyager_config.get_chain(&on.to_string()).await? { - AnyChain::EthereumMainnet(on) => { - on.execution_height_of_beacon_slot(slot).await - } - AnyChain::EthereumMinimal(on) => { - on.execution_height_of_beacon_slot(slot).await - } - chain => panic!( - "chain type for `{}` not supported for this method", - chain.chain_id() - ), - }) - } - }, - }, - Command::Signer(cmd) => match cmd { - SignerCmd::Balances { on } => match on { - Some(on) => { - let on = voyager_config.get_chain(&on).await.unwrap(); + Command::Queue(_cli_msg) => { + todo!() + } + // Command::Queue(cli_msg) => { + // let db = match voyager_config.voyager.queue { + // AnyQueueConfig::PgQueue(cfg) => cfg.into_pg_pool().await.unwrap(), + // _ => panic!("no database set in config"), + // }; + + // type Item = sqlx::types::Json>; + + // match cli_msg { + // // NOTE: Temporarily disabled until i figure out a better way to implement this with the new queue design + // // cli::QueueCmd::History { id, max_depth } => { + // // // let results = query_as!( + // // // Record, + // // // r#"SELECT id as "id!", parent, item as "item!: Item" FROM get_list($1, $2) ORDER BY id ASC"#, + // // // id.inner(), + // // // max_depth.inner() + // // // ) + // // // .fetch_all(&db) + // // // .await + // // // .unwrap(); + + // // // println!("{}", serde_json::to_string_pretty(&results).unwrap()); + + // // todo!(); + // // } + // cli::QueueCmd::Failed { page, per_page } => { + // #[derive(Debug, serde::Serialize)] + // struct Record { + // id: i64, + // message: String, + // item: Item, + // } + + // let results = query_as!( + // Record, + // r#"SELECT id, item as "item: Item", message as "message!" FROM queue WHERE status = 'failed' ORDER BY id ASC LIMIT $1 OFFSET $2"#, + // per_page.inner(), + // ((page.inner() - 1) * per_page.inner()), + // ) + // .fetch_all(&db) + // .await + // .unwrap(); + + // print_json(&results); + // } + // } + // } + Command::Handshake(_) => todo!(), + // Command::Handshake(HandshakeCmd { + // chain_a, + // chain_b, + // ty, + // }) => { + // let chain_a = voyager_config.get_chain(&chain_a).await?; + // let chain_b = voyager_config.get_chain(&chain_b).await?; + + // let chains = Arc::new(chains_from_config(voyager_config.chain).await.unwrap()); + + // let all_msgs = match (chain_a, chain_b) { + // (AnyChain::Union(union), AnyChain::Cosmos(cosmos)) => { + // mk_handshake::>(&union, &Wasm(cosmos), ty, chains).await + // } + // (AnyChain::Union(union), AnyChain::EthereumMainnet(ethereum)) => { + // mk_handshake::, Ethereum>( + // &Wasm(union), + // ðereum, + // ty, + // chains, + // ) + // .await + // } + // (AnyChain::Union(union), AnyChain::EthereumMinimal(ethereum)) => { + // mk_handshake::, Ethereum>( + // &Wasm(union), + // ðereum, + // ty, + // chains, + // ) + // .await + // } + // (AnyChain::Union(union), AnyChain::Scroll(scroll)) => { + // mk_handshake::, Scroll>(&Wasm(union), &scroll, ty, chains).await + // } + // (AnyChain::Union(union), AnyChain::Arbitrum(scroll)) => { + // mk_handshake::, Arbitrum>(&Wasm(union), &scroll, ty, chains).await + // } + // (AnyChain::Union(union), AnyChain::Berachain(berachain)) => { + // mk_handshake::, Berachain>(&Wasm(union), &berachain, ty, chains) + // .await + // } + // (AnyChain::Cosmos(cosmos), AnyChain::Union(union)) => { + // mk_handshake::, Union>(&Wasm(cosmos), &union, ty, chains).await + // } + // (AnyChain::Cosmos(cosmos_a), AnyChain::Cosmos(cosmos_b)) => { + // mk_handshake::(&cosmos_a, &cosmos_b, ty, chains).await + // } + // (AnyChain::EthereumMainnet(ethereum), AnyChain::Union(union)) => { + // mk_handshake::, Wasm>( + // ðereum, + // &Wasm(union), + // ty, + // chains, + // ) + // .await + // } + // (AnyChain::EthereumMinimal(ethereum), AnyChain::Union(union)) => { + // mk_handshake::, Wasm>( + // ðereum, + // &Wasm(union), + // ty, + // chains, + // ) + // .await + // } + // (AnyChain::Scroll(scroll), AnyChain::Union(union)) => { + // mk_handshake::>(&scroll, &Wasm(union), ty, chains).await + // } + // (AnyChain::Arbitrum(scroll), AnyChain::Union(union)) => { + // mk_handshake::>(&scroll, &Wasm(union), ty, chains).await + // } + // (AnyChain::Berachain(berachain), AnyChain::Union(union)) => { + // mk_handshake::>(&berachain, &Wasm(union), ty, chains) + // .await + // } + // _ => panic!("invalid"), + // }; + + // print_json(&all_msgs); + // } + Command::InitFetch { chain_id } => { + voyager_config.voyager.queue = AnyQueueConfig::InMemory; + + let voyager = Voyager::new(voyager_config).await?; + + let chain = voyager + .context + .chain_module::(&ChainId::new(&chain_id)) + .unwrap(); - any_chain!(|on| { - print_json(&on.balances().await); - }); - } - None => { - let chains = chains_from_config(voyager_config.chain).await.unwrap(); + let height = chain.query_latest_height().await.unwrap(); - let balances = signer_balances(&chains).await; + voyager.shutdown().await; - print_json(&balances); - } - }, + print_json(&call::>(FetchBlock { + chain_id: ChainId::new(chain_id), + height, + })); + } + Command::Util(util) => match util { + UtilCmd::IbcCommitmentKey { + path, + commitment_slot, + } => print_json(&ibc_commitment_key(&path.to_string(), commitment_slot).to_be_hex()), }, } Ok(()) } -async fn signer_balances(chains: &Chains) -> HashMap { - let mut balances = HashMap::new(); - - for (chain_id, chain) in &chains.chains { - any_chain!(|chain| { - balances.insert( - chain_id.to_string(), - serde_json::to_value(chain.balances().await).unwrap(), - ); - }); - } - - balances -} - -async fn query( - voyager_config: &mut Config, - on_name: String, - tracking: String, - cmd: QueryCmd, - at: QueryHeight, -) -> Result<(), VoyagerError> { - let on = voyager_config.get_chain(&on_name).await?; - let tracking = voyager_config - .chain - .get(&tracking) - .expect("chain not found in config") - .clone(); - - let chains = Arc::new( - chains_from_config( - [voyager_config - .chain - .remove_entry(&on_name) - .expect("chain is present as it was retrieved previously")] - .into_iter() - .collect(), - ) - .await - .unwrap(), - ); - match cmd { - QueryCmd::IbcPath(path) => { - let json = match (on, &tracking.ty) { - (AnyChain::Union(union), ChainConfigType::Cosmos(_)) => { - any_state_proof_to_json::>(chains, path, union, at).await - } - ( - AnyChain::Union(union), - ChainConfigType::Ethereum(EthereumChainConfig { - preset_base: PresetBaseKind::Mainnet, - .. - }), - ) => { - // NOTE: ChainSpec is arbitrary - any_state_proof_to_json::, Ethereum>( - chains, - path, - Wasm(union), - at, - ) - .await - } - (AnyChain::Union(union), ChainConfigType::Scroll(_)) => { - any_state_proof_to_json::, Scroll>(chains, path, Wasm(union), at) - .await - } - (AnyChain::Union(union), ChainConfigType::Arbitrum(_)) => { - any_state_proof_to_json::, Arbitrum>(chains, path, Wasm(union), at) - .await - } - ( - AnyChain::Union(union), - ChainConfigType::Ethereum(EthereumChainConfig { - preset_base: PresetBaseKind::Minimal, - .. - }), - ) => { - any_state_proof_to_json::, Ethereum>( - chains, - path, - Wasm(union), - at, - ) - .await - } - (AnyChain::Union(union), ChainConfigType::Berachain(_)) => { - any_state_proof_to_json::, Berachain>(chains, path, Wasm(union), at) - .await - } - (AnyChain::Cosmos(cosmos), ChainConfigType::Union(_)) => { - // NOTE: ChainSpec is arbitrary - any_state_proof_to_json::, Union>(chains, path, Wasm(cosmos), at) - .await - } - (AnyChain::EthereumMainnet(ethereum), ChainConfigType::Union(_)) => { - any_state_proof_to_json::, Wasm>( - chains, path, ethereum, at, - ) - .await - } - - (AnyChain::EthereumMinimal(ethereum), ChainConfigType::Union(_)) => { - any_state_proof_to_json::, Wasm>( - chains, path, ethereum, at, - ) - .await - } - - (AnyChain::Scroll(scroll), ChainConfigType::Union(_)) => { - any_state_proof_to_json::>(chains, path, scroll, at).await - } - - (AnyChain::Arbitrum(arbitrum), ChainConfigType::Union(_)) => { - any_state_proof_to_json::>(chains, path, arbitrum, at) - .await - } - - (AnyChain::Berachain(berachain), ChainConfigType::Union(_)) => { - any_state_proof_to_json::>(chains, path, berachain, at) - .await - } - (AnyChain::Cosmos(cosmos), ChainConfigType::Cosmos(_)) => { - any_state_proof_to_json::(chains, path, cosmos, at).await - } - - _ => panic!("unsupported"), - }; - - print_json(&json); - } - }; - - Ok(()) -} - -async fn run_migrations(_voyager_config: Config) -> Result<(), VoyagerError> { - // let AnyQueueConfig::PgQueue(PgQueueConfig { database_url, .. }) = voyager_config.voyager.queue - // else { - // return Err(VoyagerError::Migrations( - // MigrationsError::IncorrectQueueConfig, - // )); - // }; - - // let pool = PgPool::connect(&database_url) - // .await - // .map_err(MigrationsError::Sqlx)?; - - // pg_queue::MIGRATOR - // .run(&pool) - // .await - // .map_err(MigrationsError::Migrate)?; - - // Ok(()) - - todo!() -} - fn print_json(t: &T) { println!("{}", serde_json::to_string(&t).unwrap()) } - -async fn mk_handshake( - a: &A, - b: &B, - ty: HandshakeType, - chains: Arc, -) -> Op -where - A: relay_message::ChainExt> + LightClientType, - B: relay_message::ChainExt> + LightClientType, - - relay_message::AnyLightClientIdentified: - From>>, - relay_message::AnyLightClientIdentified: - From>>, - - relay_message::AnyLightClientIdentified: - From>>, - relay_message::AnyLightClientIdentified: - From>>, - - relay_message::AnyLightClientIdentified: - From>>, - relay_message::AnyLightClientIdentified: - From>>, - - relay_message::AnyLightClientIdentified: - From>>, - relay_message::AnyLightClientIdentified: - From>>, - - relay_message::AnyLightClientIdentified: - From>>, - relay_message::AnyLightClientIdentified: - From>>, - - relay_message::Identified>: - relay_message::use_aggregate::IsAggregateData, - relay_message::Identified>: - relay_message::use_aggregate::IsAggregateData, - - relay_message::Identified< - A, - B, - relay_message::data::IbcState, - >: relay_message::use_aggregate::IsAggregateData, - relay_message::Identified< - B, - A, - relay_message::data::IbcState, - >: relay_message::use_aggregate::IsAggregateData, -{ - let get_next_client_sequences = || async { - run_to_completion::< - TupleAggregator, - RelayMessage, - ( - relay_message::Identified>, - ( - relay_message::Identified>, - (), - ), - ), - InMemoryQueue, - _, - _, - >( - TupleAggregator, - chains.clone(), - (), - [ - fetch(relay_message::id::( - a.chain_id(), - relay_message::fetch::FetchState { - at: QueryHeight::Latest, - path: NextClientSequencePath {}.into(), - }, - )), - fetch(relay_message::id::( - b.chain_id(), - relay_message::fetch::FetchState { - at: QueryHeight::Latest, - path: NextClientSequencePath {}.into(), - }, - )), - ], - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await - }; - - let get_next_connection_sequences = || async { - run_to_completion::< - TupleAggregator, - RelayMessage, - ( - relay_message::Identified>, - ( - relay_message::Identified>, - (), - ), - ), - InMemoryQueue, - _, - _, - >( - TupleAggregator, - chains.clone(), - (), - [ - fetch(relay_message::id::( - a.chain_id(), - relay_message::fetch::FetchState { - at: QueryHeight::Latest, - path: NextConnectionSequencePath {}.into(), - }, - )), - fetch(relay_message::id::( - b.chain_id(), - relay_message::fetch::FetchState { - at: QueryHeight::Latest, - path: NextConnectionSequencePath {}.into(), - }, - )), - ], - NormalizeFinal::default(), - Pure(NormalizeFinal::default()), - ) - .await - }; - - let mk_create_client_msgs = |client_a_config: serde_json::Value, - client_b_config: serde_json::Value, - next_client_sequence_a, - next_client_sequence_b, - msgs: Op| { - let client_config_a = - serde_json::from_value::<::Config>(client_a_config) - .unwrap(); - let client_config_b = - serde_json::from_value::<::Config>(client_b_config) - .unwrap(); - - seq([ - // create both clients, in parallel - conc::([ - aggregate( - [ - fetch(relay_message::id::( - b.chain_id(), - relay_message::fetch::FetchSelfClientState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - fetch(relay_message::id::( - b.chain_id(), - relay_message::fetch::FetchSelfConsensusState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - ], - [], - relay_message::id::( - a.chain_id(), - relay_message::aggregate::AggregateMsgCreateClient { - config: client_config_a, - __marker: PhantomData, - }, - ), - ), - aggregate( - [ - fetch(relay_message::id::( - a.chain_id(), - relay_message::fetch::FetchSelfClientState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - fetch(relay_message::id::( - a.chain_id(), - relay_message::fetch::FetchSelfConsensusState { - at: QueryHeight::Latest, - __marker: PhantomData, - }, - )), - ], - [], - relay_message::id::( - b.chain_id(), - relay_message::aggregate::AggregateMsgCreateClient { - config: client_config_b, - __marker: PhantomData, - }, - ), - ), - ]), - // wait for the next client sequence to increase - conc([ - aggregate( - [fetch(relay_message::id::( - a.chain_id(), - relay_message::fetch::FetchState { - at: QueryHeight::Latest, - path: NextClientSequencePath {}.into(), - }, - ))], - [], - relay_message::id::( - a.chain_id(), - AggregateWaitForNextClientSequence { - // increment because we wait for the current next sequence to increase - sequence: next_client_sequence_a + 1, - __marker: PhantomData, - }, - ), - ), - aggregate( - [fetch(relay_message::id::( - b.chain_id(), - relay_message::fetch::FetchState { - at: QueryHeight::Latest, - path: NextClientSequencePath {}.into(), - }, - ))], - [], - relay_message::id::( - b.chain_id(), - AggregateWaitForNextClientSequence { - // increment because we wait for the current next sequence to increase - sequence: next_client_sequence_b + 1, - __marker: PhantomData, - }, - ), - ), - ]), - // queue update messages, along with any additional messages to be handled after the clients are created (i.e. connection and channel handshakes) - conc( - [ - repeat( - None, - seq([ - event(relay_message::id::( - a.chain_id(), - relay_message::event::Command::UpdateClient { - client_id: mk_client_id::(next_client_sequence_a), - __marker: PhantomData, - }, - )), - defer_relative(10), - ]), - ), - repeat( - None, - seq([ - event(relay_message::id::( - b.chain_id(), - relay_message::event::Command::UpdateClient { - client_id: mk_client_id::(next_client_sequence_b), - __marker: PhantomData, - }, - )), - defer_relative(10), - ]), - ), - ] - .into_iter() - .chain([msgs]), - ), - ]) - }; - - let mk_connection_msgs = |client_a_id, client_b_id, connection_ordering| { - effect::(relay_message::id::( - a.chain_id(), - relay_message::effect::MsgConnectionOpenInitData(MsgConnectionOpenInit { - client_id: client_a_id, - counterparty: connection::counterparty::Counterparty { - client_id: client_b_id, - connection_id: "".to_string().parse().unwrap(), - prefix: MerklePrefix { - // TODO: Make configurable - key_prefix: b"ibc".to_vec(), - }, - }, - version: Version { - identifier: "1".into(), - features: connection_ordering, - }, - delay_period: unionlabs::DELAY_PERIOD, - }), - )) - }; - - let mk_wait_for_connection_open = |sequence_a: u64, sequence_b: u64| { - seq([ - aggregate( - [fetch(relay_message::id::( - a.chain_id(), - relay_message::fetch::FetchState { - at: QueryHeight::Latest, - path: NextConnectionSequencePath {}.into(), - }, - ))], - [], - relay_message::id::( - a.chain_id(), - AggregateWaitForNextConnectionSequence { - sequence: sequence_a + 1, - __marker: PhantomData, - }, - ), - ), - aggregate( - [fetch(relay_message::id::( - b.chain_id(), - relay_message::fetch::FetchState { - at: QueryHeight::Latest, - path: NextConnectionSequencePath {}.into(), - }, - ))], - [], - relay_message::id::( - b.chain_id(), - AggregateWaitForNextConnectionSequence { - sequence: sequence_b + 1, - __marker: PhantomData, - }, - ), - ), - // wait for the connection on chain B to be open, since if B is open then A will also be open - aggregate( - [fetch(relay_message::id::( - b.chain_id(), - relay_message::fetch::FetchState { - at: QueryHeight::Latest, - path: ConnectionPath { - connection_id: format!("connection-{}", sequence_b).parse().unwrap(), - } - .into(), - }, - ))], - [], - relay_message::id::( - b.chain_id(), - AggregateWaitForConnectionOpen { - connection_id: format!("connection-{}", sequence_b).parse().unwrap(), - __marker: PhantomData, - }, - ), - ), - ]) - }; - - let mk_channel_msgs = |connection_a_id, port_a, port_b, channel_ordering, channel_version| { - effect::(relay_message::id::( - a.chain_id(), - relay_message::effect::MsgChannelOpenInitData { - msg: MsgChannelOpenInit { - port_id: port_a, - channel: Channel { - state: channel::state::State::Init, - ordering: channel_ordering, - counterparty: channel::counterparty::Counterparty { - port_id: port_b, - channel_id: "".to_string(), - }, - connection_hops: vec![connection_a_id], - version: channel_version, - }, - }, - __marker: PhantomData, - }, - )) - }; - - let msgs = match ty { - HandshakeType::Client { - client_a_config, - client_b_config, - } => { - let (sequence_a, (sequence_b, ())) = get_next_client_sequences().await; - - mk_create_client_msgs( - client_a_config, - client_b_config, - sequence_a.t.state, - sequence_b.t.state, - Op::Noop, - ) - } - HandshakeType::ClientConnection { - client_a_config, - client_b_config, - connection_ordering, - } => { - let (client_sequence_a, (client_sequence_b, ())) = get_next_client_sequences().await; - - mk_create_client_msgs( - client_a_config, - client_b_config, - client_sequence_a.t.state, - client_sequence_b.t.state, - mk_connection_msgs( - mk_client_id::(client_sequence_a.t.state), - mk_client_id::(client_sequence_b.t.state), - connection_ordering, - ), - ) - } - HandshakeType::ClientConnectionChannel { - client_a_config, - client_b_config, - port_a, - port_b, - channel_version, - connection_ordering, - channel_ordering, - } => { - assert!(connection_ordering.contains(&channel_ordering)); - - let (client_sequence_a, (client_sequence_b, ())) = get_next_client_sequences().await; - let (connection_sequence_a, (connection_sequence_b, ())) = - get_next_connection_sequences().await; - - mk_create_client_msgs( - client_a_config, - client_b_config, - client_sequence_a.t.state, - client_sequence_b.t.state, - seq([ - mk_connection_msgs( - mk_client_id::(client_sequence_a.t.state), - mk_client_id::(client_sequence_b.t.state), - connection_ordering, - ), - mk_wait_for_connection_open( - connection_sequence_a.t.state, - connection_sequence_b.t.state, - ), - mk_channel_msgs( - format!("connection-{}", connection_sequence_a.t.state) - .parse() - .unwrap(), - port_a, - port_b, - channel_ordering, - channel_version, - ), - ]), - ) - } - HandshakeType::ConnectionChannel { - client_a, - client_b, - port_a, - port_b, - channel_version, - connection_ordering, - channel_ordering, - } => { - assert!(connection_ordering.contains(&channel_ordering)); - - let (connection_sequence_a, (connection_sequence_b, ())) = - get_next_connection_sequences().await; - - seq([ - mk_connection_msgs( - client_a.try_into().unwrap(), - client_b.try_into().unwrap(), - connection_ordering, - ), - mk_wait_for_connection_open( - connection_sequence_a.t.state, - connection_sequence_b.t.state, - ), - mk_channel_msgs( - format!("connection-{}", connection_sequence_a.t.state) - .parse() - .unwrap(), - port_a, - port_b, - channel_ordering, - channel_version, - ), - ]) - } - HandshakeType::Connection { - client_a, - client_b, - connection_ordering, - } => mk_connection_msgs( - client_a.try_into().unwrap(), - client_b.try_into().unwrap(), - connection_ordering, - ), - HandshakeType::Channel { - connection_a, - port_a, - port_b, - channel_version, - channel_ordering, - } => mk_channel_msgs( - connection_a, - port_a, - port_b, - channel_ordering, - channel_version, - ), - }; - - VoyagerMessage::from_op(msgs) -} - -async fn mk_init_fetch(a: &A) -> Op -where - A: block_message::ChainExt, - block_message::AnyChainIdentified: - From>>, -{ - fetch(VoyagerFetch::Block( - block_message::id::( - a.chain_id(), - block_message::fetch::FetchBlock:: { - height: a.query_latest_height().await.unwrap(), - }, - ) - .into(), - )) -} - -fn mk_client_id, Tr: Chain>(sequence: u64) -> ClientIdOf { - format!( - "{}-{}", - >::TYPE.identifier_prefix(), - sequence - ) - .parse() - .unwrap() -} - -// #[tokio::test] -// async fn size() { -// tracing_subscriber::fmt() -// .with_env_filter(EnvFilter::from_default_env()) -// .init(); - -// // dbg!(mem::size_of::>()); - -// let msg: QueueMsg = -// seq([seq([seq([seq([seq([seq([seq([seq([seq([seq( -// [seq([seq([seq([seq([seq([queue_msg::noop()])])])])])], -// )])])])])])])])])]); - -// msg.handle(&chains_from_config(Default::default()).await.unwrap(), 0) -// .await -// .unwrap(); -// } diff --git a/voyager/src/passes.rs b/voyager/src/passes.rs deleted file mode 100644 index ac6374c8ae..0000000000 --- a/voyager/src/passes.rs +++ /dev/null @@ -1,2 +0,0 @@ -// pub mod block_passthrough; -pub mod tx_batch; diff --git a/voyager/src/passes/block_passthrough.rs b/voyager/src/passes/block_passthrough.rs deleted file mode 100644 index 9a8ba59d40..0000000000 --- a/voyager/src/passes/block_passthrough.rs +++ /dev/null @@ -1,40 +0,0 @@ -use queue_msg::{ - optimize::{OptimizationResult, PurePass}, - Op, -}; -use voyager_message::VoyagerMessage; - -/// Marks all block_message messages as ready, such that they can be processed sooner. -/// -/// Intended to be run as a pre-push pass to skip the roundtrip between the optimizer and the queue. -#[derive(Clone, Debug)] -pub struct BlockPassthrough; - -impl PurePass for BlockPassthrough { - fn run_pass_pure(&self, msgs: Vec>) -> OptimizationResult { - msgs.into_iter().enumerate().map(|(idx, msg)| match msg { - Op::Event(_) => todo!(), - Op::Data(_) => todo!(), - Op::Fetch(_) => todo!(), - Op::Effect(_) => todo!(), - Op::Wait(_) => todo!(), - Op::Defer(_) => todo!(), - Op::Repeat { times, msg } => todo!(), - Op::Timeout { - timeout_timestamp, - msg, - } => todo!(), - Op::Seq(_) => todo!(), - Op::Conc(_) => todo!(), - Op::Race(_) => todo!(), - Op::Retry { remaining, msg } => todo!(), - Op::Aggregate { - queue, - data, - receiver, - } => todo!(), - Op::Void(_) => todo!(), - Op::Noop => todo!(), - }) - } -} diff --git a/voyager/src/passes/tx_batch.rs b/voyager/src/passes/tx_batch.rs deleted file mode 100644 index 83fb73ac44..0000000000 --- a/voyager/src/passes/tx_batch.rs +++ /dev/null @@ -1,273 +0,0 @@ -use std::{ - collections::HashMap, - num::{NonZeroU8, NonZeroUsize}, -}; - -use itertools::Itertools; -use queue_msg::{ - effect, - optimize::{OptimizationResult, PurePass}, - retry, Op, -}; -use relay_message::{ - effect::{AnyEffect, BatchMsg, Effect}, - id, identified, AnyLightClientIdentified, ChainExt, RelayMessage, -}; -use serde::{Deserialize, Serialize}; -use tracing::{debug, info}; -use unionlabs::traits::ChainIdOf; -use voyager_message::{FromOp, VoyagerEffect, VoyagerMessage}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct TxBatch { - // TODO: Make these per-chain-id mappings? - pub retry_count: NonZeroU8, - pub min_batch_size: NonZeroUsize, - pub max_batch_size: NonZeroUsize, -} - -impl PurePass for TxBatch { - fn run_pass_pure(&self, msgs: Vec>) -> OptimizationResult { - let mut opt_res = OptimizationResult { - optimize_further: vec![], - ready: vec![], - }; - - let mut ethereum_mainnet_on_union_batch = Batcher::new(self); - let mut ethereum_minimal_on_union_batch = Batcher::new(self); - let mut scroll_on_union_batch = Batcher::new(self); - let mut arbitrum_on_union_batch = Batcher::new(self); - let mut berachain_on_union_batch = Batcher::new(self); - let mut wasm_cosmos_on_union_batch = Batcher::new(self); - let mut cosmos_on_union_batch = Batcher::new(self); - let mut union_on_ethereum_mainnet = Batcher::new(self); - let mut union_on_ethereum_minimal = Batcher::new(self); - let mut union_on_scroll = Batcher::new(self); - let mut union_on_arbitrum = Batcher::new(self); - let mut union_on_berachain = Batcher::new(self); - let mut union_on_wasm_cosmos = Batcher::new(self); - let mut union_on_cosmos = Batcher::new(self); - let mut cosmos_on_cosmos = Batcher::new(self); - - debug!(count = msgs.len(), "optimizing messages"); - - let mut do_batch = |idx, effect| match effect { - AnyLightClientIdentified::EthereumMainnetOnUnion(effect) => { - ethereum_mainnet_on_union_batch.push(idx, effect) - } - AnyLightClientIdentified::EthereumMinimalOnUnion(effect) => { - ethereum_minimal_on_union_batch.push(idx, effect) - } - AnyLightClientIdentified::ScrollOnUnion(effect) => { - scroll_on_union_batch.push(idx, effect) - } - AnyLightClientIdentified::ArbitrumOnUnion(effect) => { - arbitrum_on_union_batch.push(idx, effect) - } - AnyLightClientIdentified::BerachainOnUnion(effect) => { - berachain_on_union_batch.push(idx, effect) - } - AnyLightClientIdentified::WasmCosmosOnUnion(effect) => { - wasm_cosmos_on_union_batch.push(idx, effect) - } - AnyLightClientIdentified::CosmosOnUnion(effect) => { - cosmos_on_union_batch.push(idx, effect) - } - AnyLightClientIdentified::UnionOnEthereumMainnet(effect) => { - union_on_ethereum_mainnet.push(idx, effect) - } - AnyLightClientIdentified::UnionOnEthereumMinimal(effect) => { - union_on_ethereum_minimal.push(idx, effect) - } - AnyLightClientIdentified::UnionOnScroll(effect) => union_on_scroll.push(idx, effect), - AnyLightClientIdentified::UnionOnArbitrum(effect) => { - union_on_arbitrum.push(idx, effect) - } - AnyLightClientIdentified::UnionOnBerachain(effect) => { - union_on_berachain.push(idx, effect) - } - AnyLightClientIdentified::UnionOnWasmCosmos(effect) => { - union_on_wasm_cosmos.push(idx, effect) - } - AnyLightClientIdentified::UnionOnCosmos(effect) => union_on_cosmos.push(idx, effect), - AnyLightClientIdentified::CosmosOnCosmos(effect) => cosmos_on_cosmos.push(idx, effect), - }; - - for (idx, msg) in msgs.into_iter().enumerate() { - match msg { - Op::Retry { remaining: _, msg } => match *msg { - Op::Effect(VoyagerEffect::Relay(effect)) => do_batch(idx, effect), - msg => opt_res.optimize_further.push((vec![idx], msg)), - }, - Op::Effect(VoyagerEffect::Relay(effect)) => do_batch(idx, effect), - msg => opt_res.optimize_further.push((vec![idx], msg)), - } - } - - opt_res - .ready - .extend(ethereum_mainnet_on_union_batch.into_batch().ready); - opt_res - .ready - .extend(ethereum_minimal_on_union_batch.into_batch().ready); - opt_res - .ready - .extend(scroll_on_union_batch.into_batch().ready); - opt_res - .ready - .extend(arbitrum_on_union_batch.into_batch().ready); - opt_res - .ready - .extend(berachain_on_union_batch.into_batch().ready); - opt_res - .ready - .extend(wasm_cosmos_on_union_batch.into_batch().ready); - opt_res - .ready - .extend(cosmos_on_union_batch.into_batch().ready); - - opt_res - .ready - .extend(union_on_ethereum_mainnet.into_batch().ready); - opt_res - .ready - .extend(union_on_ethereum_minimal.into_batch().ready); - opt_res.ready.extend(union_on_scroll.into_batch().ready); - opt_res.ready.extend(union_on_arbitrum.into_batch().ready); - opt_res.ready.extend(union_on_berachain.into_batch().ready); - opt_res - .ready - .extend(union_on_wasm_cosmos.into_batch().ready); - opt_res.ready.extend(union_on_cosmos.into_batch().ready); - opt_res.ready.extend(cosmos_on_cosmos.into_batch().ready); - - opt_res - } -} - -struct Batcher<'a, Hc: ChainExt, Tr: ChainExt> { - config: &'a TxBatch, - #[allow(clippy::type_complexity)] // leave me alone - // bucket by chain id and then again by batch size - batches: HashMap, Vec<(usize, Effect)>>, -} - -impl<'a, Hc: ChainExt, Tr: ChainExt> Batcher<'a, Hc, Tr> { - fn new(config: &'a TxBatch) -> Self { - Self { - config, - batches: Default::default(), - } - } - - fn push(&mut self, idx: usize, effect: identified!(Effect)) { - let entry = self.batches.entry(effect.chain_id.clone()).or_default(); - match effect.t { - Effect::Batch(b) => { - for e in b.0 { - entry.push((idx, e)) - } - } - e => { - entry.push((idx, e)); - } - } - } - - fn into_batch(self) -> OptimizationResult - where - AnyLightClientIdentified: From)>, - { - let ready = self - .batches - .into_iter() - .flat_map(|(chain_id, msgs): (ChainIdOf, _)| { - msgs.into_iter() - .chunks(self.config.max_batch_size.get()) - .into_iter() - .map(|chunk| { - let (ids, mut batch) = chunk.into_iter().collect::<(Vec<_>, Vec<_>)>(); - - if batch.len() == 1 { - ( - ids, - VoyagerMessage::from_op(retry( - self.config.retry_count, - effect::(id( - chain_id.clone(), - batch.pop().expect("length is 1; qed;"), - )), - )), - ) - } else { - info!(batch_size = batch.len(), %chain_id, "batched messages"); - - ( - ids, - VoyagerMessage::from_op(retry( - self.config.retry_count, - effect::(id(chain_id.clone(), BatchMsg(batch))), - )), - ) - } - }) - .collect::>() - }) - .collect::, Op)>>(); - - OptimizationResult { - optimize_further: vec![], - ready, - } - } -} - -#[cfg(test)] -mod tests { - use chain_utils::{ethereum::Ethereum, union::Union, wasm::Wasm}; - use relay_message::effect::MsgConnectionOpenInitData; - use unionlabs::{ - ethereum::config::Mainnet, - ibc::core::{ - commitment::merkle_prefix::MerklePrefix, - connection::{ - counterparty::Counterparty, msg_connection_open_init::MsgConnectionOpenInit, - }, - }, - }; - - use super::*; - - #[test] - fn test_batch() { - let msg = VoyagerMessage::from_op(effect::(id( - "union".parse().unwrap(), - MsgConnectionOpenInitData::, Ethereum>(MsgConnectionOpenInit { - client_id: "client_id".parse().unwrap(), - counterparty: Counterparty { - client_id: "counterparty".parse().unwrap(), - connection_id: "".parse().unwrap(), - prefix: MerklePrefix { - key_prefix: b"".to_vec(), - }, - }, - version: unionlabs::ibc::core::connection::version::Version { - identifier: "1".to_owned(), - features: [].to_vec(), - }, - delay_period: 0, - }), - ))); - - let msgs = [msg.clone(), msg].to_vec(); - - let batcher = TxBatch { - retry_count: 3.try_into().unwrap(), - min_batch_size: 1.try_into().unwrap(), - max_batch_size: 10.try_into().unwrap(), - }; - - dbg!(batcher.run_pass_pure(msgs)); - } -} diff --git a/voyager/src/queue.rs b/voyager/src/queue.rs index 53ddc9737d..8277a08d9a 100644 --- a/voyager/src/queue.rs +++ b/voyager/src/queue.rs @@ -1,11 +1,10 @@ #![allow(clippy::type_complexity)] use std::{ - collections::{BTreeMap, HashMap}, error::Error, fmt::{Debug, Display}, net::SocketAddr, - sync::Arc, + panic::AssertUnwindSafe, }; use axum::{ @@ -13,42 +12,40 @@ use axum::{ routing::{get, post}, Json, }; -use chain_utils::{any_chain, AnyChain, AnyChainTryFromConfigError, Chains}; use frame_support_procedural::{CloneNoBound, DebugNoBound}; -use futures::{channel::mpsc::UnboundedSender, Future, SinkExt, StreamExt, TryStreamExt}; +use futures::{ + channel::mpsc::UnboundedSender, future::BoxFuture, stream::FuturesUnordered, Future, FutureExt, + SinkExt, StreamExt, +}; use pg_queue::{PgQueue, PgQueueConfig}; use prometheus::TextEncoder; use queue_msg::{ - optimize::{ - passes::{FinalPass, Normalize}, - Pass, Pure, PurePass, - }, - Engine, InMemoryQueue, Op, Queue, QueueMessage, + optimize::{OptimizationResult, Pass, PurePass}, + Captures, Engine, InMemoryQueue, Op, Queue, QueueMessage, }; -use relay_message::RelayMessage; use reqwest::StatusCode; use serde::{Deserialize, Serialize}; -use tokio::task::JoinSet; -use tracing::{debug, error, info, trace}; -use unionlabs::traits::{Chain, FromStrExact}; -use voyager_message::VoyagerMessage; - -use crate::{ - config::{ChainConfig, Config}, - passes::tx_batch::TxBatch, - signer_balances, +use serde_json::Value; +use tracing::{debug, error, info, info_span, trace, trace_span}; +use tracing_futures::Instrument; +use unionlabs::ErrorReporter; +use voyager_message::{ + context::Context, module::PluginModuleClient, pass::JaqInterestFilter, rpc::VoyagerRpcServer, + VoyagerMessage, }; +use crate::config::Config; + type BoxDynError = Box; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Voyager { - pub chains: Arc, + pub context: Context, num_workers: u16, - pub laddr: SocketAddr, + pub rest_laddr: SocketAddr, + pub rpc_laddr: SocketAddr, // NOTE: pub temporarily pub queue: AnyQueue, - pub tx_batch: TxBatch, pub optimizer_delay_milliseconds: u64, } @@ -118,10 +115,10 @@ impl Queue for AnyQueue { &'a self, pre_reenqueue_passes: &'a O, f: F, - ) -> impl Future, Self::Error>> + Send + '_ + ) -> impl Future, Self::Error>> + Send + Captures<'a> where - F: (FnOnce(Op) -> Fut) + Send + 'static, - Fut: Future>, String>)> + Send + 'static, + F: (FnOnce(Op) -> Fut) + Send + Captures<'a>, + Fut: Future>, String>)> + Send + Captures<'a>, R: Send + Sync + 'static, O: PurePass, { @@ -145,15 +142,16 @@ impl Queue for AnyQueue { async fn optimize<'a, O: Pass>( &'a self, + tag: &'a str, optimizer: &'a O, ) -> Result<(), sqlx::Either> { match self { AnyQueue::InMemory(queue) => queue - .optimize(optimizer) + .optimize(tag, optimizer) .await .map_err(|e| e.map_left(AnyQueueError::InMemory)), AnyQueue::PgQueue(queue) => queue - .optimize(optimizer) + .optimize(tag, optimizer) .await .map_err(|e| e.map_left(AnyQueueError::PgQueue)), } @@ -235,223 +233,274 @@ impl Queue for AnyQueue { pub enum VoyagerInitError { #[error("multiple configured chains have the same chain id `{chain_id}`")] DuplicateChainId { chain_id: String }, - #[error("error initializing chain")] - ChainInit(#[from] AnyChainTryFromConfigError), #[error("error initializing queue")] QueueInit(#[source] AnyQueueError), + #[error("error initializing plugins")] + Plugin(#[source] BoxDynError), } impl Voyager { pub async fn new(config: Config) -> Result { - let chains = chains_from_config(config.chain).await?; + // let chains = chains_from_config(config.chain).await?; let queue = AnyQueue::new(config.voyager.queue.clone()) .await .map_err(VoyagerInitError::QueueInit)?; Ok(Self { - chains: Arc::new(chains), + context: Context::new(config.plugins) + .await + .map_err(VoyagerInitError::Plugin)?, num_workers: config.voyager.num_workers, - laddr: config.voyager.laddr, + rest_laddr: config.voyager.rest_laddr, + rpc_laddr: config.voyager.rpc_laddr, queue, - tx_batch: config.voyager.tx_batch, + // tx_batch: config.voyager.tx_batch, optimizer_delay_milliseconds: config.voyager.optimizer_delay_milliseconds, }) } - pub fn worker(&self) -> Engine { - Engine::new(self.chains.clone()) - } + pub async fn run(self) -> Result<(), BoxDynError> { + let interest_filter = JaqInterestFilter::new( + self.context + .interest_filters() + .clone() + .into_iter() + .collect(), + )?; + + { + // set up msg server + let (queue_tx, queue_rx) = futures::channel::mpsc::unbounded::>(); + + let app = axum::Router::new() + .route("/msg", post(msg)) + .route("/msgs", post(msgs)) + .route("/health", get(|| async move { StatusCode::OK })) + .route("/metrics", get(metrics)) + // .route( + // "/signer/balances", + // get({ + // let chains = self.chains.clone(); + // || async move { Json(signer_balances(&chains).await) } + // }), + // ) + .with_state(queue_tx.clone()); + + // #[axum::debug_handler] + async fn msg( + State(mut sender): State>>, + Json(msg): Json>, + ) -> StatusCode { + sender.send(msg).await.expect("receiver should not close"); - pub async fn run(self) -> Result<(), RunError> { - // set up msg server - let (queue_tx, queue_rx) = futures::channel::mpsc::unbounded::>(); - - let app = axum::Router::new() - .route("/msg", post(msg)) - .route("/msgs", post(msgs)) - .route("/health", get(|| async move { StatusCode::OK })) - .route("/metrics", get(metrics)) - .route( - "/signer/balances", - get({ - let chains = self.chains.clone(); - || async move { Json(signer_balances(&chains).await) } - }), - ) - .with_state(queue_tx.clone()); - - // #[axum::debug_handler] - async fn msg( - State(mut sender): State>>, - Json(msg): Json>, - ) -> StatusCode { - sender.send(msg).await.expect("receiver should not close"); - - StatusCode::OK - } + StatusCode::OK + } - // #[axum::debug_handler] - async fn msgs( - State(mut sender): State>>, - Json(msgs): Json>>, - ) -> StatusCode { - for msg in msgs { - sender.send(msg).await.expect("receiver should not close"); + // #[axum::debug_handler] + async fn msgs( + State(mut sender): State>>, + Json(msgs): Json>>, + ) -> StatusCode { + for msg in msgs { + sender.send(msg).await.expect("receiver should not close"); + } + + StatusCode::OK } - StatusCode::OK - } + async fn metrics() -> Result { + TextEncoder::new() + .encode_to_string(&prometheus::gather()) + .map_err(|err| { + error!(?err, "could not gather metrics"); + StatusCode::INTERNAL_SERVER_ERROR + }) + } - async fn metrics() -> Result { - TextEncoder::new() - .encode_to_string(&prometheus::gather()) - .map_err(|err| { - error!(?err, "could not gather metrics"); - StatusCode::INTERNAL_SERVER_ERROR - }) - } + tokio::spawn(axum::Server::bind(&self.rest_laddr).serve(app.into_make_service())); - tokio::spawn(axum::Server::bind(&self.laddr).serve(app.into_make_service())); + let mut tasks = + FuturesUnordered::, _>>>::new(); - let mut join_set = JoinSet::>::new(); + tasks.push(Box::pin( + AssertUnwindSafe(async { + let server = jsonrpsee::server::Server::builder() + .build(self.rpc_laddr) + .await?; + let mut module = jsonrpsee::RpcModule::new(&self.context); - let q = self.queue.clone(); - join_set.spawn({ - async move { - debug!("checking for new messages"); + module + .merge(self.context.rpc_server.clone().into_rpc()) + .unwrap(); - pin_utils::pin_mut!(queue_rx); + let addr = server.local_addr()?; + let handle = server.start(module); - while let Some(msg) = queue_rx.next().await { - info!( - json = %serde_json::to_string(&msg).unwrap(), - "received new message", - ); + info!("rpc listening on {addr}"); - q.enqueue(msg, &Normalize::default()).await?; - } + handle + .stopped() + .instrument(trace_span!("voyager_rpc_server")) + .await; - Ok(()) - } - }); - - for i in 0..self.num_workers { - info!("spawning worker {i}"); - - let engine = Engine::new(self.chains.clone()); - let q = self.queue.clone(); - - join_set.spawn(Box::pin(async move { - // let passes = ( - // Normalize::default(), - // ( - // TxBatch { - // size_limit: self.max_batch_size, - // }, - // FinalPass, - // ), - // ); - - engine - .run(&q, &Normalize::default()) - .try_for_each(|data| async move { - info!(data = %serde_json::to_string(&data).unwrap(), "received data outside of an aggregation"); - - Ok(()) - }) - .await - })); - } + Err("rpc server exited".into()) + }) + .catch_unwind(), + )); - join_set.spawn(async move { - let q = self.queue.clone(); + tasks.push(Box::pin( + AssertUnwindSafe(async { + debug!("checking for new messages"); - let passes = (Normalize::default(), (self.tx_batch.clone(), FinalPass)); + pin_utils::pin_mut!(queue_rx); - loop { - debug!("optimizing"); + while let Some(msg) = queue_rx.next().await { + info!( + json = %serde_json::to_string(&msg).unwrap(), + "received new message", + ); - q.optimize(&Pure(passes.clone())).await.map_err(|e| { - e.map_either::<_, _, BoxDynError, BoxDynError>(|x| Box::new(x), |x| Box::new(x)) - .into_inner() - })?; + self.queue.enqueue(msg, &interest_filter).await?; + } - tokio::time::sleep(std::time::Duration::from_millis( - self.optimizer_delay_milliseconds, - )) - .await; + Ok(()) + }) + .catch_unwind(), + )); + + info!("spawning {} workers", self.num_workers); + + for id in 0..self.num_workers { + info!("spawning worker {id}"); + + // let engine = ; + + tasks.push(Box::pin( + AssertUnwindSafe( + Engine::new(&self.context, &self.queue, &interest_filter) + .run() + .for_each(|res| async move { + match res { + Ok(data) => { + info!( + data = %serde_json::to_string(&data).unwrap(), + "received data outside of an aggregation" + ); + } + Err(error) => { + error!( + error = %ErrorReporter(&*error), + "error processing message" + ) + } + } + }) + .map(Ok) + .instrument(trace_span!("engine task", %id)), + ) + .catch_unwind(), + )); } - }); - let errs = vec![]; + struct PluginOptPass { + client: T, + } - // TODO: figure out - while let Some(res) = join_set.join_next().await { - match res { - Ok(Ok(())) => {} - Ok(Err(err)) => { - error!(%err, "error processing message"); - panic!(); - } - Err(err) => { - error!(%err, "error processing message"); - panic!(); + impl + Send + Sync> Pass + for PluginOptPass<&'_ T> + { + type Error = jsonrpsee::core::client::Error; + + fn run_pass( + &self, + msgs: Vec>, + ) -> impl Future, Self::Error>> + Send + { + self.client.run_pass(msgs) } } - } - // while let Some(res) = join_set.join_next().await { - // match res { - // Ok(Ok(())) => {} - // Ok(Err(err)) => { - // tracing::error!(%err, "error running task"); - // errs.push(err); - // } - // Err(err) => { - // tracing::error!(%err, "error running task"); - // errs.push(Box::new(err)); - // } - // } - // } - - Err(RunError { errs }) - } -} - -pub async fn chains_from_config( - config: BTreeMap, -) -> Result { - let mut chains = HashMap::new(); - - fn insert_into_chain_map>( - map: &mut HashMap, - chain: C, - ) { - let chain_id = chain.chain_id(); - map.insert(chain_id.to_string(), chain.into()); - - info!( - %chain_id, - chain_type = ::EXPECTING, - "registered chain" - ); - } + for (plugin_name, filter) in self.context.interest_filters() { + info!(%plugin_name, "spawning optimizer"); + + tasks.push(Box::pin( + AssertUnwindSafe( + async { + let plugin_name = plugin_name.clone(); + + let pass = PluginOptPass { + client: self + .context + .plugin_client_raw(&plugin_name) + .unwrap() + .client(), + }; + + loop { + trace!("optimizing"); + + let res = self + .queue + .optimize(&plugin_name.to_owned(), &pass) + .await + .map_err(|e| { + e.map_either::<_, _, BoxDynError, BoxDynError>( + |x| Box::new(x), + |x| Box::new(x), + ) + .into_inner() + }); + + if let Err(error) = res { + error!( + error = %ErrorReporter(&*error), + "optimization pass returned with error" + ); + } + + tokio::time::sleep(std::time::Duration::from_millis( + self.optimizer_delay_milliseconds, + )) + .await; + } + } + .instrument(info_span!("optimize", %plugin_name)) + .instrument(trace_span!("optimize_verbose", %filter)), + ) + .catch_unwind(), + )); + } - for (chain_name, chain_config) in config { - if !chain_config.enabled { - info!(%chain_name, "chain not enabled, skipping"); - continue; + while let Some(res) = tasks.next().await { + match res { + Ok(Ok(())) => { + info!("task exited gracefully"); + } + Ok(Err(error)) => { + error!( + error = %ErrorReporter(&*error), + "task returned with an error" + ); + break; + } + Err(_err) => { + // can't do anything with dyn Any + error!("task panicked"); + break; + } + } + } } - let chain = AnyChain::try_from_config(chain_config.ty).await?; + self.context.shutdown().await; - any_chain!(|chain| { - insert_into_chain_map(&mut chains, chain); - }); + Err(RunError { errs: vec![] }.into()) } - Ok(Chains { chains }) + pub async fn shutdown(self) { + self.context.shutdown().await + } } #[derive(Debug)] diff --git a/voyager/voyager-config.json b/voyager/voyager-config.json index 0b6377bb68..8099f0badf 100644 --- a/voyager/voyager-config.json +++ b/voyager/voyager-config.json @@ -226,7 +226,7 @@ }, "voyager": { "num_workers": 10, - "laddr": "0.0.0.0:65534", + "laddr": "0.0.0.0:7717", "max_batch_size": 20, "queue": { "type": "pg-queue", diff --git a/voyager/voyager.nix b/voyager/voyager.nix index ca920694c1..02ec40bda6 100644 --- a/voyager/voyager.nix +++ b/voyager/voyager.nix @@ -8,6 +8,20 @@ }; }; + voy-modules-list = builtins.filter + (member: + (pkgs.lib.hasPrefix "voyager/modules" member) + || (pkgs.lib.hasPrefix "voyager/plugins" member) + ) + (builtins.fromTOML (builtins.readFile ../Cargo.toml)).workspace.members; + + voyager-modules = crane.buildWorkspaceMember { + crateDirFromRoot = voy-modules-list; + pname = "voyager-modules"; + version = "0.0.0"; + dev = true; + }; + voyager = crane.buildWorkspaceMember attrs; voyager-dev = pkgs.lib.warn "voyager-dev is not intended to be used in production" @@ -22,7 +36,7 @@ runtimeInputs = [ pkgs.curl ]; text = '' set -e - curl localhost:65534/msg -H "content-type: application/json" -d "$@" + curl localhost:7177/msg -H "content-type: application/json" -d "$@" ''; }; ethereum-multi-send = pkgs.writeShellApplication { @@ -47,8 +61,8 @@ ''; }; voyager-dev = mkCi false voyager-dev.packages.voyager-dev; - }; - checks = voyager.checks; + } // voyager-modules.packages; + checks = voyager.checks // voyager-modules.checks; }; flake.nixosModules.voyager = { lib, pkgs, config, ... }: @@ -63,11 +77,21 @@ type = types.package; default = self.packages.${pkgs.system}.voyager; }; - chains = mkOption { + plugins = mkOption { # The configuration design is breaking quite often, would be a waste # of effort to fix the type for now. - type = types.attrs; + type = types.listOf (types.submodule { + options = { + enabled = mkOption { + type = types.bool; + default = true; + }; + path = mkOption { type = types.path; }; + config = mkOption { type = types.attrs; }; + }; + }); }; + optimizer-delay-milliseconds = mkOption { type = types.int; default = 100; }; workers = mkOption { type = types.int; default = 20; @@ -91,28 +115,33 @@ log-level = mkOption { type = types.str; default = "info"; - description = "RUST_LOG passed to voyager"; + # TODO: Support RUST_LOG per plugin (this will need to be done in voyager) + description = "RUST_LOG passed to voyager and all of the plugins."; example = "voyager=debug"; }; log-format = mkOption { type = types.enum [ "json" "text" ]; default = "json"; + # TODO: This is kinda dirty, find a better way? Probably through each plugin's config + description = "The log format for voyager. This will also be passed to all of the plugins as RUST_LOG_FORMAT."; example = "text"; }; stack-size = mkOption { type = types.nullOr types.number; + description = "The stack size (in bytes) for worker threads. See for more information."; default = null; example = 20971520; }; - # laddr = mkOption { - # type = types.str; - # default = "0.0.0.0:65534"; - # example = "0.0.0.0:65534"; - # }; - # max-batch-size = mkOption { - # type = types.number; - # example = 10; - # }; + rest_laddr = mkOption { + type = types.str; + default = "0.0.0.0:7177"; + example = "0.0.0.0:7177"; + }; + rpc_laddr = mkOption { + type = types.str; + default = "0.0.0.0:7178"; + example = "0.0.0.0:7178"; + }; voyager-extra = mkOption { type = types.attrs; default = { }; @@ -122,7 +151,7 @@ config = let configJson = pkgs.writeText "config.json" (builtins.toJSON { - chain = cfg.chains; + plugins = cfg.plugins; voyager = cfg.voyager-extra // { num_workers = cfg.workers; queue = { @@ -176,6 +205,7 @@ }; environment = { RUST_LOG = "${cfg.log-level}"; + RUST_LOG_FORMAT = "${cfg.log-format}"; }; }; };