diff --git a/.cargo/config.toml b/.cargo/config.toml index e7630f18..ecdbcfb9 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -8,6 +8,12 @@ sov-ibc = { path = "crates/modules/sov-ibc" } sov-ibc-transfer = { path = "crates/modules/sov-ibc-transfer" } sov-consensus-state-tracker = { path = "crates/modules/sov-consensus-state-tracker" } +hermes-sovereign-chain-components = { path = "./crates/relayer/sovereign-chain-components" } +hermes-sovereign-rollup-components = { path = "./crates/relayer/sovereign-rollup-components" } +hermes-sovereign-relayer = { path = "./crates/relayer/sovereign-relayer" } +hermes-sovereign-test-components = { path = "./crates/relayer/sovereign-test-components" } +hermes-sovereign-integration-tests = { path = "./crates/relayer/sovereign-integration-tests" } + ibc = { git = "https://github.com/cosmos/ibc-rs.git", branch = "rano/downgrade-borsh" } ibc-core = { git = "https://github.com/cosmos/ibc-rs.git", branch = "rano/downgrade-borsh" } ibc-core-client = { git = "https://github.com/cosmos/ibc-rs.git", branch = "rano/downgrade-borsh" } @@ -20,6 +26,51 @@ ibc-primitives = { git = "https://github.com/cosmos/ibc-rs.git", branch = ibc-query = { git = "https://github.com/cosmos/ibc-rs.git", branch = "rano/downgrade-borsh" } ibc-testkit = { git = "https://github.com/cosmos/ibc-rs.git", branch = "rano/downgrade-borsh" } +hermes-relayer-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } +hermes-relayer-components-extra = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } + +hermes-runtime-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } +hermes-async-runtime-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } +hermes-tokio-runtime-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } +hermes-runtime = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } + +hermes-encoding-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } +hermes-protobuf-encoding-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } + +hermes-logging-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } +hermes-tracing-logging-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } + +hermes-test-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } +hermes-ibc-test-suite = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } + +hermes-cli-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } + +hermes-cosmos-chain-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } +hermes-cosmos-relayer = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } +hermes-cosmos-test-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } +hermes-cosmos-integration-tests = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } + +hermes-celestia-chain = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } +hermes-celestia-test-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } +hermes-celestia-integration-tests = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } + +hermes-wasm-client-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } +hermes-wasm-test-components = { git = "https://github.com/informalsystems/hermes-sdk.git", branch = "main" } + +cgp-core = { git = "https://github.com/informalsystems/cgp.git", branch = "main" } +cgp-component = { git = "https://github.com/informalsystems/cgp.git", branch = "main" } +cgp-component-macro = { git = "https://github.com/informalsystems/cgp.git", branch = "main" } +cgp-error = { git = "https://github.com/informalsystems/cgp.git", branch = "main" } +cgp-error-eyre = { git = "https://github.com/informalsystems/cgp.git", branch = "main" } +cgp-async = { git = "https://github.com/informalsystems/cgp.git", branch = "main" } +cgp-async-macro = { git = "https://github.com/informalsystems/cgp.git", branch = "main" } +cgp-run = { git = "https://github.com/informalsystems/cgp.git", branch = "main" } +cgp-inner = { git = "https://github.com/informalsystems/cgp.git", branch = "main" } + +ibc-relayer = { git = "https://github.com/informalsystems/hermes.git", rev = "d60057f8" } +ibc-telemetry = { git = "https://github.com/informalsystems/hermes.git", rev = "d60057f8" } +ibc-relayer-types = { git = "https://github.com/informalsystems/hermes.git", rev = "d60057f8" } + cosmrs = { git = "https://github.com/cosmos/cosmos-rust.git", rev = "4b1332e" } basecoin = { git = "https://github.com/informalsystems/basecoin-rs.git", branch = "rano/sov-support" } basecoin-store = { git = "https://github.com/informalsystems/basecoin-rs.git", branch = "rano/sov-support" } diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2f13122f..fc59dedc 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -142,4 +142,4 @@ jobs: - uses: actions-rs/cargo@v1 with: command: test - args: --all-features --no-fail-fast --workspace -- --nocapture + args: --all-features --no-fail-fast --workspace -- --nocapture --exclude hermes-sovereign-integration-tests diff --git a/Cargo.lock b/Cargo.lock index 5fc122f9..011f5033 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,20 +23,11 @@ dependencies = [ "fallible-iterator 0.3.0", "gimli 0.28.1", "memmap2 0.5.10", - "object 0.32.2", + "object", "rustc-demangle", "smallvec", ] -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli 0.29.0", -] - [[package]] name = "adler" version = "1.0.2" @@ -452,7 +443,18 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "event-listener", + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -488,6 +490,23 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "async-tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3609af4bbf701ddaf1f6bb4e6257dff4ff8932327d0e685d3f653724c258b1ac" +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", +] + [[package]] name = "auto_impl" version = "1.2.0" @@ -536,7 +555,11 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", "sync_wrapper 0.1.2", + "tokio", "tower", "tower-layer", "tower-service", @@ -611,16 +634,16 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ - "addr2line 0.22.0", + "addr2line", "cc", "cfg-if", "libc", "miniz_oxide", - "object 0.36.0", + "object", "rustc-demangle", ] @@ -864,6 +887,7 @@ dependencies = [ "hex-conservative", "hex_lit", "secp256k1", + "serde", ] [[package]] @@ -871,6 +895,9 @@ name = "bitcoin-internals" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" +dependencies = [ + "serde", +] [[package]] name = "bitcoin_hashes" @@ -880,6 +907,7 @@ checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" dependencies = [ "bitcoin-internals", "hex-conservative", + "serde", ] [[package]] @@ -1016,6 +1044,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ "sha2 0.10.8", + "tinyvec", ] [[package]] @@ -1030,6 +1059,16 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +[[package]] +name = "byte-unit" +version = "4.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da78b32057b8fdfc352504708feeba7216dcd65a2c9ab02978cbd288d1279b6c" +dependencies = [ + "serde", + "utf8-width", +] + [[package]] name = "bytecheck" version = "0.6.12" @@ -1174,6 +1213,93 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cgp-async" +version = "0.1.0" +source = "git+https://github.com/informalsystems/cgp.git?branch=main#9c323af08b5076397005fd0e8912687c71ebacd4" +dependencies = [ + "cgp-async-macro", +] + +[[package]] +name = "cgp-async-macro" +version = "0.1.0" +source = "git+https://github.com/informalsystems/cgp.git?branch=main#9c323af08b5076397005fd0e8912687c71ebacd4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "cgp-component" +version = "0.1.0" +source = "git+https://github.com/informalsystems/cgp.git?branch=main#9c323af08b5076397005fd0e8912687c71ebacd4" +dependencies = [ + "cgp-async", + "cgp-component-macro", +] + +[[package]] +name = "cgp-component-macro" +version = "0.1.0" +source = "git+https://github.com/informalsystems/cgp.git?branch=main#9c323af08b5076397005fd0e8912687c71ebacd4" +dependencies = [ + "itertools 0.11.0", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "cgp-core" +version = "0.1.0" +source = "git+https://github.com/informalsystems/cgp.git?branch=main#9c323af08b5076397005fd0e8912687c71ebacd4" +dependencies = [ + "cgp-async", + "cgp-component", + "cgp-error", + "cgp-inner", + "cgp-run", +] + +[[package]] +name = "cgp-error" +version = "0.1.0" +source = "git+https://github.com/informalsystems/cgp.git?branch=main#9c323af08b5076397005fd0e8912687c71ebacd4" +dependencies = [ + "cgp-async", + "cgp-component", +] + +[[package]] +name = "cgp-error-eyre" +version = "0.1.0" +source = "git+https://github.com/informalsystems/cgp.git?branch=main#9c323af08b5076397005fd0e8912687c71ebacd4" +dependencies = [ + "cgp-core", + "eyre", +] + +[[package]] +name = "cgp-inner" +version = "0.1.0" +source = "git+https://github.com/informalsystems/cgp.git?branch=main#9c323af08b5076397005fd0e8912687c71ebacd4" +dependencies = [ + "cgp-async", + "cgp-component", +] + +[[package]] +name = "cgp-run" +version = "0.1.0" +source = "git+https://github.com/informalsystems/cgp.git?branch=main#9c323af08b5076397005fd0e8912687c71ebacd4" +dependencies = [ + "cgp-async", + "cgp-component", + "cgp-error", +] + [[package]] name = "chrono" version = "0.4.38" @@ -1264,6 +1390,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -1311,6 +1446,17 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +[[package]] +name = "contracts" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d1429e3bd78171c65aa010eabcdf8f863ba3254728dbfb0ad4b1545beac15c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -1597,6 +1743,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -1794,6 +1949,16 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "dashmap" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +dependencies = [ + "cfg-if", + "num_cpus", +] + [[package]] name = "dashmap" version = "5.5.3" @@ -1852,6 +2017,12 @@ dependencies = [ "serde", ] +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + [[package]] name = "derivative" version = "2.2.0" @@ -1906,6 +2077,16 @@ 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", + "dirs-sys-next", +] + [[package]] name = "dirs-sys" version = "0.4.1" @@ -1918,6 +2099,17 @@ dependencies = [ "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", +] + [[package]] name = "displaydoc" version = "0.2.4" @@ -2034,6 +2226,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ed25519-dalek-bip32" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b49a684b133c4980d7ee783936af771516011c8cd15f429dbda77245e282f03" +dependencies = [ + "derivation-path", + "ed25519-dalek", + "hmac", + "sha2 0.10.8", +] + [[package]] name = "ed25519-zebra" version = "3.1.0" @@ -2174,6 +2378,27 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + [[package]] name = "eyre" version = "0.6.12" @@ -2466,12 +2691,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" - [[package]] name = "glob" version = "0.3.1" @@ -2574,6 +2793,12 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" + [[package]] name = "hashbrown" version = "0.12.3" @@ -2630,79 +2855,627 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +name = "hermes-async-runtime-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" dependencies = [ - "serde", + "async-trait", + "cgp-core", + "futures-channel", + "futures-core", + "futures-util", + "hermes-runtime-components", ] [[package]] -name = "hex-conservative" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" - -[[package]] -name = "hex_lit" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +name = "hermes-celestia-chain" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" dependencies = [ - "digest 0.10.7", + "cgp-core", + "hermes-cosmos-relayer", + "hermes-relayer-components", + "hermes-runtime", + "ibc-relayer", + "ibc-relayer-types", ] [[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +name = "hermes-celestia-integration-tests" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" dependencies = [ - "bytes", - "fnv", - "itoa", + "cgp-core", + "cgp-error-eyre", + "eyre", + "hermes-async-runtime-components", + "hermes-celestia-test-components", + "hermes-cosmos-chain-components", + "hermes-cosmos-integration-tests", + "hermes-cosmos-relayer", + "hermes-cosmos-test-components", + "hermes-ibc-test-suite", + "hermes-relayer-components", + "hermes-relayer-components-extra", + "hermes-runtime", + "hermes-runtime-components", + "hermes-test-components", + "ibc-proto", + "ibc-relayer", + "ibc-relayer-types", + "prost", + "serde_json", + "sha2 0.10.8", + "stable-eyre", + "subtle-encoding", + "tendermint-rpc", + "tokio", + "toml 0.8.14", ] [[package]] -name = "http" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" -dependencies = [ - "bytes", - "fnv", - "itoa", +name = "hermes-celestia-test-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "hermes-cosmos-test-components", + "hermes-relayer-components", + "hermes-runtime", + "hermes-runtime-components", + "hermes-test-components", + "ibc-relayer", + "ibc-relayer-types", + "tendermint 0.36.0", + "tokio", + "toml 0.8.14", ] [[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", +name = "hermes-cli-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "cgp-error-eyre", + "hermes-cosmos-chain-components", + "hermes-encoding-components", + "hermes-protobuf-encoding-components", + "hermes-relayer-components", + "ibc-proto", + "ibc-relayer", + "ibc-relayer-types", + "prost", + "serde", + "tendermint-proto 0.36.0", + "tracing", ] [[package]] -name = "http-body" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +name = "hermes-cosmos-chain-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "bech32 0.9.1", + "cgp-core", + "eyre", + "futures", + "hermes-encoding-components", + "hermes-protobuf-encoding-components", + "hermes-relayer-components", + "hermes-relayer-components-extra", + "hermes-runtime", + "http 0.2.12", + "ibc", + "ibc-proto", + "ibc-relayer", + "ibc-relayer-types", + "ics23", + "itertools 0.12.1", + "prost", + "prost-types", + "serde_json", + "tendermint 0.36.0", + "tendermint-proto 0.36.0", + "tendermint-rpc", + "tokio", + "tonic", + "tracing", +] + +[[package]] +name = "hermes-cosmos-integration-tests" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "eyre", + "hermes-async-runtime-components", + "hermes-cosmos-chain-components", + "hermes-cosmos-relayer", + "hermes-cosmos-test-components", + "hermes-ibc-test-suite", + "hermes-logging-components", + "hermes-relayer-components", + "hermes-relayer-components-extra", + "hermes-runtime", + "hermes-runtime-components", + "hermes-test-components", + "hermes-wasm-test-components", + "ibc-proto", + "ibc-relayer", + "ibc-relayer-types", + "prost", + "serde_json", + "stable-eyre", + "tendermint-rpc", + "tokio", + "toml 0.8.14", + "tracing", + "tracing-subscriber 0.3.18", +] + +[[package]] +name = "hermes-cosmos-relayer" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "eyre", + "futures", + "hermes-async-runtime-components", + "hermes-cli-components", + "hermes-cosmos-chain-components", + "hermes-cosmos-test-components", + "hermes-encoding-components", + "hermes-logging-components", + "hermes-protobuf-encoding-components", + "hermes-relayer-components", + "hermes-relayer-components-extra", + "hermes-runtime", + "hermes-runtime-components", + "hermes-test-components", + "hermes-tracing-logging-components", + "hermes-wasm-client-components", + "http 0.2.12", + "ibc", + "ibc-proto", + "ibc-relayer", + "ibc-relayer-types", + "ibc-telemetry", + "itertools 0.12.1", + "moka", + "opentelemetry 0.17.0", + "prost", + "prost-types", + "serde", + "serde_derive", + "tendermint 0.36.0", + "tendermint-proto 0.36.0", + "tendermint-rpc", + "tokio", + "tonic", + "tracing", +] + +[[package]] +name = "hermes-cosmos-test-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "hdpath", + "hermes-cosmos-chain-components", + "hermes-relayer-components", + "hermes-runtime", + "hermes-runtime-components", + "hermes-test-components", + "ibc-proto", + "ibc-relayer", + "ibc-relayer-types", + "itertools 0.12.1", + "prost", + "serde", + "serde_json", + "sha2 0.10.8", + "subtle-encoding", + "toml 0.8.14", +] + +[[package]] +name = "hermes-encoding-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", +] + +[[package]] +name = "hermes-ibc-test-suite" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "hermes-logging-components", + "hermes-relayer-components", + "hermes-test-components", +] + +[[package]] +name = "hermes-logging-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", +] + +[[package]] +name = "hermes-protobuf-encoding-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "hermes-encoding-components", + "prost", + "prost-types", +] + +[[package]] +name = "hermes-relayer-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "hermes-encoding-components", + "hermes-logging-components", + "hermes-runtime-components", +] + +[[package]] +name = "hermes-relayer-components-extra" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "hermes-logging-components", + "hermes-relayer-components", + "hermes-runtime-components", +] + +[[package]] +name = "hermes-runtime" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "hermes-async-runtime-components", + "hermes-runtime-components", + "hermes-tokio-runtime-components", + "tokio", +] + +[[package]] +name = "hermes-runtime-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", +] + +[[package]] +name = "hermes-sovereign-chain-components" +version = "0.1.0" +dependencies = [ + "base64 0.22.1", + "bech32 0.9.1", + "borsh", + "cgp-core", + "cgp-error-eyre", + "ed25519-dalek", + "eyre", + "hermes-cosmos-chain-components", + "hermes-encoding-components", + "hermes-protobuf-encoding-components", + "hermes-relayer-components", + "hermes-runtime", + "hermes-runtime-components", + "hermes-sovereign-rollup-components", + "hermes-wasm-client-components", + "hex", + "ibc", + "ibc-proto", + "ibc-query", + "ibc-relayer", + "ibc-relayer-types", + "jsonrpsee 0.22.5", + "prost", + "serde", + "serde-json-wasm", + "serde_json", + "sha2 0.10.8", + "sov-celestia-client", + "tokio", + "tonic", +] + +[[package]] +name = "hermes-sovereign-integration-tests" +version = "0.1.0" +dependencies = [ + "borsh", + "cgp-core", + "eyre", + "futures", + "hermes-celestia-integration-tests", + "hermes-celestia-test-components", + "hermes-cosmos-chain-components", + "hermes-cosmos-integration-tests", + "hermes-cosmos-relayer", + "hermes-cosmos-test-components", + "hermes-relayer-components", + "hermes-runtime", + "hermes-runtime-components", + "hermes-sovereign-chain-components", + "hermes-sovereign-relayer", + "hermes-sovereign-rollup-components", + "hermes-sovereign-test-components", + "hermes-test-components", + "hermes-wasm-client-components", + "hermes-wasm-test-components", + "hex", + "ibc", + "ibc-proto", + "ibc-relayer", + "ibc-relayer-types", + "jsonrpsee 0.22.5", + "rand", + "serde", + "serde_json", + "sha2 0.10.8", + "sov-celestia-client", + "stable-eyre", + "tokio", + "toml 0.8.14", + "tracing", + "tracing-subscriber 0.3.18", +] + +[[package]] +name = "hermes-sovereign-relayer" +version = "0.1.0" +dependencies = [ + "cgp-core", + "cgp-error-eyre", + "ed25519-dalek", + "eyre", + "futures", + "hermes-celestia-chain", + "hermes-cosmos-chain-components", + "hermes-cosmos-relayer", + "hermes-encoding-components", + "hermes-logging-components", + "hermes-protobuf-encoding-components", + "hermes-relayer-components", + "hermes-runtime", + "hermes-runtime-components", + "hermes-sovereign-chain-components", + "hermes-sovereign-rollup-components", + "hermes-sovereign-test-components", + "hermes-test-components", + "hermes-wasm-client-components", + "ibc", + "ibc-proto", + "ibc-relayer", + "ibc-relayer-types", + "jsonrpsee 0.22.5", + "sov-celestia-client", +] + +[[package]] +name = "hermes-sovereign-rollup-components" +version = "0.1.0" +dependencies = [ + "base64 0.22.1", + "bech32 0.9.1", + "borsh", + "cgp-core", + "ed25519-dalek", + "eyre", + "futures", + "hermes-cosmos-chain-components", + "hermes-encoding-components", + "hermes-protobuf-encoding-components", + "hermes-relayer-components", + "hermes-runtime-components", + "hermes-wasm-client-components", + "hex", + "ibc", + "ibc-proto", + "ibc-query", + "ibc-relayer", + "ibc-relayer-types", + "jmt", + "jsonrpsee 0.22.5", + "prost", + "serde", + "serde-json-wasm", + "serde_json", + "sha2 0.10.8", + "sov-celestia-client", + "tokio", +] + +[[package]] +name = "hermes-sovereign-test-components" +version = "0.1.0" +dependencies = [ + "bech32 0.9.1", + "cgp-core", + "ed25519-dalek", + "hermes-celestia-test-components", + "hermes-cosmos-test-components", + "hermes-relayer-components", + "hermes-runtime", + "hermes-runtime-components", + "hermes-sovereign-chain-components", + "hermes-sovereign-rollup-components", + "hermes-test-components", + "hex", + "ibc", + "ibc-relayer", + "ibc-relayer-types", + "jsonrpsee 0.22.5", + "rand", + "serde", + "serde_json", + "sha2 0.10.8", + "toml 0.8.14", +] + +[[package]] +name = "hermes-test-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "hermes-relayer-components", + "hermes-relayer-components-extra", + "hermes-runtime-components", +] + +[[package]] +name = "hermes-tokio-runtime-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "futures", + "hermes-async-runtime-components", + "hermes-runtime-components", + "rand", + "tokio", + "tokio-stream", +] + +[[package]] +name = "hermes-tracing-logging-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "hermes-logging-components", + "hermes-relayer-components", + "hermes-relayer-components-extra", + "tracing", +] + +[[package]] +name = "hermes-wasm-client-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "cgp-error-eyre", + "hermes-cosmos-chain-components", + "hermes-encoding-components", + "hermes-protobuf-encoding-components", + "hermes-relayer-components", + "ibc", + "ibc-proto", + "ibc-relayer-types", + "prost", + "tendermint-proto 0.36.0", +] + +[[package]] +name = "hermes-wasm-test-components" +version = "0.1.0" +source = "git+https://github.com/informalsystems/hermes-sdk.git?branch=main#d330d914694be60408800925a763ba9799d98a45" +dependencies = [ + "cgp-core", + "cgp-error-eyre", + "hermes-cosmos-test-components", + "hermes-relayer-components", + "hermes-runtime-components", + "hermes-test-components", + "serde_json", + "toml 0.8.14", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-conservative" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" + +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", "http 1.1.0", @@ -2739,6 +3512,22 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f58b778a5761513caf593693f8951c97a5b610841e754788400f32102eefdff1" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "humantime-serde" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" +dependencies = [ + "humantime", + "serde", +] + [[package]] name = "hyper" version = "0.14.29" @@ -2932,6 +3721,7 @@ name = "ibc-client-tendermint-types" version = "0.53.0" source = "git+https://github.com/cosmos/ibc-rs.git?branch=rano/downgrade-borsh#ee4a9c306b8910098dd89d3749592fe91c35bddb" dependencies = [ + "borsh", "displaydoc", "ibc-core-client-types", "ibc-core-commitment-types", @@ -3186,6 +3976,7 @@ name = "ibc-core-host-cosmos" version = "0.53.0" source = "git+https://github.com/cosmos/ibc-rs.git?branch=rano/downgrade-borsh#ee4a9c306b8910098dd89d3749592fe91c35bddb" dependencies = [ + "borsh", "derive_more", "displaydoc", "ibc-app-transfer-types", @@ -3312,7 +4103,119 @@ dependencies = [ "ibc-proto", "schemars", "serde", - "tonic", + "tonic", +] + +[[package]] +name = "ibc-relayer" +version = "0.27.3" +source = "git+https://github.com/informalsystems/hermes.git?rev=d60057f8#d60057f8d54e9d288d23977626133fb48ee7da7d" +dependencies = [ + "anyhow", + "async-stream", + "bech32 0.9.1", + "bitcoin", + "bs58", + "byte-unit", + "bytes", + "crossbeam-channel", + "digest 0.10.7", + "dirs-next", + "ed25519", + "ed25519-dalek", + "ed25519-dalek-bip32", + "flex-error", + "futures", + "generic-array", + "hdpath", + "hex", + "http 0.2.12", + "humantime", + "humantime-serde", + "ibc-proto", + "ibc-relayer-types", + "ibc-telemetry", + "itertools 0.12.1", + "moka", + "num-bigint 0.4.5", + "num-rational", + "once_cell", + "prost", + "regex", + "reqwest", + "retry", + "ripemd", + "secp256k1", + "semver 1.0.23", + "serde", + "serde_derive", + "serde_json", + "sha2 0.10.8", + "signature", + "strum", + "subtle-encoding", + "tendermint 0.36.0", + "tendermint-light-client", + "tendermint-light-client-detector", + "tendermint-light-client-verifier", + "tendermint-proto 0.36.0", + "tendermint-rpc", + "thiserror", + "tiny-bip39", + "tiny-keccak", + "tokio", + "tokio-stream", + "toml 0.8.14", + "tonic", + "tracing", + "tracing-subscriber 0.3.18", + "uuid", +] + +[[package]] +name = "ibc-relayer-types" +version = "0.27.3" +source = "git+https://github.com/informalsystems/hermes.git?rev=d60057f8#d60057f8d54e9d288d23977626133fb48ee7da7d" +dependencies = [ + "bytes", + "derive_more", + "flex-error", + "ibc-proto", + "ics23", + "itertools 0.12.1", + "num-rational", + "primitive-types", + "prost", + "regex", + "serde", + "serde_derive", + "serde_json", + "subtle-encoding", + "tendermint 0.36.0", + "tendermint-light-client-verifier", + "tendermint-proto 0.36.0", + "time", + "uint", +] + +[[package]] +name = "ibc-telemetry" +version = "0.27.3" +source = "git+https://github.com/informalsystems/hermes.git?rev=d60057f8#d60057f8d54e9d288d23977626133fb48ee7da7d" +dependencies = [ + "axum 0.6.20", + "dashmap 5.5.3", + "ibc-relayer-types", + "moka", + "once_cell", + "opentelemetry 0.19.0", + "opentelemetry-prometheus", + "prometheus", + "serde", + "serde_json", + "tendermint 0.36.0", + "tokio", + "tracing", ] [[package]] @@ -3606,6 +4509,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.12.1" @@ -3743,7 +4655,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" dependencies = [ "anyhow", - "async-lock", + "async-lock 2.8.0", "async-trait", "beef", "futures-timer", @@ -4213,6 +5125,30 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" +[[package]] +name = "moka" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e0d88686dc561d743b40de8269b26eaf0dc58781bde087b0984646602021d08" +dependencies = [ + "async-lock 3.4.0", + "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", +] + [[package]] name = "more-asserts" version = "0.2.2" @@ -4325,6 +5261,7 @@ checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" dependencies = [ "num-integer", "num-traits", + "serde", ] [[package]] @@ -4367,6 +5304,18 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint 0.4.5", + "num-integer", + "num-traits", + "serde", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -4398,15 +5347,6 @@ dependencies = [ "ruzstd", ] -[[package]] -name = "object" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.19.0" @@ -4425,6 +5365,84 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "opentelemetry" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8" +dependencies = [ + "async-trait", + "crossbeam-channel", + "dashmap 4.0.2", + "fnv", + "futures-channel", + "futures-executor", + "futures-util", + "js-sys", + "lazy_static", + "percent-encoding", + "pin-project", + "rand", + "thiserror", +] + +[[package]] +name = "opentelemetry" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4b8347cc26099d3aeee044065ecc3ae11469796b4d65d065a23a584ed92a6f" +dependencies = [ + "opentelemetry_api", + "opentelemetry_sdk", +] + +[[package]] +name = "opentelemetry-prometheus" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a9f186f6293ebb693caddd0595e66b74a6068fa51048e26e0bf9c95478c639c" +dependencies = [ + "opentelemetry 0.19.0", + "prometheus", + "protobuf", +] + +[[package]] +name = "opentelemetry_api" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed41783a5bf567688eb38372f2b7a8530f5a607a4b49d38dd7573236c23ca7e2" +dependencies = [ + "fnv", + "futures-channel", + "futures-util", + "indexmap 1.9.3", + "once_cell", + "pin-project-lite", + "thiserror", + "urlencoding", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1" +dependencies = [ + "async-trait", + "crossbeam-channel", + "dashmap 5.5.3", + "fnv", + "futures-channel", + "futures-executor", + "futures-util", + "once_cell", + "opentelemetry_api", + "percent-encoding", + "rand", + "thiserror", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -4463,6 +5481,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" version = "0.12.3" @@ -4848,6 +5872,21 @@ dependencies = [ "syn 1.0.109", ] +[[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", + "web-sys", + "winapi", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -4914,6 +5953,15 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "raw-cpuid" +version = "11.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "rawpointer" version = "0.2.1" @@ -5079,6 +6127,12 @@ dependencies = [ "winreg", ] +[[package]] +name = "retry" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9166d72162de3575f950507683fac47e30f6f2c3836b71b7fbc61aa517c9c5f4" + [[package]] name = "rfc6979" version = "0.4.0" @@ -5260,7 +6314,7 @@ version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "922588cb4b884b3951316a65581ccdfd1174af93c54093190878366812073329" dependencies = [ - "addr2line 0.21.0", + "addr2line", "anyhow", "ark-bn254", "ark-groth16", @@ -5838,6 +6892,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.203" @@ -5957,6 +7021,17 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sha2" version = "0.9.9" @@ -6604,6 +7679,17 @@ dependencies = [ "der", ] +[[package]] +name = "stable-eyre" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556fec8c2da34c70b75f16d88df8a8cd7e652e567ff097b7e9df0022c8695cc4" +dependencies = [ + "backtrace", + "eyre", + "indenter", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -6749,6 +7835,12 @@ dependencies = [ "libc", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "tap" version = "1.0.1" @@ -6843,10 +7935,12 @@ dependencies = [ "ed25519-consensus", "flex-error", "futures", + "k256", "num-traits", "once_cell", "prost", "prost-types", + "ripemd", "serde", "serde_bytes", "serde_json", @@ -6905,6 +7999,54 @@ dependencies = [ "url", ] +[[package]] +name = "tendermint-light-client" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "331544139bbcf353acb5f56e733093d8e4bf2522cda0491b4bba7039ef0b944e" +dependencies = [ + "contracts", + "crossbeam-channel", + "derive_more", + "flex-error", + "futures", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "static_assertions", + "tendermint 0.36.0", + "tendermint-light-client-verifier", + "tendermint-rpc", + "time", + "tokio", + "tracing", +] + +[[package]] +name = "tendermint-light-client-detector" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73d0ffaf614bd2db605c4762e3a31a536b73cd45488fa5bace050135ca348f28" +dependencies = [ + "crossbeam-channel", + "derive_more", + "flex-error", + "futures", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "static_assertions", + "tendermint 0.36.0", + "tendermint-light-client", + "tendermint-proto 0.36.0", + "tendermint-rpc", + "time", + "tracing", +] + [[package]] name = "tendermint-light-client-verifier" version = "0.36.0" @@ -6992,6 +8134,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21e3c231a3632cab53f92ad4161c730c468c08cfe4f0aa5a6735b53b390aecbd" dependencies = [ "async-trait", + "async-tungstenite", "bytes", "flex-error", "futures", @@ -7142,6 +8285,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.7.6" @@ -7341,7 +8493,11 @@ dependencies = [ "percent-encoding", "pin-project", "prost", + "rustls-native-certs 0.7.0", + "rustls-pemfile 2.1.2", + "rustls-pki-types", "tokio", + "tokio-rustls 0.25.0", "tokio-stream", "tower", "tower-layer", @@ -7523,6 +8679,16 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.2.25" @@ -7542,20 +8708,50 @@ dependencies = [ "nu-ansi-term", "once_cell", "regex", + "serde", + "serde_json", "sharded-slab", "smallvec", "thread_local", "tracing", "tracing-core", "tracing-log", + "tracing-serde", ] +[[package]] +name = "triomphe" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369" + [[package]] name = "try-lock" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand", + "rustls 0.22.4", + "rustls-pki-types", + "sha1", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "twox-hash" version = "1.6.3" @@ -7707,12 +8903,30 @@ dependencies = [ "percent-encoding", ] +[[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 = "utf16_iter" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" +[[package]] +name = "utf8-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -7730,6 +8944,9 @@ name = "uuid" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +dependencies = [ + "getrandom", +] [[package]] name = "valuable" @@ -8018,7 +9235,7 @@ dependencies = [ "cfg-if", "corosensei", "crossbeam-queue", - "dashmap", + "dashmap 5.5.3", "derivative", "enum-iterator", "fnv", diff --git a/Cargo.toml b/Cargo.toml index 564110d6..3b3ee03b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,11 @@ members = [ "crates/modules/sov-ibc-transfer", "crates/modules/sov-consensus-state-tracker", "crates/test/sov-ibc-mocks", + "crates/relayer/sovereign-chain-components", + "crates/relayer/sovereign-rollup-components", + "crates/relayer/sovereign-relayer", + "crates/relayer/sovereign-test-components", + "crates/relayer/sovereign-integration-tests", ] exclude = [ @@ -55,27 +60,8 @@ sov-ibc = { version = "0.1.0" } sov-ibc-transfer = { version = "0.1.0" } sov-consensus-state-tracker = { version = "0.1.0" } -# external dependencies -anyhow = "1.0.68" -base64 = { version = "0.21", default-features = false } -borsh = { version = "0.10.3", features = [ "rc", "bytes" ] } -bytes = { version = "1.2.1", default-features = false } -derive_more = { version = "0.99.11", features = [ "from", "try_into" ] } -digest = "0.10.6" -hex = "0.4.3" -jmt = { version = "0.9.0" } -jsonrpsee = { version = "0.22.5", features = [ "jsonrpsee-types", "macros", "client", "server" ] } -prost = { version = "0.12", default-features = false } -prost-build = { version = "0.12", default-features = false } -sha2 = { version = "0.10.6", default-features = false } -serde = { version = "1.0", default-features = false, features = [ "derive", "rc" ] } -serde_json = "1.0" -schemars = { version = "0.8.12", features = [ "derive" ] } -tempfile = "3.5" -thiserror = "1.0.38" -tracing = { version = "0.1.40", default-features = false } - # ibc depedenencies +ibc = { version = "0.53.0", default-features = false } ibc-core = { version = "0.53.0", default-features = false, features = [ "borsh", "schema" ] } ibc-core-client = { version = "0.53.0", default-features = false } ibc-core-host-cosmos = { version = "0.53.0", default-features = false } @@ -115,4 +101,75 @@ sov-mock-zkvm = { version = "0.3.0" } sov-prover-storage-manager = { version = "0.3.0" } const-rollup-config = { version = "0.3.0" } +# Hermes SDK relayer dependencies + +hermes-runtime-components = { version = "0.1.0" } +hermes-async-runtime-components = { version = "0.1.0" } +hermes-tokio-runtime-components = { version = "0.1.0" } +hermes-runtime = { version = "0.1.0" } + +hermes-encoding-components = { version = "0.1.0" } +hermes-protobuf-encoding-components = { version = "0.1.0" } + +hermes-logging-components = { version = "0.1.0" } + +hermes-relayer-components = { version = "0.1.0" } +hermes-relayer-components-extra = { version = "0.1.0" } + +hermes-test-components = { version = "0.1.0" } + +hermes-cosmos-chain-components = { version = "0.1.0" } +hermes-cosmos-relayer = { version = "0.1.0" } +hermes-cosmos-test-components = { version = "0.1.0" } +hermes-cosmos-integration-tests = { version = "0.1.0" } + +hermes-wasm-client-components = { version = "0.1.0" } +hermes-wasm-test-components = { version = "0.1.0" } + +hermes-celestia-chain = { version = "0.1.0" } +hermes-celestia-test-components = { version = "0.1.0" } +hermes-celestia-integration-tests = { version = "0.1.0" } + +hermes-sovereign-chain-components = { version = "0.1.0" } +hermes-sovereign-rollup-components = { version = "0.1.0" } +hermes-sovereign-relayer = { version = "0.1.0" } +hermes-sovereign-test-components = { version = "0.1.0" } +hermes-sovereign-integration-tests = { version = "0.1.0" } + +ibc-relayer = { version = "0.27.3" } +ibc-relayer-types = { version = "0.27.3" } +ibc-telemetry = { version = "0.27.3" } + +cgp-core = { version = "0.1.0" } +cgp-error-eyre = { version = "0.1.0" } + +# external dependencies +anyhow = "1.0.68" +base64 = { version = "0.21", default-features = false } +borsh = { version = "0.10.3", features = [ "rc", "bytes" ] } +bytes = { version = "1.2.1", default-features = false } +derive_more = { version = "0.99.11", features = [ "from", "try_into" ] } +digest = "0.10.6" +hex = "0.4.3" +jmt = { version = "0.9.0" } +jsonrpsee = { version = "0.22.5", features = [ "jsonrpsee-types", "macros", "client", "server" ] } +prost = { version = "0.12", default-features = false } +prost-build = { version = "0.12", default-features = false } +sha2 = { version = "0.10.6", default-features = false } +serde = { version = "1.0", default-features = false, features = [ "derive", "rc" ] } +serde_json = "1.0" +schemars = { version = "0.8.12", features = [ "derive" ] } +tempfile = "3.5" +thiserror = "1.0.38" +tracing = { version = "0.1.40", default-features = false } +bech32 = { version = "0.9.1" } +eyre = { version = "0.6.12" } +tokio = { version = "1.36" } +tonic = { version = "0.11" } +ed25519-dalek = { version = "2.1.1" } +futures = { version = "0.3.30", default-features = false } +rand = { version = "0.8.5" } +toml = { version = "0.8.12" } +tracing-subscriber = { version = "0.3.18" } + # Note: the `[patch.crates-io]` section is placed at `./cargo/config.toml` diff --git a/crates/relayer/sovereign-chain-components/Cargo.toml b/crates/relayer/sovereign-chain-components/Cargo.toml new file mode 100644 index 00000000..f785d8b2 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "hermes-sovereign-chain-components" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } +readme = "README.md" +description = """ + Context-generic client components for communicating with a Sovereign rollup node +""" + +[dependencies] +cgp-core = { workspace = true } +cgp-error-eyre = { workspace = true } +hermes-runtime = { workspace = true } +hermes-relayer-components = { workspace = true } +hermes-runtime-components = { workspace = true } +hermes-sovereign-rollup-components = { workspace = true } +hermes-cosmos-chain-components = { workspace = true } +hermes-wasm-client-components = { workspace = true } +hermes-encoding-components = { workspace = true } +hermes-protobuf-encoding-components = { workspace = true } + +ibc-proto = { workspace = true } +ibc-relayer = { workspace = true } +ibc-relayer-types = { workspace = true } +sov-celestia-client = { workspace = true, features = [ "test-util" ] } +ibc = { workspace = true } +ibc-query = { workspace = true } + +tokio = { workspace = true } +eyre = { workspace = true } +jsonrpsee = { workspace = true, features = [ "http-client" ] } +prost = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +bech32 = { workspace = true } +borsh = { workspace = true } +tonic = { workspace = true } +ed25519-dalek = { version = "2.1.1" } +sha2 = { version = "0.10.8" } +hex = { version = "0.4.3" } +base64 = { version = "0.22.1" } +serde-json-wasm = { version = "1.0.1" } diff --git a/crates/relayer/sovereign-chain-components/src/cosmos/components.rs b/crates/relayer/sovereign-chain-components/src/cosmos/components.rs new file mode 100644 index 00000000..3752760d --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/cosmos/components.rs @@ -0,0 +1,71 @@ +use cgp_core::prelude::*; +use hermes_cosmos_chain_components::impls::channel::channel_handshake_message::BuildCosmosChannelHandshakeMessage; +use hermes_cosmos_chain_components::impls::connection::connection_handshake_message::BuildCosmosConnectionHandshakeMessage; +use hermes_cosmos_chain_components::impls::types::create_client_options::ProvideCosmosCreateClientSettings; +use hermes_relayer_components::chain::impls::queries::query_and_convert_client_state::QueryAndConvertRawClientState; +use hermes_relayer_components::chain::impls::queries::query_and_convert_consensus_state::QueryAndConvertRawConsensusState; +use hermes_relayer_components::chain::traits::message_builders::channel_handshake::{ + ChannelOpenAckMessageBuilderComponent, ChannelOpenConfirmMessageBuilderComponent, + ChannelOpenInitMessageBuilderComponent, ChannelOpenTryMessageBuilderComponent, +}; +use hermes_relayer_components::chain::traits::message_builders::connection_handshake::{ + ConnectionOpenAckMessageBuilderComponent, ConnectionOpenConfirmMessageBuilderComponent, + ConnectionOpenInitMessageBuilderComponent, ConnectionOpenTryMessageBuilderComponent, +}; +use hermes_relayer_components::chain::traits::message_builders::create_client::CreateClientMessageBuilderComponent; +use hermes_relayer_components::chain::traits::message_builders::update_client::UpdateClientMessageBuilderComponent; +use hermes_relayer_components::chain::traits::queries::client_state::{ + ClientStateQuerierComponent, ClientStateWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::consensus_state::{ + ConsensusStateQuerierComponent, ConsensusStateWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::consensus_state_height::ConsensusStateHeightsQuerierComponent; +use hermes_relayer_components::chain::traits::types::create_client::CreateClientMessageOptionsTypeComponent; +use hermes_relayer_components::chain::traits::types::ibc::CounterpartyMessageHeightGetterComponent; + +use crate::cosmos::impls::message_height::GetSovereignRollupHeightFromCosmosMessage; +use crate::cosmos::impls::queries::consensus_state_heights::QuerySovereignConsensusStateHeightsFromGrpc; +use crate::cosmos::impls::sovereign_to_cosmos::client::create_client_message::BuildCreateSovereignClientMessageOnCosmos; +use crate::cosmos::impls::sovereign_to_cosmos::client::update_client_message::BuildUpdateSovereignClientMessageOnCosmos; + +pub struct SovereignCosmosComponents; + +delegate_components! { + SovereignCosmosComponents { + [ + ClientStateQuerierComponent, + ClientStateWithProofsQuerierComponent, + ]: + QueryAndConvertRawClientState, + [ + ConsensusStateQuerierComponent, + ConsensusStateWithProofsQuerierComponent, + ]: + QueryAndConvertRawConsensusState, + UpdateClientMessageBuilderComponent: + BuildUpdateSovereignClientMessageOnCosmos, + CreateClientMessageOptionsTypeComponent: + ProvideCosmosCreateClientSettings, + CreateClientMessageBuilderComponent: + BuildCreateSovereignClientMessageOnCosmos, + [ + ConnectionOpenInitMessageBuilderComponent, + ConnectionOpenTryMessageBuilderComponent, + ConnectionOpenAckMessageBuilderComponent, + ConnectionOpenConfirmMessageBuilderComponent, + ]: + BuildCosmosConnectionHandshakeMessage, + [ + ChannelOpenInitMessageBuilderComponent, + ChannelOpenTryMessageBuilderComponent, + ChannelOpenAckMessageBuilderComponent, + ChannelOpenConfirmMessageBuilderComponent, + ]: + BuildCosmosChannelHandshakeMessage, + ConsensusStateHeightsQuerierComponent: + QuerySovereignConsensusStateHeightsFromGrpc, + CounterpartyMessageHeightGetterComponent: + GetSovereignRollupHeightFromCosmosMessage, + } +} diff --git a/crates/relayer/sovereign-chain-components/src/cosmos/impls/message_height.rs b/crates/relayer/sovereign-chain-components/src/cosmos/impls/message_height.rs new file mode 100644 index 00000000..bea07c89 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/cosmos/impls/message_height.rs @@ -0,0 +1,30 @@ +use hermes_cosmos_chain_components::traits::message::CosmosMessage; +use hermes_relayer_components::chain::traits::types::height::HasHeightType; +use hermes_relayer_components::chain::traits::types::ibc::CounterpartyMessageHeightGetter; +use hermes_relayer_components::chain::traits::types::message::HasMessageType; +use hermes_sovereign_rollup_components::types::height::RollupHeight; + +pub struct GetSovereignRollupHeightFromCosmosMessage; + +impl CounterpartyMessageHeightGetter + for GetSovereignRollupHeightFromCosmosMessage +where + Chain: HasMessageType, + Counterparty: HasHeightType, +{ + fn counterparty_message_height_for_update_client( + message: &CosmosMessage, + ) -> Option { + let height = message + .message + .counterparty_message_height_for_update_client()?; + + if height.revision_number() == 0 { + Some(RollupHeight { + slot_number: height.revision_height(), + }) + } else { + None + } + } +} diff --git a/crates/relayer/sovereign-chain-components/src/cosmos/impls/mod.rs b/crates/relayer/sovereign-chain-components/src/cosmos/impls/mod.rs new file mode 100644 index 00000000..4de7bde4 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/cosmos/impls/mod.rs @@ -0,0 +1,3 @@ +pub mod message_height; +pub mod queries; +pub mod sovereign_to_cosmos; diff --git a/crates/relayer/sovereign-chain-components/src/cosmos/impls/queries/consensus_state_heights.rs b/crates/relayer/sovereign-chain-components/src/cosmos/impls/queries/consensus_state_heights.rs new file mode 100644 index 00000000..1e0744bc --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/cosmos/impls/queries/consensus_state_heights.rs @@ -0,0 +1,56 @@ +use cgp_core::CanRaiseError; +use hermes_cosmos_chain_components::traits::grpc_address::HasGrpcAddress; +use hermes_relayer_components::chain::traits::queries::consensus_state_height::ConsensusStateHeightsQuerier; +use hermes_relayer_components::chain::traits::types::height::HasHeightType; +use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; +use hermes_sovereign_rollup_components::types::height::RollupHeight; +use ibc_proto::ibc::core::client::v1::query_client::QueryClient; +use ibc_relayer::chain::requests::QueryConsensusStateHeightsRequest; +use ibc_relayer_types::core::ics24_host::identifier::ClientId; +use tonic::transport::Error as TransportError; +use tonic::Status; + +pub struct QuerySovereignConsensusStateHeightsFromGrpc; + +impl ConsensusStateHeightsQuerier + for QuerySovereignConsensusStateHeightsFromGrpc +where + Chain: HasIbcChainTypes + + HasGrpcAddress + + CanRaiseError + + CanRaiseError, + Counterparty: HasHeightType, +{ + async fn query_consensus_state_heights( + chain: &Chain, + client_id: &ClientId, + ) -> Result, Chain::Error> { + let mut client = QueryClient::connect(chain.grpc_address().clone()) + .await + .map_err(Chain::raise_error)? + .max_decoding_message_size(33554432); + + let request = QueryConsensusStateHeightsRequest { + client_id: client_id.clone(), + pagination: None, + }; + + let response = client + .consensus_state_heights(tonic::Request::new(request.into())) + .await + .map_err(Chain::raise_error)? + .into_inner(); + + let mut heights: Vec = response + .consensus_state_heights + .into_iter() + .map(|height| RollupHeight { + slot_number: height.revision_height, + }) + .collect(); + + heights.sort_unstable(); + + Ok(heights) + } +} diff --git a/crates/relayer/sovereign-chain-components/src/cosmos/impls/queries/mod.rs b/crates/relayer/sovereign-chain-components/src/cosmos/impls/queries/mod.rs new file mode 100644 index 00000000..cd95a533 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/cosmos/impls/queries/mod.rs @@ -0,0 +1 @@ +pub mod consensus_state_heights; diff --git a/crates/relayer/sovereign-chain-components/src/cosmos/impls/sovereign_to_cosmos/client/create_client_message.rs b/crates/relayer/sovereign-chain-components/src/cosmos/impls/sovereign_to_cosmos/client/create_client_message.rs new file mode 100644 index 00000000..77c4e459 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/cosmos/impls/sovereign_to_cosmos/client/create_client_message.rs @@ -0,0 +1,82 @@ +use cgp_core::CanRaiseError; +use hermes_cosmos_chain_components::traits::message::{CosmosMessage, ToCosmosMessage}; +use hermes_cosmos_chain_components::types::messages::client::create::CosmosCreateClientMessage; +use hermes_encoding_components::traits::convert::CanConvert; +use hermes_encoding_components::traits::encoded::HasEncodedType; +use hermes_encoding_components::traits::encoder::CanEncode; +use hermes_encoding_components::traits::has_encoding::HasDefaultEncoding; +use hermes_protobuf_encoding_components::types::Any; +use hermes_relayer_components::chain::traits::message_builders::create_client::CreateClientMessageBuilder; +use hermes_relayer_components::chain::traits::types::create_client::{ + HasCreateClientMessageOptionsType, HasCreateClientPayloadType, +}; +use hermes_relayer_components::chain::traits::types::message::HasMessageType; +use hermes_sovereign_rollup_components::types::client_state::SovereignClientState; +use hermes_sovereign_rollup_components::types::consensus_state::SovereignConsensusState; +use hermes_wasm_client_components::types::client_state::WasmClientState; +use hermes_wasm_client_components::types::consensus_state::WasmConsensusState; +use prost::EncodeError; + +use crate::sovereign::types::payloads::client::SovereignCreateClientPayload; + +/** + Build a message to create a Sovereign client on a Cosmos chain +*/ +pub struct BuildCreateSovereignClientMessageOnCosmos; + +impl CreateClientMessageBuilder + for BuildCreateSovereignClientMessageOnCosmos +where + Chain: HasMessageType + + HasCreateClientMessageOptionsType + + CanRaiseError + + CanRaiseError, + Counterparty: HasDefaultEncoding + + HasCreateClientPayloadType, + Encoding: HasEncodedType> + + CanConvert + + CanConvert + + CanEncode + + CanEncode, +{ + async fn build_create_client_message( + _chain: &Chain, + _options: &Chain::CreateClientMessageOptions, + payload: SovereignCreateClientPayload, + ) -> Result { + let encoding = Counterparty::default_encoding(); + + let sov_client_state_bytes = encoding + .encode(&payload.client_state) + .map_err(Chain::raise_error)?; + + let wasm_client_state = WasmClientState { + data: sov_client_state_bytes, + checksum: payload.code_hash.clone(), + latest_height: payload.latest_height, + }; + + let wasm_client_state_any = encoding + .convert(&wasm_client_state) + .map_err(Chain::raise_error)?; + + let sov_consensus_state_bytes = encoding + .encode(&payload.consensus_state) + .map_err(Chain::raise_error)?; + + let wasm_consensus_state = WasmConsensusState { + data: sov_consensus_state_bytes, + }; + + let wasm_consensus_state_any = encoding + .convert(&wasm_consensus_state) + .map_err(Chain::raise_error)?; + + let message = CosmosCreateClientMessage { + client_state: wasm_client_state_any, + consensus_state: wasm_consensus_state_any, + }; + + Ok(message.to_cosmos_message()) + } +} diff --git a/crates/relayer/sovereign-chain-components/src/cosmos/impls/sovereign_to_cosmos/client/mod.rs b/crates/relayer/sovereign-chain-components/src/cosmos/impls/sovereign_to_cosmos/client/mod.rs new file mode 100644 index 00000000..6a99c0f1 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/cosmos/impls/sovereign_to_cosmos/client/mod.rs @@ -0,0 +1,2 @@ +pub mod create_client_message; +pub mod update_client_message; diff --git a/crates/relayer/sovereign-chain-components/src/cosmos/impls/sovereign_to_cosmos/client/update_client_message.rs b/crates/relayer/sovereign-chain-components/src/cosmos/impls/sovereign_to_cosmos/client/update_client_message.rs new file mode 100644 index 00000000..56bde923 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/cosmos/impls/sovereign_to_cosmos/client/update_client_message.rs @@ -0,0 +1,79 @@ +use cgp_core::CanRaiseError; +use hermes_cosmos_chain_components::traits::message::{CosmosMessage, ToCosmosMessage}; +use hermes_cosmos_chain_components::types::messages::client::update::CosmosUpdateClientMessage; +use hermes_relayer_components::chain::traits::message_builders::update_client::UpdateClientMessageBuilder; +use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; +use hermes_relayer_components::chain::traits::types::update_client::HasUpdateClientPayloadType; +use ibc::clients::tendermint::types::Header; +use ibc::clients::wasm_types::client_message::{ClientMessage, WASM_CLIENT_MESSAGE_TYPE_URL}; +use ibc::core::client::types::Height; +use ibc_proto::google::protobuf::Any; +use ibc_proto::ibc::lightclients::wasm::v1::ClientMessage as RawClientMessage; +use ibc_proto::Protobuf; +use ibc_relayer_types::clients::ics07_tendermint::header::Header as RelayerHeader; +use ibc_relayer_types::core::ics24_host::identifier::ClientId; +use prost::Message; +use sov_celestia_client::types::client_message::test_util::dummy_sov_header; + +use crate::sovereign::types::payloads::client::SovereignUpdateClientPayload; + +pub struct BuildUpdateSovereignClientMessageOnCosmos; + +impl UpdateClientMessageBuilder + for BuildUpdateSovereignClientMessageOnCosmos +where + Chain: HasIbcChainTypes + + CanRaiseError<&'static str>, + Counterparty: + HasUpdateClientPayloadType, +{ + async fn build_update_client_message( + _chain: &Chain, + client_id: &ClientId, + payload: SovereignUpdateClientPayload, + ) -> Result, Chain::Error> { + // FIXME: allow multiple DA update headers to be embedded in the update client message + let [header]: [RelayerHeader; 1] = <[RelayerHeader; 1]>::try_from(payload.datachain_header) + .map_err(|_| Chain::raise_error("the relayer currently only supports building UpdateClient message with exactly one DA update header"))?; + + let header = Header { + signed_header: header.signed_header, + validator_set: header.validator_set, + trusted_height: Height::new( + header.trusted_height.revision_number(), + header.trusted_height.revision_height(), + ) + .unwrap(), + trusted_next_validator_set: header.trusted_validator_set, + }; + + let header = dummy_sov_header( + header, + payload.initial_state_height.revision_height(), + payload.final_state_height.revision_height(), + payload.final_user_hash.into(), + ); + // Convert Sovereign header to Any + let any_header = Any::from(header); + + // Create Wasm ClientMessage containing the Sovereign + // header converted to Any + let wasm_message = ClientMessage { + data: any_header.encode_to_vec(), + }; + + // Convert Wasm ClientMessage to Any + let any_wasm_message = Any { + type_url: WASM_CLIENT_MESSAGE_TYPE_URL.to_owned(), + value: Protobuf::::encode_vec(wasm_message), + }; + + // Send the Wasm message converted to Any + let message = CosmosUpdateClientMessage { + client_id: client_id.clone(), + header: any_wasm_message, + }; + + Ok(vec![message.to_cosmos_message()]) + } +} diff --git a/crates/relayer/sovereign-chain-components/src/cosmos/impls/sovereign_to_cosmos/mod.rs b/crates/relayer/sovereign-chain-components/src/cosmos/impls/sovereign_to_cosmos/mod.rs new file mode 100644 index 00000000..b9babe5b --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/cosmos/impls/sovereign_to_cosmos/mod.rs @@ -0,0 +1 @@ +pub mod client; diff --git a/crates/relayer/sovereign-chain-components/src/cosmos/mod.rs b/crates/relayer/sovereign-chain-components/src/cosmos/mod.rs new file mode 100644 index 00000000..fc6f2c7a --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/cosmos/mod.rs @@ -0,0 +1,7 @@ +/*! + Context-generic client implementations for the Cosmos chain context, + with the counterparty being a Sovereign rollup +*/ + +pub mod components; +pub mod impls; diff --git a/crates/relayer/sovereign-chain-components/src/encoding/components.rs b/crates/relayer/sovereign-chain-components/src/encoding/components.rs new file mode 100644 index 00000000..d0f62e17 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/encoding/components.rs @@ -0,0 +1,34 @@ +use cgp_core::prelude::*; +use hermes_encoding_components::impls::delegate::DelegateEncoding; +use hermes_encoding_components::impls::encoded::ProvideEncodedBytes; +use hermes_encoding_components::impls::schema::ProvideStringSchema; +use hermes_encoding_components::traits::convert::ConverterComponent; +use hermes_encoding_components::traits::decoder::DecoderComponent; +use hermes_encoding_components::traits::encoded::EncodedTypeComponent; +use hermes_encoding_components::traits::encoder::EncoderComponent; +use hermes_encoding_components::traits::schema::{SchemaGetterComponent, SchemaTypeComponent}; + +use crate::encoding::impls::convert::SovereignConverterComponents; +use crate::encoding::impls::encoder::SovereignEncoderComponents; +use crate::encoding::impls::type_url::SovereignTypeUrlSchemas; + +pub struct SovereignEncodingComponents; + +delegate_components! { + #[mark_component(IsSovereignEncodingComponent)] + SovereignEncodingComponents { + EncodedTypeComponent: + ProvideEncodedBytes, + SchemaTypeComponent: + ProvideStringSchema, + ConverterComponent: + DelegateEncoding, + [ + EncoderComponent, + DecoderComponent, + ]: + DelegateEncoding, + SchemaGetterComponent: + DelegateEncoding, + } +} diff --git a/crates/relayer/sovereign-chain-components/src/encoding/impls/convert.rs b/crates/relayer/sovereign-chain-components/src/encoding/impls/convert.rs new file mode 100644 index 00000000..1265eda0 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/encoding/impls/convert.rs @@ -0,0 +1,78 @@ +use cgp_core::prelude::*; +use hermes_cosmos_chain_components::encoding::components::CosmosEncodingComponents; +use hermes_cosmos_chain_components::types::tendermint::{ + ProtoTendermintClientState, ProtoTendermintConsensusState, TendermintClientState, + TendermintConsensusState, +}; +use hermes_encoding_components::impls::convert::{ConvertFrom, TryConvertFrom}; +use hermes_protobuf_encoding_components::types::Any; +use hermes_sovereign_rollup_components::types::client_state::{ + EncodeWrappedSovereignClientState, ProtoSovereignClientState, SovereignClientState, + WrappedSovereignClientState, +}; +use hermes_sovereign_rollup_components::types::consensus_state::{ + ProtoSovereignConsensusState, SovereignConsensusState, +}; +use hermes_wasm_client_components::impls::encoding::components::WasmEncodingComponents; +use hermes_wasm_client_components::types::client_state::{ProtoWasmClientState, WasmClientState}; +use hermes_wasm_client_components::types::consensus_state::{ + DecodeViaWasmConsensusState, EncodeViaWasmConsensusState, ProtoWasmConsensusState, + WasmConsensusState, +}; + +pub struct SovereignConverterComponents; + +delegate_components! { + SovereignConverterComponents { + [ + (TendermintClientState, ProtoTendermintClientState), + (ProtoTendermintClientState, TendermintClientState), + (TendermintConsensusState, ProtoTendermintConsensusState), + (ProtoTendermintConsensusState, TendermintConsensusState), + (TendermintClientState, Any), + (Any, TendermintClientState), + (TendermintConsensusState, Any), + (Any, TendermintConsensusState), + ]: + CosmosEncodingComponents, + + [ + (WasmClientState, ProtoWasmClientState), + (ProtoWasmClientState, WasmClientState), + + (WasmConsensusState, ProtoWasmConsensusState), + (ProtoWasmConsensusState, WasmConsensusState), + + (WasmClientState, Any), + (Any, WasmClientState), + + (WasmConsensusState, Any), + (Any, WasmConsensusState), + ]: + WasmEncodingComponents, + + (SovereignClientState, ProtoSovereignClientState): + ConvertFrom, + + (ProtoSovereignClientState, SovereignClientState): + TryConvertFrom, + + (SovereignConsensusState, ProtoSovereignConsensusState): + ConvertFrom, + + (ProtoSovereignConsensusState, SovereignConsensusState): + TryConvertFrom, + + (SovereignConsensusState, Any): + EncodeViaWasmConsensusState, + + (Any, SovereignConsensusState): + DecodeViaWasmConsensusState, + + [ + (Any, WrappedSovereignClientState), + (WrappedSovereignClientState, Any), + ]: + EncodeWrappedSovereignClientState + } +} diff --git a/crates/relayer/sovereign-chain-components/src/encoding/impls/encoder.rs b/crates/relayer/sovereign-chain-components/src/encoding/impls/encoder.rs new file mode 100644 index 00000000..431d5e5f --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/encoding/impls/encoder.rs @@ -0,0 +1,80 @@ +use cgp_core::prelude::*; +use hermes_cosmos_chain_components::encoding::components::CosmosEncodingComponents; +use hermes_cosmos_chain_components::types::tendermint::{ + ProtoTendermintClientState, ProtoTendermintConsensusState, TendermintClientState, + TendermintConsensusState, +}; +use hermes_encoding_components::impls::convert_and_encode::ConvertAndEncode; +use hermes_protobuf_encoding_components::impls::protobuf::EncodeAsProtobuf; +use hermes_protobuf_encoding_components::impls::via_any::EncodeViaAny; +use hermes_protobuf_encoding_components::types::{Any, Protobuf}; +use hermes_relayer_components::chain::traits::types::proof::ViaCommitmentProof; +use hermes_sovereign_rollup_components::impls::borsh_encode::{EncodeWithBorsh, ViaBorsh}; +use hermes_sovereign_rollup_components::types::client_state::{ + ProtoSovereignClientState, SovereignClientState, +}; +use hermes_sovereign_rollup_components::types::commitment_proof::JellyfishMerkleProof; +use hermes_sovereign_rollup_components::types::consensus_state::{ + ProtoSovereignConsensusState, SovereignConsensusState, +}; +use hermes_wasm_client_components::impls::encoding::components::WasmEncodingComponents; +use hermes_wasm_client_components::types::client_state::{ + DecodeViaWasmClientState, ProtoWasmClientState, WasmClientState, +}; +use hermes_wasm_client_components::types::consensus_state::{ + EncodeViaWasmConsensusState, ProtoWasmConsensusState, WasmConsensusState, +}; + +pub struct SovereignEncoderComponents; + +delegate_components! { + SovereignEncoderComponents { + [ + (Protobuf, Vec), + (ViaCommitmentProof, Vec), + + (Any, TendermintClientState), + (Protobuf, TendermintClientState), + (Protobuf, ProtoTendermintClientState), + (Any, TendermintConsensusState), + (Protobuf, TendermintConsensusState), + (Protobuf, ProtoTendermintConsensusState), + (Protobuf, Any), + ]: + CosmosEncodingComponents, + + [ + (Any, WasmClientState), + (Protobuf, WasmClientState), + (Protobuf, ProtoWasmClientState), + + (Any, WasmConsensusState), + (Protobuf, WasmConsensusState), + (Protobuf, ProtoWasmConsensusState), + ]: + WasmEncodingComponents, + + (Any, SovereignClientState): + EncodeViaAny, + (Protobuf, SovereignClientState): + ConvertAndEncode, + (Protobuf, ProtoSovereignClientState): + EncodeAsProtobuf, + + (Any, SovereignConsensusState): + EncodeViaAny, + (Protobuf, SovereignConsensusState): + ConvertAndEncode, + (Protobuf, ProtoSovereignConsensusState): + EncodeAsProtobuf, + + (WasmClientState, SovereignClientState): + DecodeViaWasmClientState, + + (WasmConsensusState, SovereignConsensusState): + EncodeViaWasmConsensusState, + + (ViaBorsh, JellyfishMerkleProof): + EncodeWithBorsh, + } +} diff --git a/crates/relayer/sovereign-chain-components/src/encoding/impls/mod.rs b/crates/relayer/sovereign-chain-components/src/encoding/impls/mod.rs new file mode 100644 index 00000000..452e422c --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/encoding/impls/mod.rs @@ -0,0 +1,3 @@ +pub mod convert; +pub mod encoder; +pub mod type_url; diff --git a/crates/relayer/sovereign-chain-components/src/encoding/impls/type_url.rs b/crates/relayer/sovereign-chain-components/src/encoding/impls/type_url.rs new file mode 100644 index 00000000..f08e1180 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/encoding/impls/type_url.rs @@ -0,0 +1,44 @@ +use cgp_core::prelude::*; +use hermes_cosmos_chain_components::encoding::components::CosmosEncodingComponents; +use hermes_cosmos_chain_components::types::tendermint::{ + TendermintClientState, TendermintConsensusState, +}; +use hermes_protobuf_encoding_components::impl_type_url; +use hermes_sovereign_rollup_components::types::client_state::SovereignClientState; +use hermes_sovereign_rollup_components::types::consensus_state::SovereignConsensusState; +use hermes_wasm_client_components::impls::encoding::components::WasmEncodingComponents; +use hermes_wasm_client_components::types::client_state::WasmClientState; +use hermes_wasm_client_components::types::consensus_state::WasmConsensusState; + +pub struct SovereignTypeUrlSchemas; + +delegate_components! { + SovereignTypeUrlSchemas { + [ + TendermintClientState, + TendermintConsensusState, + ]: + CosmosEncodingComponents, + + [ + WasmClientState, + WasmConsensusState, + ]: + WasmEncodingComponents, + + SovereignClientState: + SovereignClientStateUrl, + SovereignConsensusState: + SovereignConsensusStateUrl, + } +} + +impl_type_url!( + SovereignClientStateUrl, + "/ibc.lightclients.sovereign.tendermint.v1.ClientState", +); + +impl_type_url!( + SovereignConsensusStateUrl, + "/ibc.lightclients.sovereign.tendermint.v1.ConsensusState", +); diff --git a/crates/relayer/sovereign-chain-components/src/encoding/mod.rs b/crates/relayer/sovereign-chain-components/src/encoding/mod.rs new file mode 100644 index 00000000..11b7926d --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/encoding/mod.rs @@ -0,0 +1,2 @@ +pub mod components; +pub mod impls; diff --git a/crates/relayer/sovereign-chain-components/src/lib.rs b/crates/relayer/sovereign-chain-components/src/lib.rs new file mode 100644 index 00000000..3750b0cc --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/lib.rs @@ -0,0 +1,5 @@ +#![recursion_limit = "256"] + +pub mod cosmos; +pub mod encoding; +pub mod sovereign; diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/components.rs b/crates/relayer/sovereign-chain-components/src/sovereign/components.rs new file mode 100644 index 00000000..b76d009f --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/components.rs @@ -0,0 +1,315 @@ +use cgp_core::prelude::*; +use hermes_cosmos_chain_components::impls::channel::channel_handshake_message::BuildCosmosChannelHandshakeMessage; +use hermes_cosmos_chain_components::impls::connection::connection_handshake_message::BuildCosmosConnectionHandshakeMessage; +use hermes_cosmos_chain_components::impls::packet::packet_fields::CosmosPacketFieldReader; +use hermes_cosmos_chain_components::impls::packet::packet_message::BuildCosmosPacketMessages; +use hermes_relayer_components::chain::impls::forward::queries::chain_status::ForwardQueryChainStatus; +use hermes_relayer_components::chain::impls::forward::queries::channel_end::ForwardQueryChannelEnd; +use hermes_relayer_components::chain::impls::forward::queries::client_state::ForwardQueryClientState; +use hermes_relayer_components::chain::impls::forward::queries::connection_end::ForwardQueryConnectionEnd; +use hermes_relayer_components::chain::impls::forward::queries::consensus_state::ForwardQueryConsensusState; +use hermes_relayer_components::chain::impls::forward::queries::consensus_state_height::ForwardQueryConsensusStateHeight; +use hermes_relayer_components::chain::impls::forward::queries::packet_acknowledgement::ForwardQueryPacketAcknowledgement; +use hermes_relayer_components::chain::impls::forward::queries::packet_commitment::ForwardQueryPacketCommitment; +use hermes_relayer_components::chain::impls::forward::queries::packet_receipt::ForwardQueryPacketReceipt; +use hermes_relayer_components::chain::impls::forward::send_message::ForwardSendMessage; +use hermes_relayer_components::chain::impls::payload_builders::channel::BuildChannelHandshakePayload; +use hermes_relayer_components::chain::impls::payload_builders::connection::BuildConnectionHandshakePayload; +use hermes_relayer_components::chain::impls::payload_builders::packet::BuildPacketPayloads; +use hermes_relayer_components::chain::impls::types::payloads::channel::ProvideChannelPayloadTypes; +use hermes_relayer_components::chain::impls::types::payloads::connection::ProvideConnectionPayloadTypes; +use hermes_relayer_components::chain::impls::types::payloads::packet::ProvidePacketPayloadTypes; +use hermes_relayer_components::chain::traits::commitment_prefix::{ + CommitmentPrefixTypeComponent, IbcCommitmentPrefixGetterComponent, +}; +use hermes_relayer_components::chain::traits::message_builders::ack_packet::AckPacketMessageBuilderComponent; +use hermes_relayer_components::chain::traits::message_builders::channel_handshake::{ + ChannelOpenAckMessageBuilderComponent, ChannelOpenConfirmMessageBuilderComponent, + ChannelOpenInitMessageBuilderComponent, ChannelOpenTryMessageBuilderComponent, +}; +use hermes_relayer_components::chain::traits::message_builders::connection_handshake::{ + ConnectionOpenAckMessageBuilderComponent, ConnectionOpenConfirmMessageBuilderComponent, + ConnectionOpenInitMessageBuilderComponent, ConnectionOpenTryMessageBuilderComponent, +}; +use hermes_relayer_components::chain::traits::message_builders::create_client::CreateClientMessageBuilderComponent; +use hermes_relayer_components::chain::traits::message_builders::receive_packet::ReceivePacketMessageBuilderComponent; +use hermes_relayer_components::chain::traits::message_builders::timeout_unordered_packet::TimeoutUnorderedPacketMessageBuilderComponent; +use hermes_relayer_components::chain::traits::message_builders::update_client::UpdateClientMessageBuilderComponent; +use hermes_relayer_components::chain::traits::packet::fields::PacketFieldsReaderComponent; +use hermes_relayer_components::chain::traits::payload_builders::ack_packet::AckPacketPayloadBuilderComponent; +use hermes_relayer_components::chain::traits::payload_builders::channel_handshake::{ + ChannelOpenAckPayloadBuilderComponent, ChannelOpenConfirmPayloadBuilderComponent, + ChannelOpenTryPayloadBuilderComponent, +}; +use hermes_relayer_components::chain::traits::payload_builders::connection_handshake::{ + ConnectionOpenAckPayloadBuilderComponent, ConnectionOpenConfirmPayloadBuilderComponent, + ConnectionOpenInitPayloadBuilderComponent, ConnectionOpenTryPayloadBuilderComponent, +}; +use hermes_relayer_components::chain::traits::payload_builders::create_client::CreateClientPayloadBuilderComponent; +use hermes_relayer_components::chain::traits::payload_builders::receive_packet::ReceivePacketPayloadBuilderComponent; +use hermes_relayer_components::chain::traits::payload_builders::timeout_unordered_packet::TimeoutUnorderedPacketPayloadBuilderComponent; +use hermes_relayer_components::chain::traits::payload_builders::update_client::UpdateClientPayloadBuilderComponent; +use hermes_relayer_components::chain::traits::queries::chain_status::ChainStatusQuerierComponent; +use hermes_relayer_components::chain::traits::queries::channel_end::{ + ChannelEndQuerierComponent, ChannelEndWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::client_state::{ + ClientStateQuerierComponent, ClientStateWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::connection_end::{ + ConnectionEndQuerierComponent, ConnectionEndWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::consensus_state::{ + ConsensusStateQuerierComponent, ConsensusStateWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::consensus_state_height::ConsensusStateHeightQuerierComponent; +use hermes_relayer_components::chain::traits::queries::packet_acknowledgement::PacketAcknowledgementQuerierComponent; +use hermes_relayer_components::chain::traits::queries::packet_commitment::PacketCommitmentQuerierComponent; +use hermes_relayer_components::chain::traits::queries::packet_receipt::PacketReceiptQuerierComponent; +use hermes_relayer_components::chain::traits::send_message::MessageSenderComponent; +use hermes_relayer_components::chain::traits::types::chain_id::ChainIdTypeComponent; +use hermes_relayer_components::chain::traits::types::channel::{ + ChannelEndTypeComponent, ChannelOpenAckPayloadTypeComponent, + ChannelOpenConfirmPayloadTypeComponent, ChannelOpenTryPayloadTypeComponent, + InitChannelOptionsTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::client_state::{ + ClientStateFieldsGetterComponent, ClientStateTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::connection::{ + ConnectionEndTypeComponent, ConnectionOpenAckPayloadTypeComponent, + ConnectionOpenConfirmPayloadTypeComponent, ConnectionOpenInitPayloadTypeComponent, + ConnectionOpenTryPayloadTypeComponent, InitConnectionOptionsTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::consensus_state::ConsensusStateTypeComponent; +use hermes_relayer_components::chain::traits::types::create_client::{ + CreateClientEventComponent, CreateClientMessageOptionsTypeComponent, + CreateClientPayloadOptionsTypeComponent, CreateClientPayloadTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::event::EventTypeComponent; +use hermes_relayer_components::chain::traits::types::height::{ + HeightFieldComponent, HeightIncrementerComponent, HeightTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::ibc::{ + CounterpartyMessageHeightGetterComponent, IbcChainTypesComponent, +}; +use hermes_relayer_components::chain::traits::types::ibc_events::channel::{ + ChannelOpenInitEventComponent, ChannelOpenTryEventComponent, +}; +use hermes_relayer_components::chain::traits::types::ibc_events::connection::{ + ConnectionOpenInitEventComponent, ConnectionOpenTryEventComponent, +}; +use hermes_relayer_components::chain::traits::types::ibc_events::send_packet::SendPacketEventComponent; +use hermes_relayer_components::chain::traits::types::ibc_events::write_ack::WriteAckEventComponent; +use hermes_relayer_components::chain::traits::types::message::MessageTypeComponent; +use hermes_relayer_components::chain::traits::types::packet::IbcPacketTypesProviderComponent; +use hermes_relayer_components::chain::traits::types::packets::ack::{ + AckPacketPayloadTypeComponent, AcknowledgementTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::packets::receive::{ + PacketCommitmentTypeComponent, ReceivePacketPayloadTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::packets::timeout::{ + PacketReceiptTypeComponent, TimeoutUnorderedPacketPayloadTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::proof::{ + CommitmentProofBytesGetterComponent, CommitmentProofHeightGetterComponent, + CommitmentProofTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::status::ChainStatusTypeComponent; +use hermes_relayer_components::chain::traits::types::timestamp::TimestampTypeComponent; +use hermes_relayer_components::chain::traits::types::update_client::UpdateClientPayloadTypeComponent; +use hermes_relayer_components::transaction::traits::types::fee::FeeTypeComponent; +use hermes_relayer_components::transaction::traits::types::nonce::NonceTypeComponent; +use hermes_relayer_components::transaction::traits::types::signer::SignerTypeComponent; +use hermes_relayer_components::transaction::traits::types::transaction::TransactionTypeComponent; +use hermes_relayer_components::transaction::traits::types::tx_hash::TransactionHashTypeComponent; +use hermes_relayer_components::transaction::traits::types::tx_response::TxResponseTypeComponent; +use hermes_sovereign_rollup_components::impls::commitment_prefix::ProvideSovereignIbcCommitmentPrefix; +use hermes_sovereign_rollup_components::impls::cosmos_to_sovereign::client::create_client_message::BuildCreateCosmosClientMessageOnSovereign; +use hermes_sovereign_rollup_components::impls::cosmos_to_sovereign::client::update_client_message::BuildUpdateCosmosClientMessageOnSovereign; +use hermes_sovereign_rollup_components::impls::events::ProvideSovereignEvents; +use hermes_sovereign_rollup_components::impls::message_height::GetCosmosHeightFromSovereignMessage; +use hermes_sovereign_rollup_components::impls::types::client_state::ProvideSovereignClientState; +use hermes_sovereign_rollup_components::impls::types::consensus_state::ProvideSovereignConsensusState; +use hermes_sovereign_rollup_components::impls::types::transaction::ProvideSovereignTransactionTypes; + +use crate::sovereign::impls::sovereign_to_cosmos::client::create_client_payload::BuildSovereignCreateClientPayload; +use crate::sovereign::impls::sovereign_to_cosmos::client::update_client_payload::BuildSovereignUpdateClientPayload; +use crate::sovereign::impls::types::chain::ProvideSovereignChainTypes; +use crate::sovereign::impls::types::payload::ProvideSovereignPayloadTypes; + +pub struct SovereignChainClientComponents; + +delegate_components! { + #[mark_component(IsSovereignChainClientComponent)] + SovereignChainClientComponents { + [ + HeightTypeComponent, + HeightFieldComponent, + HeightIncrementerComponent, + TimestampTypeComponent, + ChainIdTypeComponent, + MessageTypeComponent, + EventTypeComponent, + ChainStatusTypeComponent, + IbcChainTypesComponent, + IbcPacketTypesProviderComponent, + CommitmentPrefixTypeComponent, + CommitmentProofTypeComponent, + CommitmentProofHeightGetterComponent, + CommitmentProofBytesGetterComponent, + PacketCommitmentTypeComponent, + AcknowledgementTypeComponent, + PacketReceiptTypeComponent, + ConnectionEndTypeComponent, + ChannelEndTypeComponent, + ]: + ProvideSovereignChainTypes, + [ + CreateClientEventComponent, + ConnectionOpenInitEventComponent, + ConnectionOpenTryEventComponent, + ChannelOpenInitEventComponent, + ChannelOpenTryEventComponent, + SendPacketEventComponent, + WriteAckEventComponent, + ]: + ProvideSovereignEvents, + [ + CreateClientPayloadOptionsTypeComponent, + CreateClientMessageOptionsTypeComponent, + CreateClientPayloadTypeComponent, + UpdateClientPayloadTypeComponent, + InitConnectionOptionsTypeComponent, + InitChannelOptionsTypeComponent, + ]: + ProvideSovereignPayloadTypes, + [ + ConnectionOpenInitPayloadTypeComponent, + ConnectionOpenTryPayloadTypeComponent, + ConnectionOpenAckPayloadTypeComponent, + ConnectionOpenConfirmPayloadTypeComponent, + ]: + ProvideConnectionPayloadTypes, + [ + ChannelOpenTryPayloadTypeComponent, + ChannelOpenAckPayloadTypeComponent, + ChannelOpenConfirmPayloadTypeComponent, + ]: + ProvideChannelPayloadTypes, + [ + ReceivePacketPayloadTypeComponent, + AckPacketPayloadTypeComponent, + TimeoutUnorderedPacketPayloadTypeComponent, + ]: + ProvidePacketPayloadTypes, + [ + ClientStateTypeComponent, + ClientStateFieldsGetterComponent, + ]: + ProvideSovereignClientState, + ConsensusStateTypeComponent: + ProvideSovereignConsensusState, + [ + TransactionTypeComponent, + NonceTypeComponent, + FeeTypeComponent, + SignerTypeComponent, + TransactionHashTypeComponent, + TxResponseTypeComponent, + ]: + ProvideSovereignTransactionTypes, + IbcCommitmentPrefixGetterComponent: + ProvideSovereignIbcCommitmentPrefix, + PacketFieldsReaderComponent: + CosmosPacketFieldReader, + MessageSenderComponent: + ForwardSendMessage, + CreateClientPayloadBuilderComponent: + BuildSovereignCreateClientPayload, + CreateClientMessageBuilderComponent: + BuildCreateCosmosClientMessageOnSovereign, + UpdateClientPayloadBuilderComponent: + BuildSovereignUpdateClientPayload, + UpdateClientMessageBuilderComponent: + BuildUpdateCosmosClientMessageOnSovereign, + + [ + ConnectionOpenInitPayloadBuilderComponent, + ConnectionOpenTryPayloadBuilderComponent, + ConnectionOpenAckPayloadBuilderComponent, + ConnectionOpenConfirmPayloadBuilderComponent, + ]: + BuildConnectionHandshakePayload, + [ + ConnectionOpenInitMessageBuilderComponent, + ConnectionOpenTryMessageBuilderComponent, + ConnectionOpenAckMessageBuilderComponent, + ConnectionOpenConfirmMessageBuilderComponent, + ]: + BuildCosmosConnectionHandshakeMessage, + + [ + ChannelOpenTryPayloadBuilderComponent, + ChannelOpenAckPayloadBuilderComponent, + ChannelOpenConfirmPayloadBuilderComponent, + ]: + BuildChannelHandshakePayload, + + [ + ChannelOpenInitMessageBuilderComponent, + ChannelOpenTryMessageBuilderComponent, + ChannelOpenAckMessageBuilderComponent, + ChannelOpenConfirmMessageBuilderComponent, + ]: + BuildCosmosChannelHandshakeMessage, + + [ + ReceivePacketMessageBuilderComponent, + AckPacketMessageBuilderComponent, + TimeoutUnorderedPacketMessageBuilderComponent, + ]: + BuildCosmosPacketMessages, + + [ + ReceivePacketPayloadBuilderComponent, + AckPacketPayloadBuilderComponent, + TimeoutUnorderedPacketPayloadBuilderComponent, + ]: + BuildPacketPayloads, + + ChainStatusQuerierComponent: + ForwardQueryChainStatus, + [ + ClientStateQuerierComponent, + ClientStateWithProofsQuerierComponent, + ]: + ForwardQueryClientState, + [ + ConsensusStateQuerierComponent, + ConsensusStateWithProofsQuerierComponent, + ]: + ForwardQueryConsensusState, + [ + ConnectionEndQuerierComponent, + ConnectionEndWithProofsQuerierComponent, + ]: + ForwardQueryConnectionEnd, + [ + ChannelEndQuerierComponent, + ChannelEndWithProofsQuerierComponent, + ]: + ForwardQueryChannelEnd, + PacketCommitmentQuerierComponent: + ForwardQueryPacketCommitment, + PacketAcknowledgementQuerierComponent: + ForwardQueryPacketAcknowledgement, + PacketReceiptQuerierComponent: + ForwardQueryPacketReceipt, + ConsensusStateHeightQuerierComponent: + ForwardQueryConsensusStateHeight, + CounterpartyMessageHeightGetterComponent: + GetCosmosHeightFromSovereignMessage, + } +} diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/impls/mod.rs b/crates/relayer/sovereign-chain-components/src/sovereign/impls/mod.rs new file mode 100644 index 00000000..0aaa12df --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/impls/mod.rs @@ -0,0 +1,2 @@ +pub mod sovereign_to_cosmos; +pub mod types; diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/impls/sovereign_to_cosmos/client/create_client_payload.rs b/crates/relayer/sovereign-chain-components/src/sovereign/impls/sovereign_to_cosmos/client/create_client_payload.rs new file mode 100644 index 00000000..93006efd --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/impls/sovereign_to_cosmos/client/create_client_payload.rs @@ -0,0 +1,119 @@ +use cgp_core::CanRaiseError; +use hermes_cosmos_chain_components::traits::chain_handle::HasBlockingChainHandle; +use hermes_relayer_components::chain::traits::payload_builders::create_client::CreateClientPayloadBuilder; +use hermes_relayer_components::chain::traits::queries::chain_status::CanQueryChainHeight; +use hermes_relayer_components::chain::traits::types::create_client::{ + HasCreateClientPayloadOptionsType, HasCreateClientPayloadType, +}; +use hermes_relayer_components::chain::traits::types::height::HasHeightType; +use hermes_sovereign_rollup_components::impls::queries::slot_hash::CanQuerySlotHash; +use hermes_sovereign_rollup_components::types::height::RollupHeight; +use ibc::core::client::types::Height; +use ibc_relayer::chain::handle::ChainHandle; +use ibc_relayer::chain::requests::{QueryHeight, QueryHostConsensusStateRequest}; +use ibc_relayer::consensus_state::AnyConsensusState; +use ibc_relayer_types::Height as RelayerHeight; +use sov_celestia_client::types::client_state::ClientState; +use sov_celestia_client::types::consensus_state::{SovTmConsensusState, TmConsensusParams}; +use sov_celestia_client::types::sovereign::SovereignConsensusParams; + +use crate::sovereign::traits::chain::data_chain::HasDataChain; +use crate::sovereign::traits::chain::rollup::HasRollup; +use crate::sovereign::types::payloads::client::{ + SovereignCreateClientOptions, SovereignCreateClientPayload, +}; + +/** + Build a create client payload from a Sovereign rollup, to be + used as a create message to a Cosmos counterparty chain +*/ +pub struct BuildSovereignCreateClientPayload; + +impl CreateClientPayloadBuilder + for BuildSovereignCreateClientPayload +where + Chain: HasRollup + + HasDataChain + + HasCreateClientPayloadOptionsType< + Counterparty, + CreateClientPayloadOptions = SovereignCreateClientOptions, + > + HasCreateClientPayloadType + + CanRaiseError, + Rollup: CanQueryChainHeight + CanQuerySlotHash + HasHeightType, + DataChain: HasBlockingChainHandle, +{ + async fn build_create_client_payload( + chain: &Chain, + create_client_options: &SovereignCreateClientOptions, + ) -> Result { + let rollup = chain.rollup(); + + // Build client state + let rollup_height = rollup + .query_chain_height() + .await + .map_err(Chain::raise_error)?; + + let slot_hash = rollup + .query_slot_hash(&rollup_height) + .await + .map_err(Chain::raise_error)?; + + let latest_height = Height::new(0, rollup_height.slot_number).unwrap(); + + let mut sovereign_client_params = create_client_options.sovereign_client_params.clone(); + sovereign_client_params.latest_height = latest_height; + + let genesis_da_height = sovereign_client_params.genesis_da_height; + + let client_state = ClientState::new( + sovereign_client_params, + create_client_options.tendermint_params_config.clone(), + ); + + let da_latest_height = RelayerHeight::new( + create_client_options + .sovereign_client_params + .genesis_da_height + .revision_number(), + rollup_height.slot_number + genesis_da_height.revision_height(), + ) + .unwrap(); + + let host_consensus_state_query = QueryHostConsensusStateRequest { + height: QueryHeight::Specific(da_latest_height), + }; + + let any_consensus_state = chain + .data_chain() + .with_blocking_chain_handle(move |chain_handle| { + Ok(chain_handle + .query_host_consensus_state(host_consensus_state_query) + .unwrap()) + }) + .await + .unwrap(); + + let AnyConsensusState::Tendermint(tm_consensus_state) = any_consensus_state; + + let tendermint_params = TmConsensusParams::new( + tm_consensus_state.timestamp, + tm_consensus_state.next_validators_hash, + ); + + let sovereign_params = SovereignConsensusParams::new(slot_hash.user_hash.to_vec().into()); + + let consensus_state = SovTmConsensusState::new(sovereign_params, tendermint_params); + + // Retrieve code hash + let code_hash = create_client_options.code_hash.clone(); + + // Build Create client payload + Ok(SovereignCreateClientPayload { + client_state, + consensus_state, + code_hash, + latest_height, + }) + } +} diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/impls/sovereign_to_cosmos/client/mod.rs b/crates/relayer/sovereign-chain-components/src/sovereign/impls/sovereign_to_cosmos/client/mod.rs new file mode 100644 index 00000000..7886be7a --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/impls/sovereign_to_cosmos/client/mod.rs @@ -0,0 +1,2 @@ +pub mod create_client_payload; +pub mod update_client_payload; diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/impls/sovereign_to_cosmos/client/update_client_payload.rs b/crates/relayer/sovereign-chain-components/src/sovereign/impls/sovereign_to_cosmos/client/update_client_payload.rs new file mode 100644 index 00000000..e1e1eb76 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/impls/sovereign_to_cosmos/client/update_client_payload.rs @@ -0,0 +1,150 @@ +use std::time::Duration; + +use cgp_core::CanRaiseError; +use hermes_cosmos_chain_components::types::payloads::client::CosmosUpdateClientPayload; +use hermes_cosmos_chain_components::types::tendermint::TendermintClientState; +use hermes_relayer_components::chain::traits::payload_builders::update_client::{ + CanBuildUpdateClientPayload, UpdateClientPayloadBuilder, +}; +use hermes_relayer_components::chain::traits::types::client_state::HasClientStateType; +use hermes_relayer_components::chain::traits::types::height::HasHeightType; +use hermes_relayer_components::chain::traits::types::update_client::HasUpdateClientPayloadType; +use hermes_sovereign_rollup_components::impls::queries::slot_hash::CanQuerySlotHash; +use hermes_sovereign_rollup_components::types::client_state::WrappedSovereignClientState; +use hermes_sovereign_rollup_components::types::height::RollupHeight; +use ibc::core::client::types::error::ClientError as IbcClientError; +use ibc::core::client::types::Height as IbcHeight; +use ibc_relayer_types::clients::ics07_tendermint::client_state::AllowUpdate; +use ibc_relayer_types::core::ics02_client::error::Error as Ics02Error; +use ibc_relayer_types::core::ics02_client::height::Height; +use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold as RelayerTrustThreshold; +use ibc_relayer_types::core::ics23_commitment::specs::ProofSpecs; +use ibc_relayer_types::core::ics24_host::identifier::ChainId as RelayerChainId; +use sov_celestia_client::types::client_state::TendermintClientParams; + +use crate::sovereign::traits::chain::data_chain::HasDataChain; +use crate::sovereign::traits::chain::rollup::HasRollup; +use crate::sovereign::types::payloads::client::SovereignUpdateClientPayload; + +/** + Build an update client payload from a Sovereign rollup, to be used later + for sending an update client message to a Cosmos counterparty chain. +*/ +pub struct BuildSovereignUpdateClientPayload; + +impl UpdateClientPayloadBuilder + for BuildSovereignUpdateClientPayload +where + Chain: HasHeightType + + HasUpdateClientPayloadType + + HasClientStateType + + HasRollup + + HasDataChain + + CanRaiseError + + CanRaiseError + + CanRaiseError + + CanRaiseError, + DataChain: HasHeightType + + HasClientStateType + + CanBuildUpdateClientPayload, + Rollup: HasHeightType + CanQuerySlotHash, +{ + async fn build_update_client_payload( + chain: &Chain, + trusted_height: &RollupHeight, + target_height: &RollupHeight, + client_state: Chain::ClientState, + ) -> Result { + let rollup = chain.rollup(); + let data_chain = chain.data_chain(); + + let sovereign_params = &client_state.sovereign_client_state.sovereign_params; + + // DA height is higher than rollup height. This requires adding + // the genesis Height to the trusted and target Heights + let da_trusted_height = Height::new( + sovereign_params.genesis_da_height.revision_number(), + trusted_height.slot_number + sovereign_params.genesis_da_height.revision_height(), + ) + .map_err(Chain::raise_error)?; + + let da_target_height = Height::new( + sovereign_params.genesis_da_height.revision_number(), + target_height.slot_number + sovereign_params.genesis_da_height.revision_height(), + ) + .map_err(Chain::raise_error)?; + + let rollup_trusted_height = IbcHeight::new( + sovereign_params.latest_height.revision_number(), + trusted_height.slot_number, + ) + .map_err(Chain::raise_error)?; + + let rollup_target_height = IbcHeight::new( + sovereign_params.latest_height.revision_number(), + target_height.slot_number, + ) + .map_err(Chain::raise_error)?; + + let da_client_state = convert_tm_params_to_client_state( + &client_state.sovereign_client_state.da_params, + &da_target_height, + ) + .map_err(Chain::raise_error)?; + + let da_payload = data_chain + .build_update_client_payload(&da_trusted_height, &da_target_height, da_client_state) + .await + .map_err(Chain::raise_error)?; + + let slot_hash = rollup + .query_slot_hash(target_height) + .await + .map_err(Chain::raise_error)?; + + Ok(SovereignUpdateClientPayload { + datachain_header: da_payload.headers, + initial_state_height: rollup_trusted_height, + final_state_height: rollup_target_height, + final_user_hash: slot_hash.user_hash, + final_kernel_hash: slot_hash.kernel_hash, + final_root_hash: slot_hash.root_hash, + }) + } +} + +/// This is a temporary solution which converts the TendermintParams to Tendermint ClientState. +/// The Sovereign client state only has a TendermintParams field, but in order to build the +/// client update payload, the DA chain's client state is required. +/// Until the Light client is decoupled from the Cosmos SDK in order to build the DA header +/// half the Tendermint ClientState value are mocked. +/// See issue: https://github.com/informalsystems/hermes-sdk/issues/204 +fn convert_tm_params_to_client_state( + tm_params: &TendermintClientParams, + da_target_height: &Height, +) -> Result { + let relayer_chain_id = RelayerChainId::from_string(&tm_params.chain_id.to_string()); + + let relayer_trust_threshold = RelayerTrustThreshold::new( + tm_params.trust_level.numerator(), + tm_params.trust_level.denominator(), + )?; + + Ok(TendermintClientState { + chain_id: relayer_chain_id, + trust_threshold: relayer_trust_threshold, + // trusting_period was removed from `TendermintClientParams` + // https://github.com/informalsystems/sovereign-ibc/commit/a9aaa80c4fe7b21fa777ae2a186838aac1fed68c#diff-8735596286f5213c6003fc9dc4c719fe9c9d4f14b7a385f1418f766ef48faa54L17 + trusting_period: Duration::from_secs(300), + unbonding_period: tm_params.unbonding_period, + max_clock_drift: tm_params.max_clock_drift, + latest_height: *da_target_height, + proof_specs: ProofSpecs::default(), + upgrade_path: vec![], + allow_update: AllowUpdate { + after_expiry: false, + after_misbehaviour: false, + }, + frozen_height: None, + }) +} diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/impls/sovereign_to_cosmos/mod.rs b/crates/relayer/sovereign-chain-components/src/sovereign/impls/sovereign_to_cosmos/mod.rs new file mode 100644 index 00000000..b9babe5b --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/impls/sovereign_to_cosmos/mod.rs @@ -0,0 +1 @@ +pub mod client; diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/impls/types/chain.rs b/crates/relayer/sovereign-chain-components/src/sovereign/impls/types/chain.rs new file mode 100644 index 00000000..1a612eb8 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/impls/types/chain.rs @@ -0,0 +1,62 @@ +use cgp_core::prelude::*; +use hermes_relayer_components::chain::traits::commitment_prefix::CommitmentPrefixTypeComponent; +use hermes_relayer_components::chain::traits::types::chain_id::ProvideChainIdType; +use hermes_relayer_components::chain::traits::types::channel::ChannelEndTypeComponent; +use hermes_relayer_components::chain::traits::types::connection::ConnectionEndTypeComponent; +use hermes_relayer_components::chain::traits::types::event::EventTypeComponent; +use hermes_relayer_components::chain::traits::types::height::{ + HeightFieldComponent, HeightIncrementerComponent, HeightTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::ibc::IbcChainTypesComponent; +use hermes_relayer_components::chain::traits::types::message::MessageTypeComponent; +use hermes_relayer_components::chain::traits::types::packet::IbcPacketTypesProviderComponent; +use hermes_relayer_components::chain::traits::types::packets::ack::AcknowledgementTypeComponent; +use hermes_relayer_components::chain::traits::types::packets::receive::PacketCommitmentTypeComponent; +use hermes_relayer_components::chain::traits::types::packets::timeout::PacketReceiptTypeComponent; +use hermes_relayer_components::chain::traits::types::proof::{ + CommitmentProofBytesGetterComponent, CommitmentProofHeightGetterComponent, + CommitmentProofTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::status::ChainStatusTypeComponent; +use hermes_relayer_components::chain::traits::types::timestamp::TimestampTypeComponent; +use hermes_sovereign_rollup_components::impls::types::rollup::ProvideSovereignRollupTypes; +use ibc_relayer_types::core::ics24_host::identifier::ChainId; + +pub struct ProvideSovereignChainTypes; + +delegate_components! { + ProvideSovereignChainTypes { + [ + HeightTypeComponent, + HeightFieldComponent, + HeightIncrementerComponent, + TimestampTypeComponent, + MessageTypeComponent, + EventTypeComponent, + ChainStatusTypeComponent, + IbcChainTypesComponent, + IbcPacketTypesProviderComponent, + CommitmentPrefixTypeComponent, + CommitmentProofTypeComponent, + CommitmentProofHeightGetterComponent, + CommitmentProofBytesGetterComponent, + PacketCommitmentTypeComponent, + AcknowledgementTypeComponent, + PacketReceiptTypeComponent, + ConnectionEndTypeComponent, + ChannelEndTypeComponent, + ]: + ProvideSovereignRollupTypes, + + } +} + +impl ProvideChainIdType for ProvideSovereignChainTypes +where + Chain: Async, +{ + // TODO: A rollup chain ID should be a composite of the rollup ID + // and the DA chain ID. But for now we will handle only the DA chain ID + // for simplicity. + type ChainId = ChainId; +} diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/impls/types/mod.rs b/crates/relayer/sovereign-chain-components/src/sovereign/impls/types/mod.rs new file mode 100644 index 00000000..dd20bc77 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/impls/types/mod.rs @@ -0,0 +1,2 @@ +pub mod chain; +pub mod payload; diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/impls/types/payload.rs b/crates/relayer/sovereign-chain-components/src/sovereign/impls/types/payload.rs new file mode 100644 index 00000000..467e82cb --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/impls/types/payload.rs @@ -0,0 +1,95 @@ +use cgp_core::prelude::Async; +use hermes_cosmos_chain_components::types::channel::CosmosInitChannelOptions; +use hermes_cosmos_chain_components::types::connection::CosmosInitConnectionOptions; +use hermes_relayer_components::chain::traits::types::channel::ProvideInitChannelOptionsType; +use hermes_relayer_components::chain::traits::types::connection::ProvideInitConnectionOptionsType; +use hermes_relayer_components::chain::traits::types::create_client::{ + ProvideCreateClientMessageOptionsType, ProvideCreateClientPayloadOptionsType, + ProvideCreateClientPayloadType, +}; +use hermes_relayer_components::chain::traits::types::packets::ack::ProvideAckPacketPayloadType; +use hermes_relayer_components::chain::traits::types::packets::receive::ProvideReceivePacketPayloadType; +use hermes_relayer_components::chain::traits::types::packets::timeout::ProvideTimeoutUnorderedPacketPayloadType; +use hermes_relayer_components::chain::traits::types::update_client::ProvideUpdateClientPayloadType; + +use crate::sovereign::types::payloads::client::{ + SovereignCreateClientOptions, SovereignCreateClientPayload, SovereignUpdateClientPayload, +}; +use crate::sovereign::types::payloads::packet::{ + SovereignAckPacketPayload, SovereignReceivePacketPayload, + SovereignTimeoutUnorderedPacketPayload, +}; + +pub struct ProvideSovereignPayloadTypes; + +impl ProvideCreateClientPayloadOptionsType + for ProvideSovereignPayloadTypes +where + Chain: Async, +{ + type CreateClientPayloadOptions = SovereignCreateClientOptions; +} + +impl ProvideCreateClientMessageOptionsType + for ProvideSovereignPayloadTypes +where + Chain: Async, +{ + type CreateClientMessageOptions = (); +} + +impl ProvideCreateClientPayloadType + for ProvideSovereignPayloadTypes +where + Chain: Async, +{ + type CreateClientPayload = SovereignCreateClientPayload; +} + +impl ProvideUpdateClientPayloadType + for ProvideSovereignPayloadTypes +where + Chain: Async, +{ + type UpdateClientPayload = SovereignUpdateClientPayload; +} + +impl ProvideInitConnectionOptionsType + for ProvideSovereignPayloadTypes +where + Chain: Async, +{ + type InitConnectionOptions = CosmosInitConnectionOptions; +} + +impl ProvideInitChannelOptionsType + for ProvideSovereignPayloadTypes +where + Chain: Async, +{ + type InitChannelOptions = CosmosInitChannelOptions; +} + +impl ProvideReceivePacketPayloadType + for ProvideSovereignPayloadTypes +where + Chain: Async, +{ + type ReceivePacketPayload = SovereignReceivePacketPayload; +} + +impl ProvideAckPacketPayloadType + for ProvideSovereignPayloadTypes +where + Chain: Async, +{ + type AckPacketPayload = SovereignAckPacketPayload; +} + +impl ProvideTimeoutUnorderedPacketPayloadType + for ProvideSovereignPayloadTypes +where + Chain: Async, +{ + type TimeoutUnorderedPacketPayload = SovereignTimeoutUnorderedPacketPayload; +} diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/mod.rs b/crates/relayer/sovereign-chain-components/src/sovereign/mod.rs new file mode 100644 index 00000000..a66782ac --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/mod.rs @@ -0,0 +1,9 @@ +/*! + Context-generic client implementations for the Sovereign chain context, + with a counterparty Cosmos chain context. +*/ + +pub mod components; +pub mod impls; +pub mod traits; +pub mod types; diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/traits/chain/data_chain.rs b/crates/relayer/sovereign-chain-components/src/sovereign/traits/chain/data_chain.rs new file mode 100644 index 00000000..aefaba67 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/traits/chain/data_chain.rs @@ -0,0 +1,11 @@ +use cgp_core::prelude::*; + +#[derive_component(DataChainTypeComponent, ProvideDataChainType)] +pub trait HasDataChainType: Async { + type DataChain: Async; +} + +#[derive_component(DataChainGetterComponent, DataChainGetter)] +pub trait HasDataChain: HasDataChainType { + fn data_chain(&self) -> &Self::DataChain; +} diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/traits/chain/mod.rs b/crates/relayer/sovereign-chain-components/src/sovereign/traits/chain/mod.rs new file mode 100644 index 00000000..5c28e189 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/traits/chain/mod.rs @@ -0,0 +1,2 @@ +pub mod data_chain; +pub mod rollup; diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/traits/chain/rollup.rs b/crates/relayer/sovereign-chain-components/src/sovereign/traits/chain/rollup.rs new file mode 100644 index 00000000..3b911d35 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/traits/chain/rollup.rs @@ -0,0 +1,11 @@ +use cgp_core::prelude::*; + +#[derive_component(RollupTypeComponent, ProvideRollupType)] +pub trait HasRollupType: Async { + type Rollup: Async; +} + +#[derive_component(RollupGetterComponent, RollupGetter)] +pub trait HasRollup: HasRollupType { + fn rollup(&self) -> &Self::Rollup; +} diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/traits/data_chain/mod.rs b/crates/relayer/sovereign-chain-components/src/sovereign/traits/data_chain/mod.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/traits/data_chain/mod.rs @@ -0,0 +1 @@ + diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/traits/mod.rs b/crates/relayer/sovereign-chain-components/src/sovereign/traits/mod.rs new file mode 100644 index 00000000..93ecd46f --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/traits/mod.rs @@ -0,0 +1,3 @@ +pub mod chain; +pub mod data_chain; +pub mod rollup; diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/traits/rollup/mod.rs b/crates/relayer/sovereign-chain-components/src/sovereign/traits/rollup/mod.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/traits/rollup/mod.rs @@ -0,0 +1 @@ + diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/types/mod.rs b/crates/relayer/sovereign-chain-components/src/sovereign/types/mod.rs new file mode 100644 index 00000000..01074c63 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/types/mod.rs @@ -0,0 +1 @@ +pub mod payloads; diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/channel.rs b/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/channel.rs new file mode 100644 index 00000000..dbdaa28c --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/channel.rs @@ -0,0 +1,21 @@ +use ibc_relayer_types::core::ics04_channel::version::Version; +use ibc_relayer_types::core::ics23_commitment::commitment::CommitmentProofBytes; +use ibc_relayer_types::Height; + +pub struct SovereignInitChannelOptions { + // TODO: fill in fields +} + +pub struct SovereignChannelOpenTryPayload { + // TODO: fill in fields +} + +pub struct SovereignChannelOpenAckPayload { + pub version: Version, + pub update_height: Height, + pub proof_try: CommitmentProofBytes, +} + +pub struct SovereignChannelOpenConfirmPayload { + // TODO: fill in fields +} diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/client.rs b/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/client.rs new file mode 100644 index 00000000..b3ff5349 --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/client.rs @@ -0,0 +1,28 @@ +use hermes_sovereign_rollup_components::types::client_state::SovereignClientState; +use ibc::core::client::types::Height; +use ibc_relayer_types::clients::ics07_tendermint::header::Header; +use sov_celestia_client::types::client_state::TendermintClientParams; +use sov_celestia_client::types::consensus_state::SovTmConsensusState; +use sov_celestia_client::types::sovereign::SovereignClientParams; + +pub struct SovereignCreateClientPayload { + pub client_state: SovereignClientState, + pub consensus_state: SovTmConsensusState, + pub code_hash: Vec, + pub latest_height: Height, +} + +pub struct SovereignUpdateClientPayload { + pub datachain_header: Vec
, + pub initial_state_height: Height, + pub final_state_height: Height, + pub final_user_hash: [u8; 32], + pub final_kernel_hash: [u8; 32], + pub final_root_hash: [u8; 32], +} + +pub struct SovereignCreateClientOptions { + pub tendermint_params_config: TendermintClientParams, + pub sovereign_client_params: SovereignClientParams, + pub code_hash: Vec, +} diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/connection.rs b/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/connection.rs new file mode 100644 index 00000000..4a54d06f --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/connection.rs @@ -0,0 +1,26 @@ +use hermes_sovereign_rollup_components::types::client_state::SovereignClientState; +use ibc_relayer_types::core::ics02_client::height::Height; +use ibc_relayer_types::core::ics03_connection::version::Version; +use ibc_relayer_types::core::ics23_commitment::commitment::CommitmentProofBytes; +use ibc_relayer_types::proofs::ConsensusProof; + +pub struct SovereignConnectionOpenInitPayload { + pub commitment_prefix: Vec, +} + +pub struct SovereignConnectionOpenTryPayload { + // TODO: fill in fields +} + +pub struct SovereignConnectionOpenAckPayload { + pub client_state: SovereignClientState, + pub version: Version, + pub update_height: Height, + pub proof_try: CommitmentProofBytes, + pub proof_client: CommitmentProofBytes, + pub proof_consensus: ConsensusProof, +} + +pub struct SovereignConnectionOpenConfirmPayload { + // TODO: fill in fields +} diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/mod.rs b/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/mod.rs new file mode 100644 index 00000000..ec1d278b --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/mod.rs @@ -0,0 +1,2 @@ +pub mod client; +pub mod packet; diff --git a/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/packet.rs b/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/packet.rs new file mode 100644 index 00000000..d8a4aabe --- /dev/null +++ b/crates/relayer/sovereign-chain-components/src/sovereign/types/payloads/packet.rs @@ -0,0 +1,11 @@ +pub struct SovereignReceivePacketPayload { + // TODO: fill in fields +} + +pub struct SovereignAckPacketPayload { + // TODO: fill in fields +} + +pub struct SovereignTimeoutUnorderedPacketPayload { + // TODO: fill in fields +} diff --git a/crates/relayer/sovereign-integration-tests/.gitignore b/crates/relayer/sovereign-integration-tests/.gitignore new file mode 100644 index 00000000..64dd9fd0 --- /dev/null +++ b/crates/relayer/sovereign-integration-tests/.gitignore @@ -0,0 +1 @@ +ibc_08-wasm_client_data/ \ No newline at end of file diff --git a/crates/relayer/sovereign-integration-tests/Cargo.toml b/crates/relayer/sovereign-integration-tests/Cargo.toml new file mode 100644 index 00000000..cdd7e627 --- /dev/null +++ b/crates/relayer/sovereign-integration-tests/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "hermes-sovereign-integration-tests" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } +readme = "README.md" +description = """ + Concrete integration test cases for testing Sovereign to Cosmos relaying +""" + +[dependencies] +cgp-core = { workspace = true } +hermes-runtime-components = { workspace = true } +hermes-runtime = { workspace = true } +hermes-relayer-components = { workspace = true } +hermes-test-components = { workspace = true } +hermes-cosmos-chain-components = { workspace = true } +hermes-cosmos-relayer = { workspace = true } +hermes-cosmos-test-components = { workspace = true } +hermes-wasm-test-components = { workspace = true } +hermes-wasm-client-components = { workspace = true } +hermes-cosmos-integration-tests = { workspace = true } +hermes-celestia-test-components = { workspace = true } +hermes-celestia-integration-tests = { workspace = true } +hermes-sovereign-test-components = { workspace = true } +hermes-sovereign-chain-components = { workspace = true } +hermes-sovereign-rollup-components = { workspace = true } +hermes-sovereign-relayer = { workspace = true } + +ibc-relayer = { workspace = true } +ibc-relayer-types = { workspace = true } +ibc-proto = { workspace = true } +ibc = { workspace = true } + +sov-celestia-client = { workspace = true, features = [ "test-util" ] } + +eyre = { workspace = true } +futures = { workspace = true } +tokio = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +toml = { workspace = true } +rand = { workspace = true } +stable-eyre = { version = "0.2.2" } +jsonrpsee = { workspace = true, features = [ "http-client", "ws-client" ] } +borsh = { workspace = true } +sha2 = { workspace = true } +hex = { version = "0.4.3" } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = [ "env-filter", "json" ] } diff --git a/crates/relayer/sovereign-integration-tests/src/contexts/mod.rs b/crates/relayer/sovereign-integration-tests/src/contexts/mod.rs new file mode 100644 index 00000000..5e62d524 --- /dev/null +++ b/crates/relayer/sovereign-integration-tests/src/contexts/mod.rs @@ -0,0 +1,2 @@ +pub mod rollup_driver; +pub mod sovereign_bootstrap; diff --git a/crates/relayer/sovereign-integration-tests/src/contexts/rollup_driver.rs b/crates/relayer/sovereign-integration-tests/src/contexts/rollup_driver.rs new file mode 100644 index 00000000..fb7a28a3 --- /dev/null +++ b/crates/relayer/sovereign-integration-tests/src/contexts/rollup_driver.rs @@ -0,0 +1,49 @@ +use alloc::collections::BTreeMap; + +use cgp_core::prelude::*; +use cgp_core::{ErrorRaiserComponent, ErrorTypeComponent}; +use hermes_cosmos_relayer::types::error::{DebugError, ProvideCosmosError}; +use hermes_runtime::impls::types::runtime::ProvideHermesRuntime; +use hermes_runtime_components::traits::runtime::RuntimeTypeComponent; +use hermes_sovereign_chain_components::sovereign::traits::chain::rollup::{ + RollupGetter, RollupTypeComponent, +}; +use hermes_sovereign_relayer::contexts::sovereign_rollup::SovereignRollup; +use hermes_sovereign_test_components::types::rollup_genesis_config::SovereignGenesisConfig; +use hermes_sovereign_test_components::types::rollup_node_config::SovereignRollupNodeConfig; +use hermes_sovereign_test_components::types::wallet::SovereignWallet; +use tokio::process::Child; + +use crate::impls::rollup::ProvideSovereignRollupType; + +pub struct SovereignRollupDriver { + pub rollup: SovereignRollup, + pub node_config: SovereignRollupNodeConfig, + pub genesis_config: SovereignGenesisConfig, + pub wallets: BTreeMap, + pub rollup_process: Child, +} + +pub struct SovereignRollupDriverComponents; + +impl HasComponents for SovereignRollupDriver { + type Components = SovereignRollupDriverComponents; +} + +delegate_components! { + SovereignRollupDriverComponents { + ErrorTypeComponent: + ProvideCosmosError, + ErrorRaiserComponent: + DebugError, + RuntimeTypeComponent: + ProvideHermesRuntime, + RollupTypeComponent: ProvideSovereignRollupType, + } +} + +impl RollupGetter for SovereignRollupDriverComponents { + fn rollup(rollup_driver: &SovereignRollupDriver) -> &SovereignRollup { + &rollup_driver.rollup + } +} diff --git a/crates/relayer/sovereign-integration-tests/src/contexts/sovereign_bootstrap.rs b/crates/relayer/sovereign-integration-tests/src/contexts/sovereign_bootstrap.rs new file mode 100644 index 00000000..c79e7e46 --- /dev/null +++ b/crates/relayer/sovereign-integration-tests/src/contexts/sovereign_bootstrap.rs @@ -0,0 +1,104 @@ +use std::path::PathBuf; + +use cgp_core::prelude::*; +use cgp_core::{delegate_all, ErrorRaiserComponent, ErrorTypeComponent}; +use hermes_celestia_integration_tests::contexts::bridge_driver::CelestiaBridgeDriver; +use hermes_celestia_test_components::bootstrap::traits::types::bridge_driver::ProvideBridgeDriverType; +use hermes_cosmos_integration_tests::contexts::chain_driver::CosmosChainDriver; +use hermes_cosmos_relayer::contexts::chain::CosmosChain; +use hermes_cosmos_relayer::types::error::{DebugError, ProvideCosmosError}; +use hermes_cosmos_test_components::bootstrap::traits::fields::account_prefix::AccountPrefixGetter; +use hermes_runtime::impls::types::runtime::ProvideHermesRuntime; +use hermes_runtime::types::runtime::HermesRuntime; +use hermes_runtime_components::traits::runtime::{RuntimeGetter, RuntimeTypeComponent}; +use hermes_sovereign_chain_components::sovereign::traits::chain::rollup::ProvideRollupType; +use hermes_sovereign_relayer::contexts::sovereign_rollup::SovereignRollup; +use hermes_sovereign_test_components::bootstrap::components::{ + IsSovereignBootstrapComponent, SovereignBootstrapComponents as BaseSovereignBootstrapComponents, +}; +use hermes_sovereign_test_components::bootstrap::traits::bootstrap_rollup::CanBootstrapRollup; +use hermes_sovereign_test_components::bootstrap::traits::build_rollup_driver::RollupDriverBuilderComponent; +use hermes_sovereign_test_components::bootstrap::traits::rollup_command_path::RollupCommandPathGetter; +use hermes_sovereign_test_components::bootstrap::traits::rollup_store_dir::RollupStoreDirGetter; +use hermes_sovereign_test_components::bootstrap::traits::types::rollup_driver::ProvideRollupDriverType; +use hermes_test_components::chain_driver::traits::types::chain::ProvideChainType; +use hermes_test_components::driver::traits::types::chain_driver::ProvideChainDriverType; + +use crate::contexts::rollup_driver::SovereignRollupDriver; +use crate::impls::build_rollup_driver::BuildSovereignRollupDriver; + +pub struct SovereignBootstrap { + pub runtime: HermesRuntime, + pub rollup_store_dir: PathBuf, + pub rollup_command_path: PathBuf, + pub account_prefix: String, +} + +pub struct SovereignBootstrapComponents; + +delegate_all!( + IsSovereignBootstrapComponent, + BaseSovereignBootstrapComponents, + SovereignBootstrapComponents, +); + +delegate_components! { + SovereignBootstrapComponents { + ErrorTypeComponent: ProvideCosmosError, + ErrorRaiserComponent: DebugError, + RuntimeTypeComponent: ProvideHermesRuntime, + RollupDriverBuilderComponent: BuildSovereignRollupDriver, + } +} + +impl HasComponents for SovereignBootstrap { + type Components = SovereignBootstrapComponents; +} + +impl ProvideChainType for SovereignBootstrapComponents { + type Chain = CosmosChain; +} + +impl ProvideChainDriverType for SovereignBootstrapComponents { + type ChainDriver = CosmosChainDriver; +} + +impl ProvideBridgeDriverType for SovereignBootstrapComponents { + type BridgeDriver = CelestiaBridgeDriver; +} + +impl ProvideRollupType for SovereignBootstrapComponents { + type Rollup = SovereignRollup; +} + +impl ProvideRollupDriverType for SovereignBootstrapComponents { + type RollupDriver = SovereignRollupDriver; +} + +impl RuntimeGetter for SovereignBootstrapComponents { + fn runtime(bootstrap: &SovereignBootstrap) -> &HermesRuntime { + &bootstrap.runtime + } +} + +impl RollupStoreDirGetter for SovereignBootstrapComponents { + fn rollup_store_dir(bootstrap: &SovereignBootstrap) -> &PathBuf { + &bootstrap.rollup_store_dir + } +} + +impl AccountPrefixGetter for SovereignBootstrapComponents { + fn account_prefix(bootstrap: &SovereignBootstrap) -> &str { + &bootstrap.account_prefix + } +} + +impl RollupCommandPathGetter for SovereignBootstrapComponents { + fn rollup_command_path(bootstrap: &SovereignBootstrap) -> &PathBuf { + &bootstrap.rollup_command_path + } +} + +pub trait CheckCanBootstrapRollup: CanBootstrapRollup {} + +impl CheckCanBootstrapRollup for SovereignBootstrap {} diff --git a/crates/relayer/sovereign-integration-tests/src/impls/build_rollup_driver.rs b/crates/relayer/sovereign-integration-tests/src/impls/build_rollup_driver.rs new file mode 100644 index 00000000..9480e078 --- /dev/null +++ b/crates/relayer/sovereign-integration-tests/src/impls/build_rollup_driver.rs @@ -0,0 +1,96 @@ +use alloc::collections::BTreeMap; +use core::time::Duration; + +use cgp_core::CanRaiseError; +use hermes_runtime::types::runtime::HermesRuntime; +use hermes_runtime_components::traits::runtime::HasRuntime; +use hermes_sovereign_chain_components::sovereign::traits::chain::rollup::HasRollupType; +use hermes_sovereign_relayer::contexts::sovereign_rollup::SovereignRollup; +use hermes_sovereign_test_components::bootstrap::traits::build_rollup_driver::RollupDriverBuilder; +use hermes_sovereign_test_components::bootstrap::traits::types::rollup_driver::HasRollupDriverType; +use hermes_sovereign_test_components::bootstrap::traits::types::rollup_genesis_config::HasRollupGenesisConfigType; +use hermes_sovereign_test_components::bootstrap::traits::types::rollup_node_config::HasRollupNodeConfigType; +use hermes_sovereign_test_components::types::rollup_genesis_config::SovereignGenesisConfig; +use hermes_sovereign_test_components::types::rollup_node_config::SovereignRollupNodeConfig; +use hermes_sovereign_test_components::types::wallet::SovereignWallet; +use jsonrpsee::core::ClientError; +use jsonrpsee::http_client::HttpClientBuilder; +use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; +use tokio::process::Child; +use tokio::time::sleep; + +use crate::contexts::rollup_driver::SovereignRollupDriver; + +pub struct BuildSovereignRollupDriver; + +impl RollupDriverBuilder for BuildSovereignRollupDriver +where + Bootstrap: HasRuntime + + HasRollupType + + HasRollupDriverType + + HasRollupNodeConfigType + + HasRollupGenesisConfigType + + CanRaiseError + + CanRaiseError<&'static str>, +{ + async fn build_rollup_driver( + bootstrap: &Bootstrap, + node_config: SovereignRollupNodeConfig, + genesis_config: SovereignGenesisConfig, + wallets: BTreeMap, + rollup_process: Child, + ) -> Result { + let rpc_config = &node_config.runner.rpc_config; + let bind_host = &rpc_config.bind_host; + let bind_port = rpc_config.bind_port; + + let rpc_client = HttpClientBuilder::default() + .build(format!("http://{}:{}", bind_host, bind_port)) + .map_err(Bootstrap::raise_error)?; + + let subscription_client = build_subscription_client(bind_host, bind_port) + .await + .map_err(Bootstrap::raise_error)?; + + let relayer_wallet = wallets + .get("relayer") + .ok_or_else(|| Bootstrap::raise_error("expect relayer wallet"))?; + + let rollup = SovereignRollup::new( + bootstrap.runtime().clone(), + relayer_wallet.signing_key.clone(), + rpc_client, + subscription_client, + ); + + Ok(SovereignRollupDriver { + rollup, + node_config, + genesis_config, + wallets, + rollup_process, + }) + } +} + +async fn build_subscription_client( + bind_host: &String, + bind_port: u16, +) -> Result { + let build_client = + || WsClientBuilder::default().build(format!("ws://{}:{}", bind_host, bind_port)); + + // The WebSocket server may not start in time during test. + // In such case, we will wait for at most 10s for the server to start + for _ in 0..10 { + let result = build_client().await; + + if let Ok(client) = result { + return Ok(client); + } + + sleep(Duration::from_secs(1)).await; + } + + build_client().await +} diff --git a/crates/relayer/sovereign-integration-tests/src/impls/mod.rs b/crates/relayer/sovereign-integration-tests/src/impls/mod.rs new file mode 100644 index 00000000..cbdd0ca0 --- /dev/null +++ b/crates/relayer/sovereign-integration-tests/src/impls/mod.rs @@ -0,0 +1,2 @@ +pub mod build_rollup_driver; +pub mod rollup; diff --git a/crates/relayer/sovereign-integration-tests/src/impls/rollup.rs b/crates/relayer/sovereign-integration-tests/src/impls/rollup.rs new file mode 100644 index 00000000..85990431 --- /dev/null +++ b/crates/relayer/sovereign-integration-tests/src/impls/rollup.rs @@ -0,0 +1,12 @@ +use cgp_core::Async; +use hermes_sovereign_chain_components::sovereign::traits::chain::rollup::ProvideRollupType; +use hermes_sovereign_relayer::contexts::sovereign_rollup::SovereignRollup; + +pub struct ProvideSovereignRollupType; + +impl ProvideRollupType for ProvideSovereignRollupType +where + ChainDriver: Async, +{ + type Rollup = SovereignRollup; +} diff --git a/crates/relayer/sovereign-integration-tests/src/lib.rs b/crates/relayer/sovereign-integration-tests/src/lib.rs new file mode 100644 index 00000000..0eb8d6db --- /dev/null +++ b/crates/relayer/sovereign-integration-tests/src/lib.rs @@ -0,0 +1,4 @@ +extern crate alloc; + +pub mod contexts; +pub mod impls; diff --git a/crates/relayer/sovereign-integration-tests/tests/bootstrap.rs b/crates/relayer/sovereign-integration-tests/tests/bootstrap.rs new file mode 100644 index 00000000..08419f72 --- /dev/null +++ b/crates/relayer/sovereign-integration-tests/tests/bootstrap.rs @@ -0,0 +1,156 @@ +#![recursion_limit = "256"] + +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; + +use eyre::eyre; +use hermes_celestia_integration_tests::contexts::bootstrap::CelestiaBootstrap; +use hermes_celestia_test_components::bootstrap::traits::bootstrap_bridge::CanBootstrapBridge; +use hermes_cosmos_relayer::contexts::builder::CosmosBuilder; +use hermes_cosmos_relayer::types::error::Error; +use hermes_relayer_components::transaction::traits::send_messages_with_signer::CanSendMessagesWithSigner; +use hermes_runtime::types::runtime::HermesRuntime; +use hermes_sovereign_integration_tests::contexts::sovereign_bootstrap::SovereignBootstrap; +use hermes_sovereign_rollup_components::types::message::SovereignMessage; +use hermes_sovereign_rollup_components::types::messages::bank::{BankMessage, CoinFields}; +use hermes_sovereign_test_components::bootstrap::traits::bootstrap_rollup::CanBootstrapRollup; +use hermes_test_components::bootstrap::traits::chain::CanBootstrapChain; +use hermes_test_components::chain::traits::queries::balance::CanQueryBalance; +use tokio::runtime::Builder; + +#[test] +fn test_sovereign_bootstrap() -> Result<(), Error> { + let _ = stable_eyre::install(); + + let tokio_runtime = Arc::new(Builder::new_multi_thread().enable_all().build()?); + + let runtime = HermesRuntime::new(tokio_runtime.clone()); + + let builder = Arc::new(CosmosBuilder::new_with_default(runtime.clone())); + + let store_postfix = format!( + "{}-{}", + SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis(), + rand::random::() + ); + + let store_dir = std::env::current_dir()?.join(format!("test-data/{store_postfix}")); + + let celestia_bootstrap = CelestiaBootstrap { + runtime: runtime.clone(), + builder: builder.clone(), + chain_store_dir: store_dir.join("chains"), + bridge_store_dir: store_dir.join("bridges"), + }; + + let sovereign_bootstrap = SovereignBootstrap { + runtime: runtime.clone(), + rollup_store_dir: format!("./test-data/{store_postfix}/rollups").into(), + rollup_command_path: "rollup".into(), + account_prefix: "sov".into(), + }; + + tokio_runtime.block_on(async move { + let chain_driver = celestia_bootstrap.bootstrap_chain("private").await?; + + let bridge_driver = celestia_bootstrap.bootstrap_bridge(&chain_driver).await?; + + let rollup_driver = sovereign_bootstrap + .bootstrap_rollup(&chain_driver, &bridge_driver, "test-rollup") + .await?; + + { + // Temporary test to check that rollup driver is bootstrapped properly + + let rollup = &rollup_driver.rollup; + + let wallet_a = rollup_driver + .wallets + .get("user-a") + .ok_or_else(|| eyre!("expect user-a wallet"))?; + + let wallet_b = rollup_driver + .wallets + .get("user-b") + .ok_or_else(|| eyre!("expect user-a wallet"))?; + + let transfer_denom = &rollup_driver.genesis_config.transfer_token_address; + + let address_a = &wallet_a.address.address; + let address_b = &wallet_b.address.address; + let transfer_denom = &transfer_denom.address; + + assert_eq!( + rollup + .query_balance(address_a, transfer_denom) + .await? + .quantity, + 1_000_000_000_000 + ); + assert_eq!( + rollup + .query_balance(address_b, transfer_denom) + .await? + .quantity, + 1_000_000_000_000 + ); + + { + let message = SovereignMessage::Bank(BankMessage::Transfer { + to: wallet_b.address.address_bytes.clone(), + coins: CoinFields { + amount: 1000, + token_address: rollup_driver + .genesis_config + .transfer_token_address + .address_bytes + .clone(), + }, + }); + + let events = rollup + .send_messages_with_signer(&wallet_a.signing_key, &[message]) + .await?; + + println!("TokenTransfer events: {:?}", events); + + tokio::time::sleep(core::time::Duration::from_secs(1)).await; + + assert_eq!( + rollup + .query_balance(address_a, transfer_denom) + .await? + .quantity, + 999_999_999_000 + ); + + assert_eq!( + rollup + .query_balance(address_b, transfer_denom) + .await? + .quantity, + 1_000_000_001_000 + ); + } + + { + let message = SovereignMessage::Bank(BankMessage::CreateToken { + salt: 0, + token_name: "test".into(), + initial_balance: 1000, + minter_address: wallet_a.address.address_bytes.clone(), + authorized_minters: Vec::new(), + }); + + let events = rollup + .send_messages_with_signer(&wallet_a.signing_key, &[message]) + .await?; + + println!("CreateToken events: {:?}", events); + } + } + >::Ok(()) + })?; + + Ok(()) +} diff --git a/crates/relayer/sovereign-integration-tests/tests/cosmos_to_sovereign.rs b/crates/relayer/sovereign-integration-tests/tests/cosmos_to_sovereign.rs new file mode 100644 index 00000000..a2fb3659 --- /dev/null +++ b/crates/relayer/sovereign-integration-tests/tests/cosmos_to_sovereign.rs @@ -0,0 +1,245 @@ +#![recursion_limit = "256"] + +use core::time::Duration; +use std::collections::BTreeSet; +use std::env::var; +use std::path::PathBuf; +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; + +use futures::lock::Mutex; +use hermes_celestia_integration_tests::contexts::bootstrap::CelestiaBootstrap; +use hermes_celestia_test_components::bootstrap::traits::bootstrap_bridge::CanBootstrapBridge; +use hermes_cosmos_chain_components::types::channel::CosmosInitChannelOptions; +use hermes_cosmos_relayer::contexts::builder::CosmosBuilder; +use hermes_cosmos_relayer::types::error::Error; +use hermes_cosmos_wasm_relayer::context::cosmos_bootstrap::CosmosWithWasmClientBootstrap; +use hermes_relayer_components::chain::traits::types::chain_id::HasChainId; +use hermes_relayer_components::relay::impls::channel::bootstrap::CanBootstrapChannel; +use hermes_relayer_components::relay::impls::connection::bootstrap::CanBootstrapConnection; +use hermes_relayer_components::relay::traits::client_creator::CanCreateClient; +use hermes_relayer_components::relay::traits::target::{DestinationTarget, SourceTarget}; +use hermes_runtime::types::runtime::HermesRuntime; +use hermes_sovereign_chain_components::sovereign::traits::chain::rollup::HasRollup; +use hermes_sovereign_chain_components::sovereign::types::payloads::client::SovereignCreateClientOptions; +use hermes_sovereign_integration_tests::contexts::sovereign_bootstrap::SovereignBootstrap; +use hermes_sovereign_relayer::contexts::cosmos_to_sovereign_relay::CosmosToSovereignRelay; +use hermes_sovereign_relayer::contexts::sovereign_chain::SovereignChain; +use hermes_sovereign_test_components::bootstrap::traits::bootstrap_rollup::CanBootstrapRollup; +use hermes_test_components::bootstrap::traits::chain::CanBootstrapChain; +use hermes_test_components::chain::traits::queries::balance::CanQueryBalance; +use hermes_test_components::chain_driver::traits::types::chain::HasChain; +use ibc::core::client::types::Height; +use ibc_relayer::chain::client::ClientSettings; +use ibc_relayer::chain::cosmos::client::Settings; +use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; +use ibc_relayer_types::core::ics24_host::identifier::PortId; +use sha2::{Digest, Sha256}; +use sov_celestia_client::types::client_state::test_util::TendermintParamsConfig; +use sov_celestia_client::types::sovereign::SovereignParamsConfig; +use tokio::runtime::Builder; + +#[test] +fn test_cosmos_to_sovereign() -> Result<(), Error> { + tracing_subscriber::fmt() + .with_max_level(tracing::Level::INFO) + .init(); + + let _ = stable_eyre::install(); + + let tokio_runtime = Arc::new(Builder::new_multi_thread().enable_all().build()?); + + let runtime = HermesRuntime::new(tokio_runtime.clone()); + + let builder = Arc::new(CosmosBuilder::new_with_default(runtime.clone())); + + let store_postfix = format!( + "{}-{}", + SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis(), + rand::random::() + ); + + let store_dir = std::env::current_dir()?.join(format!("test-data/{store_postfix}")); + + let wasm_client_code_path = + PathBuf::from(var("WASM_FILE_PATH").expect("Wasm file is required")); + + let cosmos_bootstrap = Arc::new(CosmosWithWasmClientBootstrap { + runtime: runtime.clone(), + builder: builder.clone(), + should_randomize_identifiers: true, + chain_store_dir: format!("./test-data/{store_postfix}/chains").into(), + chain_command_path: "simd".into(), + account_prefix: "sov".into(), + staking_denom: "stake".into(), + transfer_denom: "coin".into(), + wasm_client_code_path: wasm_client_code_path.clone(), + }); + + let celestia_bootstrap = CelestiaBootstrap { + runtime: runtime.clone(), + builder: builder.clone(), + chain_store_dir: store_dir.join("chains"), + bridge_store_dir: store_dir.join("bridges"), + }; + + let node_binary = var("ROLLUP_PATH") + .unwrap_or_else(|_| "rollup".to_string()) + .into(); + + let sovereign_bootstrap = SovereignBootstrap { + runtime: runtime.clone(), + rollup_store_dir: store_dir.join("rollups"), + rollup_command_path: node_binary, + account_prefix: "sov".into(), + }; + + tokio_runtime.block_on(async move { + let cosmos_chain_driver = cosmos_bootstrap.bootstrap_chain("cosmos").await?; + + let celestia_chain_driver = celestia_bootstrap.bootstrap_chain("private").await?; + + let bridge_driver = celestia_bootstrap + .bootstrap_bridge(&celestia_chain_driver) + .await?; + + let rollup_driver = sovereign_bootstrap + .bootstrap_rollup(&celestia_chain_driver, &bridge_driver, "test-rollup") + .await?; + + let cosmos_chain = cosmos_chain_driver.chain(); + let rollup = rollup_driver.rollup(); + + let sovereign_chain = SovereignChain { + runtime: runtime.clone(), + data_chain: celestia_chain_driver.chain().clone(), + rollup: rollup.clone(), + }; + + let sovereign_client_id = { + let create_client_settings = ClientSettings::Tendermint(Settings { + max_clock_drift: Duration::from_secs(40), + trusting_period: None, + trust_threshold: TrustThreshold::ONE_THIRD, + }); + + CosmosToSovereignRelay::create_client( + DestinationTarget, + &sovereign_chain, + cosmos_chain, + &create_client_settings, + &(), + ) + .await? + }; + + println!( + "client ID of Cosmos on Sovereign: {:?}", + sovereign_client_id + ); + + let cosmos_client_id = { + let wasm_client_bytes = tokio::fs::read(&wasm_client_code_path).await?; + + let wasm_code_hash: [u8; 32] = { + let mut hasher = Sha256::new(); + hasher.update(wasm_client_bytes); + hasher.finalize().into() + }; + + let rollup_genesis_da_height = + Height::new(0, rollup_driver.node_config.runner.genesis_height)?; + + let sovereign_params = SovereignParamsConfig::builder() + .genesis_da_height(rollup_genesis_da_height) + .latest_height(Height::min(0)) // dummy value; overwritten by rollup latest height while creating client payload + .build(); + + let celestia_chain_id = celestia_chain_driver.chain().chain_id(); + + let tendermint_params = TendermintParamsConfig::builder() + .chain_id(celestia_chain_id.to_string().parse()?) + .build(); + + let create_client_settings = SovereignCreateClientOptions { + tendermint_params_config: tendermint_params, + sovereign_client_params: sovereign_params, + code_hash: wasm_code_hash.into(), + }; + + CosmosToSovereignRelay::create_client( + SourceTarget, + cosmos_chain, + &sovereign_chain, + &create_client_settings, + &(), + ) + .await? + }; + + println!("client ID of Sovereign on Cosmos: {:?}", cosmos_client_id); + + let cosmos_to_sovereign_relay = CosmosToSovereignRelay { + runtime: runtime.clone(), + src_chain: cosmos_chain.clone(), + dst_chain: sovereign_chain.clone(), + src_client_id: cosmos_client_id.clone(), + dst_client_id: sovereign_client_id.clone(), + packet_lock_mutex: Arc::new(Mutex::new(BTreeSet::new())), + }; + + let (connection_id_a, connection_id_b) = cosmos_to_sovereign_relay + .bootstrap_connection(&Default::default()) + .await?; + + println!( + "connection id on Cosmos: {}, connection id on Sovereign: {}", + connection_id_a, connection_id_b + ); + + let (channel_id_a, channel_b) = cosmos_to_sovereign_relay + .bootstrap_channel( + &PortId::transfer(), + &PortId::transfer(), + &CosmosInitChannelOptions::new(connection_id_a), + ) + .await?; + + println!( + "channel id on Cosmos: {}, channel id on Sovereign: {}", + channel_id_a, channel_b + ); + + let wallet_a = &cosmos_chain_driver.user_wallet_a; + + let address_a = &wallet_a.address; + + let wallet_b = rollup_driver.wallets.get("user-a").unwrap(); + + let _address_b = &wallet_b.address.address; + + let denom_a = &cosmos_chain_driver.genesis_config.transfer_denom; + + let _balance_a1 = cosmos_chain.query_balance(address_a, denom_a).await?; + + // FIXME: Submitting IBC transfer message to the Wasm contract on Cosmos is broken + + // let packet = >::ibc_transfer_token( + // &cosmos_chain, + // &channel_id_a, + // &PortId::transfer(), + // wallet_a, + // address_b, + // &Amount::new(1000, denom_a.clone()), + // ) + // .await?; + + // println!("packet for IBC transfer from Cosmos: {}", packet); + + // cosmos_to_sovereign_relay.relay_packet(&packet).await?; + + >::Ok(()) + })?; + + Ok(()) +} diff --git a/crates/relayer/sovereign-integration-tests/tests/sovereign_to_cosmos.rs b/crates/relayer/sovereign-integration-tests/tests/sovereign_to_cosmos.rs new file mode 100644 index 00000000..ac0bc863 --- /dev/null +++ b/crates/relayer/sovereign-integration-tests/tests/sovereign_to_cosmos.rs @@ -0,0 +1,244 @@ +#![recursion_limit = "256"] + +use core::time::Duration; +use std::collections::BTreeSet; +use std::env::var; +use std::path::PathBuf; +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; + +use futures::lock::Mutex; +use hermes_celestia_integration_tests::contexts::bootstrap::CelestiaBootstrap; +use hermes_celestia_test_components::bootstrap::traits::bootstrap_bridge::CanBootstrapBridge; +use hermes_cosmos_chain_components::types::channel::CosmosInitChannelOptions; +use hermes_cosmos_relayer::contexts::builder::CosmosBuilder; +use hermes_cosmos_relayer::types::error::Error; +use hermes_cosmos_wasm_relayer::context::cosmos_bootstrap::CosmosWithWasmClientBootstrap; +use hermes_relayer_components::chain::traits::types::chain_id::HasChainId; +use hermes_relayer_components::relay::impls::channel::bootstrap::CanBootstrapChannel; +use hermes_relayer_components::relay::impls::connection::bootstrap::CanBootstrapConnection; +use hermes_relayer_components::relay::traits::client_creator::CanCreateClient; +use hermes_relayer_components::relay::traits::target::{DestinationTarget, SourceTarget}; +use hermes_runtime::types::runtime::HermesRuntime; +use hermes_sovereign_chain_components::sovereign::traits::chain::rollup::HasRollup; +use hermes_sovereign_chain_components::sovereign::types::payloads::client::SovereignCreateClientOptions; +use hermes_sovereign_integration_tests::contexts::sovereign_bootstrap::SovereignBootstrap; +use hermes_sovereign_relayer::contexts::sovereign_chain::SovereignChain; +use hermes_sovereign_relayer::contexts::sovereign_to_cosmos_relay::SovereignToCosmosRelay; +use hermes_sovereign_test_components::bootstrap::traits::bootstrap_rollup::CanBootstrapRollup; +use hermes_test_components::bootstrap::traits::chain::CanBootstrapChain; +use hermes_test_components::chain::traits::queries::balance::CanQueryBalance; +use hermes_test_components::chain_driver::traits::types::chain::HasChain; +use ibc::core::client::types::Height; +use ibc_relayer::chain::client::ClientSettings; +use ibc_relayer::chain::cosmos::client::Settings; +use ibc_relayer_types::core::ics02_client::trust_threshold::TrustThreshold; +use ibc_relayer_types::core::ics24_host::identifier::PortId; +use sha2::{Digest, Sha256}; +use sov_celestia_client::types::client_state::test_util::TendermintParamsConfig; +use sov_celestia_client::types::sovereign::SovereignParamsConfig; +use tokio::runtime::Builder; + +#[test] +fn test_sovereign_to_cosmos() -> Result<(), Error> { + tracing_subscriber::fmt() + .with_max_level(tracing::Level::INFO) + .init(); + + let _ = stable_eyre::install(); + + let tokio_runtime = Arc::new(Builder::new_multi_thread().enable_all().build()?); + + let runtime = HermesRuntime::new(tokio_runtime.clone()); + + let builder = Arc::new(CosmosBuilder::new_with_default(runtime.clone())); + + let store_postfix = format!( + "{}-{}", + SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis(), + rand::random::() + ); + + let store_dir = std::env::current_dir()?.join(format!("test-data/{store_postfix}")); + + let wasm_client_code_path = + PathBuf::from(var("WASM_FILE_PATH").expect("Wasm file is required")); + + let cosmos_bootstrap = Arc::new(CosmosWithWasmClientBootstrap { + runtime: runtime.clone(), + builder: builder.clone(), + should_randomize_identifiers: true, + chain_store_dir: format!("./test-data/{store_postfix}/chains").into(), + chain_command_path: "simd".into(), + account_prefix: "sov".into(), + staking_denom: "stake".into(), + transfer_denom: "coin".into(), + wasm_client_code_path: wasm_client_code_path.clone(), + }); + + let celestia_bootstrap = CelestiaBootstrap { + runtime: runtime.clone(), + builder: builder.clone(), + chain_store_dir: store_dir.join("chains"), + bridge_store_dir: store_dir.join("bridges"), + }; + + let node_binary = var("ROLLUP_PATH") + .unwrap_or_else(|_| "rollup".to_string()) + .into(); + + let sovereign_bootstrap = SovereignBootstrap { + runtime: runtime.clone(), + rollup_store_dir: store_dir.join("rollups"), + rollup_command_path: node_binary, + account_prefix: "sov".into(), + }; + + tokio_runtime.block_on(async move { + let cosmos_chain_driver = cosmos_bootstrap.bootstrap_chain("cosmos").await?; + + let celestia_chain_driver = celestia_bootstrap.bootstrap_chain("private").await?; + + let bridge_driver = celestia_bootstrap + .bootstrap_bridge(&celestia_chain_driver) + .await?; + + let rollup_driver = sovereign_bootstrap + .bootstrap_rollup(&celestia_chain_driver, &bridge_driver, "test-rollup") + .await?; + + let cosmos_chain = cosmos_chain_driver.chain(); + let rollup = rollup_driver.rollup(); + + let sovereign_chain = SovereignChain { + runtime: runtime.clone(), + data_chain: celestia_chain_driver.chain().clone(), + rollup: rollup.clone(), + }; + + let sovereign_client_id = { + let create_client_settings = ClientSettings::Tendermint(Settings { + max_clock_drift: Duration::from_secs(40), + trusting_period: None, + trust_threshold: TrustThreshold::ONE_THIRD, + }); + + SovereignToCosmosRelay::create_client( + SourceTarget, + &sovereign_chain, + cosmos_chain, + &create_client_settings, + &(), + ) + .await? + }; + + println!( + "client ID of Cosmos on Sovereign: {:?}", + sovereign_client_id + ); + + let cosmos_client_id = { + let wasm_client_bytes = tokio::fs::read(&wasm_client_code_path).await?; + + let wasm_code_hash: [u8; 32] = { + let mut hasher = Sha256::new(); + hasher.update(wasm_client_bytes); + hasher.finalize().into() + }; + + let rollup_genesis_da_height = + Height::new(0, rollup_driver.node_config.runner.genesis_height)?; + + let sovereign_params = SovereignParamsConfig::builder() + .genesis_da_height(rollup_genesis_da_height) + .latest_height(Height::min(0)) // dummy value; overwritten by rollup latest height while creating client payload + .build(); + + let celestia_chain_id = celestia_chain_driver.chain().chain_id(); + + let tendermint_params = TendermintParamsConfig::builder() + .chain_id(celestia_chain_id.to_string().parse()?) + .build(); + + let create_client_settings = SovereignCreateClientOptions { + tendermint_params_config: tendermint_params, + sovereign_client_params: sovereign_params, + code_hash: wasm_code_hash.into(), + }; + + SovereignToCosmosRelay::create_client( + DestinationTarget, + cosmos_chain, + &sovereign_chain, + &create_client_settings, + &(), + ) + .await? + }; + + println!("client ID of Sovereign on Cosmos: {:?}", cosmos_client_id); + + let sovereign_to_cosmos_relay = SovereignToCosmosRelay { + runtime: runtime.clone(), + src_chain: sovereign_chain.clone(), + dst_chain: cosmos_chain.clone(), + src_client_id: sovereign_client_id.clone(), + dst_client_id: cosmos_client_id.clone(), + packet_lock_mutex: Arc::new(Mutex::new(BTreeSet::new())), + }; + + let (connection_id_a, connection_id_b) = sovereign_to_cosmos_relay + .bootstrap_connection(&Default::default()) + .await?; + + println!( + "connection id on Sovereign: {}, connection id on Cosmos: {}", + connection_id_a, connection_id_b + ); + + // FIXME: run bootstrap channel test + let (channel_id_a, channel_b) = sovereign_to_cosmos_relay + .bootstrap_channel( + &PortId::transfer(), + &PortId::transfer(), + &CosmosInitChannelOptions::new(connection_id_a), + ) + .await?; + + println!( + "channel id on Sovereign: {}, channel id on Cosmos: {}", + channel_id_a, channel_b + ); + + let wallet_b = &cosmos_chain_driver.user_wallet_a; + + let _address_b = &wallet_b.address; + + let wallet_a = rollup_driver.wallets.get("user-a").unwrap(); + + let address_a = &wallet_a.address.address; + + let denom_a = &rollup_driver.genesis_config.transfer_token_address.address; + + let _balance_a1 = rollup.query_balance(address_a, denom_a).await?; + + // let packet = >::ibc_transfer_token( + // &cosmos_chain, + // &channel_id_a, + // &PortId::transfer(), + // wallet_a, + // address_b, + // &Amount::new(1000, denom_a.clone()), + // ) + // .await?; + + // println!("packet for IBC transfer from Cosmos: {}", packet); + + // sovereign_to_cosmos_relay.relay_packet(&packet).await?; + + >::Ok(()) + })?; + + Ok(()) +} diff --git a/crates/relayer/sovereign-relayer/Cargo.toml b/crates/relayer/sovereign-relayer/Cargo.toml new file mode 100644 index 00000000..0647f92d --- /dev/null +++ b/crates/relayer/sovereign-relayer/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "hermes-sovereign-relayer" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } +readme = "README.md" +description = """ + Concrete context implementation for building a Sovereign to Cosmos relayer +""" + +[dependencies] +cgp-core = { workspace = true } +cgp-error-eyre = { workspace = true } +hermes-runtime-components = { workspace = true } +hermes-runtime = { workspace = true } +hermes-relayer-components = { workspace = true } +hermes-test-components = { workspace = true } +hermes-cosmos-relayer = { workspace = true } +hermes-celestia-chain = { workspace = true } +hermes-sovereign-chain-components = { workspace = true } +hermes-sovereign-rollup-components = { workspace = true } +hermes-sovereign-test-components = { workspace = true } +hermes-wasm-client-components = { workspace = true } +hermes-cosmos-chain-components = { workspace = true } +hermes-encoding-components = { workspace = true } +hermes-protobuf-encoding-components = { workspace = true } +hermes-logging-components = { workspace = true } + +ibc = { workspace = true } +ibc-relayer = { workspace = true } +ibc-relayer-types = { workspace = true } +ibc-proto = { workspace = true } +sov-celestia-client = { workspace = true } + +eyre = { workspace = true } +futures = { workspace = true } +ed25519-dalek = { workspace = true } +jsonrpsee = { workspace = true, features = [ "http-client", "ws-client" ] } diff --git a/crates/relayer/sovereign-relayer/src/contexts/cosmos_to_sovereign_relay.rs b/crates/relayer/sovereign-relayer/src/contexts/cosmos_to_sovereign_relay.rs new file mode 100644 index 00000000..fc58a80f --- /dev/null +++ b/crates/relayer/sovereign-relayer/src/contexts/cosmos_to_sovereign_relay.rs @@ -0,0 +1,151 @@ +use std::collections::BTreeSet; +use std::sync::Arc; + +use cgp_core::prelude::*; +use cgp_core::{delegate_all, ErrorRaiserComponent, ErrorTypeComponent}; +use cgp_error_eyre::{ProvideEyreError, RaiseDebugError}; +use futures::lock::Mutex; +use hermes_cosmos_relayer::contexts::chain::CosmosChain; +use hermes_cosmos_relayer::contexts::logger::ProvideCosmosLogger; +use hermes_logging_components::traits::has_logger::{ + GlobalLoggerGetterComponent, LoggerGetterComponent, LoggerTypeComponent, +}; +use hermes_relayer_components::components::default::closures::relay::packet_relayer::CanUseDefaultPacketRelayer; +use hermes_relayer_components::components::default::relay::{ + DefaultRelayComponents, IsDefaultRelayComponent, +}; +use hermes_relayer_components::relay::impls::packet_filters::allow_all::AllowAll; +use hermes_relayer_components::relay::impls::packet_lock::{ + PacketMutex, PacketMutexGetter, ProvidePacketLockWithMutex, +}; +use hermes_relayer_components::relay::impls::packet_relayers::general::full_relay::FullCycleRelayer; +use hermes_relayer_components::relay::traits::chains::{ + CanRaiseRelayChainErrors, HasRelayChains, ProvideRelayChains, +}; +use hermes_relayer_components::relay::traits::channel::open_handshake::CanRelayChannelOpenHandshake; +use hermes_relayer_components::relay::traits::channel::open_init::CanInitChannel; +use hermes_relayer_components::relay::traits::client_creator::CanCreateClient; +use hermes_relayer_components::relay::traits::connection::open_handshake::CanRelayConnectionOpenHandshake; +use hermes_relayer_components::relay::traits::connection::open_init::CanInitConnection; +use hermes_relayer_components::relay::traits::ibc_message_sender::{CanSendIbcMessages, MainSink}; +use hermes_relayer_components::relay::traits::packet::HasRelayPacketFields; +use hermes_relayer_components::relay::traits::packet_filter::PacketFilterComponent; +use hermes_relayer_components::relay::traits::packet_lock::{HasPacketLock, PacketLockComponent}; +use hermes_relayer_components::relay::traits::packet_relayer::{CanRelayPacket, PacketRelayer}; +use hermes_relayer_components::relay::traits::packet_relayers::ack_packet::CanRelayAckPacket; +use hermes_relayer_components::relay::traits::packet_relayers::receive_packet::CanRelayReceivePacket; +use hermes_relayer_components::relay::traits::packet_relayers::timeout_unordered_packet::CanRelayTimeoutUnorderedPacket; +use hermes_relayer_components::relay::traits::target::{DestinationTarget, SourceTarget}; +use hermes_relayer_components::relay::traits::update_client_message_builder::CanBuildTargetUpdateClientMessage; +use hermes_runtime::impls::types::runtime::ProvideHermesRuntime; +use hermes_runtime::types::runtime::HermesRuntime; +use hermes_runtime_components::traits::runtime::{RuntimeGetter, RuntimeTypeComponent}; +use ibc_relayer_types::core::ics04_channel::packet::{Packet, Sequence}; +use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, ClientId, PortId}; + +use crate::contexts::sovereign_chain::SovereignChain; + +pub struct CosmosToSovereignRelay { + pub runtime: HermesRuntime, + pub src_chain: CosmosChain, + pub dst_chain: SovereignChain, + pub src_client_id: ClientId, + pub dst_client_id: ClientId, + pub packet_lock_mutex: Arc>>, +} + +pub trait CanUseCosmosToSovereignRelay: + HasRelayChains + + HasRelayPacketFields + + CanRaiseRelayChainErrors + + CanCreateClient + + CanCreateClient + + CanBuildTargetUpdateClientMessage + + CanBuildTargetUpdateClientMessage + + CanInitConnection + + CanInitChannel + + CanSendIbcMessages + + CanSendIbcMessages + + CanRelayConnectionOpenHandshake + + CanRelayChannelOpenHandshake + + CanRelayReceivePacket + + CanRelayAckPacket + + CanRelayTimeoutUnorderedPacket + + HasPacketLock + + CanRelayPacket +{ +} + +impl CanUseDefaultPacketRelayer for CosmosToSovereignRelay {} + +impl CanUseCosmosToSovereignRelay for CosmosToSovereignRelay {} + +pub trait CanUsePacketRelayer: PacketRelayer {} + +impl CanUsePacketRelayer for FullCycleRelayer {} + +pub struct CosmosToSovereignRelayComponents; + +impl HasComponents for CosmosToSovereignRelay { + type Components = CosmosToSovereignRelayComponents; +} + +delegate_all!( + IsDefaultRelayComponent, + DefaultRelayComponents, + CosmosToSovereignRelayComponents, +); + +delegate_components! { + CosmosToSovereignRelayComponents { + ErrorTypeComponent: ProvideEyreError, + ErrorRaiserComponent: RaiseDebugError, + RuntimeTypeComponent: ProvideHermesRuntime, + [ + LoggerTypeComponent, + LoggerGetterComponent, + GlobalLoggerGetterComponent, + ]: + ProvideCosmosLogger, + PacketLockComponent: + ProvidePacketLockWithMutex, + PacketFilterComponent: + AllowAll, + } +} + +impl RuntimeGetter for CosmosToSovereignRelayComponents { + fn runtime(relay: &CosmosToSovereignRelay) -> &HermesRuntime { + &relay.runtime + } +} + +impl ProvideRelayChains for CosmosToSovereignRelayComponents { + type SrcChain = CosmosChain; + + type DstChain = SovereignChain; + + type Packet = Packet; + + fn src_chain(relay: &CosmosToSovereignRelay) -> &CosmosChain { + &relay.src_chain + } + + fn dst_chain(relay: &CosmosToSovereignRelay) -> &SovereignChain { + &relay.dst_chain + } + + fn src_client_id(relay: &CosmosToSovereignRelay) -> &ClientId { + &relay.src_client_id + } + + fn dst_client_id(relay: &CosmosToSovereignRelay) -> &ClientId { + &relay.dst_client_id + } +} + +impl PacketMutexGetter for CosmosToSovereignRelayComponents { + fn packet_mutex(relay: &CosmosToSovereignRelay) -> &PacketMutex { + &relay.packet_lock_mutex + } +} diff --git a/crates/relayer/sovereign-relayer/src/contexts/encoding.rs b/crates/relayer/sovereign-relayer/src/contexts/encoding.rs new file mode 100644 index 00000000..16594aaf --- /dev/null +++ b/crates/relayer/sovereign-relayer/src/contexts/encoding.rs @@ -0,0 +1,94 @@ +use cgp_core::prelude::*; +use cgp_core::{delegate_all, ErrorRaiserComponent, ErrorTypeComponent}; +use cgp_error_eyre::{ProvideEyreError, RaiseDebugError}; +use hermes_cosmos_chain_components::types::tendermint::{ + TendermintClientState, TendermintConsensusState, +}; +use hermes_encoding_components::impls::default_encoding::GetDefaultEncoding; +use hermes_encoding_components::traits::convert::CanConvertBothWays; +use hermes_encoding_components::traits::decoder::CanDecode; +use hermes_encoding_components::traits::encode_and_decode::CanEncodeAndDecode; +use hermes_encoding_components::traits::has_encoding::{ + DefaultEncodingGetter, EncodingGetterComponent, HasEncodingType, ProvideEncodingType, +}; +use hermes_protobuf_encoding_components::types::{Any, Protobuf}; +use hermes_sovereign_chain_components::encoding::components::{ + IsSovereignEncodingComponent, SovereignEncodingComponents as BaseSovereignEncodingComponents, +}; +use hermes_sovereign_rollup_components::types::client_state::{ + SovereignClientState, WrappedSovereignClientState, +}; +use hermes_sovereign_rollup_components::types::consensus_state::SovereignConsensusState; +use hermes_wasm_client_components::types::client_state::{ProtoWasmClientState, WasmClientState}; +use hermes_wasm_client_components::types::consensus_state::WasmConsensusState; + +pub struct SovereignEncoding; + +pub struct SovereignEncodingComponents; + +impl HasComponents for SovereignEncoding { + type Components = SovereignEncodingComponents; +} + +delegate_all!( + IsSovereignEncodingComponent, + BaseSovereignEncodingComponents, + SovereignEncodingComponents +); + +delegate_components! { + SovereignEncodingComponents { + ErrorTypeComponent: ProvideEyreError, + ErrorRaiserComponent: RaiseDebugError, + } +} + +pub struct ProvideSovereignEncoding; + +impl ProvideEncodingType for ProvideSovereignEncoding +where + Context: Async, +{ + type Encoding = SovereignEncoding; +} + +impl DefaultEncodingGetter for ProvideSovereignEncoding +where + Context: HasEncodingType, +{ + fn default_encoding() -> &'static SovereignEncoding { + &SovereignEncoding + } +} + +delegate_components! { + ProvideSovereignEncoding { + EncodingGetterComponent: GetDefaultEncoding, + } +} + +pub trait CanUseSovereignEncoding: + CanEncodeAndDecode + + CanEncodeAndDecode + + CanEncodeAndDecode + + CanEncodeAndDecode + + CanEncodeAndDecode + + CanEncodeAndDecode + + CanEncodeAndDecode + + CanEncodeAndDecode + + CanDecode + + CanEncodeAndDecode + + CanConvertBothWays + + CanConvertBothWays + + CanEncodeAndDecode + + CanEncodeAndDecode + + CanEncodeAndDecode + + CanEncodeAndDecode + + CanConvertBothWays + + CanConvertBothWays + + CanConvertBothWays + + CanConvertBothWays +{ +} + +impl CanUseSovereignEncoding for SovereignEncoding {} diff --git a/crates/relayer/sovereign-relayer/src/contexts/mod.rs b/crates/relayer/sovereign-relayer/src/contexts/mod.rs new file mode 100644 index 00000000..045cafa8 --- /dev/null +++ b/crates/relayer/sovereign-relayer/src/contexts/mod.rs @@ -0,0 +1,6 @@ +pub mod cosmos_to_sovereign_relay; +pub mod encoding; +pub mod sovereign_chain; +pub mod sovereign_cosmos_birelay; +pub mod sovereign_rollup; +pub mod sovereign_to_cosmos_relay; diff --git a/crates/relayer/sovereign-relayer/src/contexts/sovereign_chain.rs b/crates/relayer/sovereign-relayer/src/contexts/sovereign_chain.rs new file mode 100644 index 00000000..82278c34 --- /dev/null +++ b/crates/relayer/sovereign-relayer/src/contexts/sovereign_chain.rs @@ -0,0 +1,274 @@ +use cgp_core::prelude::*; +use cgp_core::{delegate_all, ErrorRaiserComponent, ErrorTypeComponent, ProvideInner}; +use cgp_error_eyre::{ProvideEyreError, RaiseDebugError}; +use eyre::Error; +use hermes_cosmos_chain_components::types::channel::CosmosInitChannelOptions; +use hermes_cosmos_relayer::contexts::chain::CosmosChain; +use hermes_cosmos_relayer::contexts::logger::ProvideCosmosLogger; +use hermes_encoding_components::traits::has_encoding::{ + DefaultEncodingGetterComponent, EncodingGetterComponent, EncodingTypeComponent, HasEncoding, +}; +use hermes_logging_components::traits::has_logger::{ + GlobalLoggerGetterComponent, LoggerGetterComponent, LoggerTypeComponent, +}; +use hermes_relayer_components::chain::impls::wait_chain_reach_height::CanWaitChainReachHeight; +use hermes_relayer_components::chain::traits::message_builders::ack_packet::CanBuildAckPacketMessage; +use hermes_relayer_components::chain::traits::message_builders::channel_handshake::{ + CanBuildChannelOpenAckMessage, CanBuildChannelOpenConfirmMessage, + CanBuildChannelOpenInitMessage, CanBuildChannelOpenTryMessage, +}; +use hermes_relayer_components::chain::traits::message_builders::connection_handshake::{ + CanBuildConnectionOpenAckMessage, CanBuildConnectionOpenConfirmMessage, + CanBuildConnectionOpenInitMessage, CanBuildConnectionOpenTryMessage, +}; +use hermes_relayer_components::chain::traits::message_builders::create_client::CanBuildCreateClientMessage; +use hermes_relayer_components::chain::traits::message_builders::receive_packet::CanBuildReceivePacketMessage; +use hermes_relayer_components::chain::traits::message_builders::timeout_unordered_packet::CanBuildTimeoutUnorderedPacketMessage; +use hermes_relayer_components::chain::traits::packet::fields::CanReadPacketFields; +use hermes_relayer_components::chain::traits::payload_builders::ack_packet::CanBuildAckPacketPayload; +use hermes_relayer_components::chain::traits::payload_builders::channel_handshake::{ + CanBuildChannelOpenAckPayload, CanBuildChannelOpenConfirmPayload, CanBuildChannelOpenTryPayload, +}; +use hermes_relayer_components::chain::traits::payload_builders::connection_handshake::{ + CanBuildConnectionOpenAckPayload, CanBuildConnectionOpenConfirmPayload, + CanBuildConnectionOpenInitPayload, CanBuildConnectionOpenTryPayload, +}; +use hermes_relayer_components::chain::traits::payload_builders::receive_packet::CanBuildReceivePacketPayload; +use hermes_relayer_components::chain::traits::payload_builders::timeout_unordered_packet::CanBuildTimeoutUnorderedPacketPayload; +use hermes_relayer_components::chain::traits::payload_builders::update_client::CanBuildUpdateClientPayload; +use hermes_relayer_components::chain::traits::queries::chain_status::CanQueryChainStatus; +use hermes_relayer_components::chain::traits::queries::channel_end::{ + CanQueryChannelEnd, CanQueryChannelEndWithProofs, +}; +use hermes_relayer_components::chain::traits::queries::client_state::{ + CanQueryClientState, CanQueryClientStateWithProofs, +}; +use hermes_relayer_components::chain::traits::queries::connection_end::{ + CanQueryConnectionEnd, CanQueryConnectionEndWithProofs, +}; +use hermes_relayer_components::chain::traits::queries::consensus_state::{ + CanQueryConsensusState, CanQueryConsensusStateWithProofs, +}; +use hermes_relayer_components::chain::traits::queries::consensus_state_height::CanQueryConsensusStateHeight; +use hermes_relayer_components::chain::traits::queries::packet_acknowledgement::CanQueryPacketAcknowledgement; +use hermes_relayer_components::chain::traits::queries::packet_commitment::CanQueryPacketCommitment; +use hermes_relayer_components::chain::traits::queries::packet_is_received::ReceivedPacketQuerier; +use hermes_relayer_components::chain::traits::queries::packet_receipt::CanQueryPacketReceipt; +use hermes_relayer_components::chain::traits::send_message::CanSendMessages; +use hermes_relayer_components::chain::traits::types::chain_id::{ + ChainIdGetter, HasChainId, HasChainIdType, +}; +use hermes_relayer_components::chain::traits::types::channel::{ + HasChannelEndType, HasChannelOpenTryPayloadType, HasInitChannelOptionsType, +}; +use hermes_relayer_components::chain::traits::types::client_state::{ + HasClientStateFields, HasClientStateType, +}; +use hermes_relayer_components::chain::traits::types::connection::{ + HasConnectionEndType, HasInitConnectionOptionsType, +}; +use hermes_relayer_components::chain::traits::types::consensus_state::HasConsensusStateType; +use hermes_relayer_components::chain::traits::types::create_client::{ + HasCreateClientEvent, HasCreateClientPayloadOptionsType, +}; +use hermes_relayer_components::chain::traits::types::height::{ + CanIncrementHeight, HasHeightFields, +}; +use hermes_relayer_components::chain::traits::types::ibc::HasCounterpartyMessageHeight; +use hermes_relayer_components::chain::traits::types::ibc_events::channel::HasChannelOpenInitEvent; +use hermes_relayer_components::chain::traits::types::ibc_events::connection::{ + HasConnectionOpenInitEvent, HasConnectionOpenTryEvent, +}; +use hermes_relayer_components::chain::traits::types::ibc_events::send_packet::HasSendPacketEvent; +use hermes_relayer_components::chain::traits::types::ibc_events::write_ack::HasWriteAckEvent; +use hermes_relayer_components::chain::traits::types::message::HasMessageType; +use hermes_relayer_components::chain::traits::types::proof::HasCommitmentProofType; +use hermes_relayer_components::chain::traits::types::update_client::HasUpdateClientPayloadType; +use hermes_relayer_components::chain::types::payloads::channel::ChannelOpenTryPayload; +use hermes_runtime::impls::types::runtime::ProvideHermesRuntime; +use hermes_runtime::types::runtime::HermesRuntime; +use hermes_runtime_components::traits::runtime::{RuntimeGetter, RuntimeTypeComponent}; +use hermes_sovereign_chain_components::sovereign::components::{ + IsSovereignChainClientComponent, SovereignChainClientComponents, +}; +use hermes_sovereign_chain_components::sovereign::traits::chain::data_chain::{ + DataChainGetter, HasDataChain, ProvideDataChainType, +}; +use hermes_sovereign_chain_components::sovereign::traits::chain::rollup::{ + ProvideRollupType, RollupGetter, +}; +use hermes_sovereign_rollup_components::types::client_state::WrappedSovereignClientState; +use hermes_sovereign_rollup_components::types::commitment_proof::SovereignCommitmentProof; +use hermes_sovereign_rollup_components::types::consensus_state::SovereignConsensusState; +use hermes_sovereign_rollup_components::types::height::RollupHeight; +use hermes_sovereign_rollup_components::types::message::SovereignMessage; +use ibc::core::channel::types::channel::ChannelEnd; +use ibc::core::connection::types::ConnectionEnd; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use ibc_relayer_types::core::ics24_host::identifier::{ChainId, ChannelId, PortId}; + +use crate::contexts::encoding::{ProvideSovereignEncoding, SovereignEncoding}; +use crate::contexts::sovereign_rollup::SovereignRollup; + +#[derive(Clone)] +pub struct SovereignChain { + pub runtime: HermesRuntime, + pub data_chain: CosmosChain, + pub rollup: SovereignRollup, +} + +pub struct SovereignChainComponents; + +impl HasComponents for SovereignChain { + type Components = SovereignChainComponents; +} + +delegate_all!( + IsSovereignChainClientComponent, + SovereignChainClientComponents, + SovereignChainComponents, +); + +delegate_components! { + SovereignChainComponents { + ErrorTypeComponent: ProvideEyreError, + ErrorRaiserComponent: RaiseDebugError, + RuntimeTypeComponent: ProvideHermesRuntime, + [ + EncodingTypeComponent, + EncodingGetterComponent, + DefaultEncodingGetterComponent, + ]: + ProvideSovereignEncoding, + [ + LoggerTypeComponent, + LoggerGetterComponent, + GlobalLoggerGetterComponent, + ]: + ProvideCosmosLogger, + } +} + +impl ProvideDataChainType for SovereignChainComponents { + type DataChain = CosmosChain; +} + +impl DataChainGetter for SovereignChainComponents { + fn data_chain(chain: &SovereignChain) -> &CosmosChain { + &chain.data_chain + } +} + +impl ProvideRollupType for SovereignChainComponents { + type Rollup = SovereignRollup; +} + +impl RollupGetter for SovereignChainComponents { + fn rollup(chain: &SovereignChain) -> &SovereignRollup { + &chain.rollup + } +} + +impl ProvideInner for SovereignChainComponents { + type Inner = SovereignRollup; + + fn inner(chain: &SovereignChain) -> &SovereignRollup { + &chain.rollup + } +} + +impl RuntimeGetter for SovereignChainComponents { + fn runtime(chain: &SovereignChain) -> &HermesRuntime { + &chain.runtime + } +} + +impl ChainIdGetter for SovereignChainComponents { + fn chain_id(chain: &SovereignChain) -> &ChainId { + chain.data_chain.chain_id() + } +} + +impl ReceivedPacketQuerier for SovereignChainComponents { + async fn query_packet_is_received( + _chain: &SovereignChain, + _port_id: &PortId, + _channel_id: &ChannelId, + _sequence: &Sequence, + ) -> Result { + // TODO: stub + Ok(false) + } +} + +pub trait CanUseSovereignChain: + HasDataChain + + HasChainIdType + + HasUpdateClientPayloadType + + HasHeightFields + + HasMessageType + + HasCommitmentProofType + + CanIncrementHeight + + CanSendMessages + + CanQueryChainStatus + + CanWaitChainReachHeight + + HasCounterpartyMessageHeight + + HasClientStateType + + HasConsensusStateType + + HasConnectionEndType + + HasChannelEndType + + HasInitChannelOptionsType + + HasChannelOpenTryPayloadType< + CosmosChain, + ChannelOpenTryPayload = ChannelOpenTryPayload, + > + CanBuildUpdateClientPayload + + HasEncoding + + CanBuildCreateClientMessage + + HasCreateClientPayloadOptionsType + + HasCreateClientEvent + + HasConnectionOpenInitEvent + + HasChannelOpenInitEvent + + CanReadPacketFields + + CanQueryClientState + + CanQueryClientStateWithProofs + + CanQueryConsensusState + + CanQueryConsensusStateWithProofs + + CanQueryConsensusStateHeight + + CanQueryConnectionEnd + + CanQueryConnectionEndWithProofs + + CanQueryChannelEnd + + CanQueryChannelEndWithProofs + + CanQueryPacketCommitment + + CanQueryPacketAcknowledgement + + CanQueryPacketReceipt + + HasClientStateFields + + HasInitConnectionOptionsType + + CanBuildConnectionOpenInitPayload + + CanBuildConnectionOpenTryPayload + + CanBuildConnectionOpenAckPayload + + CanBuildConnectionOpenConfirmPayload + + CanBuildConnectionOpenInitMessage + + CanBuildConnectionOpenTryMessage + + CanBuildConnectionOpenAckMessage + + CanBuildConnectionOpenConfirmMessage + + CanBuildChannelOpenTryPayload + + CanBuildChannelOpenAckPayload + + CanBuildChannelOpenConfirmPayload + + CanBuildChannelOpenInitMessage + + CanBuildChannelOpenTryMessage + + CanBuildChannelOpenAckMessage + + CanBuildChannelOpenConfirmMessage + + CanBuildReceivePacketMessage + + CanBuildAckPacketMessage + + CanBuildTimeoutUnorderedPacketMessage + + CanBuildReceivePacketPayload + + CanBuildAckPacketPayload + + CanBuildTimeoutUnorderedPacketPayload + + HasConnectionOpenInitEvent + + HasConnectionOpenTryEvent + + HasSendPacketEvent + + HasWriteAckEvent +{ +} + +impl CanUseSovereignChain for SovereignChain {} diff --git a/crates/relayer/sovereign-relayer/src/contexts/sovereign_cosmos_birelay.rs b/crates/relayer/sovereign-relayer/src/contexts/sovereign_cosmos_birelay.rs new file mode 100644 index 00000000..6e247ac9 --- /dev/null +++ b/crates/relayer/sovereign-relayer/src/contexts/sovereign_cosmos_birelay.rs @@ -0,0 +1,62 @@ +use cgp_core::prelude::*; +use cgp_core::{ErrorRaiserComponent, ErrorTypeComponent}; +use cgp_error_eyre::{ProvideEyreError, RaiseDebugError}; +use hermes_cosmos_relayer::contexts::chain::CosmosChain; +use hermes_relayer_components::birelay::traits::two_way::{ + ProvideTwoChainTypes, ProvideTwoWayRelayTypes, TwoWayRelayGetter, +}; +use hermes_runtime::impls::types::runtime::ProvideHermesRuntime; +use hermes_runtime::types::runtime::HermesRuntime; +use hermes_runtime_components::traits::runtime::{RuntimeGetter, RuntimeTypeComponent}; + +use crate::contexts::cosmos_to_sovereign_relay::CosmosToSovereignRelay; +use crate::contexts::sovereign_chain::SovereignChain; +use crate::contexts::sovereign_to_cosmos_relay::SovereignToCosmosRelay; + +pub struct SovereignCosmosBiRelay { + pub runtime: HermesRuntime, + pub relay_a_to_b: CosmosToSovereignRelay, + pub relay_b_to_a: SovereignToCosmosRelay, +} + +pub struct SovereignCosmosBiRelayComponents; + +impl HasComponents for SovereignCosmosBiRelay { + type Components = SovereignCosmosBiRelayComponents; +} + +delegate_components! { + SovereignCosmosBiRelayComponents { + ErrorTypeComponent: ProvideEyreError, + ErrorRaiserComponent: RaiseDebugError, + RuntimeTypeComponent: ProvideHermesRuntime, + } +} + +impl RuntimeGetter for SovereignCosmosBiRelayComponents { + fn runtime(relay: &SovereignCosmosBiRelay) -> &HermesRuntime { + &relay.runtime + } +} + +impl ProvideTwoChainTypes for SovereignCosmosBiRelayComponents { + type ChainA = CosmosChain; + + type ChainB = SovereignChain; +} + +impl ProvideTwoWayRelayTypes for SovereignCosmosBiRelayComponents { + type RelayAToB = CosmosToSovereignRelay; + + type RelayBToA = SovereignToCosmosRelay; +} + +impl TwoWayRelayGetter for SovereignCosmosBiRelayComponents { + fn relay_a_to_b(birelay: &SovereignCosmosBiRelay) -> &CosmosToSovereignRelay { + &birelay.relay_a_to_b + } + + fn relay_b_to_a(birelay: &SovereignCosmosBiRelay) -> &SovereignToCosmosRelay { + &birelay.relay_b_to_a + } +} diff --git a/crates/relayer/sovereign-relayer/src/contexts/sovereign_rollup.rs b/crates/relayer/sovereign-relayer/src/contexts/sovereign_rollup.rs new file mode 100644 index 00000000..17dbba29 --- /dev/null +++ b/crates/relayer/sovereign-relayer/src/contexts/sovereign_rollup.rs @@ -0,0 +1,497 @@ +use std::sync::Arc; + +use cgp_core::prelude::*; +use cgp_core::{ErrorRaiserComponent, ErrorTypeComponent, HasComponents}; +use cgp_error_eyre::{ProvideEyreError, RaiseDebugError}; +use ed25519_dalek::SigningKey; +use futures::lock::Mutex; +use hermes_cosmos_relayer::contexts::chain::CosmosChain; +use hermes_cosmos_relayer::contexts::logger::ProvideCosmosLogger; +use hermes_encoding_components::traits::has_encoding::{ + DefaultEncodingGetterComponent, EncodingGetterComponent, EncodingTypeComponent, HasEncoding, +}; +use hermes_logging_components::traits::has_logger::{ + GlobalLoggerGetterComponent, HasLogger, LoggerGetterComponent, LoggerTypeComponent, +}; +use hermes_relayer_components::chain::traits::commitment_prefix::CommitmentPrefixTypeComponent; +use hermes_relayer_components::chain::traits::message_builders::ack_packet::{ + AckPacketMessageBuilderComponent, CanBuildAckPacketMessage, +}; +use hermes_relayer_components::chain::traits::message_builders::channel_handshake::{ + CanBuildChannelOpenInitMessage, ChannelOpenAckMessageBuilderComponent, + ChannelOpenConfirmMessageBuilderComponent, ChannelOpenInitMessageBuilderComponent, + ChannelOpenTryMessageBuilderComponent, +}; +use hermes_relayer_components::chain::traits::message_builders::connection_handshake::{ + CanBuildConnectionOpenAckMessage, CanBuildConnectionOpenConfirmMessage, + CanBuildConnectionOpenInitMessage, CanBuildConnectionOpenTryMessage, + ConnectionOpenAckMessageBuilderComponent, ConnectionOpenConfirmMessageBuilderComponent, + ConnectionOpenInitMessageBuilderComponent, ConnectionOpenTryMessageBuilderComponent, +}; +use hermes_relayer_components::chain::traits::message_builders::create_client::{ + CanBuildCreateClientMessage, CreateClientMessageBuilderComponent, +}; +use hermes_relayer_components::chain::traits::message_builders::receive_packet::{ + CanBuildReceivePacketMessage, ReceivePacketMessageBuilderComponent, +}; +use hermes_relayer_components::chain::traits::message_builders::timeout_unordered_packet::{ + CanBuildTimeoutUnorderedPacketMessage, TimeoutUnorderedPacketMessageBuilderComponent, +}; +use hermes_relayer_components::chain::traits::message_builders::update_client::UpdateClientMessageBuilderComponent; +use hermes_relayer_components::chain::traits::queries::chain_status::{ + CanQueryChainStatus, ChainStatusQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::channel_end::{ + CanQueryChannelEnd, CanQueryChannelEndWithProofs, ChannelEndQuerierComponent, + ChannelEndWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::client_state::{ + CanQueryClientState, CanQueryClientStateWithProofs, ClientStateQuerierComponent, + ClientStateWithProofsQuerierComponent, RawClientStateQuerierComponent, + RawClientStateWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::connection_end::{ + CanQueryConnectionEnd, CanQueryConnectionEndWithProofs, ConnectionEndQuerierComponent, + ConnectionEndWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::consensus_state::{ + CanQueryConsensusState, CanQueryConsensusStateWithProofs, ConsensusStateQuerierComponent, + ConsensusStateWithProofsQuerierComponent, RawConsensusStateQuerierComponent, + RawConsensusStateWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::consensus_state_height::{ + CanQueryConsensusStateHeights, ConsensusStateHeightQuerierComponent, + ConsensusStateHeightsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::packet_acknowledgement::{ + CanQueryPacketAcknowledgement, PacketAcknowledgementQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::packet_commitment::{ + CanQueryPacketCommitment, PacketCommitmentQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::packet_receipt::{ + CanQueryPacketReceipt, PacketReceiptQuerierComponent, +}; +use hermes_relayer_components::chain::traits::send_message::{ + CanSendMessages, MessageSenderComponent, +}; +use hermes_relayer_components::chain::traits::types::chain_id::{ + ChainIdGetter, ChainIdTypeComponent, HasChainId, +}; +use hermes_relayer_components::chain::traits::types::channel::{ + ChannelEndTypeComponent, ChannelOpenAckPayloadTypeComponent, + ChannelOpenConfirmPayloadTypeComponent, ChannelOpenTryPayloadTypeComponent, + InitChannelOptionsTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::client_state::{ + ClientStateFieldsGetterComponent, ClientStateTypeComponent, HasClientStateType, + RawClientStateTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::connection::{ + ConnectionEndTypeComponent, ConnectionOpenAckPayloadTypeComponent, + ConnectionOpenConfirmPayloadTypeComponent, ConnectionOpenInitPayloadTypeComponent, + ConnectionOpenTryPayloadTypeComponent, HasInitConnectionOptionsType, + InitConnectionOptionsTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::consensus_state::{ + ConsensusStateTypeComponent, RawConsensusStateTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::create_client::{ + CreateClientEventComponent, CreateClientMessageOptionsTypeComponent, + CreateClientPayloadOptionsTypeComponent, CreateClientPayloadTypeComponent, + HasCreateClientEvent, +}; +use hermes_relayer_components::chain::traits::types::event::EventTypeComponent; +use hermes_relayer_components::chain::traits::types::height::{ + HasHeightFields, HeightFieldComponent, HeightTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::ibc::{ + CounterpartyMessageHeightGetterComponent, HasCounterpartyMessageHeight, IbcChainTypesComponent, +}; +use hermes_relayer_components::chain::traits::types::ibc_events::channel::{ + ChannelOpenInitEventComponent, ChannelOpenTryEventComponent, +}; +use hermes_relayer_components::chain::traits::types::ibc_events::connection::{ + ConnectionOpenInitEventComponent, ConnectionOpenTryEventComponent, HasConnectionOpenInitEvent, +}; +use hermes_relayer_components::chain::traits::types::ibc_events::send_packet::SendPacketEventComponent; +use hermes_relayer_components::chain::traits::types::ibc_events::write_ack::WriteAckEventComponent; +use hermes_relayer_components::chain::traits::types::message::MessageTypeComponent; +use hermes_relayer_components::chain::traits::types::packet::IbcPacketTypesProviderComponent; +use hermes_relayer_components::chain::traits::types::packets::ack::AcknowledgementTypeComponent; +use hermes_relayer_components::chain::traits::types::packets::receive::PacketCommitmentTypeComponent; +use hermes_relayer_components::chain::traits::types::packets::timeout::PacketReceiptTypeComponent; +use hermes_relayer_components::chain::traits::types::proof::{ + CommitmentProofBytesGetterComponent, CommitmentProofHeightGetterComponent, + CommitmentProofTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::status::ChainStatusTypeComponent; +use hermes_relayer_components::chain::traits::types::timestamp::TimestampTypeComponent; +use hermes_relayer_components::chain::traits::types::update_client::UpdateClientPayloadTypeComponent; +use hermes_relayer_components::error::impls::retry::ReturnRetryable; +use hermes_relayer_components::error::traits::retry::RetryableErrorComponent; +use hermes_relayer_components::transaction::impls::poll_tx_response::PollTimeoutGetterComponent; +use hermes_relayer_components::transaction::traits::default_signer::DefaultSignerGetter; +use hermes_relayer_components::transaction::traits::encode_tx::{CanEncodeTx, TxEncoderComponent}; +use hermes_relayer_components::transaction::traits::estimate_tx_fee::{ + CanEstimateTxFee, TxFeeEstimatorComponent, +}; +use hermes_relayer_components::transaction::traits::nonce::allocate_nonce::{ + CanAllocateNonce, NonceAllocatorComponent, +}; +use hermes_relayer_components::transaction::traits::nonce::nonce_guard::{ + HasNonceGuard, NonceGuardComponent, +}; +use hermes_relayer_components::transaction::traits::nonce::nonce_mutex::{ + HasMutexForNonceAllocation, ProvideMutexForNonceAllocation, +}; +use hermes_relayer_components::transaction::traits::nonce::query_nonce::{ + CanQueryNonce, NonceQuerierComponent, +}; +use hermes_relayer_components::transaction::traits::parse_events::TxResponseAsEventsParserComponent; +use hermes_relayer_components::transaction::traits::poll_tx_response::{ + CanPollTxResponse, TxResponsePollerComponent, +}; +use hermes_relayer_components::transaction::traits::query_tx_response::{ + CanQueryTxResponse, TxResponseQuerierComponent, +}; +use hermes_relayer_components::transaction::traits::send_messages_with_signer::{ + CanSendMessagesWithSigner, MessagesWithSignerSenderComponent, +}; +use hermes_relayer_components::transaction::traits::send_messages_with_signer_and_nonce::{ + CanSendMessagesWithSignerAndNonce, MessagesWithSignerAndNonceSenderComponent, +}; +use hermes_relayer_components::transaction::traits::simulation_fee::{ + FeeForSimulationGetterComponent, HasFeeForSimulation, +}; +use hermes_relayer_components::transaction::traits::submit_tx::{ + CanSubmitTx, TxSubmitterComponent, +}; +use hermes_relayer_components::transaction::traits::types::fee::FeeTypeComponent; +use hermes_relayer_components::transaction::traits::types::nonce::NonceTypeComponent; +use hermes_relayer_components::transaction::traits::types::signer::SignerTypeComponent; +use hermes_relayer_components::transaction::traits::types::transaction::TransactionTypeComponent; +use hermes_relayer_components::transaction::traits::types::tx_hash::TransactionHashTypeComponent; +use hermes_relayer_components::transaction::traits::types::tx_response::TxResponseTypeComponent; +use hermes_runtime::impls::types::runtime::ProvideHermesRuntime; +use hermes_runtime::types::runtime::HermesRuntime; +use hermes_runtime_components::traits::mutex::MutexGuardOf; +use hermes_runtime_components::traits::runtime::{RuntimeGetter, RuntimeTypeComponent}; +use hermes_sovereign_rollup_components::components::SovereignRollupClientComponents; +use hermes_sovereign_rollup_components::traits::json_rpc_client::{ + JsonRpcClientGetter, JsonRpcClientTypeComponent, +}; +use hermes_sovereign_rollup_components::types::client_state::WrappedSovereignClientState; +use hermes_sovereign_rollup_components::types::rollup_id::RollupId; +use hermes_sovereign_rollup_components::types::tx::nonce_guard::SovereignNonceGuard; +use hermes_sovereign_test_components::rollup::components::SovereignRollupTestComponents; +use hermes_test_components::chain::traits::assert::eventual_amount::{ + CanAssertEventualAmount, EventualAmountAsserterComponent, +}; +use hermes_test_components::chain::traits::assert::poll_assert::PollAssertDurationGetterComponent; +use hermes_test_components::chain::traits::messages::ibc_transfer::{ + CanBuildIbcTokenTransferMessage, IbcTokenTransferMessageBuilderComponent, +}; +use hermes_test_components::chain::traits::queries::balance::{ + BalanceQuerierComponent, CanQueryBalance, +}; +use hermes_test_components::chain::traits::transfer::ibc_transfer::TokenIbcTransferrerComponent; +use hermes_test_components::chain::traits::transfer::timeout::IbcTransferTimeoutCalculatorComponent; +use hermes_test_components::chain::traits::types::address::AddressTypeComponent; +use hermes_test_components::chain::traits::types::amount::AmountTypeComponent; +use hermes_test_components::chain::traits::types::denom::DenomTypeComponent; +use hermes_test_components::chain::traits::types::memo::{ + DefaultMemoGetterComponent, HasMemoType, MemoTypeComponent, +}; +use hermes_test_components::chain::traits::types::wallet::WalletTypeComponent; +use jsonrpsee::http_client::HttpClient; +use jsonrpsee::ws_client::WsClient; + +use crate::contexts::encoding::{ProvideSovereignEncoding, SovereignEncoding}; + +#[derive(Clone)] +pub struct SovereignRollup { + pub runtime: HermesRuntime, + pub rpc_client: HttpClient, + pub subscription_client: Arc, + pub signing_key: SigningKey, + pub nonce_mutex: Arc>, +} + +impl SovereignRollup { + pub fn new( + runtime: HermesRuntime, + signing_key: SigningKey, + rpc_client: HttpClient, + subscription_client: WsClient, + ) -> Self { + Self { + runtime, + signing_key, + rpc_client, + subscription_client: Arc::new(subscription_client), + nonce_mutex: Arc::new(Mutex::new(())), + } + } +} + +pub struct SovereignRollupComponents; + +impl HasComponents for SovereignRollup { + type Components = SovereignRollupComponents; +} + +delegate_components! { + SovereignRollupComponents { + ErrorTypeComponent: + ProvideEyreError, + ErrorRaiserComponent: + RaiseDebugError, + RetryableErrorComponent: + ReturnRetryable, + RuntimeTypeComponent: + ProvideHermesRuntime, + [ + LoggerTypeComponent, + LoggerGetterComponent, + GlobalLoggerGetterComponent, + ]: + ProvideCosmosLogger, + [ + EncodingTypeComponent, + EncodingGetterComponent, + DefaultEncodingGetterComponent, + ]: + ProvideSovereignEncoding, + [ + HeightTypeComponent, + HeightFieldComponent, + TimestampTypeComponent, + ChainIdTypeComponent, + MessageTypeComponent, + EventTypeComponent, + ChainStatusTypeComponent, + CommitmentPrefixTypeComponent, + CommitmentProofTypeComponent, + CommitmentProofHeightGetterComponent, + CommitmentProofBytesGetterComponent, + PacketCommitmentTypeComponent, + AcknowledgementTypeComponent, + PacketReceiptTypeComponent, + ConnectionEndTypeComponent, + ChannelEndTypeComponent, + + ClientStateTypeComponent, + ClientStateFieldsGetterComponent, + ConsensusStateTypeComponent, + + IbcChainTypesComponent, + IbcPacketTypesProviderComponent, + TransactionTypeComponent, + NonceTypeComponent, + NonceGuardComponent, + FeeTypeComponent, + SignerTypeComponent, + TransactionHashTypeComponent, + TxResponseTypeComponent, + + CreateClientEventComponent, + ConnectionOpenInitEventComponent, + ConnectionOpenTryEventComponent, + ChannelOpenInitEventComponent, + ChannelOpenTryEventComponent, + SendPacketEventComponent, + WriteAckEventComponent, + + CreateClientPayloadOptionsTypeComponent, + CreateClientMessageOptionsTypeComponent, + CreateClientPayloadTypeComponent, + UpdateClientPayloadTypeComponent, + InitConnectionOptionsTypeComponent, + + ConnectionOpenInitPayloadTypeComponent, + ConnectionOpenTryPayloadTypeComponent, + ConnectionOpenAckPayloadTypeComponent, + ConnectionOpenConfirmPayloadTypeComponent, + + InitChannelOptionsTypeComponent, + ChannelOpenTryPayloadTypeComponent, + ChannelOpenAckPayloadTypeComponent, + ChannelOpenConfirmPayloadTypeComponent, + + NonceAllocatorComponent, + MessageSenderComponent, + MessagesWithSignerSenderComponent, + MessagesWithSignerAndNonceSenderComponent, + TxResponsePollerComponent, + + JsonRpcClientTypeComponent, + TxEncoderComponent, + TxFeeEstimatorComponent, + FeeForSimulationGetterComponent, + TxSubmitterComponent, + NonceQuerierComponent, + TxResponseQuerierComponent, + PollTimeoutGetterComponent, + TxResponseAsEventsParserComponent, + + CreateClientMessageBuilderComponent, + UpdateClientMessageBuilderComponent, + + ChainStatusQuerierComponent, + + RawClientStateTypeComponent, + RawClientStateQuerierComponent, + RawClientStateWithProofsQuerierComponent, + ClientStateQuerierComponent, + ClientStateWithProofsQuerierComponent, + + RawConsensusStateTypeComponent, + RawConsensusStateQuerierComponent, + RawConsensusStateWithProofsQuerierComponent, + ConsensusStateQuerierComponent, + ConsensusStateWithProofsQuerierComponent, + + ConsensusStateHeightsQuerierComponent, + ConsensusStateHeightQuerierComponent, + + ConnectionEndQuerierComponent, + ConnectionEndWithProofsQuerierComponent, + + ChannelEndQuerierComponent, + ChannelEndWithProofsQuerierComponent, + + PacketCommitmentQuerierComponent, + PacketAcknowledgementQuerierComponent, + PacketReceiptQuerierComponent, + + AckPacketMessageBuilderComponent, + ReceivePacketMessageBuilderComponent, + TimeoutUnorderedPacketMessageBuilderComponent, + + ConnectionOpenInitMessageBuilderComponent, + ConnectionOpenTryMessageBuilderComponent, + ConnectionOpenAckMessageBuilderComponent, + ConnectionOpenConfirmMessageBuilderComponent, + + ChannelOpenInitMessageBuilderComponent, + ChannelOpenTryMessageBuilderComponent, + ChannelOpenAckMessageBuilderComponent, + ChannelOpenConfirmMessageBuilderComponent, + + CounterpartyMessageHeightGetterComponent + ]: + SovereignRollupClientComponents, + [ + AddressTypeComponent, + DenomTypeComponent, + AmountTypeComponent, + WalletTypeComponent, + MemoTypeComponent, + DefaultMemoGetterComponent, + TokenIbcTransferrerComponent, + IbcTransferTimeoutCalculatorComponent, + IbcTokenTransferMessageBuilderComponent, + BalanceQuerierComponent, + EventualAmountAsserterComponent, + PollAssertDurationGetterComponent, + ]: + SovereignRollupTestComponents, + } +} + +impl RuntimeGetter for SovereignRollupComponents { + fn runtime(rollup: &SovereignRollup) -> &HermesRuntime { + &rollup.runtime + } +} + +impl JsonRpcClientGetter for SovereignRollupComponents { + fn json_rpc_client(rollup: &SovereignRollup) -> &HttpClient { + &rollup.rpc_client + } +} + +impl ChainIdGetter for SovereignRollupComponents { + fn chain_id(_chain: &SovereignRollup) -> &RollupId { + static DUMMY_ROLLUP_ID: RollupId = RollupId(0); + + &DUMMY_ROLLUP_ID + } +} + +impl DefaultSignerGetter for SovereignRollupComponents { + fn get_default_signer(rollup: &SovereignRollup) -> &SigningKey { + &rollup.signing_key + } +} + +impl ProvideMutexForNonceAllocation for SovereignRollupComponents { + fn mutex_for_nonce_allocation<'a>( + rollup: &'a SovereignRollup, + _signer: &SigningKey, + ) -> &'a Mutex<()> { + &rollup.nonce_mutex + } + + fn mutex_to_nonce_guard<'a>( + mutex_guard: MutexGuardOf<'a, HermesRuntime, ()>, + nonce: u64, + ) -> SovereignNonceGuard<'a> { + SovereignNonceGuard { mutex_guard, nonce } + } +} + +pub trait CanUseSovereignRollup: + CanQueryBalance + + HasChainId + + HasHeightFields + + CanEncodeTx + + CanEstimateTxFee + + HasFeeForSimulation + + CanSubmitTx + + HasNonceGuard + + HasMutexForNonceAllocation + + CanQueryNonce + + CanAllocateNonce + + CanSendMessages + + CanSendMessagesWithSigner + + CanSendMessagesWithSignerAndNonce + + CanQueryTxResponse + + CanPollTxResponse + + CanAssertEventualAmount + + HasLogger + + CanQueryChainStatus + + HasMemoType> + + HasEncoding + + HasCounterpartyMessageHeight + + HasClientStateType + + CanBuildCreateClientMessage + + HasCreateClientEvent + + HasConnectionOpenInitEvent + + CanQueryClientState + + CanQueryClientStateWithProofs + + CanQueryConsensusState + + CanQueryConsensusStateWithProofs + + CanQueryConsensusStateHeights + + CanQueryConnectionEnd + + CanQueryConnectionEndWithProofs + + CanQueryChannelEnd + + CanQueryChannelEndWithProofs + + CanQueryPacketCommitment + + CanQueryPacketAcknowledgement + + CanQueryPacketReceipt + + CanBuildAckPacketMessage + + CanBuildReceivePacketMessage + + CanBuildTimeoutUnorderedPacketMessage + + HasInitConnectionOptionsType + + CanBuildConnectionOpenInitMessage + + CanBuildConnectionOpenTryMessage + + CanBuildConnectionOpenAckMessage + + CanBuildConnectionOpenConfirmMessage + + CanBuildChannelOpenInitMessage + + CanBuildIbcTokenTransferMessage +{ +} + +impl CanUseSovereignRollup for SovereignRollup {} diff --git a/crates/relayer/sovereign-relayer/src/contexts/sovereign_to_cosmos_relay.rs b/crates/relayer/sovereign-relayer/src/contexts/sovereign_to_cosmos_relay.rs new file mode 100644 index 00000000..fcbd3b4f --- /dev/null +++ b/crates/relayer/sovereign-relayer/src/contexts/sovereign_to_cosmos_relay.rs @@ -0,0 +1,141 @@ +use std::collections::BTreeSet; +use std::sync::Arc; + +use cgp_core::prelude::*; +use cgp_core::{delegate_all, ErrorRaiserComponent, ErrorTypeComponent}; +use cgp_error_eyre::{ProvideEyreError, RaiseDebugError}; +use futures::lock::Mutex; +use hermes_cosmos_relayer::contexts::chain::CosmosChain; +use hermes_cosmos_relayer::contexts::logger::ProvideCosmosLogger; +use hermes_logging_components::traits::has_logger::{ + GlobalLoggerGetterComponent, LoggerGetterComponent, LoggerTypeComponent, +}; +use hermes_relayer_components::components::default::relay::{ + DefaultRelayComponents, IsDefaultRelayComponent, +}; +use hermes_relayer_components::relay::impls::packet_filters::allow_all::AllowAll; +use hermes_relayer_components::relay::impls::packet_lock::{ + PacketMutex, PacketMutexGetter, ProvidePacketLockWithMutex, +}; +use hermes_relayer_components::relay::traits::chains::{ + CanRaiseRelayChainErrors, HasRelayChains, ProvideRelayChains, +}; +use hermes_relayer_components::relay::traits::channel::open_handshake::CanRelayChannelOpenHandshake; +use hermes_relayer_components::relay::traits::channel::open_init::CanInitChannel; +use hermes_relayer_components::relay::traits::client_creator::CanCreateClient; +use hermes_relayer_components::relay::traits::connection::open_handshake::CanRelayConnectionOpenHandshake; +use hermes_relayer_components::relay::traits::connection::open_init::CanInitConnection; +use hermes_relayer_components::relay::traits::ibc_message_sender::{CanSendIbcMessages, MainSink}; +use hermes_relayer_components::relay::traits::packet_filter::PacketFilterComponent; +use hermes_relayer_components::relay::traits::packet_lock::{HasPacketLock, PacketLockComponent}; +use hermes_relayer_components::relay::traits::packet_relayer::CanRelayPacket; +use hermes_relayer_components::relay::traits::packet_relayers::ack_packet::CanRelayAckPacket; +use hermes_relayer_components::relay::traits::packet_relayers::receive_packet::CanRelayReceivePacket; +use hermes_relayer_components::relay::traits::packet_relayers::timeout_unordered_packet::CanRelayTimeoutUnorderedPacket; +use hermes_relayer_components::relay::traits::target::{DestinationTarget, SourceTarget}; +use hermes_relayer_components::relay::traits::update_client_message_builder::CanBuildTargetUpdateClientMessage; +use hermes_runtime::impls::types::runtime::ProvideHermesRuntime; +use hermes_runtime::types::runtime::HermesRuntime; +use hermes_runtime_components::traits::runtime::{RuntimeGetter, RuntimeTypeComponent}; +use ibc_relayer_types::core::ics04_channel::packet::{Packet, Sequence}; +use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, ClientId, PortId}; + +use crate::contexts::sovereign_chain::SovereignChain; + +pub struct SovereignToCosmosRelay { + pub runtime: HermesRuntime, + pub src_chain: SovereignChain, + pub dst_chain: CosmosChain, + pub src_client_id: ClientId, + pub dst_client_id: ClientId, + pub packet_lock_mutex: Arc>>, +} + +pub trait CanUseSovereignToCosmosRelay: + HasRelayChains + + CanRaiseRelayChainErrors + + CanCreateClient + + CanCreateClient + + CanBuildTargetUpdateClientMessage + + CanBuildTargetUpdateClientMessage + + CanInitConnection + + CanInitChannel + + CanSendIbcMessages + + CanSendIbcMessages + + CanRelayConnectionOpenHandshake + + CanRelayChannelOpenHandshake + + CanRelayReceivePacket + + CanRelayAckPacket + + CanRelayTimeoutUnorderedPacket + + HasPacketLock + + CanRelayPacket +{ +} + +impl CanUseSovereignToCosmosRelay for SovereignToCosmosRelay {} + +pub struct SovereignToCosmosRelayComponents; + +impl HasComponents for SovereignToCosmosRelay { + type Components = SovereignToCosmosRelayComponents; +} + +delegate_all!( + IsDefaultRelayComponent, + DefaultRelayComponents, + SovereignToCosmosRelayComponents, +); + +delegate_components! { + SovereignToCosmosRelayComponents { + ErrorTypeComponent: ProvideEyreError, + ErrorRaiserComponent: RaiseDebugError, + RuntimeTypeComponent: ProvideHermesRuntime, + [ + LoggerTypeComponent, + LoggerGetterComponent, + GlobalLoggerGetterComponent, + ]: + ProvideCosmosLogger, + PacketLockComponent: + ProvidePacketLockWithMutex, + PacketFilterComponent: + AllowAll, + } +} + +impl RuntimeGetter for SovereignToCosmosRelayComponents { + fn runtime(relay: &SovereignToCosmosRelay) -> &HermesRuntime { + &relay.runtime + } +} + +impl ProvideRelayChains for SovereignToCosmosRelayComponents { + type SrcChain = SovereignChain; + + type DstChain = CosmosChain; + + type Packet = Packet; + + fn src_chain(relay: &SovereignToCosmosRelay) -> &SovereignChain { + &relay.src_chain + } + + fn dst_chain(relay: &SovereignToCosmosRelay) -> &CosmosChain { + &relay.dst_chain + } + + fn src_client_id(relay: &SovereignToCosmosRelay) -> &ClientId { + &relay.src_client_id + } + + fn dst_client_id(relay: &SovereignToCosmosRelay) -> &ClientId { + &relay.dst_client_id + } +} + +impl PacketMutexGetter for SovereignToCosmosRelayComponents { + fn packet_mutex(relay: &SovereignToCosmosRelay) -> &PacketMutex { + &relay.packet_lock_mutex + } +} diff --git a/crates/relayer/sovereign-relayer/src/exts/cosmos/chain.rs b/crates/relayer/sovereign-relayer/src/exts/cosmos/chain.rs new file mode 100644 index 00000000..f43c7c7f --- /dev/null +++ b/crates/relayer/sovereign-relayer/src/exts/cosmos/chain.rs @@ -0,0 +1,91 @@ +use cgp_core::prelude::*; +use hermes_cosmos_chain_components::components::delegate::DelegateCosmosChainComponents; +use hermes_cosmos_relayer::contexts::chain::CosmosChain; +use hermes_relayer_components::chain::traits::message_builders::ack_packet::CanBuildAckPacketMessage; +use hermes_relayer_components::chain::traits::message_builders::channel_handshake::{ + CanBuildChannelOpenAckMessage, CanBuildChannelOpenConfirmMessage, + CanBuildChannelOpenInitMessage, CanBuildChannelOpenTryMessage, +}; +use hermes_relayer_components::chain::traits::message_builders::connection_handshake::{ + CanBuildConnectionOpenAckMessage, CanBuildConnectionOpenConfirmMessage, + CanBuildConnectionOpenInitMessage, CanBuildConnectionOpenTryMessage, +}; +use hermes_relayer_components::chain::traits::message_builders::create_client::CanBuildCreateClientMessage; +use hermes_relayer_components::chain::traits::message_builders::receive_packet::CanBuildReceivePacketMessage; +use hermes_relayer_components::chain::traits::message_builders::timeout_unordered_packet::CanBuildTimeoutUnorderedPacketMessage; +use hermes_relayer_components::chain::traits::message_builders::update_client::CanBuildUpdateClientMessage; +use hermes_relayer_components::chain::traits::payload_builders::ack_packet::CanBuildAckPacketPayload; +use hermes_relayer_components::chain::traits::payload_builders::channel_handshake::{ + CanBuildChannelOpenAckPayload, CanBuildChannelOpenConfirmPayload, CanBuildChannelOpenTryPayload, +}; +use hermes_relayer_components::chain::traits::payload_builders::connection_handshake::{ + CanBuildConnectionOpenAckPayload, CanBuildConnectionOpenConfirmPayload, + CanBuildConnectionOpenInitPayload, CanBuildConnectionOpenTryPayload, +}; +use hermes_relayer_components::chain::traits::payload_builders::create_client::CanBuildCreateClientPayload; +use hermes_relayer_components::chain::traits::payload_builders::receive_packet::CanBuildReceivePacketPayload; +use hermes_relayer_components::chain::traits::payload_builders::timeout_unordered_packet::CanBuildTimeoutUnorderedPacketPayload; +use hermes_relayer_components::chain::traits::payload_builders::update_client::CanBuildUpdateClientPayload; +use hermes_relayer_components::chain::traits::queries::client_state::{ + CanQueryClientState, CanQueryClientStateWithProofs, +}; +use hermes_relayer_components::chain::traits::queries::consensus_state::{ + CanQueryConsensusState, CanQueryConsensusStateWithProofs, +}; +use hermes_relayer_components::chain::traits::queries::consensus_state_height::{ + CanQueryConsensusStateHeight, CanQueryConsensusStateHeights, +}; +use hermes_relayer_components::chain::traits::types::channel::HasInitChannelOptionsType; +use hermes_relayer_components::chain::traits::types::client_state::HasClientStateFields; +use hermes_relayer_components::chain::traits::types::create_client::HasCreateClientPayloadOptionsType; +use hermes_relayer_components::chain::traits::types::ibc::HasCounterpartyMessageHeight; +use hermes_sovereign_chain_components::cosmos::components::SovereignCosmosComponents; + +use crate::contexts::sovereign_chain::SovereignChain; + +delegate_components! { + DelegateCosmosChainComponents { + SovereignChain: SovereignCosmosComponents, + } +} + +pub trait CanUseCosmosChainWithSovereign: + CanQueryClientState + + CanQueryClientStateWithProofs + + CanQueryConsensusState + + CanQueryConsensusStateWithProofs + + CanQueryConsensusStateHeight + + CanQueryConsensusStateHeights + + CanBuildCreateClientMessage + + CanBuildUpdateClientMessage + + CanBuildConnectionOpenInitMessage + + CanBuildConnectionOpenTryMessage + + CanBuildConnectionOpenAckMessage + + CanBuildConnectionOpenConfirmMessage + + CanBuildConnectionOpenInitPayload + + CanBuildConnectionOpenTryPayload + + CanBuildConnectionOpenAckPayload + + CanBuildConnectionOpenConfirmPayload + + CanBuildChannelOpenTryPayload + + CanBuildChannelOpenAckPayload + + CanBuildChannelOpenConfirmPayload + + CanBuildChannelOpenInitMessage + + CanBuildChannelOpenTryMessage + + CanBuildChannelOpenAckMessage + + CanBuildChannelOpenConfirmMessage + + CanBuildReceivePacketPayload + + CanBuildAckPacketPayload + + CanBuildTimeoutUnorderedPacketPayload + + CanBuildReceivePacketMessage + + CanBuildAckPacketMessage + + CanBuildTimeoutUnorderedPacketMessage + + HasCreateClientPayloadOptionsType + + CanBuildCreateClientPayload + + CanBuildUpdateClientPayload + + HasClientStateFields + + HasInitChannelOptionsType + + HasCounterpartyMessageHeight +{ +} + +impl CanUseCosmosChainWithSovereign for CosmosChain {} diff --git a/crates/relayer/sovereign-relayer/src/exts/cosmos/mod.rs b/crates/relayer/sovereign-relayer/src/exts/cosmos/mod.rs new file mode 100644 index 00000000..28ac57df --- /dev/null +++ b/crates/relayer/sovereign-relayer/src/exts/cosmos/mod.rs @@ -0,0 +1 @@ +pub mod chain; diff --git a/crates/relayer/sovereign-relayer/src/exts/mod.rs b/crates/relayer/sovereign-relayer/src/exts/mod.rs new file mode 100644 index 00000000..d18beac5 --- /dev/null +++ b/crates/relayer/sovereign-relayer/src/exts/mod.rs @@ -0,0 +1 @@ +pub mod cosmos; diff --git a/crates/relayer/sovereign-relayer/src/lib.rs b/crates/relayer/sovereign-relayer/src/lib.rs new file mode 100644 index 00000000..62fb9dfe --- /dev/null +++ b/crates/relayer/sovereign-relayer/src/lib.rs @@ -0,0 +1,6 @@ +#![recursion_limit = "256"] +#![allow(clippy::needless_lifetimes)] +#![allow(clippy::type_complexity)] + +pub mod contexts; +pub mod exts; diff --git a/crates/relayer/sovereign-rollup-components/Cargo.toml b/crates/relayer/sovereign-rollup-components/Cargo.toml new file mode 100644 index 00000000..c7f23c45 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "hermes-sovereign-rollup-components" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } +readme = "README.md" +description = """ + Context-generic client components for communicating with a Sovereign rollup node +""" + +[dependencies] +cgp-core = { workspace = true } +hermes-relayer-components = { workspace = true } +hermes-cosmos-chain-components = { workspace = true } +hermes-wasm-client-components = { workspace = true } +hermes-runtime-components = { workspace = true } +hermes-encoding-components = { workspace = true } +hermes-protobuf-encoding-components = { workspace = true } + +ibc-proto = { workspace = true } +ibc-relayer = { workspace = true } +ibc-relayer-types = { workspace = true } +sov-celestia-client = { workspace = true, features = [ "test-util" ] } +ibc = { workspace = true } +ibc-query = { workspace = true, features = [ "serde" ] } + +tokio = { workspace = true } +eyre = { workspace = true } +jsonrpsee = { workspace = true, features = [ "http-client" ] } +prost = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +bech32 = { workspace = true } +borsh = { workspace = true } +futures = { workspace = true } +ed25519-dalek = { workspace = true } +jmt = { workspace = true } +sha2 = { workspace = true } +hex = { version = "0.4.3" } +base64 = { version = "0.22.1" } +serde-json-wasm = { version = "1.0.1" } diff --git a/crates/relayer/sovereign-rollup-components/src/components.rs b/crates/relayer/sovereign-rollup-components/src/components.rs new file mode 100644 index 00000000..8fa87bbc --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/components.rs @@ -0,0 +1,320 @@ +use cgp_core::prelude::*; +use hermes_cosmos_chain_components::impls::channel::channel_handshake_message::BuildCosmosChannelHandshakeMessage; +use hermes_cosmos_chain_components::impls::connection::connection_handshake_message::BuildCosmosConnectionHandshakeMessage; +use hermes_cosmos_chain_components::impls::packet::packet_message::BuildCosmosPacketMessages; +use hermes_cosmos_chain_components::impls::transaction::poll_timeout::DefaultPollTimeout; +use hermes_cosmos_chain_components::impls::types::client_state::ProvideAnyRawClientState; +use hermes_cosmos_chain_components::impls::types::consensus_state::ProvideAnyRawConsensusState; +use hermes_relayer_components::chain::impls::queries::consensus_state_height::QueryConsensusStateHeightsAndFindHeightBefore; +use hermes_relayer_components::chain::impls::queries::query_and_convert_client_state::QueryAndConvertRawClientState; +use hermes_relayer_components::chain::impls::queries::query_and_convert_consensus_state::QueryAndConvertRawConsensusState; +use hermes_relayer_components::chain::traits::commitment_prefix::{ + CommitmentPrefixTypeComponent, IbcCommitmentPrefixGetterComponent, +}; +use hermes_relayer_components::chain::traits::message_builders::ack_packet::AckPacketMessageBuilderComponent; +use hermes_relayer_components::chain::traits::message_builders::channel_handshake::{ + ChannelOpenAckMessageBuilderComponent, ChannelOpenConfirmMessageBuilderComponent, + ChannelOpenInitMessageBuilderComponent, ChannelOpenTryMessageBuilderComponent, +}; +use hermes_relayer_components::chain::traits::message_builders::connection_handshake::{ + ConnectionOpenAckMessageBuilderComponent, ConnectionOpenConfirmMessageBuilderComponent, + ConnectionOpenInitMessageBuilderComponent, ConnectionOpenTryMessageBuilderComponent, +}; +use hermes_relayer_components::chain::traits::message_builders::create_client::CreateClientMessageBuilderComponent; +use hermes_relayer_components::chain::traits::message_builders::receive_packet::ReceivePacketMessageBuilderComponent; +use hermes_relayer_components::chain::traits::message_builders::timeout_unordered_packet::TimeoutUnorderedPacketMessageBuilderComponent; +use hermes_relayer_components::chain::traits::message_builders::update_client::UpdateClientMessageBuilderComponent; +use hermes_relayer_components::chain::traits::queries::chain_status::ChainStatusQuerierComponent; +use hermes_relayer_components::chain::traits::queries::channel_end::{ + ChannelEndQuerierComponent, ChannelEndWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::client_state::{ + ClientStateQuerierComponent, ClientStateWithProofsQuerierComponent, + RawClientStateQuerierComponent, RawClientStateWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::connection_end::{ + ConnectionEndQuerierComponent, ConnectionEndWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::consensus_state::{ + ConsensusStateQuerierComponent, ConsensusStateWithProofsQuerierComponent, + RawConsensusStateQuerierComponent, RawConsensusStateWithProofsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::consensus_state_height::{ + ConsensusStateHeightQuerierComponent, ConsensusStateHeightsQuerierComponent, +}; +use hermes_relayer_components::chain::traits::queries::packet_acknowledgement::PacketAcknowledgementQuerierComponent; +use hermes_relayer_components::chain::traits::queries::packet_commitment::PacketCommitmentQuerierComponent; +use hermes_relayer_components::chain::traits::queries::packet_receipt::PacketReceiptQuerierComponent; +use hermes_relayer_components::chain::traits::send_message::MessageSenderComponent; +use hermes_relayer_components::chain::traits::types::chain_id::ChainIdTypeComponent; +use hermes_relayer_components::chain::traits::types::channel::{ + ChannelEndTypeComponent, ChannelOpenAckPayloadTypeComponent, + ChannelOpenConfirmPayloadTypeComponent, ChannelOpenTryPayloadTypeComponent, + InitChannelOptionsTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::client_state::{ + ClientStateFieldsGetterComponent, ClientStateTypeComponent, RawClientStateTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::connection::{ + ConnectionEndTypeComponent, ConnectionOpenAckPayloadTypeComponent, + ConnectionOpenConfirmPayloadTypeComponent, ConnectionOpenInitPayloadTypeComponent, + ConnectionOpenTryPayloadTypeComponent, InitConnectionOptionsTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::consensus_state::{ + ConsensusStateTypeComponent, RawConsensusStateTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::create_client::{ + CreateClientEventComponent, CreateClientMessageOptionsTypeComponent, + CreateClientPayloadOptionsTypeComponent, CreateClientPayloadTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::event::EventTypeComponent; +use hermes_relayer_components::chain::traits::types::height::{ + HeightFieldComponent, HeightIncrementerComponent, HeightTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::ibc::{ + CounterpartyMessageHeightGetterComponent, IbcChainTypesComponent, +}; +use hermes_relayer_components::chain::traits::types::ibc_events::channel::{ + ChannelOpenInitEventComponent, ChannelOpenTryEventComponent, +}; +use hermes_relayer_components::chain::traits::types::ibc_events::connection::{ + ConnectionOpenInitEventComponent, ConnectionOpenTryEventComponent, +}; +use hermes_relayer_components::chain::traits::types::ibc_events::send_packet::SendPacketEventComponent; +use hermes_relayer_components::chain::traits::types::ibc_events::write_ack::WriteAckEventComponent; +use hermes_relayer_components::chain::traits::types::message::MessageTypeComponent; +use hermes_relayer_components::chain::traits::types::packet::IbcPacketTypesProviderComponent; +use hermes_relayer_components::chain::traits::types::packets::ack::AcknowledgementTypeComponent; +use hermes_relayer_components::chain::traits::types::packets::receive::PacketCommitmentTypeComponent; +use hermes_relayer_components::chain::traits::types::packets::timeout::PacketReceiptTypeComponent; +use hermes_relayer_components::chain::traits::types::proof::CommitmentProofTypeComponent; +use hermes_relayer_components::chain::traits::types::status::ChainStatusTypeComponent; +use hermes_relayer_components::chain::traits::types::timestamp::TimestampTypeComponent; +use hermes_relayer_components::chain::traits::types::update_client::UpdateClientPayloadTypeComponent; +use hermes_relayer_components::components::default::transaction::DefaultTxComponents; +use hermes_relayer_components::transaction::impls::poll_tx_response::PollTimeoutGetterComponent; +use hermes_relayer_components::transaction::traits::encode_tx::TxEncoderComponent; +use hermes_relayer_components::transaction::traits::estimate_tx_fee::TxFeeEstimatorComponent; +use hermes_relayer_components::transaction::traits::nonce::allocate_nonce::NonceAllocatorComponent; +use hermes_relayer_components::transaction::traits::nonce::nonce_guard::NonceGuardComponent; +use hermes_relayer_components::transaction::traits::nonce::query_nonce::NonceQuerierComponent; +use hermes_relayer_components::transaction::traits::parse_events::TxResponseAsEventsParserComponent; +use hermes_relayer_components::transaction::traits::poll_tx_response::TxResponsePollerComponent; +use hermes_relayer_components::transaction::traits::query_tx_response::TxResponseQuerierComponent; +use hermes_relayer_components::transaction::traits::send_messages_with_signer::MessagesWithSignerSenderComponent; +use hermes_relayer_components::transaction::traits::send_messages_with_signer_and_nonce::MessagesWithSignerAndNonceSenderComponent; +use hermes_relayer_components::transaction::traits::simulation_fee::FeeForSimulationGetterComponent; +use hermes_relayer_components::transaction::traits::submit_tx::TxSubmitterComponent; +use hermes_relayer_components::transaction::traits::types::fee::FeeTypeComponent; +use hermes_relayer_components::transaction::traits::types::nonce::NonceTypeComponent; +use hermes_relayer_components::transaction::traits::types::signer::SignerTypeComponent; +use hermes_relayer_components::transaction::traits::types::transaction::TransactionTypeComponent; +use hermes_relayer_components::transaction::traits::types::tx_hash::TransactionHashTypeComponent; +use hermes_relayer_components::transaction::traits::types::tx_response::TxResponseTypeComponent; + +use crate::impls::commitment_prefix::ProvideSovereignIbcCommitmentPrefix; +use crate::impls::cosmos_to_sovereign::client::create_client_message::BuildCreateCosmosClientMessageOnSovereign; +use crate::impls::cosmos_to_sovereign::client::update_client_message::BuildUpdateCosmosClientMessageOnSovereign; +use crate::impls::events::ProvideSovereignEvents; +use crate::impls::json_rpc_client::ProvideJsonRpseeClient; +use crate::impls::message_height::GetCosmosHeightFromSovereignMessage; +use crate::impls::queries::chain_status::QuerySovereignRollupStatus; +use crate::impls::queries::channel_end::QueryChannelEndOnSovereign; +use crate::impls::queries::client_state::QueryClientStateOnSovereign; +use crate::impls::queries::connection_end::QueryConnectionEndOnSovereign; +use crate::impls::queries::consensus_state::QueryConsensusStateOnSovereign; +use crate::impls::queries::consensus_state_height::QueryConsensusStateHeightsOnSovereign; +use crate::impls::queries::packet_acknowledgement::QueryPacketAcknowledgementFromSovereign; +use crate::impls::queries::packet_commitment::QueryPacketCommitmentFromSovereign; +use crate::impls::queries::packet_receipt::QueryPacketReceiptFromSovereign; +use crate::impls::send_message::SendMessagesInSequence; +use crate::impls::transaction::encode_tx::EncodeSovereignTx; +use crate::impls::transaction::estimate_fee::ReturnSovereignTxFee; +use crate::impls::transaction::event::ParseSovTxResponseAsEvents; +use crate::impls::transaction::query_nonce::QuerySovereignNonce; +use crate::impls::transaction::query_tx_response::QuerySovereignTxResponse; +use crate::impls::transaction::submit_tx::SubmitSovereignTransaction; +use crate::impls::types::client_state::ProvideSovereignClientState; +use crate::impls::types::consensus_state::ProvideSovereignConsensusState; +use crate::impls::types::payload::ProvideSovereignRollupPayloadTypes; +use crate::impls::types::rollup::ProvideSovereignRollupTypes; +use crate::impls::types::transaction::ProvideSovereignTransactionTypes; +use crate::traits::json_rpc_client::JsonRpcClientTypeComponent; + +pub struct SovereignRollupClientComponents; + +delegate_components! { + #[mark_component(IsSovereignRollupClientComponent)] + SovereignRollupClientComponents { + [ + HeightTypeComponent, + HeightFieldComponent, + HeightIncrementerComponent, + TimestampTypeComponent, + ChainIdTypeComponent, + MessageTypeComponent, + EventTypeComponent, + IbcChainTypesComponent, + IbcPacketTypesProviderComponent, + ChainStatusTypeComponent, + CommitmentPrefixTypeComponent, + CommitmentProofTypeComponent, + PacketCommitmentTypeComponent, + AcknowledgementTypeComponent, + PacketReceiptTypeComponent, + ConnectionEndTypeComponent, + ChannelEndTypeComponent, + ]: + ProvideSovereignRollupTypes, + [ + ClientStateTypeComponent, + ClientStateFieldsGetterComponent, + ]: + ProvideSovereignClientState, + ConsensusStateTypeComponent: + ProvideSovereignConsensusState, + [ + CreateClientEventComponent, + ConnectionOpenInitEventComponent, + ConnectionOpenTryEventComponent, + ChannelOpenInitEventComponent, + ChannelOpenTryEventComponent, + SendPacketEventComponent, + WriteAckEventComponent, + ]: + ProvideSovereignEvents, + [ + CreateClientPayloadOptionsTypeComponent, + CreateClientMessageOptionsTypeComponent, + CreateClientPayloadTypeComponent, + UpdateClientPayloadTypeComponent, + InitConnectionOptionsTypeComponent, + + ConnectionOpenInitPayloadTypeComponent, + ConnectionOpenTryPayloadTypeComponent, + ConnectionOpenAckPayloadTypeComponent, + ConnectionOpenConfirmPayloadTypeComponent, + + InitChannelOptionsTypeComponent, + ChannelOpenTryPayloadTypeComponent, + ChannelOpenAckPayloadTypeComponent, + ChannelOpenConfirmPayloadTypeComponent, + ]: + ProvideSovereignRollupPayloadTypes, + [ + TransactionTypeComponent, + NonceTypeComponent, + FeeTypeComponent, + SignerTypeComponent, + TransactionHashTypeComponent, + TxResponseTypeComponent, + NonceGuardComponent, + ]: + ProvideSovereignTransactionTypes, + [ + NonceAllocatorComponent, + MessagesWithSignerSenderComponent, + MessagesWithSignerAndNonceSenderComponent, + TxResponsePollerComponent, + ]: + DefaultTxComponents, + MessageSenderComponent: + SendMessagesInSequence, + IbcCommitmentPrefixGetterComponent: + ProvideSovereignIbcCommitmentPrefix, + JsonRpcClientTypeComponent: + ProvideJsonRpseeClient, + TxResponseQuerierComponent: + QuerySovereignTxResponse, + PollTimeoutGetterComponent: + DefaultPollTimeout, + TxResponseAsEventsParserComponent: + ParseSovTxResponseAsEvents, + TxEncoderComponent: + EncodeSovereignTx, + [ + TxFeeEstimatorComponent, + FeeForSimulationGetterComponent, + ]: + ReturnSovereignTxFee<10_000>, + TxSubmitterComponent: + SubmitSovereignTransaction, + NonceQuerierComponent: + QuerySovereignNonce, + CreateClientMessageBuilderComponent: + BuildCreateCosmosClientMessageOnSovereign, + UpdateClientMessageBuilderComponent: + BuildUpdateCosmosClientMessageOnSovereign, + ChainStatusQuerierComponent: + QuerySovereignRollupStatus, + RawClientStateTypeComponent: + ProvideAnyRawClientState, + [ + RawClientStateQuerierComponent, + RawClientStateWithProofsQuerierComponent, + ]: + QueryClientStateOnSovereign, + [ + ClientStateQuerierComponent, + ClientStateWithProofsQuerierComponent, + ]: + QueryAndConvertRawClientState, + RawConsensusStateTypeComponent: + ProvideAnyRawConsensusState, + [ + RawConsensusStateQuerierComponent, + RawConsensusStateWithProofsQuerierComponent, + ]: + QueryConsensusStateOnSovereign, + [ + ConsensusStateQuerierComponent, + ConsensusStateWithProofsQuerierComponent, + ]: + QueryAndConvertRawConsensusState, + [ + ConnectionEndQuerierComponent, + ConnectionEndWithProofsQuerierComponent, + ]: + QueryConnectionEndOnSovereign, + [ + ChannelEndQuerierComponent, + ChannelEndWithProofsQuerierComponent, + ]: + QueryChannelEndOnSovereign, + PacketCommitmentQuerierComponent: + QueryPacketCommitmentFromSovereign, + PacketAcknowledgementQuerierComponent: + QueryPacketAcknowledgementFromSovereign, + PacketReceiptQuerierComponent: + QueryPacketReceiptFromSovereign, + ConsensusStateHeightsQuerierComponent: + QueryConsensusStateHeightsOnSovereign, + ConsensusStateHeightQuerierComponent: + QueryConsensusStateHeightsAndFindHeightBefore, + + [ + ConnectionOpenInitMessageBuilderComponent, + ConnectionOpenTryMessageBuilderComponent, + ConnectionOpenAckMessageBuilderComponent, + ConnectionOpenConfirmMessageBuilderComponent, + ]: + BuildCosmosConnectionHandshakeMessage, + [ + ChannelOpenInitMessageBuilderComponent, + ChannelOpenTryMessageBuilderComponent, + ChannelOpenAckMessageBuilderComponent, + ChannelOpenConfirmMessageBuilderComponent, + ]: + BuildCosmosChannelHandshakeMessage, + + [ + ReceivePacketMessageBuilderComponent, + AckPacketMessageBuilderComponent, + TimeoutUnorderedPacketMessageBuilderComponent, + ]: + BuildCosmosPacketMessages, + + CounterpartyMessageHeightGetterComponent: + GetCosmosHeightFromSovereignMessage, + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/borsh_encode.rs b/crates/relayer/sovereign-rollup-components/src/impls/borsh_encode.rs new file mode 100644 index 00000000..8718edb2 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/borsh_encode.rs @@ -0,0 +1,35 @@ +use std::io::Error as IoError; + +use borsh::{BorshDeserialize, BorshSerialize}; +use cgp_core::CanRaiseError; +use hermes_encoding_components::traits::decoder::Decoder; +use hermes_encoding_components::traits::encoded::HasEncodedType; +use hermes_encoding_components::traits::encoder::Encoder; + +pub struct ViaBorsh; + +pub struct EncodeWithBorsh; + +impl Encoder for EncodeWithBorsh +where + Encoding: HasEncodedType> + CanRaiseError, + Value: BorshSerialize, +{ + fn encode(_encoding: &Encoding, value: &Value) -> Result, Encoding::Error> { + let encoded = value.try_to_vec().map_err(Encoding::raise_error)?; + + Ok(encoded) + } +} + +impl Decoder for EncodeWithBorsh +where + Encoding: HasEncodedType> + CanRaiseError, + Value: BorshDeserialize, +{ + fn decode(_encoding: &Encoding, encoded: &Vec) -> Result { + let value = Value::try_from_slice(encoded).map_err(Encoding::raise_error)?; + + Ok(value) + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/commitment_prefix.rs b/crates/relayer/sovereign-rollup-components/src/impls/commitment_prefix.rs new file mode 100644 index 00000000..a9d96ca0 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/commitment_prefix.rs @@ -0,0 +1,19 @@ +use alloc::vec::Vec; +use std::sync::OnceLock; + +use hermes_relayer_components::chain::traits::commitment_prefix::{ + HasCommitmentPrefixType, IbcCommitmentPrefixGetter, +}; + +pub struct ProvideSovereignIbcCommitmentPrefix; + +impl IbcCommitmentPrefixGetter for ProvideSovereignIbcCommitmentPrefix +where + Chain: HasCommitmentPrefixType>, +{ + fn ibc_commitment_prefix(_chain: &Chain) -> &Vec { + static IBC_COMMITMENT_PREFIX: OnceLock> = OnceLock::new(); + + IBC_COMMITMENT_PREFIX.get_or_init(|| "sov_ibc/Ibc/".into()) + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/cosmos_to_sovereign/client/create_client_message.rs b/crates/relayer/sovereign-rollup-components/src/impls/cosmos_to_sovereign/client/create_client_message.rs new file mode 100644 index 00000000..80af90bc --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/cosmos_to_sovereign/client/create_client_message.rs @@ -0,0 +1,66 @@ +use cgp_core::CanRaiseError; +use hermes_cosmos_chain_components::methods::encode::encode_to_any; +use hermes_cosmos_chain_components::types::messages::client::create::{ + ProtoMsgCreateClient, TYPE_URL, +}; +use hermes_cosmos_chain_components::types::payloads::client::CosmosCreateClientPayload; +use hermes_cosmos_chain_components::types::tendermint::{ + TendermintClientState, TendermintConsensusState, +}; +use hermes_encoding_components::traits::convert::CanConvert; +use hermes_encoding_components::traits::has_encoding::HasEncoding; +use hermes_protobuf_encoding_components::types::Any; +use hermes_relayer_components::chain::traits::message_builders::create_client::CreateClientMessageBuilder; +use hermes_relayer_components::chain::traits::types::create_client::{ + HasCreateClientMessageOptionsType, HasCreateClientPayloadType, +}; +use hermes_relayer_components::chain::traits::types::message::HasMessageType; +use ibc_relayer_types::signer::Signer; + +use crate::types::message::SovereignMessage; +use crate::types::messages::ibc::IbcMessageWithHeight; + +/** + Build a message to create a Cosmos client on a Sovereign rollup +*/ +pub struct BuildCreateCosmosClientMessageOnSovereign; + +impl CreateClientMessageBuilder + for BuildCreateCosmosClientMessageOnSovereign +where + Chain: HasMessageType + + HasCreateClientMessageOptionsType + + HasEncoding + + CanRaiseError, + Counterparty: + HasCreateClientPayloadType, + Encoding: CanConvert + CanConvert, +{ + async fn build_create_client_message( + chain: &Chain, + _options: &Chain::CreateClientMessageOptions, + payload: CosmosCreateClientPayload, + ) -> Result { + let encoding = chain.encoding(); + + let client_state = encoding + .convert(&payload.client_state) + .map_err(Chain::raise_error)?; + + let consensus_state = encoding + .convert(&payload.consensus_state) + .map_err(Chain::raise_error)?; + + let proto_message = ProtoMsgCreateClient { + client_state: Some(client_state), + consensus_state: Some(consensus_state), + signer: Signer::dummy().to_string(), + }; + + let any_message = encode_to_any(TYPE_URL, &proto_message); + + let message = IbcMessageWithHeight::new(any_message, None).into(); + + Ok(message) + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/cosmos_to_sovereign/client/mod.rs b/crates/relayer/sovereign-rollup-components/src/impls/cosmos_to_sovereign/client/mod.rs new file mode 100644 index 00000000..6a99c0f1 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/cosmos_to_sovereign/client/mod.rs @@ -0,0 +1,2 @@ +pub mod create_client_message; +pub mod update_client_message; diff --git a/crates/relayer/sovereign-rollup-components/src/impls/cosmos_to_sovereign/client/update_client_message.rs b/crates/relayer/sovereign-rollup-components/src/impls/cosmos_to_sovereign/client/update_client_message.rs new file mode 100644 index 00000000..dbdbb0e3 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/cosmos_to_sovereign/client/update_client_message.rs @@ -0,0 +1,55 @@ +use cgp_core::prelude::HasErrorType; +use hermes_cosmos_chain_components::methods::encode::encode_to_any; +use hermes_cosmos_chain_components::types::messages::client::update::{ + ProtoMsgUpdateClient, TYPE_URL, +}; +use hermes_cosmos_chain_components::types::payloads::client::CosmosUpdateClientPayload; +use hermes_cosmos_chain_components::types::tendermint::TendermintHeader; +use hermes_relayer_components::chain::traits::message_builders::update_client::UpdateClientMessageBuilder; +use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; +use hermes_relayer_components::chain::traits::types::update_client::HasUpdateClientPayloadType; +use ibc_relayer_types::core::ics24_host::identifier::ClientId; +use ibc_relayer_types::signer::Signer; + +use crate::types::message::SovereignMessage; +use crate::types::messages::ibc::IbcMessageWithHeight; + +pub struct BuildUpdateCosmosClientMessageOnSovereign; + +impl UpdateClientMessageBuilder + for BuildUpdateCosmosClientMessageOnSovereign +where + Chain: HasIbcChainTypes + + HasErrorType, + Counterparty: + HasUpdateClientPayloadType, +{ + async fn build_update_client_message( + _chain: &Chain, + client_id: &ClientId, + payload: CosmosUpdateClientPayload, + ) -> Result, Chain::Error> { + let messages = payload + .headers + .into_iter() + .map(|header| encode_tendermint_header(client_id, header)) + .collect(); + + Ok(messages) + } +} + +pub fn encode_tendermint_header( + client_id: &ClientId, + header: TendermintHeader, +) -> SovereignMessage { + let proto_message = ProtoMsgUpdateClient { + client_id: client_id.to_string(), + client_message: Some(header.into()), + signer: Signer::dummy().to_string(), + }; + + let any_message = encode_to_any(TYPE_URL, &proto_message); + + IbcMessageWithHeight::new(any_message, None).into() +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/cosmos_to_sovereign/mod.rs b/crates/relayer/sovereign-rollup-components/src/impls/cosmos_to_sovereign/mod.rs new file mode 100644 index 00000000..b9babe5b --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/cosmos_to_sovereign/mod.rs @@ -0,0 +1 @@ +pub mod client; diff --git a/crates/relayer/sovereign-rollup-components/src/impls/errors/mod.rs b/crates/relayer/sovereign-rollup-components/src/impls/errors/mod.rs new file mode 100644 index 00000000..9526f6ed --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/errors/mod.rs @@ -0,0 +1 @@ +pub mod multi_message_unsupported; diff --git a/crates/relayer/sovereign-rollup-components/src/impls/errors/multi_message_unsupported.rs b/crates/relayer/sovereign-rollup-components/src/impls/errors/multi_message_unsupported.rs new file mode 100644 index 00000000..870f4ccb --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/errors/multi_message_unsupported.rs @@ -0,0 +1,43 @@ +use core::fmt::Debug; + +use hermes_relayer_components::chain::traits::types::message::HasMessageType; + +/** + Sovereign SDK currently only supports sending one message per transaction. + However it will eventually support sending multiple messages per transaction + in the future. + + The existing transaction interfaces and abstract implementations assume the + ability to send multiple messages per transaction. Although there are + workarounds such as defining new components, we would avoid that since + such effort would be wasted once Sovereign SDK supports multi-message + transaction. + + It is also not possible to wrap multiple concrete transactions and + pretend that they are a single transaction. This is because doing so + would result in different semantics as compared to a real transaction, + which is that all messages either succeed or fail atomically. + + For the short term, we rely on dynamically raising this error, if the + transaction context receives multiple messages. We then define a + middleware component that splits incoming messages and submit them + as individual transactions. +*/ +pub struct MultiMessageUnsupportedError<'a, Chain> +where + Chain: HasMessageType, +{ + pub messages: &'a [Chain::Message], +} + +impl<'a, Chain> Debug for MultiMessageUnsupportedError<'a, Chain> +where + Chain: HasMessageType, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, + "Sovereign rollups currently only support sending exactly one message per transaction, however {} messages are provided", + self.messages.len() + ) + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/events.rs b/crates/relayer/sovereign-rollup-components/src/impls/events.rs new file mode 100644 index 00000000..a89102b6 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/events.rs @@ -0,0 +1,212 @@ +use hermes_cosmos_chain_components::types::events::client::CosmosCreateClientEvent; +use hermes_relayer_components::chain::traits::types::create_client::ProvideCreateClientEvent; +use hermes_relayer_components::chain::traits::types::event::HasEventType; +use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; +use hermes_relayer_components::chain::traits::types::ibc_events::channel::{ + ProvideChannelOpenInitEvent, ProvideChannelOpenTryEvent, +}; +use hermes_relayer_components::chain::traits::types::ibc_events::connection::{ + ProvideConnectionOpenInitEvent, ProvideConnectionOpenTryEvent, +}; +use hermes_relayer_components::chain::traits::types::ibc_events::send_packet::ProvideSendPacketEvent; +use hermes_relayer_components::chain::traits::types::ibc_events::write_ack::ProvideWriteAckEvent; +use hermes_relayer_components::chain::traits::types::packet::HasIbcPacketTypes; +use hermes_relayer_components::chain::traits::types::packets::ack::HasAcknowledgementType; +use ibc_relayer_types::core::ics04_channel::packet::Packet; +use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId}; +use serde_json::Value; + +use crate::types::event::SovereignEvent; + +pub struct ProvideSovereignEvents; + +impl ProvideCreateClientEvent for ProvideSovereignEvents +where + Chain: HasIbcChainTypes, +{ + type CreateClientEvent = CosmosCreateClientEvent; + + fn try_extract_create_client_event(event: SovereignEvent) -> Option { + if event.module_name != "ibc" { + return None; + } + + let create_client_event_json = event.event_value.get("CreateClient")?; + + let client_id_value = create_client_event_json + .get("client_id")? + .get("client_id")?; + + if let Value::String(client_id_str) = client_id_value { + let client_id = client_id_str.parse().ok()?; + Some(CosmosCreateClientEvent { client_id }) + } else { + None + } + } + + fn create_client_event_client_id(event: &CosmosCreateClientEvent) -> &ClientId { + &event.client_id + } +} + +impl ProvideConnectionOpenInitEvent + for ProvideSovereignEvents +where + Chain: HasIbcChainTypes, +{ + type ConnectionOpenInitEvent = ConnectionId; + + fn try_extract_connection_open_init_event(event: SovereignEvent) -> Option { + if event.module_name != "ibc" { + return None; + } + + let event_json = event.event_value.get("OpenInitConnection")?; + + let connection_id_value = event_json.get("connection_id")?; + + if let Value::String(connection_id_str) = connection_id_value { + let connection_id = connection_id_str.parse().ok()?; + Some(connection_id) + } else { + None + } + } + + fn connection_open_init_event_connection_id(connection_id: &ConnectionId) -> &ConnectionId { + connection_id + } +} + +impl ProvideConnectionOpenTryEvent + for ProvideSovereignEvents +where + Chain: HasIbcChainTypes, +{ + type ConnectionOpenTryEvent = ConnectionId; + + fn try_extract_connection_open_try_event(event: SovereignEvent) -> Option { + if event.module_name != "ibc" { + return None; + } + + let event_json = event.event_value.get("OpenTryConnection")?; + + let connection_id_value = event_json.get("connection_id")?; + + if let Value::String(connection_id_str) = connection_id_value { + let connection_id = connection_id_str.parse().ok()?; + Some(connection_id) + } else { + None + } + } + + fn connection_open_try_event_connection_id(connection_id: &ConnectionId) -> &ConnectionId { + connection_id + } +} + +impl ProvideChannelOpenInitEvent + for ProvideSovereignEvents +where + Chain: HasIbcChainTypes, +{ + type ChannelOpenInitEvent = ChannelId; + + fn try_extract_channel_open_init_event(event: SovereignEvent) -> Option { + if event.module_name != "ibc" { + return None; + } + + let event_json = event.event_value.get("OpenInitChannel")?; + + let channel_id_value = event_json.get("chan_id_attr_on_a")?.get("channel_id")?; + + if let Value::String(channel_id_str) = channel_id_value { + let channel_id = channel_id_str.parse().ok()?; + Some(channel_id) + } else { + None + } + } + + fn channel_open_init_event_channel_id(channel_id: &ChannelId) -> &ChannelId { + channel_id + } +} + +impl ProvideChannelOpenTryEvent for ProvideSovereignEvents +where + Chain: HasIbcChainTypes, +{ + type ChannelOpenTryEvent = ChannelId; + + fn try_extract_channel_open_try_event(event: SovereignEvent) -> Option { + if event.module_name != "ibc" { + return None; + } + + let event_json = event.event_value.get("OpenTryChannel")?; + + let channel_id_value = event_json.get("chan_id_attr_on_b")?.get("channel_id")?; + + if let Value::String(channel_id_str) = channel_id_value { + let channel_id = channel_id_str.parse().ok()?; + Some(channel_id) + } else { + None + } + } + + fn channel_open_try_event_channel_id(channel_id: &ChannelId) -> &ChannelId { + channel_id + } +} + +impl ProvideSendPacketEvent for ProvideSovereignEvents +where + Chain: HasEventType + + HasIbcPacketTypes, +{ + type SendPacketEvent = Packet; + + fn try_extract_send_packet_event(event: &SovereignEvent) -> Option { + if event.module_name != "ibc" { + return None; + } + + println!("try extract send packet event: {:?}", event); + + // TODO + None + } + + fn extract_packet_from_send_packet_event(packet: &Packet) -> Packet { + packet.clone() + } +} + +impl ProvideWriteAckEvent for ProvideSovereignEvents +where + Chain: HasEventType + + HasAcknowledgementType>, +{ + type WriteAckEvent = Vec; + + fn try_extract_write_ack_event(event: &SovereignEvent) -> Option> { + if event.module_name != "ibc" { + return None; + } + + println!("try extract send packet event: {:?}", event); + + // TODO + None + } + + fn write_acknowledgement(ack: &Vec) -> &Vec { + ack + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/json_rpc_client.rs b/crates/relayer/sovereign-rollup-components/src/impls/json_rpc_client.rs new file mode 100644 index 00000000..65879990 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/json_rpc_client.rs @@ -0,0 +1,13 @@ +use cgp_core::Async; +use jsonrpsee::http_client::HttpClient; + +use crate::traits::json_rpc_client::ProvideJsonRpcClientType; + +pub struct ProvideJsonRpseeClient; + +impl ProvideJsonRpcClientType for ProvideJsonRpseeClient +where + Rollup: Async, +{ + type JsonRpcClient = HttpClient; +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/message_height.rs b/crates/relayer/sovereign-rollup-components/src/impls/message_height.rs new file mode 100644 index 00000000..913bb454 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/message_height.rs @@ -0,0 +1,26 @@ +use hermes_relayer_components::chain::traits::types::height::HasHeightType; +use hermes_relayer_components::chain::traits::types::ibc::CounterpartyMessageHeightGetter; +use hermes_relayer_components::chain::traits::types::message::HasMessageType; +use ibc_relayer_types::Height; + +use crate::types::message::SovereignMessage; +use crate::types::messages::ibc::IbcMessage; + +pub struct GetCosmosHeightFromSovereignMessage; + +impl CounterpartyMessageHeightGetter + for GetCosmosHeightFromSovereignMessage +where + Chain: HasMessageType, + Counterparty: HasHeightType, +{ + fn counterparty_message_height_for_update_client(message: &SovereignMessage) -> Option { + match message { + SovereignMessage::Ibc(IbcMessage::Core(message)) => message.counterparty_height, + SovereignMessage::Ibc(IbcMessage::Transfer(message)) => { + Some(message.counterparty_height) + } + _ => None, + } + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/mod.rs b/crates/relayer/sovereign-rollup-components/src/impls/mod.rs new file mode 100644 index 00000000..37e1b27c --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/mod.rs @@ -0,0 +1,11 @@ +pub mod borsh_encode; +pub mod commitment_prefix; +pub mod cosmos_to_sovereign; +pub mod errors; +pub mod events; +pub mod json_rpc_client; +pub mod message_height; +pub mod queries; +pub mod send_message; +pub mod transaction; +pub mod types; diff --git a/crates/relayer/sovereign-rollup-components/src/impls/queries/chain_status.rs b/crates/relayer/sovereign-rollup-components/src/impls/queries/chain_status.rs new file mode 100644 index 00000000..3b3aaffe --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/queries/chain_status.rs @@ -0,0 +1,45 @@ +use cgp_core::CanRaiseError; +use hermes_relayer_components::chain::traits::queries::chain_status::ChainStatusQuerier; +use hermes_relayer_components::chain::traits::types::status::HasChainStatusType; +use ibc_relayer_types::timestamp::Timestamp; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::params::ArrayParams; +use jsonrpsee::core::ClientError; +use serde::Deserialize; + +use crate::traits::json_rpc_client::HasJsonRpcClient; +use crate::types::height::RollupHeight; +use crate::types::status::SovereignRollupStatus; + +pub struct QuerySovereignRollupStatus; + +impl ChainStatusQuerier for QuerySovereignRollupStatus +where + Rollup: HasChainStatusType + + HasJsonRpcClient + + CanRaiseError, + Rollup::JsonRpcClient: ClientT, +{ + async fn query_chain_status(rollup: &Rollup) -> Result { + let response: SlotResponse = rollup + .json_rpc_client() + .request("ledger_getHead", ArrayParams::new()) + .await + .map_err(Rollup::raise_error)?; + + let height = RollupHeight { + slot_number: response.number, + }; + + // FIXME: use the relayer's local timestamp for now, as it is currently not possible + // to query the remote time from the rollup. + let timestamp = Timestamp::now(); + + Ok(SovereignRollupStatus { height, timestamp }) + } +} + +#[derive(Deserialize)] +pub struct SlotResponse { + pub number: u64, +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/queries/channel_end.rs b/crates/relayer/sovereign-rollup-components/src/impls/queries/channel_end.rs new file mode 100644 index 00000000..72dc7dd3 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/queries/channel_end.rs @@ -0,0 +1,129 @@ +use cgp_core::CanRaiseError; +use hermes_encoding_components::traits::decoder::CanDecode; +use hermes_encoding_components::traits::encoded::HasEncodedType; +use hermes_encoding_components::traits::has_encoding::HasEncoding; +use hermes_relayer_components::chain::traits::queries::channel_end::{ + ChannelEndQuerier, ChannelEndWithProofsQuerier, +}; +use hermes_relayer_components::chain::traits::types::channel::HasChannelEndType; +use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; +use hermes_relayer_components::chain::traits::types::proof::HasCommitmentProofType; +use ibc::core::channel::types::channel::ChannelEnd; +use ibc_query::core::channel::QueryChannelResponse; +use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, PortId}; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::ClientError; +use serde::Serialize; + +use crate::impls::borsh_encode::ViaBorsh; +use crate::traits::json_rpc_client::HasJsonRpcClient; +use crate::types::commitment_proof::{JellyfishMerkleProof, SovereignCommitmentProof}; +use crate::types::height::RollupHeight; +use crate::types::rpc::height::HeightParam; + +pub struct QueryChannelEndOnSovereign; + +impl ChannelEndQuerier for QueryChannelEndOnSovereign +where + Rollup: HasChannelEndType + + HasIbcChainTypes< + Counterparty, + Height = RollupHeight, + ChannelId = ChannelId, + PortId = PortId, + > + HasJsonRpcClient + + CanRaiseError, + Rollup::JsonRpcClient: ClientT, +{ + async fn query_channel_end( + rollup: &Rollup, + channel_id: &Rollup::ChannelId, + port_id: &Rollup::PortId, + height: &Rollup::Height, + ) -> Result { + let request = Request { + channel_id: channel_id.as_ref(), + port_id: port_id.as_ref(), + query_height: &(&RollupHeight { + slot_number: height.slot_number, + }) + .into(), + }; + + let response: QueryChannelResponse = rollup + .json_rpc_client() + .request("ibc_channel", (request,)) + .await + .map_err(Rollup::raise_error)?; + + Ok(response.channel) + } +} + +impl ChannelEndWithProofsQuerier + for QueryChannelEndOnSovereign +where + Rollup: HasChannelEndType + + HasIbcChainTypes< + Counterparty, + Height = RollupHeight, + ChannelId = ChannelId, + PortId = PortId, + > + HasCommitmentProofType + + HasJsonRpcClient + + HasEncoding + + CanRaiseError + + CanRaiseError, + Rollup::JsonRpcClient: ClientT, + Encoding: HasEncodedType> + CanDecode, +{ + async fn query_channel_end_with_proofs( + rollup: &Rollup, + channel_id: &Rollup::ChannelId, + port_id: &Rollup::PortId, + height: &Rollup::Height, + ) -> Result<(Rollup::ChannelEnd, SovereignCommitmentProof), Rollup::Error> { + let request = Request { + channel_id: channel_id.as_ref(), + port_id: port_id.as_ref(), + query_height: &(&RollupHeight { + slot_number: height.slot_number, + }) + .into(), + }; + + let response: QueryChannelResponse = rollup + .json_rpc_client() + .request("ibc_channel", (request,)) + .await + .map_err(Rollup::raise_error)?; + + let channel_end = response.channel; + + let proof_bytes = response.proof; + + let merkle_proof = rollup + .encoding() + .decode(&proof_bytes) + .map_err(Rollup::raise_error)?; + + let proof_height = RollupHeight { + slot_number: response.proof_height.revision_height(), + }; + + let commitment_proof = SovereignCommitmentProof { + proof_bytes, + merkle_proof, + proof_height, + }; + + Ok((channel_end, commitment_proof)) + } +} + +#[derive(Serialize)] +pub struct Request<'a> { + pub channel_id: &'a str, + pub port_id: &'a str, + pub query_height: &'a HeightParam, +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/queries/client_state.rs b/crates/relayer/sovereign-rollup-components/src/impls/queries/client_state.rs new file mode 100644 index 00000000..190c3eaa --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/queries/client_state.rs @@ -0,0 +1,123 @@ +use cgp_core::CanRaiseError; +use hermes_encoding_components::traits::decoder::CanDecode; +use hermes_encoding_components::traits::encoded::HasEncodedType; +use hermes_encoding_components::traits::has_encoding::HasEncoding; +use hermes_protobuf_encoding_components::types::Any; +use hermes_relayer_components::chain::traits::queries::client_state::{ + RawClientStateQuerier, RawClientStateWithProofsQuerier, +}; +use hermes_relayer_components::chain::traits::types::client_state::HasRawClientStateType; +use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; +use hermes_relayer_components::chain::traits::types::proof::HasCommitmentProofType; +use ibc_query::core::client::QueryClientStateResponse; +use ibc_relayer_types::core::ics24_host::identifier::ClientId; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::ClientError; +use serde::Serialize; + +use crate::impls::borsh_encode::ViaBorsh; +use crate::traits::json_rpc_client::HasJsonRpcClient; +use crate::types::commitment_proof::{JellyfishMerkleProof, SovereignCommitmentProof}; +use crate::types::height::RollupHeight; +use crate::types::rpc::height::HeightParam; + +pub struct QueryClientStateOnSovereign; + +impl RawClientStateQuerier + for QueryClientStateOnSovereign +where + Rollup: HasIbcChainTypes + + HasRawClientStateType + + HasJsonRpcClient + + CanRaiseError, + Rollup::JsonRpcClient: ClientT, +{ + async fn query_raw_client_state( + rollup: &Rollup, + client_id: &ClientId, + height: &RollupHeight, + ) -> Result { + let request = Request { + client_id: client_id.as_str(), + query_height: &(&RollupHeight { + slot_number: height.slot_number, + }) + .into(), + }; + + let response: QueryClientStateResponse = rollup + .json_rpc_client() + .request("ibc_clientState", (request,)) + .await + .map_err(Rollup::raise_error)?; + + Ok(Any { + type_url: response.client_state.type_url, + value: response.client_state.value, + }) + } +} + +impl RawClientStateWithProofsQuerier + for QueryClientStateOnSovereign +where + Rollup: HasIbcChainTypes + + HasRawClientStateType + + HasCommitmentProofType + + HasJsonRpcClient + + HasEncoding + + CanRaiseError + + CanRaiseError, + Rollup::JsonRpcClient: ClientT, + Encoding: HasEncodedType> + CanDecode, +{ + async fn query_raw_client_state_with_proofs( + rollup: &Rollup, + client_id: &ClientId, + query_height: &RollupHeight, + ) -> Result<(Any, SovereignCommitmentProof), Rollup::Error> { + let request = Request { + client_id: client_id.as_str(), + query_height: &HeightParam { + revision_number: 0, + revision_height: query_height.slot_number, + }, + }; + + let response: QueryClientStateResponse = rollup + .json_rpc_client() + .request("ibc_clientState", (request,)) + .await + .map_err(Rollup::raise_error)?; + + let client_state_any = Any { + type_url: response.client_state.type_url, + value: response.client_state.value, + }; + + let proof_bytes = response.proof; + + let merkle_proof = rollup + .encoding() + .decode(&proof_bytes) + .map_err(Rollup::raise_error)?; + + let proof_height = RollupHeight { + slot_number: response.proof_height.revision_height(), + }; + + let commitment_proof = SovereignCommitmentProof { + proof_bytes, + merkle_proof, + proof_height, + }; + + Ok((client_state_any, commitment_proof)) + } +} + +#[derive(Serialize)] +pub struct Request<'a> { + pub client_id: &'a str, + pub query_height: &'a HeightParam, +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/queries/connection_end.rs b/crates/relayer/sovereign-rollup-components/src/impls/queries/connection_end.rs new file mode 100644 index 00000000..70922a67 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/queries/connection_end.rs @@ -0,0 +1,116 @@ +use cgp_core::CanRaiseError; +use hermes_encoding_components::traits::decoder::CanDecode; +use hermes_encoding_components::traits::encoded::HasEncodedType; +use hermes_encoding_components::traits::has_encoding::HasEncoding; +use hermes_relayer_components::chain::traits::queries::connection_end::{ + ConnectionEndQuerier, ConnectionEndWithProofsQuerier, +}; +use hermes_relayer_components::chain::traits::types::connection::HasConnectionEndType; +use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; +use hermes_relayer_components::chain::traits::types::proof::HasCommitmentProofType; +use ibc::core::connection::types::ConnectionEnd; +use ibc_query::core::connection::QueryConnectionResponse; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::ClientError; +use serde::Serialize; + +use crate::impls::borsh_encode::ViaBorsh; +use crate::traits::json_rpc_client::HasJsonRpcClient; +use crate::types::commitment_proof::{JellyfishMerkleProof, SovereignCommitmentProof}; +use crate::types::height::RollupHeight; +use crate::types::rpc::height::HeightParam; + +pub struct QueryConnectionEndOnSovereign; + +impl ConnectionEndQuerier + for QueryConnectionEndOnSovereign +where + Rollup: HasConnectionEndType + + HasIbcChainTypes + + HasJsonRpcClient + + CanRaiseError, + Rollup::JsonRpcClient: ClientT, +{ + async fn query_connection_end( + rollup: &Rollup, + connection_id: &Rollup::ConnectionId, + height: &Rollup::Height, + ) -> Result { + let request = Request { + connection_id: &connection_id.to_string(), + query_height: &(&RollupHeight { + slot_number: height.slot_number, + }) + .into(), + }; + + let response: QueryConnectionResponse = rollup + .json_rpc_client() + .request("ibc_connection", (request,)) + .await + .map_err(Rollup::raise_error)?; + + Ok(response.conn_end) + } +} + +impl ConnectionEndWithProofsQuerier + for QueryConnectionEndOnSovereign +where + Rollup: HasConnectionEndType + + HasIbcChainTypes + + HasCommitmentProofType + + HasJsonRpcClient + + HasEncoding + + CanRaiseError + + CanRaiseError, + Rollup::JsonRpcClient: ClientT, + Encoding: HasEncodedType> + CanDecode, +{ + async fn query_connection_end_with_proofs( + rollup: &Rollup, + connection_id: &Rollup::ConnectionId, + query_height: &Rollup::Height, + ) -> Result<(Rollup::ConnectionEnd, SovereignCommitmentProof), Rollup::Error> { + let request = Request { + connection_id: &connection_id.to_string(), + query_height: &HeightParam { + revision_number: 0, + revision_height: query_height.slot_number, + }, + }; + + let response: QueryConnectionResponse = rollup + .json_rpc_client() + .request("ibc_connection", (request,)) + .await + .map_err(Rollup::raise_error)?; + + let connection_end = response.conn_end; + + let proof_bytes = response.proof; + + let merkle_proof = rollup + .encoding() + .decode(&proof_bytes) + .map_err(Rollup::raise_error)?; + + let proof_height = RollupHeight { + slot_number: response.proof_height.revision_height(), + }; + + let commitment_proof = SovereignCommitmentProof { + proof_bytes, + merkle_proof, + proof_height, + }; + + Ok((connection_end, commitment_proof)) + } +} + +#[derive(Serialize)] +pub struct Request<'a> { + pub connection_id: &'a str, + pub query_height: &'a HeightParam, +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/queries/consensus_state.rs b/crates/relayer/sovereign-rollup-components/src/impls/queries/consensus_state.rs new file mode 100644 index 00000000..a34a3975 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/queries/consensus_state.rs @@ -0,0 +1,143 @@ +use cgp_core::CanRaiseError; +use hermes_encoding_components::traits::decoder::CanDecode; +use hermes_encoding_components::traits::encoded::HasEncodedType; +use hermes_encoding_components::traits::has_encoding::HasEncoding; +use hermes_protobuf_encoding_components::types::Any; +use hermes_relayer_components::chain::traits::queries::consensus_state::{ + RawConsensusStateQuerier, RawConsensusStateWithProofsQuerier, +}; +use hermes_relayer_components::chain::traits::types::consensus_state::HasRawConsensusStateType; +use hermes_relayer_components::chain::traits::types::height::HasHeightFields; +use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; +use hermes_relayer_components::chain::traits::types::proof::HasCommitmentProofType; +use ibc::core::client::types::error::ClientError as Ics02Error; +use ibc::core::host::types::error::IdentifierError; +use ibc_query::core::client::QueryConsensusStateResponse; +use ibc_relayer_types::core::ics24_host::identifier::ClientId; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::ClientError; +use serde::Serialize; + +use crate::impls::borsh_encode::ViaBorsh; +use crate::traits::json_rpc_client::HasJsonRpcClient; +use crate::types::commitment_proof::{JellyfishMerkleProof, SovereignCommitmentProof}; +use crate::types::height::RollupHeight; +use crate::types::rpc::height::HeightParam; + +pub struct QueryConsensusStateOnSovereign; + +impl RawConsensusStateQuerier + for QueryConsensusStateOnSovereign +where + Rollup: HasIbcChainTypes + + HasRawConsensusStateType + + HasJsonRpcClient + + CanRaiseError + + CanRaiseError + + CanRaiseError, + Rollup::JsonRpcClient: ClientT, + Counterparty: HasHeightFields, +{ + async fn query_raw_consensus_state( + rollup: &Rollup, + client_id: &ClientId, + consensus_height: &Counterparty::Height, + query_height: &RollupHeight, + ) -> Result { + let request = Request { + client_id: client_id.as_str(), + consensus_height: &HeightParam { + revision_number: Counterparty::revision_number(consensus_height), + revision_height: Counterparty::revision_height(consensus_height), + }, + query_height: &(&RollupHeight { + slot_number: query_height.slot_number, + }) + .into(), + }; + + let response: QueryConsensusStateResponse = rollup + .json_rpc_client() + .request("ibc_consensusState", (request,)) + .await + .map_err(Rollup::raise_error)?; + + Ok(Any { + type_url: response.consensus_state.type_url, + value: response.consensus_state.value, + }) + } +} + +impl RawConsensusStateWithProofsQuerier + for QueryConsensusStateOnSovereign +where + Rollup: HasIbcChainTypes + + HasRawConsensusStateType + + HasCommitmentProofType + + HasJsonRpcClient + + HasEncoding + + CanRaiseError + + CanRaiseError + + CanRaiseError + + CanRaiseError, + Rollup::JsonRpcClient: ClientT, + Counterparty: HasHeightFields, + Encoding: HasEncodedType> + CanDecode, +{ + async fn query_raw_consensus_state_with_proofs( + rollup: &Rollup, + client_id: &ClientId, + consensus_height: &Counterparty::Height, + query_height: &RollupHeight, + ) -> Result<(Any, SovereignCommitmentProof), Rollup::Error> { + let request = Request { + client_id: client_id.as_str(), + consensus_height: &HeightParam { + revision_number: Counterparty::revision_number(consensus_height), + revision_height: Counterparty::revision_height(consensus_height), + }, + query_height: &HeightParam { + revision_number: 0, + revision_height: query_height.slot_number, + }, + }; + + let response: QueryConsensusStateResponse = rollup + .json_rpc_client() + .request("ibc_consensusState", (request,)) + .await + .map_err(Rollup::raise_error)?; + + let consensus_state_any = Any { + type_url: response.consensus_state.type_url, + value: response.consensus_state.value, + }; + + let proof_bytes = response.proof; + + let merkle_proof = rollup + .encoding() + .decode(&proof_bytes) + .map_err(Rollup::raise_error)?; + + let proof_height = RollupHeight { + slot_number: response.proof_height.revision_height(), + }; + + let commitment_proof = SovereignCommitmentProof { + proof_bytes, + merkle_proof, + proof_height, + }; + + Ok((consensus_state_any, commitment_proof)) + } +} + +#[derive(Serialize)] +pub struct Request<'a> { + pub client_id: &'a str, + pub consensus_height: &'a HeightParam, + pub query_height: &'a HeightParam, +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/queries/consensus_state_height.rs b/crates/relayer/sovereign-rollup-components/src/impls/queries/consensus_state_height.rs new file mode 100644 index 00000000..19c014c8 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/queries/consensus_state_height.rs @@ -0,0 +1,49 @@ +use cgp_core::CanRaiseError; +use hermes_relayer_components::chain::traits::queries::consensus_state_height::ConsensusStateHeightsQuerier; +use hermes_relayer_components::chain::traits::types::height::HasHeightType; +use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; +use ibc_relayer_types::core::ics24_host::identifier::ClientId; +use ibc_relayer_types::Height; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::ClientError; +use serde::{Deserialize, Serialize}; + +use crate::traits::json_rpc_client::HasJsonRpcClient; + +pub struct QueryConsensusStateHeightsOnSovereign; + +impl ConsensusStateHeightsQuerier + for QueryConsensusStateHeightsOnSovereign +where + Rollup: HasIbcChainTypes + + HasJsonRpcClient + + CanRaiseError, + // Note: The counterparty is a Cosmos chain, hence the Cosmos height type + Counterparty: HasHeightType, + Rollup::JsonRpcClient: ClientT, +{ + async fn query_consensus_state_heights( + rollup: &Rollup, + client_id: &ClientId, + ) -> Result, Rollup::Error> { + let request = Request { client_id }; + + let response: Response = rollup + .json_rpc_client() + .request("ibc_consensusStateHeights", (request,)) + .await + .map_err(Rollup::raise_error)?; + + Ok(response.consensus_state_heights) + } +} + +#[derive(Serialize)] +pub struct Request<'a> { + pub client_id: &'a ClientId, +} + +#[derive(Deserialize)] +pub struct Response { + pub consensus_state_heights: Vec, +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/queries/mod.rs b/crates/relayer/sovereign-rollup-components/src/impls/queries/mod.rs new file mode 100644 index 00000000..38bc4e95 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/queries/mod.rs @@ -0,0 +1,10 @@ +pub mod chain_status; +pub mod channel_end; +pub mod client_state; +pub mod connection_end; +pub mod consensus_state; +pub mod consensus_state_height; +pub mod packet_acknowledgement; +pub mod packet_commitment; +pub mod packet_receipt; +pub mod slot_hash; diff --git a/crates/relayer/sovereign-rollup-components/src/impls/queries/packet_acknowledgement.rs b/crates/relayer/sovereign-rollup-components/src/impls/queries/packet_acknowledgement.rs new file mode 100644 index 00000000..f03595e7 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/queries/packet_acknowledgement.rs @@ -0,0 +1,89 @@ +use cgp_core::CanRaiseError; +use hermes_encoding_components::traits::decoder::CanDecode; +use hermes_encoding_components::traits::encoded::HasEncodedType; +use hermes_encoding_components::traits::has_encoding::HasEncoding; +use hermes_relayer_components::chain::traits::queries::packet_acknowledgement::PacketAcknowledgementQuerier; +use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; +use hermes_relayer_components::chain::traits::types::packets::ack::HasAcknowledgementType; +use hermes_relayer_components::chain::traits::types::proof::HasCommitmentProofType; +use ibc_query::core::channel::QueryPacketAcknowledgementResponse; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::ClientError; +use serde::Serialize; + +use crate::impls::borsh_encode::ViaBorsh; +use crate::traits::json_rpc_client::HasJsonRpcClient; +use crate::types::commitment_proof::{JellyfishMerkleProof, SovereignCommitmentProof}; +use crate::types::height::RollupHeight; +use crate::types::rpc::height::HeightParam; + +pub struct QueryPacketAcknowledgementFromSovereign; + +impl PacketAcknowledgementQuerier + for QueryPacketAcknowledgementFromSovereign +where + Rollup: HasIbcChainTypes + + HasAcknowledgementType> + + HasCommitmentProofType + + HasJsonRpcClient + + HasEncoding + + CanRaiseError + + CanRaiseError, + Counterparty: HasIbcChainTypes, + Rollup::JsonRpcClient: ClientT, + Encoding: HasEncodedType> + CanDecode, +{ + async fn query_packet_acknowledgement( + rollup: &Rollup, + channel_id: &Rollup::ChannelId, + port_id: &Rollup::PortId, + sequence: &Counterparty::Sequence, + height: &Rollup::Height, + ) -> Result<(Rollup::Acknowledgement, Rollup::CommitmentProof), Rollup::Error> { + let request = Request { + channel_id: &channel_id.to_string(), + port_id: &port_id.to_string(), + sequence, + query_height: &(&RollupHeight { + slot_number: height.slot_number, + }) + .into(), + }; + + let response: QueryPacketAcknowledgementResponse = rollup + .json_rpc_client() + .request("ibc_packetAcknowledgement", (request,)) + .await + .map_err(Rollup::raise_error)?; + + let ack = Vec::from(response.acknowledgement.as_ref()); + + let proof_bytes = response.proof; + + let merkle_proof = rollup + .encoding() + .decode(&proof_bytes) + .map_err(Rollup::raise_error)?; + + let proof_height = RollupHeight { + slot_number: response.proof_height.revision_height(), + }; + + let commitment_proof = SovereignCommitmentProof { + proof_bytes, + merkle_proof, + proof_height, + }; + + Ok((ack, commitment_proof)) + } +} + +#[derive(Serialize)] +pub struct Request<'a> { + pub port_id: &'a str, + pub channel_id: &'a str, + pub sequence: &'a Sequence, + pub query_height: &'a HeightParam, +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/queries/packet_commitment.rs b/crates/relayer/sovereign-rollup-components/src/impls/queries/packet_commitment.rs new file mode 100644 index 00000000..4d47fcc9 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/queries/packet_commitment.rs @@ -0,0 +1,88 @@ +use cgp_core::CanRaiseError; +use hermes_encoding_components::traits::decoder::CanDecode; +use hermes_encoding_components::traits::encoded::HasEncodedType; +use hermes_encoding_components::traits::has_encoding::HasEncoding; +use hermes_relayer_components::chain::traits::queries::packet_commitment::PacketCommitmentQuerier; +use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; +use hermes_relayer_components::chain::traits::types::packets::receive::HasPacketCommitmentType; +use hermes_relayer_components::chain::traits::types::proof::HasCommitmentProofType; +use ibc_query::core::channel::QueryPacketCommitmentResponse; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::ClientError; +use serde::Serialize; + +use crate::impls::borsh_encode::ViaBorsh; +use crate::traits::json_rpc_client::HasJsonRpcClient; +use crate::types::commitment_proof::{JellyfishMerkleProof, SovereignCommitmentProof}; +use crate::types::height::RollupHeight; +use crate::types::rpc::height::HeightParam; + +pub struct QueryPacketCommitmentFromSovereign; + +impl PacketCommitmentQuerier + for QueryPacketCommitmentFromSovereign +where + Rollup: HasIbcChainTypes + + HasPacketCommitmentType> + + HasCommitmentProofType + + HasJsonRpcClient + + HasEncoding + + CanRaiseError + + CanRaiseError, + Rollup::JsonRpcClient: ClientT, + Encoding: HasEncodedType> + CanDecode, +{ + async fn query_packet_commitment( + rollup: &Rollup, + channel_id: &Rollup::ChannelId, + port_id: &Rollup::PortId, + sequence: &Rollup::Sequence, + height: &Rollup::Height, + ) -> Result<(Vec, SovereignCommitmentProof), Rollup::Error> { + let request = Request { + channel_id: &channel_id.to_string(), + port_id: &port_id.to_string(), + sequence, + query_height: &(&RollupHeight { + slot_number: height.slot_number, + }) + .into(), + }; + + let response: QueryPacketCommitmentResponse = rollup + .json_rpc_client() + .request("ibc_packetCommitment", (request,)) + .await + .map_err(Rollup::raise_error)?; + + let packet_commitment = response.packet_commitment.into_vec(); + + let proof_bytes = response.proof; + + let merkle_proof = rollup + .encoding() + .decode(&proof_bytes) + .map_err(Rollup::raise_error)?; + + let proof_height = RollupHeight { + slot_number: response.proof_height.revision_height(), + }; + + let commitment_proof = SovereignCommitmentProof { + proof_bytes, + merkle_proof, + proof_height, + }; + + Ok((packet_commitment, commitment_proof)) + } +} + +#[derive(Serialize)] +pub struct Request<'a> { + pub port_id: &'a str, + pub channel_id: &'a str, + pub sequence: &'a Sequence, + pub query_height: &'a HeightParam, +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/queries/packet_receipt.rs b/crates/relayer/sovereign-rollup-components/src/impls/queries/packet_receipt.rs new file mode 100644 index 00000000..4f28a05b --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/queries/packet_receipt.rs @@ -0,0 +1,87 @@ +use cgp_core::CanRaiseError; +use hermes_encoding_components::traits::decoder::CanDecode; +use hermes_encoding_components::traits::encoded::HasEncodedType; +use hermes_encoding_components::traits::has_encoding::HasEncoding; +use hermes_relayer_components::chain::traits::queries::packet_receipt::PacketReceiptQuerier; +use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; +use hermes_relayer_components::chain::traits::types::packets::timeout::HasPacketReceiptType; +use hermes_relayer_components::chain::traits::types::proof::HasCommitmentProofType; +use ibc_query::core::channel::QueryPacketReceiptResponse; +use ibc_relayer_types::core::ics04_channel::packet::Sequence; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::ClientError; +use serde::Serialize; + +use crate::impls::borsh_encode::ViaBorsh; +use crate::traits::json_rpc_client::HasJsonRpcClient; +use crate::types::commitment_proof::{JellyfishMerkleProof, SovereignCommitmentProof}; +use crate::types::height::RollupHeight; +use crate::types::rpc::height::HeightParam; + +pub struct QueryPacketReceiptFromSovereign; + +impl PacketReceiptQuerier + for QueryPacketReceiptFromSovereign +where + Rollup: HasIbcChainTypes + + HasPacketReceiptType + + HasCommitmentProofType + + HasJsonRpcClient + + HasEncoding + + CanRaiseError + + CanRaiseError, + Counterparty: HasIbcChainTypes, + Rollup::JsonRpcClient: ClientT, + Encoding: HasEncodedType> + CanDecode, +{ + async fn query_packet_receipt( + rollup: &Rollup, + channel_id: &Rollup::ChannelId, + port_id: &Rollup::PortId, + sequence: &Counterparty::Sequence, + height: &Rollup::Height, + ) -> Result<(Rollup::PacketReceipt, Rollup::CommitmentProof), Rollup::Error> { + let request = Request { + channel_id: &channel_id.to_string(), + port_id: &port_id.to_string(), + sequence, + query_height: &(&RollupHeight { + slot_number: height.slot_number, + }) + .into(), + }; + + let response: QueryPacketReceiptResponse = rollup + .json_rpc_client() + .request("ibc_packetReceipt", (request,)) + .await + .map_err(Rollup::raise_error)?; + + let proof_bytes = response.proof; + + let merkle_proof = rollup + .encoding() + .decode(&proof_bytes) + .map_err(Rollup::raise_error)?; + + let proof_height = RollupHeight { + slot_number: response.proof_height.revision_height(), + }; + + let commitment_proof = SovereignCommitmentProof { + proof_bytes, + merkle_proof, + proof_height, + }; + + Ok((response.received, commitment_proof)) + } +} + +#[derive(Serialize)] +pub struct Request<'a> { + pub port_id: &'a str, + pub channel_id: &'a str, + pub sequence: &'a Sequence, + pub query_height: &'a HeightParam, +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/queries/slot_hash.rs b/crates/relayer/sovereign-rollup-components/src/impls/queries/slot_hash.rs new file mode 100644 index 00000000..71fe21b5 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/queries/slot_hash.rs @@ -0,0 +1,81 @@ +use cgp_core::{async_trait, CanRaiseError, HasErrorType}; +use hermes_relayer_components::chain::traits::types::height::HasHeightType; +use hex::FromHexError; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::ClientError; +use serde::Deserialize; + +use crate::traits::json_rpc_client::HasJsonRpcClient; +use crate::types::height::RollupHeight; + +pub struct SlotHash { + pub root_hash: [u8; 32], + pub user_hash: [u8; 32], + pub kernel_hash: [u8; 32], +} + +#[async_trait] +pub trait CanQuerySlotHash: HasHeightType + HasErrorType { + async fn query_slot_hash(&self, height: &Self::Height) -> Result; +} + +impl CanQuerySlotHash for Rollup +where + Rollup: HasHeightType + + HasJsonRpcClient + + CanRaiseError + + CanRaiseError + + CanRaiseError<&'static str>, + Rollup::JsonRpcClient: ClientT, +{ + async fn query_slot_hash(&self, height: &RollupHeight) -> Result { + // FIXME: due to quirks on Sovereign SDK, the "actual" hash of a rollup at + // slot H is queried at slot H-1. + let slot_number = height.slot_number - 1; + + let response: SlotResponse = self + .json_rpc_client() + .request("ledger_getSlotByNumber", (slot_number,)) + .await + .map_err(Rollup::raise_error)?; + + let state_root_str = response + .state_root + .strip_prefix("0x") + .ok_or_else(|| Rollup::raise_error("expect response.state_root to contain hex"))?; + + let state_root = hex::decode(state_root_str).map_err(Rollup::raise_error)?; + + let user_hash = state_root[..32] + .try_into() + .map_err(|_| Rollup::raise_error("expect user hash to be made of 32 bytes"))?; + + let kernel_hash = state_root[32..] + .try_into() + .map_err(|_| Rollup::raise_error("expect kernel hash to be made of 32 bytes"))?; + + let root_hash_str = response + .hash + .strip_prefix("0x") + .ok_or_else(|| Rollup::raise_error("expect response.root_hash to contain hex"))?; + + let root_hash = hex::decode(root_hash_str) + .map_err(Rollup::raise_error)? + .try_into() + .map_err(|_| Rollup::raise_error("expect root hash to be made of 32 bytes"))?; + + Ok(SlotHash { + root_hash, + // First 32 bytes are user hash and the last 32 bytes are kernel hash. + user_hash, + kernel_hash, + }) + } +} + +#[derive(Deserialize)] +pub struct SlotResponse { + pub number: u64, + pub hash: String, + pub state_root: String, +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/send_message.rs b/crates/relayer/sovereign-rollup-components/src/impls/send_message.rs new file mode 100644 index 00000000..19acbbb7 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/send_message.rs @@ -0,0 +1,53 @@ +use core::marker::PhantomData; + +use cgp_core::CanRaiseError; +use hermes_relayer_components::chain::traits::send_message::MessageSender; +use hermes_relayer_components::chain::traits::types::event::HasEventType; +use hermes_relayer_components::chain::traits::types::message::HasMessageType; + +/** + As a workaround of Sovereign SDK allowing only one message per transaction, + we are sending one message at a time to the rollup, and only send the next + message if the previous message succeeded. Although it is very inefficient, + this helps us continue development without having to handle multi-transaction + failure. + + Although Sovereign SDK allows multiple transactions to be submitted at the + same time, the semantics is subtly different from sending multiple messages + per transaction. In particular, it is very challenging to recover from + faiures, in case only some of the transactions succeed. There are all kinds + of corner cases and race conditions that we would have to deal with, to ensure + that subsequent transactions do not conflict with the supposedly failed + transaction, which could in fact succeeded later without the relayer knowing. + + Because of this, we are deferring in handling such complexity, and opt for the + simpler semantics of sending one message at a time for now. +*/ +pub struct SendMessagesInSequence(pub PhantomData); + +impl MessageSender for SendMessagesInSequence +where + Chain: HasMessageType + HasEventType + CanRaiseError<&'static str>, + InSender: MessageSender, +{ + async fn send_messages( + chain: &Chain, + messages: Vec, + ) -> Result>, Chain::Error> { + let mut events = Vec::new(); + + for message in messages { + let in_events = InSender::send_messages(chain, vec![message]).await?; + + let [in_events] = <[Vec; 1]>::try_from(in_events).map_err(|_| { + Chain::raise_error( + "expected inner message sender to return exactly one list of events", + ) + })?; + + events.push(in_events); + } + + Ok(events) + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/transaction/encode_tx.rs b/crates/relayer/sovereign-rollup-components/src/impls/transaction/encode_tx.rs new file mode 100644 index 00000000..942236af --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/transaction/encode_tx.rs @@ -0,0 +1,61 @@ +use std::io::Error as IoError; + +use borsh::BorshSerialize; +use cgp_core::CanRaiseError; +use ed25519_dalek::SigningKey; +use hermes_relayer_components::chain::traits::types::chain_id::HasChainId; +use hermes_relayer_components::chain::traits::types::message::HasMessageType; +use hermes_relayer_components::transaction::traits::encode_tx::TxEncoder; +use hermes_relayer_components::transaction::traits::types::fee::HasFeeType; +use hermes_relayer_components::transaction::traits::types::nonce::HasNonceType; +use hermes_relayer_components::transaction::traits::types::signer::HasSignerType; +use hermes_relayer_components::transaction::traits::types::transaction::HasTransactionType; + +use crate::impls::errors::multi_message_unsupported::MultiMessageUnsupportedError; +use crate::types::message::SovereignMessage; +use crate::types::rollup_id::RollupId; +use crate::utils::encode_tx::encode_and_sign_sovereign_tx; + +pub struct EncodeSovereignTx; + +impl TxEncoder for EncodeSovereignTx +where + Rollup: HasSignerType + + HasNonceType + + HasFeeType + + HasMessageType + + HasTransactionType> + + HasChainId + + CanRaiseError + + for<'a> CanRaiseError>, +{ + async fn encode_tx( + rollup: &Rollup, + signer: &SigningKey, + nonce: &u64, + fee: &u64, + messages: &[SovereignMessage], + ) -> Result { + let messages_vec: Vec<&SovereignMessage> = messages.iter().collect(); + + let [message]: [&SovereignMessage; 1] = messages_vec + .try_into() + .map_err(|_| Rollup::raise_error(MultiMessageUnsupportedError { messages }))?; + + let message_bytes = message.try_to_vec().map_err(Rollup::raise_error)?; + + let rollup_id = rollup.chain_id(); + + let transaction = encode_and_sign_sovereign_tx( + signer, + message_bytes.clone(), + rollup_id.0, + 0, + *fee, + *nonce, + ) + .map_err(Rollup::raise_error)?; + + Ok(transaction) + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/transaction/estimate_fee.rs b/crates/relayer/sovereign-rollup-components/src/impls/transaction/estimate_fee.rs new file mode 100644 index 00000000..d22a6412 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/transaction/estimate_fee.rs @@ -0,0 +1,28 @@ +use cgp_core::prelude::HasErrorType; +use hermes_relayer_components::transaction::traits::estimate_tx_fee::TxFeeEstimator; +use hermes_relayer_components::transaction::traits::simulation_fee::FeeForSimulationGetter; +use hermes_relayer_components::transaction::traits::types::fee::HasFeeType; +use hermes_relayer_components::transaction::traits::types::transaction::HasTransactionType; + +pub struct ReturnSovereignTxFee; + +impl TxFeeEstimator for ReturnSovereignTxFee +where + Rollup: HasTransactionType + HasFeeType + HasErrorType, +{ + async fn estimate_tx_fee( + _rollup: &Rollup, + _tx: &Rollup::Transaction, + ) -> Result { + Ok(FEE) + } +} + +impl FeeForSimulationGetter for ReturnSovereignTxFee +where + Rollup: HasTransactionType + HasFeeType + HasErrorType, +{ + fn fee_for_simulation(_rollup: &Rollup) -> &u64 { + &FEE + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/transaction/event.rs b/crates/relayer/sovereign-rollup-components/src/impls/transaction/event.rs new file mode 100644 index 00000000..1babdeb0 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/transaction/event.rs @@ -0,0 +1,26 @@ +use core::str::Utf8Error; +use std::io::Error as IoError; + +use cgp_core::CanRaiseError; +use hermes_relayer_components::chain::traits::types::event::HasEventType; +use hermes_relayer_components::transaction::traits::parse_events::TxResponseAsEventsParser; +use hermes_relayer_components::transaction::traits::types::tx_response::HasTxResponseType; + +use crate::types::event::SovereignEvent; +use crate::types::tx::tx_response::TxResponse; + +pub struct ParseSovTxResponseAsEvents; + +impl TxResponseAsEventsParser for ParseSovTxResponseAsEvents +where + Chain: HasTxResponseType + + HasEventType + + CanRaiseError + + CanRaiseError, +{ + fn parse_tx_response_as_events( + response: TxResponse, + ) -> Result>, Chain::Error> { + Ok(vec![response.events]) + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/transaction/mod.rs b/crates/relayer/sovereign-rollup-components/src/impls/transaction/mod.rs new file mode 100644 index 00000000..793c66bf --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/transaction/mod.rs @@ -0,0 +1,6 @@ +pub mod encode_tx; +pub mod estimate_fee; +pub mod event; +pub mod query_nonce; +pub mod query_tx_response; +pub mod submit_tx; diff --git a/crates/relayer/sovereign-rollup-components/src/impls/transaction/query_nonce.rs b/crates/relayer/sovereign-rollup-components/src/impls/transaction/query_nonce.rs new file mode 100644 index 00000000..ed5bb6c1 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/transaction/query_nonce.rs @@ -0,0 +1,51 @@ +use cgp_core::prelude::HasErrorType; +use cgp_core::CanRaiseError; +use ed25519_dalek::{SigningKey, VerifyingKey}; +use hermes_relayer_components::transaction::traits::nonce::query_nonce::NonceQuerier; +use hermes_relayer_components::transaction::traits::types::nonce::HasNonceType; +use hermes_relayer_components::transaction::traits::types::signer::HasSignerType; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::ClientError; +use serde::Deserialize; +use sha2::{Digest, Sha256}; + +use crate::traits::json_rpc_client::HasJsonRpcClient; + +pub struct QuerySovereignNonce; + +impl NonceQuerier for QuerySovereignNonce +where + Rollup: HasSignerType + + HasNonceType + + HasErrorType + + HasJsonRpcClient + + CanRaiseError, + Rollup::JsonRpcClient: ClientT, +{ + async fn query_nonce(rollup: &Rollup, signer: &SigningKey) -> Result { + let key_bytes = public_key_to_hash_bytes(&signer.verifying_key()); + + let response: Response = rollup + .json_rpc_client() + .request("accounts_getAccount", (key_bytes,)) + .await + .map_err(Rollup::raise_error)?; + + match response { + Response::AccountExists { nonce } => Ok(nonce), + Response::AccountEmpty => Ok(0), + } + } +} + +#[derive(Debug, Deserialize)] +pub enum Response { + AccountExists { nonce: u64 }, + AccountEmpty, +} + +pub fn public_key_to_hash_bytes(public_key: &VerifyingKey) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(public_key); + hasher.finalize().into() +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/transaction/query_tx_response.rs b/crates/relayer/sovereign-rollup-components/src/impls/transaction/query_tx_response.rs new file mode 100644 index 00000000..eb1ee2a7 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/transaction/query_tx_response.rs @@ -0,0 +1,72 @@ +use core::ops::Range; +use core::time::Duration; + +use cgp_core::CanRaiseError; +use hermes_relayer_components::transaction::traits::query_tx_response::TxResponseQuerier; +use hermes_relayer_components::transaction::traits::types::tx_hash::HasTransactionHashType; +use hermes_relayer_components::transaction::traits::types::tx_response::HasTxResponseType; +use hermes_runtime_components::traits::runtime::HasRuntime; +use hermes_runtime_components::traits::sleep::CanSleep; +use hex::ToHex; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::ClientError; +use serde::Deserialize; + +use crate::traits::json_rpc_client::HasJsonRpcClient; +use crate::types::tx::tx_hash::TxHash; +use crate::types::tx::tx_response::{TxEffect, TxResponse}; + +pub struct QuerySovereignTxResponse; + +impl TxResponseQuerier for QuerySovereignTxResponse +where + Chain: HasTxResponseType + + HasTransactionHashType + + HasJsonRpcClient + + HasRuntime + + CanRaiseError, + Chain::JsonRpcClient: ClientT, + Chain::Runtime: CanSleep, +{ + async fn query_tx_response( + chain: &Chain, + tx_hash: &TxHash, + ) -> Result, Chain::Error> { + let response: Option = chain + .json_rpc_client() + .request("ledger_getTransactionByHash", (&tx_hash,)) + .await + .map_err(Chain::raise_error)?; + + if let Some(response) = response { + let tx_hash_str = tx_hash.0.encode_hex::(); + + let events = chain + .json_rpc_client() + .request("ledger_getEventsByTxnHash", (tx_hash_str,)) + .await + .map_err(Chain::raise_error)?; + + // FIXME: we need to wait a little bit even though the rollup reports the transaction as committed. + // This is because Sovereign SDK's storage for queries is currently lagging behind. + chain.runtime().sleep(Duration::from_secs(1)).await; + + let response = TxResponse { + hash: response.hash, + events, + custom_receipt: response.custom_receipt, + }; + + Ok(Some(response)) + } else { + Ok(None) + } + } +} + +#[derive(Debug, Deserialize)] +pub struct QueryTxResponse { + pub hash: TxHash, + pub event_range: Range, + pub custom_receipt: TxEffect, +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/transaction/submit_tx.rs b/crates/relayer/sovereign-rollup-components/src/impls/transaction/submit_tx.rs new file mode 100644 index 00000000..51228d23 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/transaction/submit_tx.rs @@ -0,0 +1,34 @@ +use cgp_core::CanRaiseError; +use hermes_relayer_components::transaction::traits::submit_tx::TxSubmitter; +use hermes_relayer_components::transaction::traits::types::transaction::HasTransactionType; +use hermes_relayer_components::transaction::traits::types::tx_hash::HasTransactionHashType; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::ClientError; + +use crate::traits::json_rpc_client::HasJsonRpcClient; +use crate::types::tx::tx_hash::TxHash; + +pub struct SubmitSovereignTransaction; + +impl TxSubmitter for SubmitSovereignTransaction +where + Chain: HasJsonRpcClient + + HasTransactionType> + + HasTransactionHashType + + CanRaiseError + + CanRaiseError, + Chain::JsonRpcClient: ClientT, +{ + async fn submit_tx(chain: &Chain, transaction: &Vec) -> Result { + let rpc_client = chain.json_rpc_client(); + + let _response: serde_json::Value = rpc_client + .request("sequencer_publishBatch", [transaction]) + .await + .map_err(Chain::raise_error)?; + + let tx_hash = TxHash::from_signed_tx_bytes(transaction); + + Ok(tx_hash) + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/types/client_state.rs b/crates/relayer/sovereign-rollup-components/src/impls/types/client_state.rs new file mode 100644 index 00000000..992b367a --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/types/client_state.rs @@ -0,0 +1,52 @@ +use core::time::Duration; + +use cgp_core::Async; +use hermes_relayer_components::chain::traits::types::client_state::{ + ClientStateFieldsGetter, HasClientStateType, ProvideClientStateType, +}; +use hermes_relayer_components::chain::traits::types::height::HasHeightType; + +use crate::types::client_state::WrappedSovereignClientState; +use crate::types::height::RollupHeight; + +pub struct ProvideSovereignClientState; + +impl ProvideClientStateType + for ProvideSovereignClientState +where + Chain: Async, +{ + type ClientState = WrappedSovereignClientState; +} + +impl ClientStateFieldsGetter + for ProvideSovereignClientState +where + Chain: HasHeightType + + HasClientStateType, +{ + fn client_state_latest_height(client_state: &WrappedSovereignClientState) -> RollupHeight { + RollupHeight { + slot_number: client_state + .sovereign_client_state + .sovereign_params + .latest_height + .revision_height(), + } + } + + fn client_state_is_frozen(client_state: &WrappedSovereignClientState) -> bool { + client_state.sovereign_client_state.is_frozen() + } + + fn client_state_has_expired( + client_state: &WrappedSovereignClientState, + elapsed: Duration, + ) -> bool { + elapsed + > client_state + .sovereign_client_state + .sovereign_params + .trusting_period + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/types/consensus_state.rs b/crates/relayer/sovereign-rollup-components/src/impls/types/consensus_state.rs new file mode 100644 index 00000000..c8b8c6ad --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/types/consensus_state.rs @@ -0,0 +1,14 @@ +use cgp_core::Async; +use hermes_relayer_components::chain::traits::types::consensus_state::ProvideConsensusStateType; + +use crate::types::consensus_state::SovereignConsensusState; + +pub struct ProvideSovereignConsensusState; + +impl ProvideConsensusStateType + for ProvideSovereignConsensusState +where + Chain: Async, +{ + type ConsensusState = SovereignConsensusState; +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/types/mod.rs b/crates/relayer/sovereign-rollup-components/src/impls/types/mod.rs new file mode 100644 index 00000000..bfda95ad --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/types/mod.rs @@ -0,0 +1,5 @@ +pub mod client_state; +pub mod consensus_state; +pub mod payload; +pub mod rollup; +pub mod transaction; diff --git a/crates/relayer/sovereign-rollup-components/src/impls/types/payload.rs b/crates/relayer/sovereign-rollup-components/src/impls/types/payload.rs new file mode 100644 index 00000000..de71b94c --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/types/payload.rs @@ -0,0 +1,43 @@ +use cgp_core::prelude::Async; +use hermes_cosmos_chain_components::types::channel::CosmosInitChannelOptions; +use hermes_cosmos_chain_components::types::connection::CosmosInitConnectionOptions; +use hermes_relayer_components::chain::traits::types::channel::ProvideInitChannelOptionsType; +use hermes_relayer_components::chain::traits::types::connection::ProvideInitConnectionOptionsType; +use hermes_relayer_components::chain::traits::types::create_client::{ + ProvideCreateClientMessageOptionsType, ProvideCreateClientPayloadOptionsType, +}; +use ibc_relayer::chain::client::ClientSettings; + +pub struct ProvideSovereignRollupPayloadTypes; + +impl ProvideCreateClientPayloadOptionsType + for ProvideSovereignRollupPayloadTypes +where + Chain: Async, +{ + type CreateClientPayloadOptions = ClientSettings; +} + +impl ProvideCreateClientMessageOptionsType + for ProvideSovereignRollupPayloadTypes +where + Chain: Async, +{ + type CreateClientMessageOptions = (); +} + +impl ProvideInitConnectionOptionsType + for ProvideSovereignRollupPayloadTypes +where + Chain: Async, +{ + type InitConnectionOptions = CosmosInitConnectionOptions; +} + +impl ProvideInitChannelOptionsType + for ProvideSovereignRollupPayloadTypes +where + Chain: Async, +{ + type InitChannelOptions = CosmosInitChannelOptions; +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/types/rollup.rs b/crates/relayer/sovereign-rollup-components/src/impls/types/rollup.rs new file mode 100644 index 00000000..59bc56df --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/types/rollup.rs @@ -0,0 +1,125 @@ +use cgp_core::prelude::*; +use hermes_cosmos_chain_components::impls::types::chain::ProvideCosmosChainTypes; +use hermes_relayer_components::chain::impls::types::receipt::ProvideBoolPacketReceipt; +use hermes_relayer_components::chain::traits::commitment_prefix::CommitmentPrefixTypeComponent; +use hermes_relayer_components::chain::traits::types::chain_id::ProvideChainIdType; +use hermes_relayer_components::chain::traits::types::channel::ChannelEndTypeComponent; +use hermes_relayer_components::chain::traits::types::connection::ConnectionEndTypeComponent; +use hermes_relayer_components::chain::traits::types::event::ProvideEventType; +use hermes_relayer_components::chain::traits::types::height::{ + HasHeightType, HeightFieldGetter, HeightIncrementer, ProvideHeightType, +}; +use hermes_relayer_components::chain::traits::types::ibc::IbcChainTypesComponent; +use hermes_relayer_components::chain::traits::types::message::ProvideMessageType; +use hermes_relayer_components::chain::traits::types::packet::IbcPacketTypesProviderComponent; +use hermes_relayer_components::chain::traits::types::packets::ack::AcknowledgementTypeComponent; +use hermes_relayer_components::chain::traits::types::packets::receive::PacketCommitmentTypeComponent; +use hermes_relayer_components::chain::traits::types::packets::timeout::PacketReceiptTypeComponent; +use hermes_relayer_components::chain::traits::types::proof::{ + CommitmentProofBytesGetterComponent, CommitmentProofHeightGetterComponent, + CommitmentProofTypeComponent, +}; +use hermes_relayer_components::chain::traits::types::status::ProvideChainStatusType; +use hermes_relayer_components::chain::traits::types::timestamp::{ + HasTimestampType, TimestampTypeComponent, +}; +use ibc_relayer_types::timestamp::Timestamp; + +use crate::types::commitment_proof::ProvideSovereignCommitmentProof; +use crate::types::event::SovereignEvent; +use crate::types::height::RollupHeight; +use crate::types::message::SovereignMessage; +use crate::types::rollup_id::RollupId; +use crate::types::status::SovereignRollupStatus; + +pub struct ProvideSovereignRollupTypes; + +impl ProvideHeightType for ProvideSovereignRollupTypes +where + Chain: Async, +{ + type Height = RollupHeight; +} + +impl HeightFieldGetter for ProvideSovereignRollupTypes +where + Chain: HasHeightType, +{ + fn revision_number(_height: &RollupHeight) -> u64 { + 0 + } + + fn revision_height(height: &RollupHeight) -> u64 { + height.slot_number + } +} + +impl HeightIncrementer for ProvideSovereignRollupTypes +where + Chain: HasHeightType + HasErrorType, +{ + fn increment_height(height: &RollupHeight) -> Result { + // FIXME: do not increment height for now, as proof height for Sovereign is not incremented + Ok(height.clone()) + } +} + +impl ProvideChainIdType for ProvideSovereignRollupTypes +where + Chain: Async, +{ + type ChainId = RollupId; +} + +impl ProvideMessageType for ProvideSovereignRollupTypes +where + Chain: Async, +{ + type Message = SovereignMessage; +} + +impl ProvideEventType for ProvideSovereignRollupTypes +where + Chain: Async, +{ + type Event = SovereignEvent; +} + +impl ProvideChainStatusType for ProvideSovereignRollupTypes +where + Chain: HasHeightType + HasTimestampType, +{ + type ChainStatus = SovereignRollupStatus; + + fn chain_status_height(status: &SovereignRollupStatus) -> &RollupHeight { + &status.height + } + + fn chain_status_timestamp(status: &Self::ChainStatus) -> &Timestamp { + &status.timestamp + } +} + +delegate_components! { + ProvideSovereignRollupTypes { + [ + TimestampTypeComponent, + IbcChainTypesComponent, + IbcPacketTypesProviderComponent, + CommitmentPrefixTypeComponent, + PacketCommitmentTypeComponent, + AcknowledgementTypeComponent, + ConnectionEndTypeComponent, + ChannelEndTypeComponent, + ]: + ProvideCosmosChainTypes, + [ + CommitmentProofTypeComponent, + CommitmentProofHeightGetterComponent, + CommitmentProofBytesGetterComponent, + ]: + ProvideSovereignCommitmentProof, + PacketReceiptTypeComponent: + ProvideBoolPacketReceipt, + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/impls/types/transaction.rs b/crates/relayer/sovereign-rollup-components/src/impls/types/transaction.rs new file mode 100644 index 00000000..bbbf50d0 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/impls/types/transaction.rs @@ -0,0 +1,70 @@ +use cgp_core::Async; +use ed25519_dalek::SigningKey; +use hermes_relayer_components::transaction::traits::nonce::nonce_guard::ProvideNonceGuard; +use hermes_relayer_components::transaction::traits::types::fee::ProvideFeeType; +use hermes_relayer_components::transaction::traits::types::nonce::{ + HasNonceType, ProvideNonceType, +}; +use hermes_relayer_components::transaction::traits::types::signer::ProvideSignerType; +use hermes_relayer_components::transaction::traits::types::transaction::ProvideTransactionType; +use hermes_relayer_components::transaction::traits::types::tx_hash::ProvideTransactionHashType; +use hermes_relayer_components::transaction::traits::types::tx_response::ProvideTxResponseType; + +use crate::types::tx::nonce_guard::SovereignNonceGuard; +use crate::types::tx::tx_hash::TxHash; +use crate::types::tx::tx_response::TxResponse; + +pub struct ProvideSovereignTransactionTypes; + +impl ProvideTransactionType for ProvideSovereignTransactionTypes +where + Chain: Async, +{ + type Transaction = Vec; + + fn tx_size(tx: &Vec) -> usize { + tx.len() + } +} + +impl ProvideNonceType for ProvideSovereignTransactionTypes +where + Chain: Async, +{ + type Nonce = u64; +} + +impl ProvideFeeType for ProvideSovereignTransactionTypes +where + Chain: Async, +{ + type Fee = u64; +} + +impl ProvideSignerType for ProvideSovereignTransactionTypes +where + Chain: Async, +{ + type Signer = SigningKey; +} + +impl ProvideTransactionHashType for ProvideSovereignTransactionTypes +where + Chain: Async, +{ + type TxHash = TxHash; +} + +impl ProvideTxResponseType for ProvideSovereignTransactionTypes +where + Chain: Async, +{ + type TxResponse = TxResponse; +} + +impl ProvideNonceGuard for ProvideSovereignTransactionTypes +where + Chain: HasNonceType, +{ + type NonceGuard<'a> = SovereignNonceGuard<'a>; +} diff --git a/crates/relayer/sovereign-rollup-components/src/lib.rs b/crates/relayer/sovereign-rollup-components/src/lib.rs new file mode 100644 index 00000000..95519c7a --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/lib.rs @@ -0,0 +1,10 @@ +#![recursion_limit = "256"] +#![allow(refining_impl_trait)] + +extern crate alloc; + +pub mod components; +pub mod impls; +pub mod traits; +pub mod types; +pub mod utils; diff --git a/crates/relayer/sovereign-rollup-components/src/traits/json_rpc_client.rs b/crates/relayer/sovereign-rollup-components/src/traits/json_rpc_client.rs new file mode 100644 index 00000000..07d055d0 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/traits/json_rpc_client.rs @@ -0,0 +1,12 @@ +use cgp_core::prelude::*; +pub use jsonrpsee::core::client::error::Error as JsonRpcClientError; + +#[derive_component(JsonRpcClientTypeComponent, ProvideJsonRpcClientType)] +pub trait HasJsonRpcClientType: Async { + type JsonRpcClient: Async; +} + +#[derive_component(JsonRpcClientGetterComponent, JsonRpcClientGetter)] +pub trait HasJsonRpcClient: HasJsonRpcClientType { + fn json_rpc_client(&self) -> &Self::JsonRpcClient; +} diff --git a/crates/relayer/sovereign-rollup-components/src/traits/mod.rs b/crates/relayer/sovereign-rollup-components/src/traits/mod.rs new file mode 100644 index 00000000..4a888dc0 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/traits/mod.rs @@ -0,0 +1 @@ +pub mod json_rpc_client; diff --git a/crates/relayer/sovereign-rollup-components/src/types/address.rs b/crates/relayer/sovereign-rollup-components/src/types/address.rs new file mode 100644 index 00000000..1f9a322f --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/address.rs @@ -0,0 +1,46 @@ +use core::fmt::Debug; + +use bech32::ToBase32; +use bech32::Variant::Bech32m; +use borsh::{BorshDeserialize, BorshSerialize}; +use hex::ToHex; + +#[derive(Clone, BorshSerialize, BorshDeserialize)] +pub struct SovereignAddressBytes { + pub addr: [u8; 32], +} + +impl Debug for SovereignAddressBytes { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "SovAddressBytes({})", self.addr.encode_hex::())?; + Ok(()) + } +} + +#[derive(Clone)] +pub struct SovereignAddress { + pub address: String, + pub address_bytes: SovereignAddressBytes, +} + +impl SovereignAddress { + pub fn new(address_bytes: [u8; 32], account_prefix: &str) -> Result { + let address = encode_address_bytes_to_address(&address_bytes, account_prefix)?; + + Ok(Self { + address, + address_bytes: SovereignAddressBytes { + addr: address_bytes, + }, + }) + } +} + +pub fn encode_address_bytes_to_address( + address_bytes: &[u8; 32], + account_prefix: &str, +) -> Result { + let base32_bytes = address_bytes.to_base32(); + let address = bech32::encode(account_prefix, base32_bytes, Bech32m)?; + Ok(address) +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/client_state.rs b/crates/relayer/sovereign-rollup-components/src/types/client_state.rs new file mode 100644 index 00000000..fc46c298 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/client_state.rs @@ -0,0 +1,66 @@ +use hermes_encoding_components::traits::convert::{CanConvert, Converter}; +use hermes_encoding_components::traits::decoder::CanDecode; +use hermes_encoding_components::traits::encoded::HasEncodedType; +use hermes_encoding_components::traits::encoder::CanEncode; +use hermes_protobuf_encoding_components::types::Any; +use hermes_wasm_client_components::types::client_state::WasmClientState; +pub use sov_celestia_client::types::client_state::SovTmClientState as SovereignClientState; +pub use sov_celestia_client::types::proto::v1::ClientState as ProtoSovereignClientState; + +#[derive(Debug)] +pub struct WrappedSovereignClientState { + pub sovereign_client_state: SovereignClientState, + pub wasm_code_hash: Vec, +} + +pub struct EncodeWrappedSovereignClientState; + +impl Converter + for EncodeWrappedSovereignClientState +where + Encoding: HasEncodedType> + + CanEncode + + CanConvert, +{ + fn convert( + encoding: &Encoding, + client_state: &WrappedSovereignClientState, + ) -> Result { + let sovereign_client_state_bytes = encoding.encode(&client_state.sovereign_client_state)?; + + let wasm_client_state = WasmClientState { + data: sovereign_client_state_bytes, + checksum: client_state.wasm_code_hash.clone(), + latest_height: client_state + .sovereign_client_state + .sovereign_params + .latest_height, + }; + + encoding.convert(&wasm_client_state) + } +} + +impl Converter + for EncodeWrappedSovereignClientState +where + Encoding: HasEncodedType> + + CanDecode + + CanConvert, +{ + fn convert( + encoding: &Encoding, + client_state_any: &Any, + ) -> Result { + let wasm_client_state = encoding.convert(client_state_any)?; + + let sovereign_client_state = encoding.decode(&wasm_client_state.data)?; + + let wrapped_sovereign_client_state = WrappedSovereignClientState { + sovereign_client_state, + wasm_code_hash: wasm_client_state.checksum, + }; + + Ok(wrapped_sovereign_client_state) + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/commitment_proof.rs b/crates/relayer/sovereign-rollup-components/src/types/commitment_proof.rs new file mode 100644 index 00000000..b2edab64 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/commitment_proof.rs @@ -0,0 +1,46 @@ +use cgp_core::Async; +use hermes_relayer_components::chain::traits::types::height::HasHeightType; +use hermes_relayer_components::chain::traits::types::proof::{ + CommitmentProofBytesGetter, CommitmentProofHeightGetter, HasCommitmentProofType, + ProvideCommitmentProofType, +}; +use jmt::proof::SparseMerkleProof; +use sha2::Sha256; + +use crate::types::height::RollupHeight; + +pub type JellyfishMerkleProof = SparseMerkleProof; + +pub struct SovereignCommitmentProof { + pub merkle_proof: JellyfishMerkleProof, + pub proof_bytes: Vec, + pub proof_height: RollupHeight, +} + +pub struct ProvideSovereignCommitmentProof; + +impl ProvideCommitmentProofType for ProvideSovereignCommitmentProof +where + Chain: Async, +{ + type CommitmentProof = SovereignCommitmentProof; +} + +impl CommitmentProofHeightGetter for ProvideSovereignCommitmentProof +where + Chain: HasCommitmentProofType + + HasHeightType, +{ + fn commitment_proof_height(proof: &SovereignCommitmentProof) -> &RollupHeight { + &proof.proof_height + } +} + +impl CommitmentProofBytesGetter for ProvideSovereignCommitmentProof +where + Chain: HasCommitmentProofType, +{ + fn commitment_proof_bytes(proof: &SovereignCommitmentProof) -> &[u8] { + &proof.proof_bytes + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/consensus_state.rs b/crates/relayer/sovereign-rollup-components/src/types/consensus_state.rs new file mode 100644 index 00000000..d7d3ba53 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/consensus_state.rs @@ -0,0 +1,2 @@ +pub use sov_celestia_client::types::consensus_state::SovTmConsensusState as SovereignConsensusState; +pub use sov_celestia_client::types::proto::v1::ConsensusState as ProtoSovereignConsensusState; diff --git a/crates/relayer/sovereign-rollup-components/src/types/event.rs b/crates/relayer/sovereign-rollup-components/src/types/event.rs new file mode 100644 index 00000000..156f8a37 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/event.rs @@ -0,0 +1,8 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize)] +pub struct SovereignEvent { + pub event_key: String, + pub event_value: serde_json::Value, + pub module_name: String, +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/height.rs b/crates/relayer/sovereign-rollup-components/src/types/height.rs new file mode 100644 index 00000000..153e201f --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/height.rs @@ -0,0 +1,22 @@ +use core::fmt::{Debug, Display}; + +use ibc_relayer_types::Height; + +#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct RollupHeight { + pub slot_number: u64, +} + +impl Display for RollupHeight { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Debug::fmt(self, f) + } +} + +impl From for RollupHeight { + fn from(height: Height) -> Self { + Self { + slot_number: height.revision_height(), + } + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/message.rs b/crates/relayer/sovereign-rollup-components/src/types/message.rs new file mode 100644 index 00000000..ac852810 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/message.rs @@ -0,0 +1,27 @@ +use borsh::BorshSerialize; +use hermes_cosmos_chain_components::traits::message::CosmosMessage; +use ibc_relayer_types::signer::Signer; + +use crate::types::messages::bank::BankMessage; +use crate::types::messages::ibc::{IbcMessage, IbcMessageWithHeight}; + +#[derive(Debug, BorshSerialize)] +pub enum SovereignMessage { + Accounts, + Bank(BankMessage), + Ibc(IbcMessage), +} + +impl From for SovereignMessage { + fn from(cosmos_message: CosmosMessage) -> Self { + let cosmos_message_any = cosmos_message.message.encode_protobuf(&Signer::dummy()); + + IbcMessageWithHeight::new( + cosmos_message_any, + cosmos_message + .message + .counterparty_message_height_for_update_client(), + ) + .into() + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/messages/bank.rs b/crates/relayer/sovereign-rollup-components/src/types/messages/bank.rs new file mode 100644 index 00000000..a3a0d40b --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/messages/bank.rs @@ -0,0 +1,24 @@ +use borsh::BorshSerialize; + +use crate::types::address::SovereignAddressBytes; + +#[derive(Debug, BorshSerialize)] +pub enum BankMessage { + CreateToken { + salt: u64, + token_name: String, + initial_balance: u64, + minter_address: SovereignAddressBytes, + authorized_minters: Vec, + }, + Transfer { + to: SovereignAddressBytes, + coins: CoinFields, + }, +} + +#[derive(Debug, BorshSerialize)] +pub struct CoinFields { + pub amount: u64, + pub token_address: SovereignAddressBytes, +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/messages/ibc.rs b/crates/relayer/sovereign-rollup-components/src/types/messages/ibc.rs new file mode 100644 index 00000000..a8942bb9 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/messages/ibc.rs @@ -0,0 +1,53 @@ +use std::io::prelude::Write; + +use borsh::BorshSerialize; +use ibc::apps::transfer::types::msgs::transfer::MsgTransfer; +use ibc_proto::google::protobuf::Any; +use ibc_relayer_types::core::ics02_client::height::Height; + +use crate::types::message::SovereignMessage; + +#[derive(Debug, BorshSerialize)] +pub enum IbcMessage { + Core(IbcMessageWithHeight), + Transfer(MsgTransferWithHeight), +} + +#[derive(Debug)] +pub struct MsgTransferWithHeight { + pub message: MsgTransfer, + pub counterparty_height: Height, +} + +#[derive(Debug)] +pub struct IbcMessageWithHeight { + pub message: Any, + pub counterparty_height: Option, +} + +impl IbcMessageWithHeight { + pub fn new(message: Any, counterparty_height: Option) -> Self { + Self { + message, + counterparty_height, + } + } +} + +impl BorshSerialize for IbcMessageWithHeight { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + self.message.serialize(writer) + } +} + +impl BorshSerialize for MsgTransferWithHeight { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + self.message.serialize(writer) + } +} + +impl From for SovereignMessage { + fn from(value: IbcMessageWithHeight) -> Self { + SovereignMessage::Ibc(IbcMessage::Core(value)) + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/messages/mod.rs b/crates/relayer/sovereign-rollup-components/src/types/messages/mod.rs new file mode 100644 index 00000000..51b0e887 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/messages/mod.rs @@ -0,0 +1,2 @@ +pub mod bank; +pub mod ibc; diff --git a/crates/relayer/sovereign-rollup-components/src/types/mod.rs b/crates/relayer/sovereign-rollup-components/src/types/mod.rs new file mode 100644 index 00000000..a3a626e5 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/mod.rs @@ -0,0 +1,12 @@ +pub mod address; +pub mod client_state; +pub mod commitment_proof; +pub mod consensus_state; +pub mod event; +pub mod height; +pub mod message; +pub mod messages; +pub mod rollup_id; +pub mod rpc; +pub mod status; +pub mod tx; diff --git a/crates/relayer/sovereign-rollup-components/src/types/proof.rs b/crates/relayer/sovereign-rollup-components/src/types/proof.rs new file mode 100644 index 00000000..150cad18 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/proof.rs @@ -0,0 +1,15 @@ +use cgp_core::Async; +use hermes_relayer_components::chain::traits::types::proof::ProvideCommitmentProofType; +use jmt::proof::SparseMerkleProof; +use sha2::Sha256; + +pub type JellyfishMerkleProof = SparseMerkleProof; + +pub struct ProvideJellyfishMerkleProof; + +impl ProvideCommitmentProofType for ProvideJellyfishMerkleProof +where + Chain: Async, +{ + type CommitmentProof = JellyfishMerkleProof; +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/rollup_id.rs b/crates/relayer/sovereign-rollup-components/src/types/rollup_id.rs new file mode 100644 index 00000000..4231ff43 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/rollup_id.rs @@ -0,0 +1,10 @@ +use core::fmt::{Debug, Display}; + +#[derive(Debug, Eq, PartialEq)] +pub struct RollupId(pub u64); + +impl Display for RollupId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Debug::fmt(self, f) + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/rpc/height.rs b/crates/relayer/sovereign-rollup-components/src/types/rpc/height.rs new file mode 100644 index 00000000..396416a2 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/rpc/height.rs @@ -0,0 +1,18 @@ +use serde::Serialize; + +use crate::types::height::RollupHeight; + +#[derive(Serialize)] +pub struct HeightParam { + pub revision_number: u64, + pub revision_height: u64, +} + +impl<'a> From<&'a RollupHeight> for HeightParam { + fn from(height: &'a RollupHeight) -> Self { + Self { + revision_number: 0, + revision_height: height.slot_number, + } + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/rpc/mod.rs b/crates/relayer/sovereign-rollup-components/src/types/rpc/mod.rs new file mode 100644 index 00000000..a2c60eda --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/rpc/mod.rs @@ -0,0 +1 @@ +pub mod height; diff --git a/crates/relayer/sovereign-rollup-components/src/types/status.rs b/crates/relayer/sovereign-rollup-components/src/types/status.rs new file mode 100644 index 00000000..ba123f70 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/status.rs @@ -0,0 +1,10 @@ +use ibc_relayer_types::timestamp::Timestamp; + +use crate::types::height::RollupHeight; + +#[derive(Debug)] +pub struct SovereignRollupStatus { + pub height: RollupHeight, + + pub timestamp: Timestamp, +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/tx/mod.rs b/crates/relayer/sovereign-rollup-components/src/types/tx/mod.rs new file mode 100644 index 00000000..e742c0b6 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/tx/mod.rs @@ -0,0 +1,4 @@ +pub mod nonce_guard; +pub mod transaction; +pub mod tx_hash; +pub mod tx_response; diff --git a/crates/relayer/sovereign-rollup-components/src/types/tx/nonce_guard.rs b/crates/relayer/sovereign-rollup-components/src/types/tx/nonce_guard.rs new file mode 100644 index 00000000..37a90a2e --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/tx/nonce_guard.rs @@ -0,0 +1,16 @@ +use core::ops::Deref; + +use futures::lock::MutexGuard; + +pub struct SovereignNonceGuard<'a> { + pub mutex_guard: MutexGuard<'a, ()>, + pub nonce: u64, +} + +impl<'a> Deref for SovereignNonceGuard<'a> { + type Target = u64; + + fn deref(&self) -> &u64 { + &self.nonce + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/tx/transaction.rs b/crates/relayer/sovereign-rollup-components/src/types/tx/transaction.rs new file mode 100644 index 00000000..2254e7e0 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/tx/transaction.rs @@ -0,0 +1,40 @@ +use borsh::BorshSerialize; +use ed25519_dalek::{Signature, VerifyingKey}; + +#[derive(BorshSerialize)] +pub struct SovereignTransaction { + pub signature: SerializeSignature, + pub pub_key: SerializePublicKey, + pub runtime_msg: Vec, + pub chain_id: u64, + pub max_priority_fee_bips: u64, + pub max_fee: u64, + pub gas_limit: Option<[u64; 2]>, + pub nonce: u64, +} + +#[derive(BorshSerialize)] +pub struct UnsignedSovereignTransaction { + pub runtime_msg: Vec, + pub chain_id: u64, + pub max_priority_fee_bips: u64, + pub max_fee: u64, + pub nonce: u64, + pub gas_limit: Option<[u64; 2]>, +} + +pub struct SerializePublicKey(pub VerifyingKey); + +pub struct SerializeSignature(pub Signature); + +impl BorshSerialize for SerializePublicKey { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_all(self.0.as_bytes()) + } +} + +impl BorshSerialize for SerializeSignature { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + writer.write_all(&self.0.to_bytes()) + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/tx/tx_hash.rs b/crates/relayer/sovereign-rollup-components/src/types/tx/tx_hash.rs new file mode 100644 index 00000000..e5afcbd3 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/tx/tx_hash.rs @@ -0,0 +1,55 @@ +use core::fmt::{Debug, Display}; + +use hex::{FromHex, ToHex}; +use serde::de::Error as _; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use sha2::{Digest, Sha256}; + +pub struct TxHash(pub [u8; 32]); + +impl TxHash { + pub fn from_signed_tx_bytes(tx_bytes: &[u8]) -> Self { + let mut hasher = Sha256::new(); + hasher.update(tx_bytes); + let hash_bytes = hasher.finalize().into(); + Self(hash_bytes) + } +} + +impl Display for TxHash { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "0x")?; + write!(f, "{}", self.0.encode_hex::())?; + Ok(()) + } +} + +impl Debug for TxHash { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self)?; + Ok(()) + } +} + +impl Serialize for TxHash { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} + +impl<'de> Deserialize<'de> for TxHash { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let hex_string_with_prefix = String::deserialize(deserializer)?; + + let hash_string = hex_string_with_prefix.trim_start_matches("0x"); + let hash_bytes = <[u8; 32]>::from_hex(hash_string).map_err(D::Error::custom)?; + + Ok(Self(hash_bytes)) + } +} diff --git a/crates/relayer/sovereign-rollup-components/src/types/tx/tx_response.rs b/crates/relayer/sovereign-rollup-components/src/types/tx/tx_response.rs new file mode 100644 index 00000000..6fbcf698 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/types/tx/tx_response.rs @@ -0,0 +1,27 @@ +use serde::Deserialize; + +use crate::types::event::SovereignEvent; +use crate::types::tx::tx_hash::TxHash; + +#[derive(Debug, Deserialize)] +pub struct TxResponse { + pub hash: TxHash, + pub events: Vec, + pub custom_receipt: TxEffect, +} + +#[derive(Debug, Deserialize)] +pub enum TxEffect { + Reverted, + Successful, + CannotReserveGas, + InsufficientBaseGas, + Duplicate, + CannotResolveContext, +} + +pub enum TxError { + Reverted, + InsufficientBaseGas, + Duplicate, +} diff --git a/crates/relayer/sovereign-rollup-components/src/utils/encode_tx.rs b/crates/relayer/sovereign-rollup-components/src/utils/encode_tx.rs new file mode 100644 index 00000000..eb9512dc --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/utils/encode_tx.rs @@ -0,0 +1,60 @@ +use borsh::ser::BorshSerialize; +use ed25519_dalek::{Signer, SigningKey}; + +use crate::types::tx::transaction::{ + SerializePublicKey, SerializeSignature, SovereignTransaction, UnsignedSovereignTransaction, +}; + +pub fn sign_sovereign_tx( + signing_key: &SigningKey, + message: Vec, + chain_id: u64, + max_priority_fee_bips: u64, + max_fee: u64, + nonce: u64, +) -> Result { + let unsigned_tx = UnsignedSovereignTransaction { + runtime_msg: message.clone(), + chain_id, + max_priority_fee_bips, + max_fee, + nonce, + gas_limit: None, + }; + + let sign_bytes = BorshSerialize::try_to_vec(&unsigned_tx)?; + + let signature = signing_key.sign(&sign_bytes); + let public_key = signing_key.verifying_key(); + + Ok(SovereignTransaction { + signature: SerializeSignature(signature), + pub_key: SerializePublicKey(public_key), + runtime_msg: message, + chain_id, + max_priority_fee_bips, + max_fee, + gas_limit: None, + nonce, + }) +} + +pub fn encode_and_sign_sovereign_tx( + signing_key: &SigningKey, + message: Vec, + chain_id: u64, + max_priority_fee_bips: u64, + max_fee: u64, + nonce: u64, +) -> Result, std::io::Error> { + let transaction = sign_sovereign_tx( + signing_key, + message, + chain_id, + max_priority_fee_bips, + max_fee, + nonce, + )?; + + transaction.try_to_vec() +} diff --git a/crates/relayer/sovereign-rollup-components/src/utils/mod.rs b/crates/relayer/sovereign-rollup-components/src/utils/mod.rs new file mode 100644 index 00000000..1b649b18 --- /dev/null +++ b/crates/relayer/sovereign-rollup-components/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod encode_tx; diff --git a/crates/relayer/sovereign-test-components/Cargo.toml b/crates/relayer/sovereign-test-components/Cargo.toml new file mode 100644 index 00000000..e22224c6 --- /dev/null +++ b/crates/relayer/sovereign-test-components/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "hermes-sovereign-test-components" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } +readme = "README.md" +description = """ + Dependencies for running Sovereign integration tests +""" + +[dependencies] +cgp-core = { workspace = true } +hermes-runtime-components = { workspace = true } +hermes-runtime = { workspace = true } +hermes-relayer-components = { workspace = true } +hermes-test-components = { workspace = true } +hermes-cosmos-test-components = { workspace = true } +hermes-celestia-test-components = { workspace = true } +hermes-sovereign-chain-components = { workspace = true } +hermes-sovereign-rollup-components = { workspace = true } + +ibc = { workspace = true } +ibc-relayer = { workspace = true } +ibc-relayer-types = { workspace = true } + +serde = { workspace = true } +serde_json = { workspace = true } +toml = { workspace = true } +ed25519-dalek = { version = "2.1.1" } +sha2 = { version = "0.10.8" } +hex = { version = "0.4.3" } +rand = { workspace = true } +bech32 = { workspace = true } +jsonrpsee = { workspace = true, features = [ "http-client" ] } diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/components.rs b/crates/relayer/sovereign-test-components/src/bootstrap/components.rs new file mode 100644 index 00000000..843b04aa --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/components.rs @@ -0,0 +1,42 @@ +use cgp_core::prelude::*; + +use crate::bootstrap::impls::bootstrap_rollup::BootstrapSovereignRollup; +use crate::bootstrap::impls::generate_rollup_genesis::GenerateSovereignGenesis; +use crate::bootstrap::impls::generate_rollup_wallets::GenerateSovereignRollupWallets; +use crate::bootstrap::impls::init_rollup_node_config::InitSovereignRollupNodeConfig; +use crate::bootstrap::impls::start_rollup::StartSovereignRollup; +use crate::bootstrap::impls::types::rollup_genesis_config::ProvideSovereignGenesisConfig; +use crate::bootstrap::impls::types::rollup_node_config::ProvideSovereignRollupNodeConfig; +use crate::bootstrap::impls::write_rollup_genesis::WriteSovereignGenesis; +use crate::bootstrap::traits::bootstrap_rollup::RollupBootstrapperComponent; +use crate::bootstrap::traits::generate_rollup_genesis::RollupGenesisGeneratorComponent; +use crate::bootstrap::traits::generate_rollup_wallets::RollupWalletGeneratorComponent; +use crate::bootstrap::traits::init_rollup_node_config::RollupNodeConfigInitializerComponent; +use crate::bootstrap::traits::start_rollup::RollupStarterComponent; +use crate::bootstrap::traits::types::rollup_genesis_config::RollupGenesisConfigTypeComponent; +use crate::bootstrap::traits::types::rollup_node_config::RollupNodeConfigTypeComponent; +use crate::bootstrap::traits::write_rollup_genesis::RollupGenesisWriterComponent; + +pub struct SovereignBootstrapComponents; + +delegate_components! { + #[mark_component(IsSovereignBootstrapComponent)] + SovereignBootstrapComponents { + RollupNodeConfigTypeComponent: + ProvideSovereignRollupNodeConfig, + RollupGenesisConfigTypeComponent: + ProvideSovereignGenesisConfig, + RollupBootstrapperComponent: + BootstrapSovereignRollup, + RollupNodeConfigInitializerComponent: + InitSovereignRollupNodeConfig, + RollupWalletGeneratorComponent: + GenerateSovereignRollupWallets, + RollupGenesisGeneratorComponent: + GenerateSovereignGenesis, + RollupGenesisWriterComponent: + WriteSovereignGenesis, + RollupStarterComponent: + StartSovereignRollup, + } +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/impls/bootstrap_rollup.rs b/crates/relayer/sovereign-test-components/src/bootstrap/impls/bootstrap_rollup.rs new file mode 100644 index 00000000..66d6aa26 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/impls/bootstrap_rollup.rs @@ -0,0 +1,109 @@ +use cgp_core::CanRaiseError; +use hermes_celestia_test_components::bootstrap::traits::types::bridge_driver::HasBridgeDriverType; +use hermes_cosmos_test_components::chain::types::wallet::CosmosTestWallet; +use hermes_runtime_components::traits::fs::create_dir::CanCreateDir; +use hermes_runtime_components::traits::fs::file_path::HasFilePathType; +use hermes_runtime_components::traits::os::child_process::HasChildProcessType; +use hermes_runtime_components::traits::runtime::HasRuntime; +use hermes_runtime_components::traits::sleep::CanSleep; +use hermes_sovereign_chain_components::sovereign::traits::chain::rollup::HasRollupType; +use hermes_test_components::chain::traits::types::wallet::HasWalletType; +use hermes_test_components::chain_driver::traits::fields::wallet::HasWallets; +use hermes_test_components::chain_driver::traits::types::chain::HasChainType; +use hermes_test_components::driver::traits::types::chain_driver::HasChainDriverType; + +use crate::bootstrap::traits::bootstrap_rollup::RollupBootstrapper; +use crate::bootstrap::traits::build_rollup_driver::CanBuildRollupDriver; +use crate::bootstrap::traits::generate_rollup_genesis::CanGenerateRollupGenesis; +use crate::bootstrap::traits::generate_rollup_wallets::CanGenerateRollupWallets; +use crate::bootstrap::traits::init_rollup_node_config::CanInitRollupNodeConfig; +use crate::bootstrap::traits::rollup_store_dir::HasRollupStoreDir; +use crate::bootstrap::traits::start_rollup::CanStartRollup; +use crate::bootstrap::traits::types::rollup_driver::HasRollupDriverType; +use crate::bootstrap::traits::write_rollup_genesis::CanWriteRollupGenesis; + +pub struct BootstrapSovereignRollup; + +impl RollupBootstrapper + for BootstrapSovereignRollup +where + Bootstrap: HasRuntime + + HasChainType + + HasRollupType + + HasChainDriverType + + HasBridgeDriverType + + HasRollupDriverType + + HasRollupStoreDir + + CanInitRollupNodeConfig + + CanGenerateRollupWallets + + CanGenerateRollupGenesis + + CanWriteRollupGenesis + + CanStartRollup + + CanBuildRollupDriver + + CanRaiseError<&'static str> + + CanRaiseError, + Chain: HasWalletType, + ChainDriver: HasChainType + HasWallets, + Rollup: HasWalletType, + Runtime: HasFilePathType + HasChildProcessType + CanCreateDir + CanSleep, +{ + async fn bootstrap_rollup( + bootstrap: &Bootstrap, + chain_driver: &ChainDriver, + bridge_driver: &Bootstrap::BridgeDriver, + rollup_id: &str, + ) -> Result { + let rollup_home_dir = Runtime::join_file_path( + bootstrap.rollup_store_dir(), + &Runtime::file_path_from_string(rollup_id), + ); + + bootstrap + .runtime() + .create_dir(&rollup_home_dir) + .await + .map_err(Bootstrap::raise_error)?; + + // TODO: Use `HasWalletAt` instead once we define a + // `CelestiaChainDriver` context that implements that. + let sequencer_wallet = chain_driver.wallets().get("sequencer").ok_or_else(|| { + Bootstrap::raise_error("expected chain driver to contain sequencer wallet") + })?; + + let sequencer_address = Chain::wallet_address(sequencer_wallet); + + let rollup_node_config = bootstrap + .init_rollup_node_config(&rollup_home_dir, bridge_driver, sequencer_address) + .await?; + + let rollup_wallets = bootstrap.generate_rollup_wallets().await?; + + let rollup_genesis = bootstrap + .generate_rollup_genesis(sequencer_address, &rollup_wallets) + .await?; + + bootstrap + .write_rollup_genesis(&rollup_home_dir, &rollup_genesis) + .await?; + + let rollup_process = bootstrap.start_rollup(&rollup_home_dir).await?; + + bootstrap + .runtime() + .sleep(core::time::Duration::from_secs(2)) + .await; + + let rollup_driver = bootstrap + .build_rollup_driver( + rollup_node_config, + rollup_genesis, + rollup_wallets, + rollup_process, + ) + .await?; + + // TODO: spawn rollup child process + + Ok(rollup_driver) + } +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/impls/generate_rollup_genesis.rs b/crates/relayer/sovereign-test-components/src/bootstrap/impls/generate_rollup_genesis.rs new file mode 100644 index 00000000..4353563e --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/impls/generate_rollup_genesis.rs @@ -0,0 +1,113 @@ +use alloc::collections::BTreeMap; + +use cgp_core::CanRaiseError; +use hermes_cosmos_test_components::bootstrap::traits::fields::account_prefix::HasAccountPrefix; +use hermes_runtime_components::traits::runtime::HasRuntime; +use hermes_sovereign_chain_components::sovereign::traits::chain::rollup::HasRollupType; +use hermes_test_components::chain::traits::types::address::HasAddressType; +use hermes_test_components::chain::traits::types::wallet::HasWalletType; +use hermes_test_components::chain_driver::traits::types::chain::HasChainType; + +use crate::bootstrap::traits::generate_rollup_genesis::RollupGenesisGenerator; +use crate::bootstrap::traits::types::rollup_genesis_config::HasRollupGenesisConfigType; +use crate::types::rollup_genesis_config::{ + AccountGenesis, AccountsGenesis, BankGenesis, ChainStateGenesis, ProverIncentivesGenesis, + SequencerRegistryGenesis, SovereignGenesisConfig, TimeGenesis, TokenGenesis, +}; +use crate::types::wallet::{encode_token_address, SovereignWallet}; + +pub struct GenerateSovereignGenesis; + +impl RollupGenesisGenerator + for GenerateSovereignGenesis +where + Bootstrap: HasRuntime + + HasRollupGenesisConfigType + + HasAccountPrefix + + HasChainType + + HasRollupType + + CanRaiseError + + CanRaiseError<&'static str>, + Chain: HasAddressType, + Rollup: HasWalletType, +{ + async fn generate_rollup_genesis( + _bootstrap: &Bootstrap, + sequencer_da_address: &Chain::Address, + rollup_wallets: &BTreeMap, + ) -> Result { + let sequencer_wallet = rollup_wallets + .get("sequencer") + .ok_or_else(|| Bootstrap::raise_error("expect sequencer wallet to be present"))?; + + let prover_wallet = rollup_wallets + .get("prover") + .ok_or_else(|| Bootstrap::raise_error("expect prover wallet to be present"))?; + + let address_and_balances = rollup_wallets + .values() + .map(|wallet| (wallet.address.address.clone(), 1_000_000_000_000)) + .collect::>(); + + // The token address is derived based on the code `get_genesis_token_address` at + // . + // At the moment of writing, the sender (deployer) address is all zeroes. + // + // NOTE: The gas token address is _hardcoded_ as a constant in the rollup starter. + // So if we use a different address, the rollup bootstrapping would fail. + let staking_token_address = + encode_token_address("stake", &[0; 32], 0, "token_").map_err(Bootstrap::raise_error)?; + + let transfer_token_address = + encode_token_address("coin", &[0; 32], 0, "token_").map_err(Bootstrap::raise_error)?; + + let accounts = rollup_wallets + .values() + .map(|wallet| AccountGenesis { + credential_id: wallet.credential_id.clone(), + address: wallet.address.address.clone(), + }) + .collect(); + + let rollup_genesis = SovereignGenesisConfig { + accounts: AccountsGenesis { accounts }, + bank: BankGenesis { + gas_token_config: TokenGenesis { + token_name: "stake".to_owned(), + token_id: staking_token_address.address.clone(), + address_and_balances: address_and_balances.clone(), + authorized_minters: vec![], + salt: 0, + }, + tokens: vec![TokenGenesis { + token_name: "coin".to_owned(), + token_id: transfer_token_address.address.clone(), + address_and_balances, + authorized_minters: vec![], + salt: 0, + }], + }, + chain_state: ChainStateGenesis { + current_time: TimeGenesis { secs: 0, nanos: 0 }, + genesis_da_height: 0, + inner_code_commitment: [0; 8], + outer_code_commitment: [0; 32], + }, + sequencer_registry: SequencerRegistryGenesis { + seq_rollup_address: sequencer_wallet.address.address.clone(), + seq_da_address: sequencer_da_address.to_string(), + minimum_bond: 10000, + is_preferred_sequencer: true, + }, + prover_incentives: ProverIncentivesGenesis { + proving_penalty: 10, + minimum_bond: 10, + initial_provers: vec![(prover_wallet.address.address.clone(), 10)], + }, + staking_token_address, + transfer_token_address, + }; + + Ok(rollup_genesis) + } +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/impls/generate_rollup_wallets.rs b/crates/relayer/sovereign-test-components/src/bootstrap/impls/generate_rollup_wallets.rs new file mode 100644 index 00000000..d9aa8325 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/impls/generate_rollup_wallets.rs @@ -0,0 +1,35 @@ +use alloc::collections::BTreeMap; + +use cgp_core::CanRaiseError; +use hermes_cosmos_test_components::bootstrap::traits::fields::account_prefix::HasAccountPrefix; +use hermes_sovereign_chain_components::sovereign::traits::chain::rollup::HasRollupType; +use hermes_test_components::chain::traits::types::wallet::HasWalletType; + +use crate::bootstrap::traits::generate_rollup_wallets::RollupWalletGenerator; +use crate::types::wallet::SovereignWallet; + +pub struct GenerateSovereignRollupWallets; + +impl RollupWalletGenerator for GenerateSovereignRollupWallets +where + Bootstrap: HasRollupType + HasAccountPrefix + CanRaiseError, + Rollup: HasWalletType, +{ + async fn generate_rollup_wallets( + bootstrap: &Bootstrap, + ) -> Result, Bootstrap::Error> { + let account_prefix = bootstrap.account_prefix(); + let wallet_ids = ["sequencer", "prover", "relayer", "user-a", "user-b"]; + + let wallets = wallet_ids + .iter() + .map(|wallet_id| { + let wallet = SovereignWallet::generate(wallet_id, account_prefix)?; + Ok((wallet_id.to_string(), wallet)) + }) + .collect::, _>>() + .map_err(Bootstrap::raise_error)?; + + Ok(BTreeMap::from_iter(wallets)) + } +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/impls/init_rollup_node_config.rs b/crates/relayer/sovereign-test-components/src/bootstrap/impls/init_rollup_node_config.rs new file mode 100644 index 00000000..a4ebd0ce --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/impls/init_rollup_node_config.rs @@ -0,0 +1,104 @@ +use core::fmt::Display; + +use cgp_core::CanRaiseError; +use hermes_celestia_test_components::bootstrap::traits::types::bridge_driver::HasBridgeDriverType; +use hermes_celestia_test_components::bridge_driver::traits::bridge_auth_token::HasBridgeAuthToken; +use hermes_celestia_test_components::bridge_driver::traits::bridge_rpc_port::HasBridgeRpcPort; +use hermes_runtime_components::traits::fs::write_file::CanWriteStringToFile; +use hermes_runtime_components::traits::os::reserve_port::CanReserveTcpPort; +use hermes_runtime_components::traits::runtime::HasRuntime; +use hermes_test_components::chain::traits::types::address::HasAddressType; +use hermes_test_components::chain_driver::traits::types::chain::HasChainType; + +use crate::bootstrap::traits::init_rollup_node_config::RollupNodeConfigInitializer; +use crate::bootstrap::traits::types::rollup_node_config::HasRollupNodeConfigType; +use crate::types::rollup_node_config::{ + SovereignAxumConfig, SovereignDaConfig, SovereignProverConfig, SovereignRollupNodeConfig, + SovereignRpcConfig, SovereignRunnerConfig, SovereignStorageConfig, +}; + +pub struct InitSovereignRollupNodeConfig; + +impl RollupNodeConfigInitializer + for InitSovereignRollupNodeConfig +where + Bootstrap: HasRuntime + + HasChainType + + HasBridgeDriverType + + HasRollupNodeConfigType + + CanRaiseError + + CanRaiseError, + Runtime: CanReserveTcpPort + CanWriteStringToFile, + Chain: HasAddressType, + BridgeDriver: HasBridgeRpcPort + HasBridgeAuthToken, + BridgeDriver::BridgeAuthToken: Display, + Bootstrap::RollupNodeConfig: From, +{ + async fn init_rollup_node_config( + bootstrap: &Bootstrap, + rollup_home_dir: &Runtime::FilePath, + bridge_driver: &BridgeDriver, + sequencer_da_address: &Chain::Address, + ) -> Result { + let runtime = bootstrap.runtime(); + + let bridge_rpc_port = bridge_driver.bridge_rpc_port(); + let auth_token = bridge_driver.bridge_auth_token(); + + let config_path = Runtime::join_file_path( + rollup_home_dir, + &Runtime::file_path_from_string("config.toml"), + ); + + let data_path = + Runtime::join_file_path(rollup_home_dir, &Runtime::file_path_from_string("data")); + + let rollup_rpc_port = runtime + .reserve_tcp_port() + .await + .map_err(Bootstrap::raise_error)?; + + let rollup_axum_port = runtime + .reserve_tcp_port() + .await + .map_err(Bootstrap::raise_error)?; + + let rollup_node_config = SovereignRollupNodeConfig { + da: SovereignDaConfig { + celestia_rpc_auth_token: auth_token.to_string(), + celestia_rpc_address: format!("http://127.0.0.1:{bridge_rpc_port}"), + max_celestia_response_body_size: 104_857_600, + celestia_rpc_timeout_seconds: 60, + own_celestia_address: sequencer_da_address.to_string(), + }, + storage: SovereignStorageConfig { + path: Runtime::file_path_to_string(&data_path), + }, + runner: SovereignRunnerConfig { + genesis_height: 1, + rpc_config: SovereignRpcConfig { + bind_host: "127.0.0.1".into(), + bind_port: rollup_rpc_port, + }, + axum_config: SovereignAxumConfig { + bind_host: "127.0.0.1".into(), + bind_port: rollup_axum_port, + }, + da_polling_interval_ms: 10000, + }, + proof_manager: SovereignProverConfig { + aggregated_proof_block_jump: 1, + }, + }; + + let rollup_node_config_str = + toml::to_string_pretty(&rollup_node_config).map_err(Bootstrap::raise_error)?; + + runtime + .write_string_to_file(&config_path, &rollup_node_config_str) + .await + .map_err(Bootstrap::raise_error)?; + + Ok(rollup_node_config.into()) + } +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/impls/mod.rs b/crates/relayer/sovereign-test-components/src/bootstrap/impls/mod.rs new file mode 100644 index 00000000..5353e9b2 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/impls/mod.rs @@ -0,0 +1,7 @@ +pub mod bootstrap_rollup; +pub mod generate_rollup_genesis; +pub mod generate_rollup_wallets; +pub mod init_rollup_node_config; +pub mod start_rollup; +pub mod types; +pub mod write_rollup_genesis; diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/impls/start_rollup.rs b/crates/relayer/sovereign-test-components/src/bootstrap/impls/start_rollup.rs new file mode 100644 index 00000000..0925c76d --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/impls/start_rollup.rs @@ -0,0 +1,74 @@ +use cgp_core::CanRaiseError; +use hermes_runtime_components::traits::fs::file_path::HasFilePathType; +use hermes_runtime_components::traits::os::child_process::CanStartChildProcess; +use hermes_runtime_components::traits::os::reserve_port::CanReserveTcpPort; +use hermes_runtime_components::traits::runtime::HasRuntime; + +use crate::bootstrap::traits::rollup_command_path::HasRollupCommandPath; +use crate::bootstrap::traits::start_rollup::RollupStarter; + +pub struct StartSovereignRollup; + +impl RollupStarter for StartSovereignRollup +where + Bootstrap: HasRuntime + HasRollupCommandPath + CanRaiseError, + Runtime: HasFilePathType + CanStartChildProcess + CanReserveTcpPort, +{ + async fn start_rollup( + bootstrap: &Bootstrap, + rollup_home_dir: &Runtime::FilePath, + ) -> Result { + let rollup_node_config_path = Runtime::join_file_path( + rollup_home_dir, + &Runtime::file_path_from_string("config.toml"), + ); + + let rollup_genesis_path = + Runtime::join_file_path(rollup_home_dir, &Runtime::file_path_from_string("genesis")); + + let rollup_chain_state_path = Runtime::join_file_path( + rollup_home_dir, + &Runtime::file_path_from_string("genesis/chain_state.json"), + ); + + let stdout_path = Runtime::join_file_path( + rollup_home_dir, + &Runtime::file_path_from_string("stdout.log"), + ); + + let stderr_path = Runtime::join_file_path( + rollup_home_dir, + &Runtime::file_path_from_string("stderr.log"), + ); + + let runtime = bootstrap.runtime(); + + let metrics_port = runtime + .reserve_tcp_port() + .await + .map_err(Bootstrap::raise_error)?; + + let child = bootstrap + .runtime() + .start_child_process( + bootstrap.rollup_command_path(), + &[ + "--rollup-config-path", + &Runtime::file_path_to_string(&rollup_node_config_path), + "--genesis-paths", + &Runtime::file_path_to_string(&rollup_genesis_path), + "--kernel-genesis-paths", + &Runtime::file_path_to_string(&rollup_chain_state_path), + "--metrics", + &metrics_port.to_string(), + ], + &[("RUST_BACKTRACE", "full")], + Some(&stdout_path), + Some(&stderr_path), + ) + .await + .map_err(Bootstrap::raise_error)?; + + Ok(child) + } +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/impls/types/mod.rs b/crates/relayer/sovereign-test-components/src/bootstrap/impls/types/mod.rs new file mode 100644 index 00000000..fed949ee --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/impls/types/mod.rs @@ -0,0 +1,2 @@ +pub mod rollup_genesis_config; +pub mod rollup_node_config; diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/impls/types/rollup_genesis_config.rs b/crates/relayer/sovereign-test-components/src/bootstrap/impls/types/rollup_genesis_config.rs new file mode 100644 index 00000000..2eef3381 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/impls/types/rollup_genesis_config.rs @@ -0,0 +1,13 @@ +use cgp_core::Async; + +use crate::bootstrap::traits::types::rollup_genesis_config::ProvideRollupGenesisConfigType; +use crate::types::rollup_genesis_config::SovereignGenesisConfig; + +pub struct ProvideSovereignGenesisConfig; + +impl ProvideRollupGenesisConfigType for ProvideSovereignGenesisConfig +where + Bootstrap: Async, +{ + type RollupGenesisConfig = SovereignGenesisConfig; +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/impls/types/rollup_node_config.rs b/crates/relayer/sovereign-test-components/src/bootstrap/impls/types/rollup_node_config.rs new file mode 100644 index 00000000..d144f2e6 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/impls/types/rollup_node_config.rs @@ -0,0 +1,13 @@ +use cgp_core::Async; + +use crate::bootstrap::traits::types::rollup_node_config::ProvideRollupNodeConfigType; +use crate::types::rollup_node_config::SovereignRollupNodeConfig; + +pub struct ProvideSovereignRollupNodeConfig; + +impl ProvideRollupNodeConfigType for ProvideSovereignRollupNodeConfig +where + Bootstrap: Async, +{ + type RollupNodeConfig = SovereignRollupNodeConfig; +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/impls/write_rollup_genesis.rs b/crates/relayer/sovereign-test-components/src/bootstrap/impls/write_rollup_genesis.rs new file mode 100644 index 00000000..a654ece3 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/impls/write_rollup_genesis.rs @@ -0,0 +1,120 @@ +use cgp_core::CanRaiseError; +use hermes_runtime_components::traits::fs::create_dir::CanCreateDir; +use hermes_runtime_components::traits::fs::file_path::HasFilePathType; +use hermes_runtime_components::traits::fs::write_file::CanWriteStringToFile; +use hermes_runtime_components::traits::runtime::HasRuntime; +use serde_json as json; + +use crate::bootstrap::traits::types::rollup_genesis_config::HasRollupGenesisConfigType; +use crate::bootstrap::traits::write_rollup_genesis::RollupGenesisWriter; +use crate::types::rollup_genesis_config::SovereignGenesisConfig; + +pub struct WriteSovereignGenesis; + +impl RollupGenesisWriter for WriteSovereignGenesis +where + Bootstrap: HasRuntime + + HasRollupGenesisConfigType + + CanRaiseError + + CanRaiseError, + Runtime: HasFilePathType + CanWriteStringToFile + CanCreateDir, +{ + async fn write_rollup_genesis( + bootstrap: &Bootstrap, + rollup_home_dir: &Runtime::FilePath, + genesis_config: &SovereignGenesisConfig, + ) -> Result<(), Bootstrap::Error> { + let runtime = bootstrap.runtime(); + + let genesis_dir = + Runtime::join_file_path(rollup_home_dir, &Runtime::file_path_from_string("genesis")); + + runtime + .create_dir(&genesis_dir) + .await + .map_err(Bootstrap::raise_error)?; + + { + let account_genesis_path = Runtime::join_file_path( + &genesis_dir, + &Runtime::file_path_from_string("accounts.json"), + ); + + let account_genesis_str = + json::to_string_pretty(&genesis_config.accounts).map_err(Bootstrap::raise_error)?; + + runtime + .write_string_to_file(&account_genesis_path, &account_genesis_str) + .await + .map_err(Bootstrap::raise_error)? + } + + { + let bank_genesis_path = + Runtime::join_file_path(&genesis_dir, &Runtime::file_path_from_string("bank.json")); + + let bank_genesis_str = + json::to_string_pretty(&genesis_config.bank).map_err(Bootstrap::raise_error)?; + + runtime + .write_string_to_file(&bank_genesis_path, &bank_genesis_str) + .await + .map_err(Bootstrap::raise_error)? + } + + { + let chain_state_genesis_path = Runtime::join_file_path( + &genesis_dir, + &Runtime::file_path_from_string("chain_state.json"), + ); + + let chain_state_genesis_str = json::to_string_pretty(&genesis_config.chain_state) + .map_err(Bootstrap::raise_error)?; + + runtime + .write_string_to_file(&chain_state_genesis_path, &chain_state_genesis_str) + .await + .map_err(Bootstrap::raise_error)? + } + + { + let sequencer_registry_genesis_path = Runtime::join_file_path( + &genesis_dir, + &Runtime::file_path_from_string("sequencer_registry.json"), + ); + + let sequencer_registry_genesis_str = + json::to_string_pretty(&genesis_config.sequencer_registry) + .map_err(Bootstrap::raise_error)?; + + runtime + .write_string_to_file( + &sequencer_registry_genesis_path, + &sequencer_registry_genesis_str, + ) + .await + .map_err(Bootstrap::raise_error)? + } + + { + let prover_incentives_genesis_path = Runtime::join_file_path( + &genesis_dir, + &Runtime::file_path_from_string("prover_incentives.json"), + ); + + let prover_incentives_genesis_str = + json::to_string_pretty(&genesis_config.prover_incentives) + .map_err(Bootstrap::raise_error)?; + + runtime + .write_string_to_file( + &prover_incentives_genesis_path, + &prover_incentives_genesis_str, + ) + .await + .map_err(Bootstrap::raise_error)? + } + + Ok(()) + } +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/mod.rs b/crates/relayer/sovereign-test-components/src/bootstrap/mod.rs new file mode 100644 index 00000000..702a1181 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/mod.rs @@ -0,0 +1,3 @@ +pub mod components; +pub mod impls; +pub mod traits; diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/bootstrap_rollup.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/bootstrap_rollup.rs new file mode 100644 index 00000000..01cda411 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/bootstrap_rollup.rs @@ -0,0 +1,18 @@ +use cgp_core::prelude::*; +use hermes_celestia_test_components::bootstrap::traits::types::bridge_driver::HasBridgeDriverType; +use hermes_test_components::driver::traits::types::chain_driver::HasChainDriverType; + +use crate::bootstrap::traits::types::rollup_driver::HasRollupDriverType; + +#[derive_component(RollupBootstrapperComponent, RollupBootstrapper)] +#[async_trait] +pub trait CanBootstrapRollup: + HasChainDriverType + HasBridgeDriverType + HasRollupDriverType + HasErrorType +{ + async fn bootstrap_rollup( + &self, + chain_driver: &Self::ChainDriver, + bridge_driver: &Self::BridgeDriver, + rollup_id: &str, + ) -> Result; +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/build_rollup_driver.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/build_rollup_driver.rs new file mode 100644 index 00000000..6fe8bddd --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/build_rollup_driver.rs @@ -0,0 +1,33 @@ +use alloc::collections::BTreeMap; + +use cgp_core::prelude::*; +use hermes_runtime_components::traits::os::child_process::{ChildProcessOf, HasChildProcessType}; +use hermes_runtime_components::traits::runtime::HasRuntimeType; +use hermes_sovereign_chain_components::sovereign::traits::chain::rollup::HasRollupType; +use hermes_test_components::chain::traits::types::wallet::{HasWalletType, WalletOf}; + +use crate::bootstrap::traits::types::rollup_driver::HasRollupDriverType; +use crate::bootstrap::traits::types::rollup_genesis_config::HasRollupGenesisConfigType; +use crate::bootstrap::traits::types::rollup_node_config::HasRollupNodeConfigType; + +#[derive_component(RollupDriverBuilderComponent, RollupDriverBuilder)] +#[async_trait] +pub trait CanBuildRollupDriver: + HasRuntimeType + + HasRollupType + + HasRollupDriverType + + HasRollupNodeConfigType + + HasRollupGenesisConfigType + + HasErrorType +where + Self::Runtime: HasChildProcessType, + Self::Rollup: HasWalletType, +{ + async fn build_rollup_driver( + &self, + rollup_node_config: Self::RollupNodeConfig, + rollup_genesis_config: Self::RollupGenesisConfig, + rollup_wallets: BTreeMap>, + rollup_process: ChildProcessOf, + ) -> Result; +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/generate_rollup_genesis.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/generate_rollup_genesis.rs new file mode 100644 index 00000000..33abac0b --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/generate_rollup_genesis.rs @@ -0,0 +1,24 @@ +use alloc::collections::BTreeMap; + +use cgp_core::prelude::*; +use hermes_sovereign_chain_components::sovereign::traits::chain::rollup::HasRollupType; +use hermes_test_components::chain::traits::types::address::{AddressOf, HasAddressType}; +use hermes_test_components::chain::traits::types::wallet::{HasWalletType, WalletOf}; +use hermes_test_components::chain_driver::traits::types::chain::HasChainType; + +use crate::bootstrap::traits::types::rollup_genesis_config::HasRollupGenesisConfigType; + +#[derive_component(RollupGenesisGeneratorComponent, RollupGenesisGenerator)] +#[async_trait] +pub trait CanGenerateRollupGenesis: + HasChainType + HasRollupType + HasRollupGenesisConfigType + HasErrorType +where + Self::Chain: HasAddressType, + Self::Rollup: HasWalletType, +{ + async fn generate_rollup_genesis( + &self, + sequencer_da_address: &AddressOf, + rollup_wallets: &BTreeMap>, + ) -> Result; +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/generate_rollup_wallets.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/generate_rollup_wallets.rs new file mode 100644 index 00000000..30029285 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/generate_rollup_wallets.rs @@ -0,0 +1,16 @@ +use alloc::collections::BTreeMap; + +use cgp_core::prelude::*; +use hermes_sovereign_chain_components::sovereign::traits::chain::rollup::HasRollupType; +use hermes_test_components::chain::traits::types::wallet::{HasWalletType, WalletOf}; + +#[derive_component(RollupWalletGeneratorComponent, RollupWalletGenerator)] +#[async_trait] +pub trait CanGenerateRollupWallets: HasRollupType + HasErrorType +where + Self::Rollup: HasWalletType, +{ + async fn generate_rollup_wallets( + &self, + ) -> Result>, Self::Error>; +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/init_rollup_node_config.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/init_rollup_node_config.rs new file mode 100644 index 00000000..4cf53647 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/init_rollup_node_config.rs @@ -0,0 +1,24 @@ +use cgp_core::prelude::*; +use hermes_celestia_test_components::bootstrap::traits::types::bridge_driver::HasBridgeDriverType; +use hermes_runtime_components::traits::fs::file_path::{FilePathOf, HasFilePathType}; +use hermes_runtime_components::traits::runtime::HasRuntimeType; +use hermes_test_components::chain::traits::types::address::{AddressOf, HasAddressType}; +use hermes_test_components::chain_driver::traits::types::chain::HasChainType; + +use crate::bootstrap::traits::types::rollup_node_config::HasRollupNodeConfigType; + +#[derive_component(RollupNodeConfigInitializerComponent, RollupNodeConfigInitializer)] +#[async_trait] +pub trait CanInitRollupNodeConfig: + HasRuntimeType + HasChainType + HasBridgeDriverType + HasRollupNodeConfigType + HasErrorType +where + Self::Runtime: HasFilePathType, + Self::Chain: HasAddressType, +{ + async fn init_rollup_node_config( + &self, + rollup_home_dir: &FilePathOf, + bridge_driver: &Self::BridgeDriver, + sequencer_da_address: &AddressOf, + ) -> Result; +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/mod.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/mod.rs new file mode 100644 index 00000000..28d03d1c --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/mod.rs @@ -0,0 +1,10 @@ +pub mod bootstrap_rollup; +pub mod build_rollup_driver; +pub mod generate_rollup_genesis; +pub mod generate_rollup_wallets; +pub mod init_rollup_node_config; +pub mod rollup_command_path; +pub mod rollup_store_dir; +pub mod start_rollup; +pub mod types; +pub mod write_rollup_genesis; diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/rollup_command_path.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/rollup_command_path.rs new file mode 100644 index 00000000..c5e903c2 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/rollup_command_path.rs @@ -0,0 +1,11 @@ +use cgp_core::prelude::*; +use hermes_runtime_components::traits::fs::file_path::{FilePathOf, HasFilePathType}; +use hermes_runtime_components::traits::runtime::HasRuntimeType; + +#[derive_component(RollupCommandPathGetterComponent, RollupCommandPathGetter)] +pub trait HasRollupCommandPath: HasRuntimeType +where + Self::Runtime: HasFilePathType, +{ + fn rollup_command_path(&self) -> &FilePathOf; +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/rollup_store_dir.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/rollup_store_dir.rs new file mode 100644 index 00000000..c4d16458 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/rollup_store_dir.rs @@ -0,0 +1,11 @@ +use cgp_core::prelude::*; +use hermes_runtime_components::traits::fs::file_path::{FilePathOf, HasFilePathType}; +use hermes_runtime_components::traits::runtime::HasRuntimeType; + +#[derive_component(RollupStoreDirGetterComponent, RollupStoreDirGetter)] +pub trait HasRollupStoreDir: HasRuntimeType +where + Self::Runtime: HasFilePathType, +{ + fn rollup_store_dir(&self) -> &FilePathOf; +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/start_rollup.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/start_rollup.rs new file mode 100644 index 00000000..3bf0efe5 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/start_rollup.rs @@ -0,0 +1,16 @@ +use cgp_core::prelude::*; +use hermes_runtime_components::traits::fs::file_path::{FilePathOf, HasFilePathType}; +use hermes_runtime_components::traits::os::child_process::{ChildProcessOf, HasChildProcessType}; +use hermes_runtime_components::traits::runtime::HasRuntimeType; + +#[derive_component(RollupStarterComponent, RollupStarter)] +#[async_trait] +pub trait CanStartRollup: HasRuntimeType + HasErrorType +where + Self::Runtime: HasChildProcessType + HasFilePathType, +{ + async fn start_rollup( + &self, + rollup_home_dir: &FilePathOf, + ) -> Result, Self::Error>; +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/types/mod.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/types/mod.rs new file mode 100644 index 00000000..34f2625d --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/types/mod.rs @@ -0,0 +1,3 @@ +pub mod rollup_driver; +pub mod rollup_genesis_config; +pub mod rollup_node_config; diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/types/rollup_driver.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/types/rollup_driver.rs new file mode 100644 index 00000000..f5297311 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/types/rollup_driver.rs @@ -0,0 +1,6 @@ +use cgp_core::prelude::*; + +#[derive_component(RollupDriverTypeComponent, ProvideRollupDriverType)] +pub trait HasRollupDriverType: Async { + type RollupDriver: Async; +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/types/rollup_genesis_config.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/types/rollup_genesis_config.rs new file mode 100644 index 00000000..b6fe9c35 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/types/rollup_genesis_config.rs @@ -0,0 +1,6 @@ +use cgp_core::prelude::*; + +#[derive_component(RollupGenesisConfigTypeComponent, ProvideRollupGenesisConfigType)] +pub trait HasRollupGenesisConfigType: Async { + type RollupGenesisConfig: Async; +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/types/rollup_node_config.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/types/rollup_node_config.rs new file mode 100644 index 00000000..82e1cfd5 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/types/rollup_node_config.rs @@ -0,0 +1,6 @@ +use cgp_core::prelude::*; + +#[derive_component(RollupNodeConfigTypeComponent, ProvideRollupNodeConfigType)] +pub trait HasRollupNodeConfigType: Async { + type RollupNodeConfig: Async; +} diff --git a/crates/relayer/sovereign-test-components/src/bootstrap/traits/write_rollup_genesis.rs b/crates/relayer/sovereign-test-components/src/bootstrap/traits/write_rollup_genesis.rs new file mode 100644 index 00000000..906c1c24 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/bootstrap/traits/write_rollup_genesis.rs @@ -0,0 +1,19 @@ +use cgp_core::prelude::*; +use hermes_runtime_components::traits::fs::file_path::{FilePathOf, HasFilePathType}; +use hermes_runtime_components::traits::runtime::HasRuntimeType; + +use crate::bootstrap::traits::types::rollup_genesis_config::HasRollupGenesisConfigType; + +#[derive_component(RollupGenesisWriterComponent, RollupGenesisWriter)] +#[async_trait] +pub trait CanWriteRollupGenesis: + HasRollupGenesisConfigType + HasRuntimeType + HasErrorType +where + Self::Runtime: HasFilePathType, +{ + async fn write_rollup_genesis( + &self, + rollup_home_dir: &FilePathOf, + genesis_config: &Self::RollupGenesisConfig, + ) -> Result<(), Self::Error>; +} diff --git a/crates/relayer/sovereign-test-components/src/lib.rs b/crates/relayer/sovereign-test-components/src/lib.rs new file mode 100644 index 00000000..98758edc --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/lib.rs @@ -0,0 +1,5 @@ +extern crate alloc; + +pub mod bootstrap; +pub mod rollup; +pub mod types; diff --git a/crates/relayer/sovereign-test-components/src/rollup/components.rs b/crates/relayer/sovereign-test-components/src/rollup/components.rs new file mode 100644 index 00000000..cdcc510b --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/rollup/components.rs @@ -0,0 +1,54 @@ +use cgp_core::prelude::*; +use hermes_cosmos_test_components::chain::impls::transfer::timeout::IbcTransferTimeoutAfterSeconds; +use hermes_cosmos_test_components::chain::impls::types::address::ProvideStringAddress; +use hermes_test_components::chain::impls::assert::default_assert_duration::ProvideDefaultPollAssertDuration; +use hermes_test_components::chain::impls::assert::poll_assert_eventual_amount::PollAssertEventualAmount; +use hermes_test_components::chain::impls::default_memo::ProvideDefaultMemo; +use hermes_test_components::chain::impls::ibc_transfer::SendIbcTransferMessage; +use hermes_test_components::chain::traits::assert::eventual_amount::EventualAmountAsserterComponent; +use hermes_test_components::chain::traits::assert::poll_assert::PollAssertDurationGetterComponent; +use hermes_test_components::chain::traits::messages::ibc_transfer::IbcTokenTransferMessageBuilderComponent; +use hermes_test_components::chain::traits::queries::balance::BalanceQuerierComponent; +use hermes_test_components::chain::traits::transfer::ibc_transfer::TokenIbcTransferrerComponent; +use hermes_test_components::chain::traits::transfer::string_memo::ProvideStringMemoType; +use hermes_test_components::chain::traits::transfer::timeout::IbcTransferTimeoutCalculatorComponent; +use hermes_test_components::chain::traits::types::address::AddressTypeComponent; +use hermes_test_components::chain::traits::types::amount::AmountTypeComponent; +use hermes_test_components::chain::traits::types::denom::DenomTypeComponent; +use hermes_test_components::chain::traits::types::memo::{ + DefaultMemoGetterComponent, MemoTypeComponent, +}; +use hermes_test_components::chain::traits::types::wallet::WalletTypeComponent; + +use crate::rollup::impls::ibc_transfer_message::BuildSovereignIbcTransferMessage; +use crate::rollup::impls::queries::balance::QuerySovereignBalance; +use crate::rollup::impls::types::amount::ProvideSovereignAmountType; +use crate::rollup::impls::types::denom::ProvideSovereignDenomType; +use crate::rollup::impls::types::wallet::ProvideSovereignWalletType; + +pub struct SovereignRollupTestComponents; + +delegate_components! { + #[mark_component(IsSovereignRollupTestComponent)] + SovereignRollupTestComponents { + AddressTypeComponent: ProvideStringAddress, + DenomTypeComponent: ProvideSovereignDenomType, + AmountTypeComponent: ProvideSovereignAmountType, + WalletTypeComponent: ProvideSovereignWalletType, + BalanceQuerierComponent: QuerySovereignBalance, + MemoTypeComponent: + ProvideStringMemoType, + DefaultMemoGetterComponent: + ProvideDefaultMemo, + TokenIbcTransferrerComponent: + SendIbcTransferMessage, + IbcTransferTimeoutCalculatorComponent: + IbcTransferTimeoutAfterSeconds<90>, + IbcTokenTransferMessageBuilderComponent: + BuildSovereignIbcTransferMessage, + EventualAmountAsserterComponent: + PollAssertEventualAmount, + PollAssertDurationGetterComponent: + ProvideDefaultPollAssertDuration, + } +} diff --git a/crates/relayer/sovereign-test-components/src/rollup/impls/ibc_transfer_message.rs b/crates/relayer/sovereign-test-components/src/rollup/impls/ibc_transfer_message.rs new file mode 100644 index 00000000..0774f0ce --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/rollup/impls/ibc_transfer_message.rs @@ -0,0 +1,45 @@ +use cgp_core::prelude::HasErrorType; +use hermes_relayer_components::chain::traits::types::ibc::HasIbcChainTypes; +use hermes_sovereign_rollup_components::types::height::RollupHeight; +use hermes_sovereign_rollup_components::types::message::SovereignMessage; +use hermes_test_components::chain::traits::messages::ibc_transfer::IbcTokenTransferMessageBuilder; +use hermes_test_components::chain::traits::types::address::HasAddressType; +use hermes_test_components::chain::traits::types::amount::HasAmountType; +use hermes_test_components::chain::traits::types::memo::HasMemoType; +use ibc_relayer_types::core::ics24_host::identifier::{ChannelId, PortId}; +use ibc_relayer_types::timestamp::Timestamp; + +use crate::types::amount::SovereignAmount; + +pub struct BuildSovereignIbcTransferMessage; + +impl IbcTokenTransferMessageBuilder + for BuildSovereignIbcTransferMessage +where + Chain: HasErrorType + + HasAddressType + + HasAmountType + + HasMemoType> + + HasIbcChainTypes< + Counterparty, + ChannelId = ChannelId, + PortId = PortId, + Height = RollupHeight, + Timestamp = Timestamp, + Message = SovereignMessage, + >, + Counterparty: HasAddressType, +{ + async fn build_ibc_token_transfer_message( + _chain: &Chain, + _channel_id: &ChannelId, + _port_id: &PortId, + _recipient_address: &Counterparty::Address, + _amount: &SovereignAmount, + _memo: &Option, + _timeout_height: Option<&RollupHeight>, + _timeout_time: Option<&Timestamp>, + ) -> Result { + todo!() + } +} diff --git a/crates/relayer/sovereign-test-components/src/rollup/impls/mod.rs b/crates/relayer/sovereign-test-components/src/rollup/impls/mod.rs new file mode 100644 index 00000000..4645567c --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/rollup/impls/mod.rs @@ -0,0 +1,3 @@ +pub mod ibc_transfer_message; +pub mod queries; +pub mod types; diff --git a/crates/relayer/sovereign-test-components/src/rollup/impls/queries/balance.rs b/crates/relayer/sovereign-test-components/src/rollup/impls/queries/balance.rs new file mode 100644 index 00000000..7ade2d95 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/rollup/impls/queries/balance.rs @@ -0,0 +1,52 @@ +use cgp_core::CanRaiseError; +use hermes_sovereign_rollup_components::traits::json_rpc_client::HasJsonRpcClient; +use hermes_test_components::chain::traits::queries::balance::BalanceQuerier; +use hermes_test_components::chain::traits::types::address::HasAddressType; +use hermes_test_components::chain::traits::types::amount::HasAmountType; +use hermes_test_components::chain::traits::types::denom::HasDenomType; +use jsonrpsee::core::client::ClientT; +use jsonrpsee::core::ClientError; +use serde::Deserialize; + +use crate::types::amount::SovereignAmount; + +#[derive(Deserialize)] +pub struct Response { + pub amount: u128, +} + +pub struct QuerySovereignBalance; + +impl BalanceQuerier for QuerySovereignBalance +where + Rollup: HasAddressType + + HasDenomType + + HasAmountType + + CanRaiseError + + CanRaiseError + + HasJsonRpcClient, + Rollup::JsonRpcClient: ClientT, +{ + async fn query_balance( + rollup: &Rollup, + address: &Rollup::Address, + denom: &Rollup::Denom, + ) -> Result { + let rpc_client = rollup.json_rpc_client(); + + let response: Response = rpc_client + .request( + "bank_balanceOf", + (None::, address.to_string(), denom.to_string()), + ) + .await + .map_err(Rollup::raise_error)?; + + let amount = SovereignAmount { + quantity: response.amount, + denom: denom.clone(), + }; + + Ok(amount) + } +} diff --git a/crates/relayer/sovereign-test-components/src/rollup/impls/queries/mod.rs b/crates/relayer/sovereign-test-components/src/rollup/impls/queries/mod.rs new file mode 100644 index 00000000..6844c2b6 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/rollup/impls/queries/mod.rs @@ -0,0 +1 @@ +pub mod balance; diff --git a/crates/relayer/sovereign-test-components/src/rollup/impls/types/amount.rs b/crates/relayer/sovereign-test-components/src/rollup/impls/types/amount.rs new file mode 100644 index 00000000..ca1b8087 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/rollup/impls/types/amount.rs @@ -0,0 +1,17 @@ +use hermes_test_components::chain::traits::types::amount::ProvideAmountType; +use hermes_test_components::chain::traits::types::denom::HasDenomType; + +use crate::types::amount::SovereignAmount; + +pub struct ProvideSovereignAmountType; + +impl ProvideAmountType for ProvideSovereignAmountType +where + Rollup: HasDenomType, +{ + type Amount = SovereignAmount; + + fn amount_denom(amount: &SovereignAmount) -> &String { + &amount.denom + } +} diff --git a/crates/relayer/sovereign-test-components/src/rollup/impls/types/denom.rs b/crates/relayer/sovereign-test-components/src/rollup/impls/types/denom.rs new file mode 100644 index 00000000..ec8afce5 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/rollup/impls/types/denom.rs @@ -0,0 +1,11 @@ +use cgp_core::Async; +use hermes_test_components::chain::traits::types::denom::ProvideDenomType; + +pub struct ProvideSovereignDenomType; + +impl ProvideDenomType for ProvideSovereignDenomType +where + Rollup: Async, +{ + type Denom = String; +} diff --git a/crates/relayer/sovereign-test-components/src/rollup/impls/types/mod.rs b/crates/relayer/sovereign-test-components/src/rollup/impls/types/mod.rs new file mode 100644 index 00000000..2decdb8f --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/rollup/impls/types/mod.rs @@ -0,0 +1,3 @@ +pub mod amount; +pub mod denom; +pub mod wallet; diff --git a/crates/relayer/sovereign-test-components/src/rollup/impls/types/wallet.rs b/crates/relayer/sovereign-test-components/src/rollup/impls/types/wallet.rs new file mode 100644 index 00000000..6810d1c1 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/rollup/impls/types/wallet.rs @@ -0,0 +1,17 @@ +use hermes_test_components::chain::traits::types::address::HasAddressType; +use hermes_test_components::chain::traits::types::wallet::ProvideWalletType; + +use crate::types::wallet::SovereignWallet; + +pub struct ProvideSovereignWalletType; + +impl ProvideWalletType for ProvideSovereignWalletType +where + Rollup: HasAddressType
, +{ + type Wallet = SovereignWallet; + + fn wallet_address(wallet: &SovereignWallet) -> &String { + &wallet.address.address + } +} diff --git a/crates/relayer/sovereign-test-components/src/rollup/mod.rs b/crates/relayer/sovereign-test-components/src/rollup/mod.rs new file mode 100644 index 00000000..11b7926d --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/rollup/mod.rs @@ -0,0 +1,2 @@ +pub mod components; +pub mod impls; diff --git a/crates/relayer/sovereign-test-components/src/types/amount.rs b/crates/relayer/sovereign-test-components/src/types/amount.rs new file mode 100644 index 00000000..d2401163 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/types/amount.rs @@ -0,0 +1,30 @@ +use core::cmp::Ordering; +use core::fmt::{self, Display}; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct SovereignAmount { + pub quantity: u128, + pub denom: String, +} + +impl SovereignAmount { + pub fn new(quantity: u128, denom: String) -> Self { + Self { quantity, denom } + } +} + +impl Display for SovereignAmount { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}{}", self.quantity, self.denom) + } +} + +impl PartialOrd for SovereignAmount { + fn partial_cmp(&self, other: &Self) -> Option { + if self.denom == other.denom { + Some(self.quantity.cmp(&other.quantity)) + } else { + None + } + } +} diff --git a/crates/relayer/sovereign-test-components/src/types/mod.rs b/crates/relayer/sovereign-test-components/src/types/mod.rs new file mode 100644 index 00000000..26a9fc6b --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/types/mod.rs @@ -0,0 +1,4 @@ +pub mod amount; +pub mod rollup_genesis_config; +pub mod rollup_node_config; +pub mod wallet; diff --git a/crates/relayer/sovereign-test-components/src/types/rollup_genesis_config.rs b/crates/relayer/sovereign-test-components/src/types/rollup_genesis_config.rs new file mode 100644 index 00000000..bce68242 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/types/rollup_genesis_config.rs @@ -0,0 +1,67 @@ +use hermes_sovereign_rollup_components::types::address::SovereignAddress; +use serde::Serialize; + +pub struct SovereignGenesisConfig { + pub accounts: AccountsGenesis, + pub bank: BankGenesis, + pub chain_state: ChainStateGenesis, + pub sequencer_registry: SequencerRegistryGenesis, + pub prover_incentives: ProverIncentivesGenesis, + pub staking_token_address: SovereignAddress, + pub transfer_token_address: SovereignAddress, +} + +#[derive(Serialize)] +pub struct AccountsGenesis { + pub accounts: Vec, +} + +#[derive(Serialize)] +pub struct AccountGenesis { + pub credential_id: String, + pub address: String, +} + +#[derive(Serialize)] +pub struct BankGenesis { + pub gas_token_config: TokenGenesis, + pub tokens: Vec, +} + +#[derive(Serialize)] +pub struct TokenGenesis { + pub token_name: String, + pub token_id: String, + pub address_and_balances: Vec<(String, u128)>, + pub authorized_minters: Vec, + pub salt: u128, +} + +#[derive(Serialize)] +pub struct ChainStateGenesis { + pub current_time: TimeGenesis, + pub genesis_da_height: u64, + pub inner_code_commitment: [u8; 8], + pub outer_code_commitment: [u8; 32], +} + +#[derive(Serialize)] +pub struct TimeGenesis { + pub secs: u64, + pub nanos: u32, +} + +#[derive(Serialize)] +pub struct SequencerRegistryGenesis { + pub seq_rollup_address: String, + pub seq_da_address: String, + pub minimum_bond: u64, + pub is_preferred_sequencer: bool, +} + +#[derive(Serialize)] +pub struct ProverIncentivesGenesis { + pub proving_penalty: u64, + pub minimum_bond: u64, + pub initial_provers: Vec<(String, u64)>, +} diff --git a/crates/relayer/sovereign-test-components/src/types/rollup_node_config.rs b/crates/relayer/sovereign-test-components/src/types/rollup_node_config.rs new file mode 100644 index 00000000..9597325b --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/types/rollup_node_config.rs @@ -0,0 +1,48 @@ +use serde::Serialize; + +#[derive(Serialize)] +pub struct SovereignRollupNodeConfig { + pub da: SovereignDaConfig, + pub storage: SovereignStorageConfig, + pub runner: SovereignRunnerConfig, + pub proof_manager: SovereignProverConfig, +} + +#[derive(Serialize)] +pub struct SovereignDaConfig { + pub celestia_rpc_auth_token: String, + pub celestia_rpc_address: String, + pub max_celestia_response_body_size: u64, + pub celestia_rpc_timeout_seconds: u64, + pub own_celestia_address: String, +} + +#[derive(Serialize)] +pub struct SovereignStorageConfig { + pub path: String, +} + +#[derive(Serialize)] +pub struct SovereignRunnerConfig { + pub genesis_height: u64, + pub rpc_config: SovereignRpcConfig, + pub axum_config: SovereignAxumConfig, + pub da_polling_interval_ms: u64, +} + +#[derive(Serialize)] +pub struct SovereignRpcConfig { + pub bind_host: String, + pub bind_port: u16, +} + +#[derive(Serialize)] +pub struct SovereignAxumConfig { + pub bind_host: String, + pub bind_port: u16, +} + +#[derive(Serialize)] +pub struct SovereignProverConfig { + pub aggregated_proof_block_jump: u64, +} diff --git a/crates/relayer/sovereign-test-components/src/types/wallet.rs b/crates/relayer/sovereign-test-components/src/types/wallet.rs new file mode 100644 index 00000000..20038fd4 --- /dev/null +++ b/crates/relayer/sovereign-test-components/src/types/wallet.rs @@ -0,0 +1,103 @@ +use bech32::ToBase32; +use bech32::Variant::Bech32m; +use ed25519_dalek::{SigningKey, VerifyingKey}; +use hermes_sovereign_rollup_components::types::address::{SovereignAddress, SovereignAddressBytes}; +use sha2::{Digest, Sha256}; + +pub struct SovereignWallet { + pub wallet_id: String, + pub signing_key: SigningKey, + pub address: SovereignAddress, + pub credential_id: String, +} + +impl SovereignWallet { + pub fn generate(wallet_id: &str, account_prefix: &str) -> Result { + let mut rng = rand::thread_rng(); + let signing_key = SigningKey::generate(&mut rng); + let address_hash_bytes = public_key_to_hash_bytes(&signing_key.verifying_key()); + let credential_id = public_key_to_credential_id(&signing_key.verifying_key()); + + let address = SovereignAddress::new(address_hash_bytes, account_prefix)?; + + Ok(Self { + wallet_id: wallet_id.to_owned(), + signing_key, + address, + credential_id, + }) + } +} + +pub fn public_key_to_hash_bytes(public_key: &VerifyingKey) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(public_key); + hasher.finalize().into() +} + +/** + Encode a public key to a Sovereign SDK address with a given account prefix. + + The encoding is based on the `to_address` function at + . + + Essentially, we hash the public key raw bytes, and then convert the raw hash bytes + using bech32. +*/ +pub fn public_key_to_sovereign_address( + public_key: &VerifyingKey, + account_prefix: &str, +) -> Result { + let key_hash_bytes: [u8; 32] = public_key_to_hash_bytes(public_key); + encode_hash_bytes_to_address(&key_hash_bytes, account_prefix) +} + +pub fn public_key_to_credential_id(public_key: &VerifyingKey) -> String { + let key_hash_bytes: [u8; 32] = public_key_to_hash_bytes(public_key); + format!("0x{}", hex::encode(key_hash_bytes)) +} + +/** + Encode a token with the sender as a Sovereign address. + + This is based on the `get_token_address` function at + . + + Essentially, we take the hash of the sender hash bytes, token name, and salt. + We then perform bech32 encoding on the raw hash value. +*/ +pub fn encode_token_address( + token_name: &str, + sender: &[u8], + salt: u64, + account_prefix: &str, +) -> Result { + let address_bytes = encode_token_address_bytes(token_name, sender, salt); + + let address = encode_hash_bytes_to_address(&address_bytes, account_prefix)?; + + Ok(SovereignAddress { + address, + address_bytes: SovereignAddressBytes { + addr: address_bytes, + }, + }) +} + +pub fn encode_token_address_bytes(token_name: &str, sender: &[u8], salt: u64) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(sender); + hasher.update(token_name.as_bytes()); + hasher.update(salt.to_le_bytes()); + + hasher.finalize().into() +} + +pub fn encode_hash_bytes_to_address( + hash_bytes: &[u8; 32], + account_prefix: &str, +) -> Result { + let base32_bytes = hash_bytes.to_base32(); + let address = bech32::encode(account_prefix, base32_bytes, Bech32m)?; + Ok(address) +} diff --git a/flake.lock b/flake.lock index 687efbc9..7d092112 100644 --- a/flake.lock +++ b/flake.lock @@ -18,31 +18,13 @@ "type": "github" } }, - "flake-utils_2": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1705309234, - "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1718149104, - "narHash": "sha256-Ds1QpobBX2yoUDx9ZruqVGJ/uQPgcXoYuobBguyKEh8=", + "lastModified": 1718870667, + "narHash": "sha256-jab3Kpc8O1z3qxwVsCMHL4+18n5Wy/HHKyu1fcsF7gs=", "owner": "nixos", "repo": "nixpkgs", - "rev": "e913ae340076bbb73d9f4d3d065c2bca7caafb16", + "rev": "9b10b8f00cb5494795e5f51b39210fed4d2b0748", "type": "github" }, "original": { @@ -54,11 +36,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1706487304, - "narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=", + "lastModified": 1718428119, + "narHash": "sha256-WdWDpNaq6u1IPtxtYHHWpl5BmabtpmLnMAx0RdJ/vo8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "90f456026d284c22b3e3497be980b2e47d0b28ac", + "rev": "e6cea36f83499eb4e9cd184c8a8e823296b50ad5", "type": "github" }, "original": { @@ -78,15 +60,14 @@ }, "rust-overlay": { "inputs": { - "flake-utils": "flake-utils_2", "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1718245100, - "narHash": "sha256-ETm3A2nUVEUwVQ30fj3ePK4rqsSbSnY4uP4LYrFrDNE=", + "lastModified": 1718936281, + "narHash": "sha256-jslEDCVFoRcNilJT0xYGSxqMjOe+USnLknpHIAZJ02A=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "4cbc2810d1dfb5960791be92df6a5f842a79bdfb", + "rev": "c9a793a5278f711a59fe77b9bf54b215667022c6", "type": "github" }, "original": { @@ -126,21 +107,6 @@ "repo": "default", "type": "github" } - }, - "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } } }, "root": "root", diff --git a/nix/sov-celestia-cw.nix b/nix/sov-celestia-cw.nix index d9ae72ff..83de9dae 100644 --- a/nix/sov-celestia-cw.nix +++ b/nix/sov-celestia-cw.nix @@ -73,6 +73,9 @@ let "rockbound-1.0.0" = "sha256-aDrNegRfsSwiNw4XLsE4rpUYDZn2N59UJbGZ6mpY180="; "tendermint-0.32.0" = "sha256-FtY7a+hBvQryATrs3mykCWFRe8ABTT6cuf5oh9IBElQ="; "cosmos-sdk-proto-0.22.0-pre" = "sha256-nRfcAbjFcvAqool+6heYK8joiU5YaSWITnO6S5MRM1E="; + "cgp-async-0.1.0" = "sha256-we0ABBhDJZiB6+6mguZlqn1aflzrMxiY0S62m55VV4I="; + "hermes-async-runtime-components-0.1.0" = "sha256-LS93S4p9IwdTx4cL7ZqcfnIA6l4kk5B9dOQ2+dtJuDs="; + "ibc-relayer-0.27.3" = "sha256-iVyZEgcMC5ZL5gmA8lW3MzLz4DDPVroi0f8r98aQo9s="; }; }; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index a1ecb059..228fc062 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.77" +channel = "1.79" components = [ "rustfmt", "rust-src", "clippy" ] profile = "minimal" targets = [