diff --git a/Cargo.lock b/Cargo.lock index eb93f2d5a..10ea2f1f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "1.0.2" @@ -269,9 +280,9 @@ dependencies = [ "cosmrs", "derive_more", "displaydoc", - "ibc", + "ibc 0.45.0", "ibc-proto 0.35.0", - "ics23", + "ics23 0.10.2", "primitive-types", "prost", "serde", @@ -283,7 +294,7 @@ dependencies = [ "tendermint-rpc", "tokio", "toml 0.8.0", - "tonic", + "tonic 0.9.2", "tonic-reflection", "tower", "tower-abci", @@ -299,9 +310,9 @@ dependencies = [ "base64 0.21.2", "derive_more", "displaydoc", - "ed25519", - "ibc", - "ics23", + "ed25519 2.2.2", + "ibc 0.45.0", + "ics23 0.10.2", "prost", "serde", "serde_json", @@ -327,7 +338,7 @@ dependencies = [ "k256", "once_cell", "pbkdf2 0.12.2", - "rand_core", + "rand_core 0.6.4", "ripemd", "sha2 0.10.7", "subtle", @@ -406,6 +417,51 @@ dependencies = [ "generic-array", ] +[[package]] +name = "borsh" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +dependencies = [ + "borsh-derive", + "hashbrown 0.11.2", +] + +[[package]] +name = "borsh-derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "bs58" version = "0.5.0" @@ -662,7 +718,7 @@ dependencies = [ "eyre", "getrandom", "k256", - "rand_core", + "rand_core 0.6.4", "serde", "serde_json", "subtle-encoding", @@ -745,7 +801,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -769,6 +825,19 @@ dependencies = [ "sct 0.6.1", ] +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + [[package]] name = "curve25519-dalek" version = "4.0.0" @@ -805,7 +874,7 @@ checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" dependencies = [ "byteorder", "digest 0.9.0", - "rand_core", + "rand_core 0.6.4", "subtle-ng", "zeroize", ] @@ -878,12 +947,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "deranged" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" - [[package]] name = "derivation-path" version = "0.2.0" @@ -970,10 +1033,19 @@ dependencies = [ "digest 0.10.7", "elliptic-curve", "rfc6979", - "signature", + "signature 2.1.0", "spki", ] +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature 1.6.4", +] + [[package]] name = "ed25519" version = "2.2.2" @@ -982,7 +1054,7 @@ checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" dependencies = [ "pkcs8", "serde", - "signature", + "signature 2.1.0", ] [[package]] @@ -993,7 +1065,19 @@ checksum = "3c8465edc8ee7436ffea81d21a019b16676ee3db267aa8d5a8d729581ecf998b" dependencies = [ "curve25519-dalek-ng", "hex", - "rand_core", + "rand_core 0.6.4", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.2.0", + "ed25519 1.5.3", "sha2 0.9.9", "zeroize", ] @@ -1004,9 +1088,9 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core", + "curve25519-dalek 4.0.0", + "ed25519 2.2.2", + "rand_core 0.6.4", "serde", "sha2 0.10.7", "zeroize", @@ -1019,7 +1103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b49a684b133c4980d7ee783936af771516011c8cd15f429dbda77245e282f03" dependencies = [ "derivation-path", - "ed25519-dalek", + "ed25519-dalek 2.0.0", "hmac", "sha2 0.10.7", ] @@ -1043,7 +1127,7 @@ dependencies = [ "generic-array", "group", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -1131,7 +1215,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1332,7 +1416,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1381,6 +1465,15 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1593,6 +1686,35 @@ dependencies = [ "tokio-io-timeout", ] +[[package]] +name = "ibc" +version = "0.27.0" +source = "git+https://github.com/cosmos/ibc-rs.git?branch=soares/relayer-next#3307b5738694b43324d4049204f7a890d0439893" +dependencies = [ + "bytes", + "derive_more", + "displaydoc", + "dyn-clone", + "erased-serde", + "ibc-proto 0.24.1", + "ics23 0.9.0", + "num-traits", + "primitive-types", + "prost", + "safe-regex", + "serde", + "serde_derive", + "serde_json", + "sha2 0.10.7", + "subtle-encoding", + "tendermint 0.28.0", + "tendermint-light-client-verifier 0.28.0", + "tendermint-proto 0.28.0", + "time", + "tracing", + "uint", +] + [[package]] name = "ibc" version = "0.45.0" @@ -1604,7 +1726,7 @@ dependencies = [ "displaydoc", "ibc-derive", "ibc-proto 0.35.0", - "ics23", + "ics23 0.10.2", "num-traits", "parking_lot", "primitive-types", @@ -1616,15 +1738,28 @@ dependencies = [ "sha2 0.10.7", "subtle-encoding", "tendermint 0.33.2", - "tendermint-light-client-verifier", + "tendermint-light-client-verifier 0.33.0", "tendermint-proto 0.33.2", "tendermint-testgen", "time", - "tonic", + "tonic 0.9.2", "tracing", "uint", ] +[[package]] +name = "ibc-cosmos" +version = "0.19.0" +dependencies = [ + "async-trait", + "ibc 0.27.0", + "ibc-framework", + "ibc-proto 0.24.1", + "tendermint 0.28.0", + "tendermint-light-client-verifier 0.28.0", + "tendermint-proto 0.28.0", +] + [[package]] name = "ibc-derive" version = "0.3.0" @@ -1637,6 +1772,13 @@ dependencies = [ "syn 2.0.37", ] +[[package]] +name = "ibc-framework" +version = "0.1.0" +dependencies = [ + "async-trait", +] + [[package]] name = "ibc-integration-test" version = "0.25.0" @@ -1657,7 +1799,26 @@ dependencies = [ "time", "tokio", "toml 0.7.6", - "tonic", + "tonic 0.9.2", +] + +[[package]] +name = "ibc-proto" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b46bcc4540116870cfb184f338b45174a7560ad46dd74e4cb4e81e005e2056" +dependencies = [ + "base64 0.13.1", + "borsh", + "bytes", + "flex-error", + "parity-scale-codec", + "prost", + "scale-info", + "serde", + "subtle-encoding", + "tendermint-proto 0.28.0", + "tonic 0.8.3", ] [[package]] @@ -1669,12 +1830,12 @@ dependencies = [ "base64 0.21.2", "bytes", "flex-error", - "ics23", + "ics23 0.10.2", "prost", "serde", "subtle-encoding", "tendermint-proto 0.33.2", - "tonic", + "tonic 0.9.2", ] [[package]] @@ -1686,12 +1847,12 @@ dependencies = [ "base64 0.21.2", "bytes", "flex-error", - "ics23", + "ics23 0.10.2", "prost", "serde", "subtle-encoding", "tendermint-proto 0.33.2", - "tonic", + "tonic 0.9.2", ] [[package]] @@ -1709,8 +1870,8 @@ dependencies = [ "crossbeam-channel 0.5.8", "digest 0.10.7", "dirs-next", - "ed25519", - "ed25519-dalek", + "ed25519 2.2.2", + "ed25519-dalek 2.0.0", "ed25519-dalek-bip32", "flex-error", "futures", @@ -1737,7 +1898,7 @@ dependencies = [ "serde_derive", "serde_json", "sha2 0.10.7", - "signature", + "signature 2.1.0", "strum", "subtle-encoding", "tendermint 0.33.2", @@ -1750,7 +1911,7 @@ dependencies = [ "tokio", "tokio-stream", "toml 0.7.6", - "tonic", + "tonic 0.9.2", "tracing", "uuid 1.4.1", ] @@ -1815,7 +1976,7 @@ dependencies = [ "tendermint 0.33.2", "tendermint-rpc", "tokio", - "tonic", + "tonic 0.9.2", "tracing", ] @@ -1827,7 +1988,7 @@ dependencies = [ "basecoin-app", "basecoin-store", "cgp-core", - "ibc", + "ibc 0.45.0", "ibc-proto 0.35.0", "ibc-relayer-components", "ibc-relayer-components-extra", @@ -1888,7 +2049,7 @@ dependencies = [ "erased-serde", "flex-error", "ibc-proto 0.34.0", - "ics23", + "ics23 0.10.2", "itertools", "num-rational", "primitive-types", @@ -1899,7 +2060,7 @@ dependencies = [ "serde_json", "subtle-encoding", "tendermint 0.33.2", - "tendermint-light-client-verifier", + "tendermint-light-client-verifier 0.33.0", "tendermint-proto 0.33.2", "tendermint-testgen", "time", @@ -1957,11 +2118,26 @@ dependencies = [ "tendermint-rpc", "tokio", "toml 0.7.6", - "tonic", + "tonic 0.9.2", "tracing", "tracing-subscriber", ] +[[package]] +name = "ics23" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca44b684ce1859cff746ff46f5765ab72e12e3c06f76a8356db8f9a2ecf43f17" +dependencies = [ + "anyhow", + "bytes", + "hex", + "prost", + "ripemd", + "sha2 0.10.7", + "sha3", +] + [[package]] name = "ics23" version = "0.10.2" @@ -2115,7 +2291,7 @@ dependencies = [ "elliptic-curve", "once_cell", "sha2 0.10.7", - "signature", + "signature 2.1.0", ] [[package]] @@ -2475,7 +2651,7 @@ version = "3.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", @@ -2650,6 +2826,15 @@ dependencies = [ "uint", ] +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml 0.5.11", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -2772,7 +2957,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2782,9 +2967,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + [[package]] name = "rand_core" version = "0.6.4" @@ -3118,6 +3309,30 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scale-info" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782" +dependencies = [ + "cfg-if 1.0.0", + "derive_more", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "912e55f6d20e0e80d63733872b40e1227c0bce1e1ab81ba67d696339bfd7fd29" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "schannel" version = "0.1.22" @@ -3397,6 +3612,12 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + [[package]] name = "signature" version = "2.1.0" @@ -3404,7 +3625,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest 0.10.7", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -3577,6 +3798,34 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "tendermint" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c518c082146825f10d6f9a32159ae46edcfd7dae8ac630c8067594bb2a784d72" +dependencies = [ + "bytes", + "ed25519 1.5.3", + "ed25519-dalek 1.0.1", + "flex-error", + "futures", + "num-traits", + "once_cell", + "prost", + "prost-types", + "serde", + "serde_bytes", + "serde_json", + "serde_repr", + "sha2 0.9.9", + "signature 1.6.4", + "subtle", + "subtle-encoding", + "tendermint-proto 0.28.0", + "time", + "zeroize", +] + [[package]] name = "tendermint" version = "0.32.2" @@ -3585,7 +3834,7 @@ checksum = "3f0a7d05cf78524782337f8edd55cbc578d159a16ad4affe2135c92f7dbac7f0" dependencies = [ "bytes", "digest 0.10.7", - "ed25519", + "ed25519 2.2.2", "ed25519-consensus", "flex-error", "futures", @@ -3600,7 +3849,7 @@ dependencies = [ "serde_json", "serde_repr", "sha2 0.10.7", - "signature", + "signature 2.1.0", "subtle", "subtle-encoding", "tendermint-proto 0.32.2", @@ -3616,7 +3865,7 @@ checksum = "7c35fe4fd24a7715571814c22416dbc40ec0f2a6e3cce75d73e19699faecd246" dependencies = [ "bytes", "digest 0.10.7", - "ed25519", + "ed25519 2.2.2", "ed25519-consensus", "flex-error", "futures", @@ -3631,7 +3880,7 @@ dependencies = [ "serde_json", "serde_repr", "sha2 0.10.7", - "signature", + "signature 2.1.0", "subtle", "subtle-encoding", "tendermint-proto 0.33.2", @@ -3671,7 +3920,7 @@ dependencies = [ "serde_json", "static_assertions", "tendermint 0.33.2", - "tendermint-light-client-verifier", + "tendermint-light-client-verifier 0.33.0", "tendermint-rpc", "time", "tokio", @@ -3702,6 +3951,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "tendermint-light-client-verifier" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c742bb914f9fb025ce0e481fbef9bb59c94d5a4bbd768798102675a2e0fb7440" +dependencies = [ + "derive_more", + "flex-error", + "serde", + "tendermint 0.28.0", + "time", +] + [[package]] name = "tendermint-light-client-verifier" version = "0.33.0" @@ -3715,6 +3977,24 @@ dependencies = [ "time", ] +[[package]] +name = "tendermint-proto" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "890f1fb6dee48900c85f0cdf711ebf130e505ac09ad918cee5c34ed477973b05" +dependencies = [ + "bytes", + "flex-error", + "num-derive", + "num-traits", + "prost", + "prost-types", + "serde", + "serde_bytes", + "subtle-encoding", + "time", +] + [[package]] name = "tendermint-proto" version = "0.32.2" @@ -3845,11 +4125,10 @@ dependencies = [ [[package]] name = "time" -version = "0.3.28" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" dependencies = [ - "deranged", "serde", "time-core", "time-macros", @@ -3857,15 +4136,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.14" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" dependencies = [ "time-core", ] @@ -4093,6 +4372,38 @@ dependencies = [ "winnow", ] +[[package]] +name = "tonic" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.13.1", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "prost-derive", + "tokio", + "tokio-stream", + "tokio-util 0.7.8", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + [[package]] name = "tonic" version = "0.9.2" @@ -4135,7 +4446,7 @@ dependencies = [ "prost-types", "tokio", "tokio-stream", - "tonic", + "tonic 0.9.2", ] [[package]] @@ -4234,6 +4545,16 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.1.3" diff --git a/Cargo.toml b/Cargo.toml index a3f7fbbfc..d1d393891 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,8 @@ members = [ "crates/relayer-runtime", "crates/relayer-cosmos", "crates/relayer-cosmos-mock", + "crates/ibc-framework", + "crates/ibc-cosmos", "tools/integration-test", "tools/test-framework", ] @@ -23,6 +25,7 @@ exclude = [ overflow-checks = true [patch.crates-io] +ibc = { version = "0.27.0", git = "https://github.com/cosmos/ibc-rs.git", branch = "soares/relayer-next" } cgp-core = { git = "https://github.com/informalsystems/cgp.git", branch = "main" } cgp-macros = { git = "https://github.com/informalsystems/cgp.git", branch = "main" } ibc-relayer-types = { git = "https://github.com/informalsystems/hermes.git", branch = "master" } diff --git a/crates/ibc-cosmos/Cargo.toml b/crates/ibc-cosmos/Cargo.toml new file mode 100644 index 000000000..e88e53b00 --- /dev/null +++ b/crates/ibc-cosmos/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "ibc-cosmos" +version = "0.19.0" +edition = "2021" +license = "Apache-2.0" +readme = "README.md" +keywords = ["blockchain", "consensus", "cosmos", "ibc", "tendermint"] +repository = "https://github.com/informalsystems/ibc-rs" +authors = ["Informal Systems "] +rust-version = "1.60" +description = """ + Implementation of an IBC Relayer in Rust, as a library +""" + +[package.metadata.docs.rs] +all-features = true + +[features] + +[dependencies] +async-trait = "0.1.56" +ibc = { version = "0.27.0" } +ibc-proto = { version = "0.24.0" } +ibc-framework = { version = "0.1.0", path = "../ibc-framework" } +tendermint = { version = "=0.28.0", default-features = false } +tendermint-proto = { version = "=0.28.0", default-features = false } +tendermint-light-client-verifier = { version = "=0.28.0", default-features = false } diff --git a/crates/ibc-cosmos/src/all_for_one/instances/mod.rs b/crates/ibc-cosmos/src/all_for_one/instances/mod.rs new file mode 100644 index 000000000..4a9b38e37 --- /dev/null +++ b/crates/ibc-cosmos/src/all_for_one/instances/mod.rs @@ -0,0 +1 @@ +pub mod update_client; diff --git a/crates/ibc-cosmos/src/all_for_one/instances/update_client/mod.rs b/crates/ibc-cosmos/src/all_for_one/instances/update_client/mod.rs new file mode 100644 index 000000000..5efd1e3f2 --- /dev/null +++ b/crates/ibc-cosmos/src/all_for_one/instances/update_client/mod.rs @@ -0,0 +1 @@ +pub mod tendermint; diff --git a/crates/ibc-cosmos/src/all_for_one/instances/update_client/tendermint.rs b/crates/ibc-cosmos/src/all_for_one/instances/update_client/tendermint.rs new file mode 100644 index 000000000..aaaf59421 --- /dev/null +++ b/crates/ibc-cosmos/src/all_for_one/instances/update_client/tendermint.rs @@ -0,0 +1,33 @@ +use core::marker::PhantomData; +use ibc_framework::core::impls::handlers::update_client::lift::LiftClientUpdateHandler; +use ibc_framework::core::traits::handlers::update_client::{ + AnyUpdateClientHandler, UpdateClientHandler, +}; + +use crate::all_for_one::traits::dynamic::AfoDynamicChainContext; +use crate::all_for_one::traits::tendermint::AfoTendermintOnlyChainContext; +use crate::clients::tendermint::client::TendermintClient; + +pub fn can_build_tendermint_update_handler( +) -> PhantomData> +where + Context: AfoTendermintOnlyChainContext, +{ + PhantomData:: +} + +pub fn can_build_tendermint_any_update_handler( +) -> PhantomData> +where + Context: AfoTendermintOnlyChainContext, +{ + PhantomData::> +} + +pub fn can_build_dynamic_tendermint_any_update_handler( +) -> PhantomData> +where + Context: AfoDynamicChainContext, +{ + PhantomData::> +} diff --git a/crates/ibc-cosmos/src/all_for_one/mod.rs b/crates/ibc-cosmos/src/all_for_one/mod.rs new file mode 100644 index 000000000..850a32dc0 --- /dev/null +++ b/crates/ibc-cosmos/src/all_for_one/mod.rs @@ -0,0 +1,2 @@ +pub mod instances; +pub mod traits; diff --git a/crates/ibc-cosmos/src/all_for_one/traits/dynamic.rs b/crates/ibc-cosmos/src/all_for_one/traits/dynamic.rs new file mode 100644 index 000000000..f09bdd65d --- /dev/null +++ b/crates/ibc-cosmos/src/all_for_one/traits/dynamic.rs @@ -0,0 +1,46 @@ +use ibc::core::ics23_commitment::merkle::MerkleProof; +use ibc::core::ics24_host::identifier::ClientId; +use ibc::timestamp::Timestamp; +use ibc::Height; +use ibc_framework::all_for_one::traits::base::AfoChainContext; +use ibc_framework::core::traits::error::InjectError; +use ibc_framework::core::traits::stores::client_reader::HasClientReader; +use ibc_proto::google::protobuf::Any; + +use crate::clients::dynamic::client::{ + DynClientHeader, DynClientState, DynConsensusState, DynMisbehavior, +}; +use crate::clients::tendermint::client::TendermintClient; +use crate::clients::tendermint::update_client::Error as UpdateTendermintClientError; + +pub trait AfoDynamicChainContext: + AfoChainContext< + Height = Height, + Timestamp = Timestamp, + Message = Any, + ClientId = ClientId, + MerkleProof = MerkleProof, + AnyClientState = DynClientState, + AnyConsensusState = DynConsensusState, + AnyClientHeader = DynClientHeader, + AnyMisbehavior = DynMisbehavior, + > + InjectError + + HasClientReader +{ +} + +impl AfoDynamicChainContext for Context where + Context: AfoChainContext< + Height = Height, + Timestamp = Timestamp, + Message = Any, + ClientId = ClientId, + MerkleProof = MerkleProof, + AnyClientState = DynClientState, + AnyConsensusState = DynConsensusState, + AnyClientHeader = DynClientHeader, + AnyMisbehavior = DynMisbehavior, + > + InjectError + + HasClientReader +{ +} diff --git a/crates/ibc-cosmos/src/all_for_one/traits/mod.rs b/crates/ibc-cosmos/src/all_for_one/traits/mod.rs new file mode 100644 index 000000000..dd4cd3a40 --- /dev/null +++ b/crates/ibc-cosmos/src/all_for_one/traits/mod.rs @@ -0,0 +1,2 @@ +pub mod dynamic; +pub mod tendermint; diff --git a/crates/ibc-cosmos/src/all_for_one/traits/tendermint.rs b/crates/ibc-cosmos/src/all_for_one/traits/tendermint.rs new file mode 100644 index 000000000..98f889a56 --- /dev/null +++ b/crates/ibc-cosmos/src/all_for_one/traits/tendermint.rs @@ -0,0 +1,46 @@ +use ibc::core::ics23_commitment::merkle::MerkleProof; +use ibc::core::ics24_host::identifier::ClientId; +use ibc::timestamp::Timestamp; +use ibc::Height; +use ibc_framework::all_for_one::traits::base::AfoChainContext; +use ibc_framework::core::traits::error::InjectError; +use ibc_framework::core::traits::stores::client_reader::HasClientReader; +use ibc_proto::google::protobuf::Any; + +use crate::clients::tendermint::client::{ + TendermintClient, TendermintClientHeader, TendermintClientState, TendermintConsensusState, + TendermintMisbehavior, +}; +use crate::clients::tendermint::update_client::Error as UpdateTendermintClientError; + +pub trait AfoTendermintOnlyChainContext: + AfoChainContext< + Height = Height, + Timestamp = Timestamp, + Message = Any, + ClientId = ClientId, + MerkleProof = MerkleProof, + AnyClientState = TendermintClientState, + AnyConsensusState = TendermintConsensusState, + AnyClientHeader = TendermintClientHeader, + AnyMisbehavior = TendermintMisbehavior, + > + InjectError + + HasClientReader +{ +} + +impl AfoTendermintOnlyChainContext for Context where + Context: AfoChainContext< + Height = Height, + Timestamp = Timestamp, + Message = Any, + ClientId = ClientId, + MerkleProof = MerkleProof, + AnyClientState = TendermintClientState, + AnyConsensusState = TendermintConsensusState, + AnyClientHeader = TendermintClientHeader, + AnyMisbehavior = TendermintMisbehavior, + > + InjectError + + HasClientReader +{ +} diff --git a/crates/ibc-cosmos/src/clients/dynamic/client.rs b/crates/ibc-cosmos/src/clients/dynamic/client.rs new file mode 100644 index 000000000..b253891bb --- /dev/null +++ b/crates/ibc-cosmos/src/clients/dynamic/client.rs @@ -0,0 +1,178 @@ +use core::time::Duration; +use ibc::clients::ics07_tendermint::client_state::ClientState as TendermintClientState; +use ibc::clients::ics07_tendermint::client_type as tendermint_client_type; +use ibc::clients::ics07_tendermint::consensus_state::ConsensusState as TendermintConsensusState; +use ibc::clients::ics07_tendermint::header::Header as TendermintClientHeader; +use ibc::clients::ics07_tendermint::misbehaviour::Misbehaviour as TendermintMisbehavior; +use ibc::core::ics02_client::client_state::ClientState; +use ibc::core::ics02_client::client_type::ClientType; +use ibc::core::ics02_client::consensus_state::ConsensusState; +use ibc::core::ics02_client::header::Header as ClientHeader; +use ibc::core::ics02_client::misbehaviour::Misbehaviour; +use ibc::timestamp::Timestamp; +use ibc::Height; +use ibc_framework::core::traits::client::{ + HasAnyClientMethods, HasAnyClientTypes, HasClientTypeFor, +}; +use ibc_framework::core::traits::host::HasHostTypes; +use ibc_framework::core::traits::prism::Prism; + +use crate::clients::tendermint::client::TendermintClient; + +pub struct DynamicClient; + +pub struct DynClientState { + pub client_state: Box, +} + +pub struct DynConsensusState { + pub consensus_state: Box, +} + +pub struct DynClientHeader { + pub client_header: Box, +} + +pub struct DynMisbehavior { + pub misbehavior: Box, +} + +impl HasAnyClientTypes for DynamicClient { + type ClientType = ClientType; + + type AnyClientState = DynClientState; + + type AnyConsensusState = DynConsensusState; + + type AnyClientHeader = DynClientHeader; + + type AnyMisbehavior = DynMisbehavior; +} + +impl Prism for DynamicClient { + fn into(client_state: TendermintClientState) -> DynClientState { + DynClientState::new(client_state) + } + + fn try_from(client_state: DynClientState) -> Option { + Self::try_from_ref(&client_state).cloned() + } + + fn try_from_ref(client_state: &DynClientState) -> Option<&TendermintClientState> { + client_state.client_state.as_any().downcast_ref() + } +} + +impl Prism for DynamicClient { + fn into(consensus_state: TendermintConsensusState) -> DynConsensusState { + DynConsensusState::new(consensus_state) + } + + fn try_from(consensus_state: DynConsensusState) -> Option { + Self::try_from_ref(&consensus_state).cloned() + } + + fn try_from_ref(consensus_state: &DynConsensusState) -> Option<&TendermintConsensusState> { + consensus_state.consensus_state.as_any().downcast_ref() + } +} + +impl Prism for DynamicClient { + fn into(client_header: TendermintClientHeader) -> DynClientHeader { + DynClientHeader::new(client_header) + } + + fn try_from(client_header: DynClientHeader) -> Option { + Self::try_from_ref(&client_header).cloned() + } + + fn try_from_ref(client_header: &DynClientHeader) -> Option<&TendermintClientHeader> { + client_header.client_header.as_any().downcast_ref() + } +} + +impl Prism for DynamicClient { + fn into(misbehavior: TendermintMisbehavior) -> DynMisbehavior { + DynMisbehavior::new(misbehavior) + } + + fn try_from(misbehavior: DynMisbehavior) -> Option { + Self::try_from_ref(&misbehavior).cloned() + } + + fn try_from_ref(misbehavior: &DynMisbehavior) -> Option<&TendermintMisbehavior> { + misbehavior.misbehavior.as_any().downcast_ref() + } +} + +impl HasClientTypeFor for DynamicClient { + fn client_type() -> Self::ClientType { + tendermint_client_type() + } +} + +impl HasHostTypes for DynamicClient { + type Height = Height; + + type Timestamp = Timestamp; + + type Duration = Duration; +} + +impl HasAnyClientMethods for DynamicClient { + fn client_state_type(client_state: &DynClientState) -> Self::ClientType { + client_state.client_state.client_type() + } + + fn client_state_is_frozen(client_state: &DynClientState) -> bool { + client_state.client_state.is_frozen() + } + + fn client_state_trusting_period(client_state: &DynClientState) -> Self::Duration { + client_state.client_state.trusting_period() + } + + fn client_state_latest_height(client_state: &DynClientState) -> Self::Height { + client_state.client_state.latest_height() + } + + fn consensus_state_timestamp(consensus_state: &DynConsensusState) -> Self::Timestamp { + consensus_state.consensus_state.timestamp() + } + + fn client_header_height(client_header: &DynClientHeader) -> Self::Height { + client_header.client_header.height() + } +} + +impl DynClientState { + fn new(client_state: impl ClientState) -> Self { + Self { + client_state: Box::new(client_state), + } + } +} + +impl DynConsensusState { + fn new(consensus_state: impl ConsensusState) -> Self { + Self { + consensus_state: Box::new(consensus_state), + } + } +} + +impl DynClientHeader { + fn new(client_header: impl ClientHeader) -> Self { + Self { + client_header: Box::new(client_header), + } + } +} + +impl DynMisbehavior { + fn new(misbehavior: impl Misbehaviour) -> Self { + Self { + misbehavior: Box::new(misbehavior), + } + } +} diff --git a/crates/ibc-cosmos/src/clients/dynamic/mod.rs b/crates/ibc-cosmos/src/clients/dynamic/mod.rs new file mode 100644 index 000000000..b9babe5bc --- /dev/null +++ b/crates/ibc-cosmos/src/clients/dynamic/mod.rs @@ -0,0 +1 @@ +pub mod client; diff --git a/crates/ibc-cosmos/src/clients/mod.rs b/crates/ibc-cosmos/src/clients/mod.rs new file mode 100644 index 000000000..dd4cd3a40 --- /dev/null +++ b/crates/ibc-cosmos/src/clients/mod.rs @@ -0,0 +1,2 @@ +pub mod dynamic; +pub mod tendermint; diff --git a/crates/ibc-cosmos/src/clients/tendermint/client.rs b/crates/ibc-cosmos/src/clients/tendermint/client.rs new file mode 100644 index 000000000..c4e8b8eda --- /dev/null +++ b/crates/ibc-cosmos/src/clients/tendermint/client.rs @@ -0,0 +1,199 @@ +use core::time::Duration; +use ibc::clients::ics07_tendermint::client_type as tendermint_client_type; +use ibc::core::ics02_client::client_state::ClientState; +use ibc::core::ics02_client::client_type::ClientType; +use ibc::core::ics02_client::consensus_state::ConsensusState; +use ibc::timestamp::Timestamp; +use ibc::Height; +use ibc_framework::core::traits::client::{ + HasAnyClientMethods, HasAnyClientTypes, HasClientTypeFor, HasClientTypes, +}; +use ibc_framework::core::traits::host::HasHostTypes; +use ibc_framework::core::traits::prism::Prism; + +pub use ibc::clients::ics07_tendermint::client_state::ClientState as TendermintClientState; +pub use ibc::clients::ics07_tendermint::consensus_state::ConsensusState as TendermintConsensusState; +pub use ibc::clients::ics07_tendermint::header::Header as TendermintClientHeader; +pub use ibc::clients::ics07_tendermint::misbehaviour::Misbehaviour as TendermintMisbehavior; + +use crate::one_for_all::traits::client::OfaCosmosClient; + +pub struct TendermintClient; + +impl OfaCosmosClient for TendermintClient { + type AnyClientState = TendermintClientState; + + type AnyConsensusState = TendermintConsensusState; + + type AnyClientHeader = TendermintClientHeader; + + type AnyMisbehavior = TendermintMisbehavior; + + fn client_state_type(client_state: &TendermintClientState) -> ClientType { + client_state.client_type() + } + + fn client_state_is_frozen(client_state: &TendermintClientState) -> bool { + client_state.is_frozen() + } + + fn client_state_trusting_period(client_state: &TendermintClientState) -> Duration { + client_state.trusting_period + } + + fn client_state_latest_height(client_state: &TendermintClientState) -> Height { + client_state.latest_height() + } + + fn consensus_state_timestamp(consensus_state: &TendermintConsensusState) -> Timestamp { + consensus_state.timestamp() + } + + fn client_header_height(client_header: &TendermintClientHeader) -> Height { + client_header.height() + } + + fn try_into_tendermint_client_state( + client_state: Self::AnyClientState, + ) -> Option { + Some(client_state) + } + + fn try_into_tendermint_client_state_ref( + client_state: &Self::AnyClientState, + ) -> Option<&TendermintClientState> { + Some(client_state) + } + + fn from_tendermint_client_state(client_state: TendermintClientState) -> Self::AnyClientState { + client_state + } + + fn try_into_tendermint_consensus_state( + consensus_state: Self::AnyConsensusState, + ) -> Option { + Some(consensus_state) + } + + fn try_into_tendermint_consensus_state_ref( + consensus_state: &Self::AnyConsensusState, + ) -> Option<&TendermintConsensusState> { + Some(consensus_state) + } + + fn from_tendermint_consensus_state( + consensus_state: TendermintConsensusState, + ) -> Self::AnyConsensusState { + consensus_state + } + + fn try_into_tendermint_client_header( + client_header: Self::AnyClientHeader, + ) -> Option { + Some(client_header) + } + + fn try_into_tendermint_client_header_ref( + client_header: &Self::AnyClientHeader, + ) -> Option<&TendermintClientHeader> { + Some(client_header) + } + + fn from_tendermint_client_header( + client_header: TendermintClientHeader, + ) -> Self::AnyClientHeader { + client_header + } + + fn try_into_tendermint_misbehavior( + misbehavior: Self::AnyMisbehavior, + ) -> Option { + Some(misbehavior) + } + + fn try_into_tendermint_misbehavior_ref( + misbehavior: &Self::AnyMisbehavior, + ) -> Option<&TendermintMisbehavior> { + Some(misbehavior) + } + + fn from_tendermint_misbehavior(misbehavior: TendermintMisbehavior) -> Self::AnyMisbehavior { + misbehavior + } +} + +impl HasClientTypes for TendermintClient { + type ClientState = TendermintClientState; + + type ConsensusState = TendermintConsensusState; + + type ClientHeader = TendermintClientHeader; + + type Misbehavior = TendermintMisbehavior; +} + +impl HasAnyClientTypes for TendermintClient { + type ClientType = ClientType; + + type AnyClientState = TendermintClientState; + + type AnyConsensusState = TendermintConsensusState; + + type AnyClientHeader = TendermintClientHeader; + + type AnyMisbehavior = TendermintMisbehavior; +} + +impl Prism for TendermintClient { + fn into(subdata: T) -> T { + subdata + } + + fn try_from(data: T) -> Option { + Some(data) + } + + fn try_from_ref(data: &T) -> Option<&T> { + Some(data) + } +} + +impl HasClientTypeFor for TendermintClient { + fn client_type() -> Self::ClientType { + tendermint_client_type() + } +} + +impl HasHostTypes for TendermintClient { + type Height = Height; + + type Timestamp = Timestamp; + + type Duration = Duration; +} + +impl HasAnyClientMethods for TendermintClient { + fn client_state_type(client_state: &TendermintClientState) -> Self::ClientType { + client_state.client_type() + } + + fn client_state_is_frozen(client_state: &TendermintClientState) -> bool { + client_state.is_frozen() + } + + fn client_state_trusting_period(client_state: &TendermintClientState) -> Self::Duration { + client_state.trusting_period + } + + fn client_state_latest_height(client_state: &TendermintClientState) -> Self::Height { + client_state.latest_height() + } + + fn consensus_state_timestamp(consensus_state: &TendermintConsensusState) -> Self::Timestamp { + consensus_state.timestamp() + } + + fn client_header_height(client_header: &TendermintClientHeader) -> Self::Height { + client_header.height() + } +} diff --git a/crates/ibc-cosmos/src/clients/tendermint/mod.rs b/crates/ibc-cosmos/src/clients/tendermint/mod.rs new file mode 100644 index 000000000..0643b8bd4 --- /dev/null +++ b/crates/ibc-cosmos/src/clients/tendermint/mod.rs @@ -0,0 +1,2 @@ +pub mod client; +pub mod update_client; diff --git a/crates/ibc-cosmos/src/clients/tendermint/update_client.rs b/crates/ibc-cosmos/src/clients/tendermint/update_client.rs new file mode 100644 index 000000000..3584b3931 --- /dev/null +++ b/crates/ibc-cosmos/src/clients/tendermint/update_client.rs @@ -0,0 +1,209 @@ +use ibc::timestamp::Timestamp; +use ibc::Height; +use ibc_framework::core::traits::client::ContainsClient; +use ibc_framework::core::traits::error::{HasError, InjectError}; +use ibc_framework::core::traits::handlers::update_client::UpdateClientHandler; +use ibc_framework::core::traits::host::HasHostMethods; +use ibc_framework::core::traits::ibc::HasIbcTypes; +use ibc_framework::core::traits::stores::client_reader::HasClientReader; +use tendermint::block::Height as BlockHeight; +use tendermint_light_client_verifier::errors::VerificationErrorDetail; +use tendermint_light_client_verifier::operations::voting_power::VotingPowerTally; +use tendermint_light_client_verifier::types::{TrustedBlockState, UntrustedBlockState}; +use tendermint_light_client_verifier::{Verdict, Verifier}; + +use crate::clients::tendermint::client::{ + TendermintClient, TendermintClientHeader, TendermintClientState, TendermintConsensusState, +}; + +pub enum Error { + MismatchRevision { + current_revision: u64, + update_revision: u64, + }, + ConsensusStateNotFound { + height: Height, + }, + RevisionHeightOverflow { + height: u64, + }, + NotEnoughTrust { + tally: VotingPowerTally, + }, + VerificationError { + detail: VerificationErrorDetail, + }, + HeaderTimestampTooHigh { + actual: Timestamp, + max: Timestamp, + }, + HeaderTimestampTooLow { + actual: Timestamp, + max: Timestamp, + }, + InvalidHeight, +} + +impl UpdateClientHandler for TendermintClient +where + Context: HasError, + Context: HasIbcTypes, + Context: HasHostMethods, + Context: HasClientReader, + Context: ContainsClient, + Context: InjectError, +{ + type Client = TendermintClient; + + fn check_client_header_and_update_state( + context: &Context, + client_id: &Context::ClientId, + client_state: &TendermintClientState, + new_client_header: &TendermintClientHeader, + ) -> Result<(TendermintClientState, TendermintConsensusState), Context::Error> { + let new_height = new_client_header.height(); + + let current_revision = client_state.chain_id.version(); + let update_revision = new_client_header.height().revision_number(); + + if current_revision != update_revision { + return Err(Context::inject_error(Error::MismatchRevision { + current_revision, + update_revision, + })); + } + + let new_consensus_state = TendermintConsensusState::from(new_client_header.clone()); + + let m_current_client_consensus_state = + context.get_consensus_state_at_height(client_id, &new_height)?; + + if m_current_client_consensus_state.as_ref() == Some(&new_consensus_state) { + return Ok((client_state.clone(), new_consensus_state)); + } + + { + let trusted_height = new_client_header.trusted_height; + + let trusted_consensus_state = context + .get_consensus_state_at_height(client_id, &trusted_height)? + .ok_or_else(|| { + Context::inject_error(Error::ConsensusStateNotFound { + height: trusted_height, + }) + })?; + + let trusted_revision_height = trusted_height.revision_height(); + + let trusted_block_height = + BlockHeight::try_from(trusted_revision_height).map_err(|_| { + Context::inject_error(Error::RevisionHeightOverflow { + height: trusted_revision_height, + }) + })?; + + let trusted_state = TrustedBlockState { + chain_id: &client_state.chain_id.clone().into(), + header_time: trusted_consensus_state.timestamp, + height: trusted_block_height, + next_validators: &new_client_header.trusted_validator_set, + next_validators_hash: trusted_consensus_state.next_validators_hash, + }; + + let untrusted_state = UntrustedBlockState { + signed_header: &new_client_header.signed_header, + validators: &new_client_header.validator_set, + // NB: This will skip the + // VerificationPredicates::next_validators_match check for the + // untrusted state. + next_validators: None, + }; + + let options = client_state.as_light_client_options().unwrap(); + + let now = context.host_timestamp().into_tm_time().unwrap(); + + let verdict = + client_state + .verifier + .verify(untrusted_state, trusted_state, &options, now); + + match verdict { + Verdict::Success => {} + Verdict::NotEnoughTrust(voting_power_tally) => { + return Err(Context::inject_error(Error::NotEnoughTrust { + tally: voting_power_tally, + })); + } + Verdict::Invalid(detail) => { + return Err(Context::inject_error(Error::VerificationError { detail })) + } + } + } + + // If the header has verified, but its corresponding consensus state + // differs from the existing consensus state for that height, freeze the + // client and return the installed consensus state. + // + // Note that this must be done *after* the light client verification. + // So that invalid headers will result in verification errors instead + // of errorneously freezing clients. + if let Some(cs) = m_current_client_consensus_state { + if cs != new_consensus_state { + return Ok(( + client_state + .clone() + .with_frozen_height(new_client_header.height()), + cs, + )); + } + } + + // Monotonicity checks for timestamps for in-the-middle updates + // (cs-new, cs-next, cs-latest) + if new_client_header.height() < client_state.latest_height() { + let m_next_consensus_state = + context.get_consensus_state_after_height(client_id, &new_height)?; + + if let Some(next_cs) = m_next_consensus_state { + // New (untrusted) header timestamp cannot occur after next + // consensus state's height + if new_client_header.signed_header.header().time > next_cs.timestamp { + return Err(Context::inject_error(Error::HeaderTimestampTooHigh { + actual: new_client_header.signed_header.header().time.into(), + max: next_cs.timestamp.into(), + })); + } + } + } + + // (cs-trusted, cs-prev, cs-new) + if new_client_header.trusted_height < new_client_header.height() { + let m_prev_consensus_state = + context.get_consensus_state_after_height(client_id, &new_height)?; + + if let Some(prev_cs) = m_prev_consensus_state { + // New (untrusted) header timestamp cannot occur before the + // previous consensus state's height + if new_client_header.signed_header.header().time < prev_cs.timestamp { + return Err(Context::inject_error(Error::HeaderTimestampTooLow { + actual: new_client_header.signed_header.header().time.into(), + max: prev_cs.timestamp.into(), + })); + } + } + } + + let latest_height = Height::new( + client_state.latest_height.revision_number(), + new_client_header.signed_header.header.height.into(), + ) + .map_err(|_| Context::inject_error(Error::InvalidHeight))?; + + let mut new_client_state = client_state.clone(); + + new_client_state.latest_height = latest_height; + + Ok((new_client_state, new_consensus_state)) + } +} diff --git a/crates/ibc-cosmos/src/lib.rs b/crates/ibc-cosmos/src/lib.rs new file mode 100644 index 000000000..1f3b8747d --- /dev/null +++ b/crates/ibc-cosmos/src/lib.rs @@ -0,0 +1,4 @@ +pub mod all_for_one; +pub mod clients; +pub mod one_for_all; +pub mod types; diff --git a/crates/ibc-cosmos/src/one_for_all/components/mod.rs b/crates/ibc-cosmos/src/one_for_all/components/mod.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/crates/ibc-cosmos/src/one_for_all/components/mod.rs @@ -0,0 +1 @@ + diff --git a/crates/ibc-cosmos/src/one_for_all/impls/chain.rs b/crates/ibc-cosmos/src/one_for_all/impls/chain.rs new file mode 100644 index 000000000..582524088 --- /dev/null +++ b/crates/ibc-cosmos/src/one_for_all/impls/chain.rs @@ -0,0 +1,237 @@ +use core::time::Duration; +use ibc::core::ics02_client::client_type::ClientType; +use ibc::core::ics23_commitment::merkle::MerkleProof; +use ibc::core::ics24_host::identifier::{ChannelId, ClientId, ConnectionId, PortId}; +use ibc::signer::Signer; +use ibc::timestamp::Timestamp; +use ibc::Height; +use ibc_framework::core::traits::client::HasAnyClientMethods; +use ibc_framework::core::traits::client::HasAnyClientTypes; +use ibc_framework::one_for_all::components::default::DefaultChainComponents; +use ibc_framework::one_for_all::traits::chain::{OfaChain, OfaChainTypes}; + +use crate::one_for_all::traits::chain::OfaCosmosChain; +use crate::one_for_all::types::chain::OfaCosmosChainWrapper; +use crate::types::event::IbcEvent; +use crate::types::message::{IbcMessage, IbcMessageType, UpdateClientMessage}; + +impl OfaChainTypes for OfaCosmosChainWrapper +where + Chain: OfaCosmosChain, +{ + type Error = Chain::Error; + + type Event = IbcEvent; + + type Height = Height; + + type Timestamp = Timestamp; + + type Duration = Duration; + + type Message = IbcMessage; + + type MessageType = IbcMessageType; + + type Signer = Signer; + + type ClientId = ClientId; + + type ConnectionId = ConnectionId; + + type ChannelId = ChannelId; + + type Port = PortId; + + type MerkleProof = MerkleProof; + + type ClientType = ClientType; + + type AnyClientState = ::AnyClientState; + + type AnyConsensusState = ::AnyConsensusState; + + type AnyClientHeader = ::AnyClientHeader; + + type AnyMisbehavior = ::AnyMisbehavior; + + type UpdateClientMessage = UpdateClientMessage; +} + +#[allow(unused_variables)] +impl OfaChain for OfaCosmosChainWrapper +where + Chain: OfaCosmosChain, +{ + type ChainComponents = DefaultChainComponents; + + type ClientComponents = Chain::AnyClient; + + fn emit_event(&self, event: &Self::Event) { + self.chain.emit_event(event) + } + + fn host_height(&self) -> Height { + self.chain.host_height() + } + + fn host_timestamp(&self) -> Timestamp { + self.chain.host_timestamp() + } + + fn add_duration(time: &Timestamp, duration: &Duration) -> Timestamp { + (*time + *duration).unwrap() + } + + fn message_type(message: &Self::Message) -> IbcMessageType { + message.message_type() + } + + fn client_state_type(client_state: &Self::AnyClientState) -> Self::ClientType { + Chain::AnyClient::client_state_type(client_state) + } + + fn client_state_is_frozen(client_state: &Self::AnyClientState) -> bool { + Chain::AnyClient::client_state_is_frozen(client_state) + } + + fn client_state_trusting_period(client_state: &Self::AnyClientState) -> Duration { + Chain::AnyClient::client_state_trusting_period(client_state) + } + + fn client_state_latest_height(client_state: &Self::AnyClientState) -> Height { + Chain::AnyClient::client_state_latest_height(client_state) + } + + fn consensus_state_timestamp(consensus_state: &Self::AnyConsensusState) -> Timestamp { + Chain::AnyClient::consensus_state_timestamp(consensus_state) + } + + fn client_header_height(client_header: &Self::AnyClientHeader) -> Height { + Chain::AnyClient::client_header_height(client_header) + } + + fn get_client_type(&self, client_id: &ClientId) -> Result { + self.chain.get_client_type(client_id) + } + + fn get_any_client_state( + &self, + client_id: &ClientId, + ) -> Result { + self.chain.get_any_client_state(client_id) + } + + fn get_latest_any_consensus_state( + &self, + client_id: &ClientId, + ) -> Result { + self.chain.get_latest_any_consensus_state(client_id) + } + + fn get_any_consensus_state_at_height( + &self, + client_id: &ClientId, + height: &Height, + ) -> Result, Self::Error> { + self.chain + .get_any_consensus_state_at_height(client_id, height) + } + + fn get_any_consensus_state_after_height( + &self, + client_id: &ClientId, + height: &Height, + ) -> Result, Self::Error> { + self.chain + .get_any_consensus_state_after_height(client_id, height) + } + + fn get_any_consensus_state_before_height( + &self, + client_id: &ClientId, + height: &Height, + ) -> Result, Self::Error> { + self.chain + .get_any_consensus_state_before_height(client_id, height) + } + + fn set_any_client_state( + &self, + client_id: &ClientId, + client_state: &Self::AnyClientState, + ) -> Result<(), Self::Error> { + self.chain.set_any_client_state(client_id, client_state) + } + + fn set_any_consensus_state( + &self, + client_id: &ClientId, + consensus_state: &Self::AnyConsensusState, + ) -> Result<(), Self::Error> { + self.chain + .set_any_consensus_state(client_id, consensus_state) + } + + fn client_type_mismatch_error(expected_client_type: &ClientType) -> Self::Error { + Chain::client_type_mismatch_error(expected_client_type) + } + + fn unknown_message_error(message_type: &IbcMessageType) -> Self::Error { + Chain::unknown_message_error(message_type) + } + + fn parse_message_error(message_type: &IbcMessageType) -> Self::Error { + Chain::parse_message_error(message_type) + } + + fn client_frozen_error(client_id: &ClientId) -> Self::Error { + Chain::client_frozen_error(client_id) + } + + fn client_expired_error( + client_id: &ClientId, + current_time: &Timestamp, + latest_allowed_update_time: &Timestamp, + ) -> Self::Error { + Chain::client_expired_error(client_id, current_time, latest_allowed_update_time) + } + + fn update_client_event( + client_id: &ClientId, + client_type: &ClientType, + consensus_height: &Height, + header: &Self::AnyClientHeader, + ) -> Self::Event { + todo!() + } + + fn misbehavior_event( + client_id: &Self::ClientId, + client_type: &Self::ClientType, + consensus_height: &Self::Height, + header: &Self::AnyClientHeader, + ) -> Self::Event { + todo!() + } + + const UPDATE_CLIENT_MESSAGE_TYPE: IbcMessageType = IbcMessageType::UpdateClient; + + fn try_extract_update_client_message( + message: &IbcMessage, + ) -> Option<&Self::UpdateClientMessage> { + match message { + IbcMessage::UpdateClient(message) => Some(message), + } + } + + fn update_client_message_client_id(message: &Self::UpdateClientMessage) -> &ClientId { + &message.client_id + } + + fn update_client_message_client_header( + message: &Self::UpdateClientMessage, + ) -> &Self::AnyClientHeader { + &message.client_header + } +} diff --git a/crates/ibc-cosmos/src/one_for_all/impls/mod.rs b/crates/ibc-cosmos/src/one_for_all/impls/mod.rs new file mode 100644 index 000000000..28ac57df5 --- /dev/null +++ b/crates/ibc-cosmos/src/one_for_all/impls/mod.rs @@ -0,0 +1 @@ +pub mod chain; diff --git a/crates/ibc-cosmos/src/one_for_all/mod.rs b/crates/ibc-cosmos/src/one_for_all/mod.rs new file mode 100644 index 000000000..3c8cbfdc5 --- /dev/null +++ b/crates/ibc-cosmos/src/one_for_all/mod.rs @@ -0,0 +1,4 @@ +pub mod components; +pub mod impls; +pub mod traits; +pub mod types; diff --git a/crates/ibc-cosmos/src/one_for_all/traits/chain.rs b/crates/ibc-cosmos/src/one_for_all/traits/chain.rs new file mode 100644 index 000000000..6a61c5b76 --- /dev/null +++ b/crates/ibc-cosmos/src/one_for_all/traits/chain.rs @@ -0,0 +1,85 @@ +use crate::types::event::IbcEvent; +use core::time::Duration; +use ibc::core::ics02_client::client_type::ClientType; +use ibc::core::ics24_host::identifier::ClientId; +use ibc::timestamp::Timestamp; +use ibc::Height; +use ibc_framework::core::traits::client::{HasAnyClientMethods, HasAnyClientTypes}; +use ibc_framework::core::traits::sync::Async; + +use crate::types::message::IbcMessageType; + +pub trait OfaCosmosChain: Async { + type Error: Async; + + type ChainComponents; + + type AnyClient: HasAnyClientMethods< + Timestamp = Timestamp, + Height = Height, + Duration = Duration, + ClientType = ClientType, + >; + + fn emit_event(&self, event: &IbcEvent); + + fn host_height(&self) -> Height; + + fn host_timestamp(&self) -> Timestamp; + + fn get_client_type(&self, client_id: &ClientId) -> Result; + + fn get_any_client_state( + &self, + client_id: &ClientId, + ) -> Result<::AnyClientState, Self::Error>; + + fn get_latest_any_consensus_state( + &self, + client_id: &ClientId, + ) -> Result<::AnyConsensusState, Self::Error>; + + fn get_any_consensus_state_at_height( + &self, + client_id: &ClientId, + height: &Height, + ) -> Result::AnyConsensusState>, Self::Error>; + + fn get_any_consensus_state_after_height( + &self, + client_id: &ClientId, + height: &Height, + ) -> Result::AnyConsensusState>, Self::Error>; + + fn get_any_consensus_state_before_height( + &self, + client_id: &ClientId, + height: &Height, + ) -> Result::AnyConsensusState>, Self::Error>; + + fn set_any_client_state( + &self, + client_id: &ClientId, + client_state: &::AnyClientState, + ) -> Result<(), Self::Error>; + + fn set_any_consensus_state( + &self, + client_id: &ClientId, + consensus_state: &::AnyConsensusState, + ) -> Result<(), Self::Error>; + + fn client_type_mismatch_error(expected_client_type: &ClientType) -> Self::Error; + + fn unknown_message_error(message_type: &IbcMessageType) -> Self::Error; + + fn parse_message_error(message_type: &IbcMessageType) -> Self::Error; + + fn client_frozen_error(client_id: &ClientId) -> Self::Error; + + fn client_expired_error( + client_id: &ClientId, + current_time: &Timestamp, + latest_allowed_update_time: &Timestamp, + ) -> Self::Error; +} diff --git a/crates/ibc-cosmos/src/one_for_all/traits/client.rs b/crates/ibc-cosmos/src/one_for_all/traits/client.rs new file mode 100644 index 000000000..69dbb595d --- /dev/null +++ b/crates/ibc-cosmos/src/one_for_all/traits/client.rs @@ -0,0 +1,75 @@ +use core::time::Duration; +use ibc::clients::ics07_tendermint::client_state::ClientState as TendermintClientState; +use ibc::clients::ics07_tendermint::consensus_state::ConsensusState as TendermintConsensusState; +use ibc::clients::ics07_tendermint::header::Header as TendermintClientHeader; +use ibc::clients::ics07_tendermint::misbehaviour::Misbehaviour as TendermintMisbehavior; +use ibc::core::ics02_client::client_type::ClientType; +use ibc::timestamp::Timestamp; +use ibc::Height; +use ibc_framework::core::traits::sync::Async; + +pub trait OfaCosmosClient: Async { + type AnyClientState: Async; + + type AnyConsensusState: Async; + + type AnyClientHeader: Async; + + type AnyMisbehavior: Async; + + fn client_state_type(client_state: &Self::AnyClientState) -> ClientType; + + fn client_state_is_frozen(client_state: &Self::AnyClientState) -> bool; + + fn client_state_trusting_period(client_state: &Self::AnyClientState) -> Duration; + + fn client_state_latest_height(client_state: &Self::AnyClientState) -> Height; + + fn consensus_state_timestamp(consensus_state: &Self::AnyConsensusState) -> Timestamp; + + fn client_header_height(client_header: &Self::AnyClientHeader) -> Height; + + fn try_into_tendermint_client_state( + client_state: Self::AnyClientState, + ) -> Option; + + fn try_into_tendermint_client_state_ref( + client_state: &Self::AnyClientState, + ) -> Option<&TendermintClientState>; + + fn from_tendermint_client_state(client_state: TendermintClientState) -> Self::AnyClientState; + + fn try_into_tendermint_consensus_state( + consensus_state: Self::AnyConsensusState, + ) -> Option; + + fn try_into_tendermint_consensus_state_ref( + consensus_state: &Self::AnyConsensusState, + ) -> Option<&TendermintConsensusState>; + + fn from_tendermint_consensus_state( + consensus_state: TendermintConsensusState, + ) -> Self::AnyConsensusState; + + fn try_into_tendermint_client_header( + client_header: Self::AnyClientHeader, + ) -> Option; + + fn try_into_tendermint_client_header_ref( + client_header: &Self::AnyClientHeader, + ) -> Option<&TendermintClientHeader>; + + fn from_tendermint_client_header( + client_header: TendermintClientHeader, + ) -> Self::AnyClientHeader; + + fn try_into_tendermint_misbehavior( + misbehavior: Self::AnyMisbehavior, + ) -> Option; + + fn try_into_tendermint_misbehavior_ref( + misbehavior: &Self::AnyMisbehavior, + ) -> Option<&TendermintMisbehavior>; + + fn from_tendermint_misbehavior(misbehavior: TendermintMisbehavior) -> Self::AnyMisbehavior; +} diff --git a/crates/ibc-cosmos/src/one_for_all/traits/mod.rs b/crates/ibc-cosmos/src/one_for_all/traits/mod.rs new file mode 100644 index 000000000..50598a1ad --- /dev/null +++ b/crates/ibc-cosmos/src/one_for_all/traits/mod.rs @@ -0,0 +1,2 @@ +pub mod chain; +pub mod client; diff --git a/crates/ibc-cosmos/src/one_for_all/types/chain.rs b/crates/ibc-cosmos/src/one_for_all/types/chain.rs new file mode 100644 index 000000000..01d25c231 --- /dev/null +++ b/crates/ibc-cosmos/src/one_for_all/types/chain.rs @@ -0,0 +1,3 @@ +pub struct OfaCosmosChainWrapper { + pub chain: Chain, +} diff --git a/crates/ibc-cosmos/src/one_for_all/types/mod.rs b/crates/ibc-cosmos/src/one_for_all/types/mod.rs new file mode 100644 index 000000000..28ac57df5 --- /dev/null +++ b/crates/ibc-cosmos/src/one_for_all/types/mod.rs @@ -0,0 +1 @@ +pub mod chain; diff --git a/crates/ibc-cosmos/src/types/event.rs b/crates/ibc-cosmos/src/types/event.rs new file mode 100644 index 000000000..9aa3c352c --- /dev/null +++ b/crates/ibc-cosmos/src/types/event.rs @@ -0,0 +1,31 @@ +use ibc::core::ics24_host::identifier::ClientId; +use ibc::Height; +use ibc_framework::core::traits::client::HasAnyClientTypes; + +pub enum IbcEvent +where + AnyClient: HasAnyClientTypes, +{ + UpdateClient(UpdateClientEvent), + Misbehavior(MisbehaviorEvent), +} + +pub struct UpdateClientEvent +where + AnyClient: HasAnyClientTypes, +{ + pub client_id: ClientId, + pub client_type: AnyClient::ClientType, + pub consensus_height: Height, + pub header: AnyClient::AnyClientHeader, +} + +pub struct MisbehaviorEvent +where + AnyClient: HasAnyClientTypes, +{ + pub client_id: ClientId, + pub client_type: AnyClient::ClientType, + pub consensus_height: Height, + pub header: AnyClient::AnyClientHeader, +} diff --git a/crates/ibc-cosmos/src/types/message.rs b/crates/ibc-cosmos/src/types/message.rs new file mode 100644 index 000000000..6a3161fae --- /dev/null +++ b/crates/ibc-cosmos/src/types/message.rs @@ -0,0 +1,35 @@ +use ibc::core::ics24_host::identifier::ClientId; +use ibc::signer::Signer; +use ibc_framework::core::traits::client::HasAnyClientTypes; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum IbcMessageType { + UpdateClient, +} + +pub enum IbcMessage +where + AnyClient: HasAnyClientTypes, +{ + UpdateClient(UpdateClientMessage), +} + +impl IbcMessage +where + AnyClient: HasAnyClientTypes, +{ + pub fn message_type(&self) -> IbcMessageType { + match self { + Self::UpdateClient(_) => IbcMessageType::UpdateClient, + } + } +} + +pub struct UpdateClientMessage +where + AnyClient: HasAnyClientTypes, +{ + pub client_id: ClientId, + pub client_header: AnyClient::AnyClientHeader, + pub signer: Signer, +} diff --git a/crates/ibc-cosmos/src/types/mod.rs b/crates/ibc-cosmos/src/types/mod.rs new file mode 100644 index 000000000..31912aa38 --- /dev/null +++ b/crates/ibc-cosmos/src/types/mod.rs @@ -0,0 +1,2 @@ +pub mod event; +pub mod message; diff --git a/crates/ibc-framework/Cargo.toml b/crates/ibc-framework/Cargo.toml new file mode 100644 index 000000000..7548a53ae --- /dev/null +++ b/crates/ibc-framework/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "ibc-framework" +version = "0.1.0" +edition = "2021" +license = "Apache-2.0" +readme = "README.md" +keywords = ["blockchain", "consensus", "cosmos", "ibc", "tendermint"] +repository = "https://github.com/informalsystems/ibc-rs" +authors = ["Informal Systems "] +rust-version = "1.60" +description = """ + Implementation of an IBC Relayer in Rust, as a library +""" + +[package.metadata.docs.rs] +all-features = true + +[features] + +[dependencies] +async-trait = "0.1.56" diff --git a/crates/ibc-framework/src/all_for_one/instances/message_handlers.rs b/crates/ibc-framework/src/all_for_one/instances/message_handlers.rs new file mode 100644 index 000000000..7899a4d9a --- /dev/null +++ b/crates/ibc-framework/src/all_for_one/instances/message_handlers.rs @@ -0,0 +1,22 @@ +use core::marker::PhantomData; + +use crate::all_for_one::traits::base::AfoChainContext; +use crate::core::impls::message_handlers::dispatch::DispatchIbcMessages; +use crate::core::impls::message_handlers::update_client::BaseUpdateClientMessageHandler; +use crate::core::traits::message_handler::MessageHandler; +use crate::core::traits::messages::update_client::UpdateClientMessageHandler; + +pub fn can_build_base_update_client_message_handler( +) -> PhantomData> +where + Context: AfoChainContext, +{ + PhantomData:: +} + +pub fn can_build_dispatch_ibc_message_handler() -> PhantomData> +where + Context: AfoChainContext, +{ + PhantomData:: +} diff --git a/crates/ibc-framework/src/all_for_one/instances/mod.rs b/crates/ibc-framework/src/all_for_one/instances/mod.rs new file mode 100644 index 000000000..ca6ee1750 --- /dev/null +++ b/crates/ibc-framework/src/all_for_one/instances/mod.rs @@ -0,0 +1 @@ +pub mod message_handlers; diff --git a/crates/ibc-framework/src/all_for_one/mod.rs b/crates/ibc-framework/src/all_for_one/mod.rs new file mode 100644 index 000000000..850a32dc0 --- /dev/null +++ b/crates/ibc-framework/src/all_for_one/mod.rs @@ -0,0 +1,2 @@ +pub mod instances; +pub mod traits; diff --git a/crates/ibc-framework/src/all_for_one/traits/base.rs b/crates/ibc-framework/src/all_for_one/traits/base.rs new file mode 100644 index 000000000..db8cf051b --- /dev/null +++ b/crates/ibc-framework/src/all_for_one/traits/base.rs @@ -0,0 +1,44 @@ +use crate::all_for_one::traits::error::AfoErrorContext; +use crate::all_for_one::traits::event::AfoEventContext; +use crate::core::traits::client::HasAnyClientMethods; +use crate::core::traits::event::HasEventEmitter; +use crate::core::traits::handlers::update_client::HasAnyUpdateClientHandler; +use crate::core::traits::host::HasHostMethods; +use crate::core::traits::ibc::HasIbcTypes; +use crate::core::traits::message::HasMessageMethods; +use crate::core::traits::messages::ibc::HasIbcMessages; +use crate::core::traits::messages::update_client::HasUpdateClientMessageHandler; +use crate::core::traits::stores::client_reader::HasAnyClientReader; +use crate::core::traits::stores::client_writer::HasAnyClientWriter; + +pub trait AfoChainContext: + AfoErrorContext + + AfoEventContext + + HasIbcTypes + + HasMessageMethods + + HasAnyClientMethods + + HasAnyClientReader + + HasAnyClientWriter + + HasAnyUpdateClientHandler + + HasHostMethods + + HasIbcMessages + + HasEventEmitter + + HasUpdateClientMessageHandler +{ +} + +impl AfoChainContext for Context where + Context: AfoErrorContext + + AfoEventContext + + HasIbcTypes + + HasMessageMethods + + HasAnyClientMethods + + HasAnyClientReader + + HasAnyClientWriter + + HasAnyUpdateClientHandler + + HasHostMethods + + HasIbcMessages + + HasEventEmitter + + HasUpdateClientMessageHandler +{ +} diff --git a/crates/ibc-framework/src/all_for_one/traits/error.rs b/crates/ibc-framework/src/all_for_one/traits/error.rs new file mode 100644 index 000000000..9c9f5f630 --- /dev/null +++ b/crates/ibc-framework/src/all_for_one/traits/error.rs @@ -0,0 +1,15 @@ +use crate::core::impls::message_handlers::dispatch::InjectDispatchError; +use crate::core::impls::message_handlers::update_client::InjectUpdateClientError; +use crate::core::traits::client::InjectClientTypeMismatchError; +use crate::core::traits::error::HasError; + +pub trait AfoErrorContext: + HasError + InjectClientTypeMismatchError + InjectDispatchError + InjectUpdateClientError +{ +} + +impl AfoErrorContext for Context where + Context: + HasError + InjectClientTypeMismatchError + InjectDispatchError + InjectUpdateClientError +{ +} diff --git a/crates/ibc-framework/src/all_for_one/traits/event.rs b/crates/ibc-framework/src/all_for_one/traits/event.rs new file mode 100644 index 000000000..0b1904316 --- /dev/null +++ b/crates/ibc-framework/src/all_for_one/traits/event.rs @@ -0,0 +1,9 @@ +use crate::core::traits::events::misbehavior::InjectMisbehaviorEvent; +use crate::core::traits::events::update_client::InjectUpdateClientEvent; + +pub trait AfoEventContext: InjectUpdateClientEvent + InjectMisbehaviorEvent {} + +impl AfoEventContext for Context where + Context: InjectUpdateClientEvent + InjectMisbehaviorEvent +{ +} diff --git a/crates/ibc-framework/src/all_for_one/traits/mod.rs b/crates/ibc-framework/src/all_for_one/traits/mod.rs new file mode 100644 index 000000000..b25d9ce4a --- /dev/null +++ b/crates/ibc-framework/src/all_for_one/traits/mod.rs @@ -0,0 +1,3 @@ +pub mod base; +pub mod error; +pub mod event; diff --git a/crates/ibc-framework/src/core/aliases/client.rs b/crates/ibc-framework/src/core/aliases/client.rs new file mode 100644 index 000000000..dbfd35b9d --- /dev/null +++ b/crates/ibc-framework/src/core/aliases/client.rs @@ -0,0 +1,15 @@ +use crate::core::traits::client::{HasAnyClientTypes, HasClientTypes}; + +pub type ClientType = ::ClientType; + +pub type AnyClientState = ::AnyClientState; + +pub type ClientState = ::ClientState; + +pub type AnyConsensusState = ::AnyConsensusState; + +pub type ConsensusState = ::ConsensusState; + +pub type AnyClientHeader = ::AnyClientHeader; + +pub type ClientHeader = ::ClientHeader; diff --git a/crates/ibc-framework/src/core/aliases/ibc.rs b/crates/ibc-framework/src/core/aliases/ibc.rs new file mode 100644 index 000000000..779f4c2aa --- /dev/null +++ b/crates/ibc-framework/src/core/aliases/ibc.rs @@ -0,0 +1,8 @@ +use crate::core::traits::host::HasHostTypes; +use crate::core::traits::ibc::HasIbcTypes; + +pub type Height = ::Height; + +pub type Timestamp = ::Timestamp; + +pub type ClientId = ::ClientId; diff --git a/crates/ibc-framework/src/core/aliases/mod.rs b/crates/ibc-framework/src/core/aliases/mod.rs new file mode 100644 index 000000000..d0dc4e23a --- /dev/null +++ b/crates/ibc-framework/src/core/aliases/mod.rs @@ -0,0 +1,2 @@ +pub mod client; +pub mod ibc; diff --git a/crates/ibc-framework/src/core/impls/client_reader.rs b/crates/ibc-framework/src/core/impls/client_reader.rs new file mode 100644 index 000000000..274a87904 --- /dev/null +++ b/crates/ibc-framework/src/core/impls/client_reader.rs @@ -0,0 +1,83 @@ +use crate::core::traits::client::{ContainsClient, HasClientTypeFor, HasClientTypes}; +use crate::core::traits::stores::client_reader::{ClientReader, HasAnyClientReader}; + +pub struct ClientReaderFromAnyClient; + +impl ClientReader for ClientReaderFromAnyClient +where + Client: HasClientTypes, + Context: HasAnyClientReader + ContainsClient + HasClientTypeFor, +{ + fn get_client_state( + context: &Context, + client_id: &Context::ClientId, + ) -> Result { + let any_client_state = context.get_any_client_state(client_id)?; + + let client_state = Context::try_from_any_client_state(any_client_state)?; + + Ok(client_state) + } + + fn get_latest_consensus_state( + context: &Context, + client_id: &Context::ClientId, + ) -> Result { + let any_consensus_state = context.get_latest_any_consensus_state(client_id)?; + + let consensus_state = Context::try_from_any_consensus_state(any_consensus_state)?; + + Ok(consensus_state) + } + + fn get_consensus_state_at_height( + context: &Context, + client_id: &Context::ClientId, + height: &Context::Height, + ) -> Result, Context::Error> { + let m_consensus_state = context.get_any_consensus_state_at_height(client_id, height)?; + + match m_consensus_state { + Some(any_consensus_state) => { + let consensus_state = Context::try_from_any_consensus_state(any_consensus_state)?; + + Ok(Some(consensus_state)) + } + None => Ok(None), + } + } + + fn get_consensus_state_after_height( + context: &Context, + client_id: &Context::ClientId, + height: &Context::Height, + ) -> Result, Context::Error> { + let m_consensus_state = context.get_any_consensus_state_after_height(client_id, height)?; + + match m_consensus_state { + Some(any_consensus_state) => { + let consensus_state = Context::try_from_any_consensus_state(any_consensus_state)?; + + Ok(Some(consensus_state)) + } + None => Ok(None), + } + } + + fn get_consensus_state_before_height( + context: &Context, + client_id: &Context::ClientId, + height: &Context::Height, + ) -> Result, Context::Error> { + let m_consensus_state = context.get_any_consensus_state_before_height(client_id, height)?; + + match m_consensus_state { + Some(any_consensus_state) => { + let consensus_state = Context::try_from_any_consensus_state(any_consensus_state)?; + + Ok(Some(consensus_state)) + } + None => Ok(None), + } + } +} diff --git a/crates/ibc-framework/src/core/impls/handlers/mod.rs b/crates/ibc-framework/src/core/impls/handlers/mod.rs new file mode 100644 index 000000000..4a9b38e37 --- /dev/null +++ b/crates/ibc-framework/src/core/impls/handlers/mod.rs @@ -0,0 +1 @@ +pub mod update_client; diff --git a/crates/ibc-framework/src/core/impls/handlers/update_client/combine.rs b/crates/ibc-framework/src/core/impls/handlers/update_client/combine.rs new file mode 100644 index 000000000..061314721 --- /dev/null +++ b/crates/ibc-framework/src/core/impls/handlers/update_client/combine.rs @@ -0,0 +1,46 @@ +use core::marker::PhantomData; + +use crate::core::impls::handlers::update_client::lift::LiftClientUpdateHandler; +use crate::core::traits::client::{ContainsClient, HasClientTypes}; +use crate::core::traits::handlers::update_client::{AnyUpdateClientHandler, UpdateClientHandler}; +use crate::core::traits::stores::client_reader::HasAnyClientReader; + +pub struct CombineClientUpdateHandler( + pub PhantomData<(Handler, NextHandlers)>, +); + +impl AnyUpdateClientHandler + for CombineClientUpdateHandler +where + Context: HasAnyClientReader, + Context: ContainsClient, + Client: HasClientTypes, + Handler: UpdateClientHandler, + NextHandlers: AnyUpdateClientHandler, + LiftClientUpdateHandler: AnyUpdateClientHandler, +{ + fn check_client_header_and_update_state( + context: &Context, + client_id: &Context::ClientId, + client_state: &Context::AnyClientState, + new_client_header: &Context::AnyClientHeader, + ) -> Result<(Context::AnyClientState, Context::AnyConsensusState), Context::Error> { + let client_type = context.get_client_type(client_id)?; + + if client_type == Context::client_type() { + >::check_client_header_and_update_state( + context, + client_id, + client_state, + new_client_header, + ) + } else { + NextHandlers::check_client_header_and_update_state( + context, + client_id, + client_state, + new_client_header, + ) + } + } +} diff --git a/crates/ibc-framework/src/core/impls/handlers/update_client/lift.rs b/crates/ibc-framework/src/core/impls/handlers/update_client/lift.rs new file mode 100644 index 000000000..c9302023c --- /dev/null +++ b/crates/ibc-framework/src/core/impls/handlers/update_client/lift.rs @@ -0,0 +1,51 @@ +use core::marker::PhantomData; + +use crate::core::traits::client::{ + ContainsClient, HasAnyClientMethods, HasClientTypes, InjectClientTypeMismatchError, +}; +use crate::core::traits::error::HasError; +use crate::core::traits::handlers::update_client::{AnyUpdateClientHandler, UpdateClientHandler}; +use crate::core::traits::ibc::HasIbcTypes; + +pub struct LiftClientUpdateHandler(pub PhantomData); + +impl AnyUpdateClientHandler for LiftClientUpdateHandler +where + Context: HasError + HasIbcTypes + HasAnyClientMethods, + Context: ContainsClient, + Client: HasClientTypes, + Handler: UpdateClientHandler, + Context: InjectClientTypeMismatchError, +{ + fn check_client_header_and_update_state( + context: &Context, + client_id: &Context::ClientId, + client_state: &Context::AnyClientState, + new_client_header: &Context::AnyClientHeader, + ) -> Result<(Context::AnyClientState, Context::AnyConsensusState), Context::Error> { + let client_type = Context::client_state_type(client_state); + + let expected_client_type = Context::client_type(); + + if client_type != expected_client_type { + return Err(Context::client_type_mismatch_error(&expected_client_type)); + } + + let client_state = Context::try_from_any_client_state_ref(client_state)?; + + let client_header = Context::try_from_any_client_header_ref(new_client_header)?; + + let (new_client_state, new_consensus_state) = + Handler::check_client_header_and_update_state( + context, + client_id, + client_state, + client_header, + )?; + + Ok(( + Context::into_any_client_state(new_client_state), + Context::into_any_consensus_state(new_consensus_state), + )) + } +} diff --git a/crates/ibc-framework/src/core/impls/handlers/update_client/mod.rs b/crates/ibc-framework/src/core/impls/handlers/update_client/mod.rs new file mode 100644 index 000000000..605ec430e --- /dev/null +++ b/crates/ibc-framework/src/core/impls/handlers/update_client/mod.rs @@ -0,0 +1,2 @@ +pub mod combine; +pub mod lift; diff --git a/crates/ibc-framework/src/core/impls/message_handlers/dispatch.rs b/crates/ibc-framework/src/core/impls/message_handlers/dispatch.rs new file mode 100644 index 000000000..bce3f8695 --- /dev/null +++ b/crates/ibc-framework/src/core/impls/message_handlers/dispatch.rs @@ -0,0 +1,38 @@ +use crate::core::traits::error::HasError; +use crate::core::traits::message::HasMessageMethods; +use crate::core::traits::message_handler::MessageHandler; +use crate::core::traits::messages::update_client::{ + HasUpdateClientMessage, HasUpdateClientMessageHandler, +}; + +pub struct DispatchIbcMessages; + +pub trait InjectDispatchError: HasMessageMethods + HasError { + fn unknown_message_error(message_type: &Self::MessageType) -> Self::Error; + + fn parse_message_error(message_type: &Self::MessageType) -> Self::Error; +} + +impl MessageHandler for DispatchIbcMessages +where + Context: HasMessageMethods, + Context: HasUpdateClientMessageHandler, + Context: InjectDispatchError, +{ + fn handle_message(context: &Context, message: &Context::Message) -> Result<(), Context::Error> { + let message_type = Context::message_type(message); + + // TODO: Handle all IBC messages here + + if message_type == ::MESSAGE_TYPE { + let update_client_message = Context::try_extract_update_client_message(message) + .ok_or_else(|| Context::parse_message_error(&message_type))?; + + context.handle_update_client_message(update_client_message)?; + + Ok(()) + } else { + Err(Context::unknown_message_error(&message_type)) + } + } +} diff --git a/crates/ibc-framework/src/core/impls/message_handlers/mod.rs b/crates/ibc-framework/src/core/impls/message_handlers/mod.rs new file mode 100644 index 000000000..5f5a4c361 --- /dev/null +++ b/crates/ibc-framework/src/core/impls/message_handlers/mod.rs @@ -0,0 +1,2 @@ +pub mod dispatch; +pub mod update_client; diff --git a/crates/ibc-framework/src/core/impls/message_handlers/update_client.rs b/crates/ibc-framework/src/core/impls/message_handlers/update_client.rs new file mode 100644 index 000000000..b9aab2f0d --- /dev/null +++ b/crates/ibc-framework/src/core/impls/message_handlers/update_client.rs @@ -0,0 +1,108 @@ +use crate::core::traits::client::HasAnyClientMethods; +use crate::core::traits::error::HasError; +use crate::core::traits::event::HasEventEmitter; +use crate::core::traits::events::misbehavior::InjectMisbehaviorEvent; +use crate::core::traits::events::update_client::InjectUpdateClientEvent; +use crate::core::traits::handlers::update_client::HasAnyUpdateClientHandler; +use crate::core::traits::host::{HasHostMethods, HasHostTypes}; +use crate::core::traits::ibc::HasIbcTypes; +use crate::core::traits::messages::update_client::{ + HasUpdateClientMessage, UpdateClientMessageHandler, +}; +use crate::core::traits::stores::client_reader::HasAnyClientReader; +use crate::core::traits::stores::client_writer::HasAnyClientWriter; + +pub trait InjectUpdateClientError: HasError + HasIbcTypes + HasHostTypes { + fn client_frozen_error(client_id: &Self::ClientId) -> Self::Error; + + fn client_expired_error( + client_id: &Self::ClientId, + current_time: &Self::Timestamp, + latest_allowed_update_time: &Self::Timestamp, + ) -> Self::Error; +} + +pub struct BaseUpdateClientMessageHandler; + +impl UpdateClientMessageHandler for BaseUpdateClientMessageHandler +where + Context: HasUpdateClientMessage, + Context: HasAnyClientReader, + Context: HasAnyUpdateClientHandler, + Context: HasAnyClientMethods, + Context: InjectUpdateClientError, + Context: HasHostMethods, + Context: HasIbcTypes, + Context: InjectUpdateClientEvent, + Context: InjectMisbehaviorEvent, + Context: HasEventEmitter, + Context: HasAnyClientWriter, +{ + fn handle_update_client_message( + context: &Context, + message: &Context::UpdateClientMessage, + ) -> Result<(), Context::Error> { + let client_id = Context::message_client_id(message); + let new_any_client_header = Context::message_client_header(message); + + let current_any_client_state = context.get_any_client_state(client_id)?; + + if Context::client_state_is_frozen(¤t_any_client_state) { + return Err(Context::client_frozen_error(client_id)); + } + + { + let current_time = context.host_timestamp(); + + let latest_consensus_state = context.get_latest_any_consensus_state(client_id)?; + + let last_updated_time = Context::consensus_state_timestamp(&latest_consensus_state); + + let trusting_period = Context::client_state_trusting_period(¤t_any_client_state); + + let latest_allowed_update_time = + Context::add_duration(&last_updated_time, &trusting_period); + + if current_time > latest_allowed_update_time { + return Err(Context::client_expired_error( + client_id, + ¤t_time, + &latest_allowed_update_time, + )); + } + } + + let (new_any_client_state, new_any_consensus_state) = context + .check_client_header_and_update_state( + client_id, + ¤t_any_client_state, + new_any_client_header, + )?; + + context.set_any_client_state(client_id, &new_any_client_state)?; + + if Context::client_state_is_frozen(&new_any_client_state) { + let event = Context::misbehavior_event( + client_id, + &Context::client_state_type(&new_any_client_state), + &Context::client_header_height(new_any_client_header), + new_any_client_header, + ); + + context.emit_event(&event); + } else { + context.set_any_consensus_state(client_id, &new_any_consensus_state)?; + + let event = Context::update_client_event( + client_id, + &Context::client_state_type(&new_any_client_state), + &Context::client_header_height(new_any_client_header), + new_any_client_header, + ); + + context.emit_event(&event); + } + + Ok(()) + } +} diff --git a/crates/ibc-framework/src/core/impls/mod.rs b/crates/ibc-framework/src/core/impls/mod.rs new file mode 100644 index 000000000..bf5a957d4 --- /dev/null +++ b/crates/ibc-framework/src/core/impls/mod.rs @@ -0,0 +1,3 @@ +pub mod client_reader; +pub mod handlers; +pub mod message_handlers; diff --git a/crates/ibc-framework/src/core/mod.rs b/crates/ibc-framework/src/core/mod.rs new file mode 100644 index 000000000..ac498e78a --- /dev/null +++ b/crates/ibc-framework/src/core/mod.rs @@ -0,0 +1,3 @@ +pub mod aliases; +pub mod impls; +pub mod traits; diff --git a/crates/ibc-framework/src/core/traits/client.rs b/crates/ibc-framework/src/core/traits/client.rs new file mode 100644 index 000000000..307509cb0 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/client.rs @@ -0,0 +1,199 @@ +use crate::core::traits::error::HasError; +use crate::core::traits::host::HasHostTypes; +use crate::core::traits::prism::Prism; +use crate::core::traits::sync::Async; + +pub trait HasAnyClientTypes: Async { + type ClientType: Eq + Async; + + type AnyClientState: Async; + + type AnyConsensusState: Async; + + type AnyClientHeader: Async; + + type AnyMisbehavior: Async; +} + +pub trait HasAnyClientMethods: HasAnyClientTypes + HasHostTypes { + fn client_state_type(client_state: &Self::AnyClientState) -> Self::ClientType; + + fn client_state_is_frozen(client_state: &Self::AnyClientState) -> bool; + + fn client_state_trusting_period(client_state: &Self::AnyClientState) -> Self::Duration; + + fn client_state_latest_height(client_state: &Self::AnyClientState) -> Self::Height; + + fn consensus_state_timestamp(consensus_state: &Self::AnyConsensusState) -> Self::Timestamp; + + fn client_header_height(client_header: &Self::AnyClientHeader) -> Self::Height; +} + +pub trait HasClientTypes: Async { + type ClientState: Async; + + type ConsensusState: Async; + + type ClientHeader: Async; + + type Misbehavior: Async; +} + +pub trait HasClientTypeFor: HasAnyClientTypes { + fn client_type() -> Self::ClientType; +} + +pub trait InjectClientTypeMismatchError: HasError + HasAnyClientTypes { + fn client_type_mismatch_error(expected_client_type: &Self::ClientType) -> Self::Error; +} + +pub trait HasClientPrisms: + HasAnyClientTypes + + Prism + + Prism + + Prism + + Prism + + HasError +where + Client: HasClientTypes, +{ + fn into_any_client_state(client_state: Client::ClientState) -> Self::AnyClientState; + + fn try_from_any_client_state( + client_state: Self::AnyClientState, + ) -> Result; + + fn try_from_any_client_state_ref( + client_state: &Self::AnyClientState, + ) -> Result<&Client::ClientState, Self::Error>; + + fn into_any_consensus_state(consensus_state: Client::ConsensusState) + -> Self::AnyConsensusState; + + fn try_from_any_consensus_state( + consensus_state: Self::AnyConsensusState, + ) -> Result; + + fn try_from_any_consensus_state_ref( + consensus_state: &Self::AnyConsensusState, + ) -> Result<&Client::ConsensusState, Self::Error>; + + fn into_any_client_header(client_header: Client::ClientHeader) -> Self::AnyClientHeader; + + fn try_from_any_client_header( + client_header: Self::AnyClientHeader, + ) -> Result; + + fn try_from_any_client_header_ref( + client_header: &Self::AnyClientHeader, + ) -> Result<&Client::ClientHeader, Self::Error>; + + fn into_any_misbehavior(misbehavior: Client::Misbehavior) -> Self::AnyMisbehavior; + + fn try_from_any_misbehavior( + misbehavior: Self::AnyMisbehavior, + ) -> Result; + + fn try_from_any_misbehavior_ref( + misbehavior: &Self::AnyMisbehavior, + ) -> Result<&Client::Misbehavior, Self::Error>; +} + +impl HasClientPrisms for Context +where + Context: HasClientTypeFor, + Client: HasClientTypes, + Context: InjectClientTypeMismatchError, + Context: Prism + + Prism + + Prism + + Prism, +{ + fn into_any_client_state(client_state: Client::ClientState) -> Self::AnyClientState { + Context::into(client_state) + } + + fn try_from_any_client_state( + client_state: Self::AnyClientState, + ) -> Result { + Context::try_from(client_state) + .ok_or_else(|| Context::client_type_mismatch_error(&Self::client_type())) + } + + fn try_from_any_client_state_ref( + client_state: &Self::AnyClientState, + ) -> Result<&Client::ClientState, Context::Error> { + Context::try_from_ref(client_state) + .ok_or_else(|| Context::client_type_mismatch_error(&Self::client_type())) + } + + fn into_any_consensus_state( + consensus_state: Client::ConsensusState, + ) -> Self::AnyConsensusState { + Context::into(consensus_state) + } + + fn try_from_any_consensus_state( + consensus_state: Self::AnyConsensusState, + ) -> Result { + Context::try_from(consensus_state) + .ok_or_else(|| Context::client_type_mismatch_error(&Self::client_type())) + } + + fn try_from_any_consensus_state_ref( + consensus_state: &Self::AnyConsensusState, + ) -> Result<&Client::ConsensusState, Context::Error> { + Context::try_from_ref(consensus_state) + .ok_or_else(|| Context::client_type_mismatch_error(&Self::client_type())) + } + + fn into_any_client_header(client_header: Client::ClientHeader) -> Self::AnyClientHeader { + Context::into(client_header) + } + + fn try_from_any_client_header( + client_header: Self::AnyClientHeader, + ) -> Result { + Context::try_from(client_header) + .ok_or_else(|| Context::client_type_mismatch_error(&Self::client_type())) + } + + fn try_from_any_client_header_ref( + client_header: &Self::AnyClientHeader, + ) -> Result<&Client::ClientHeader, Context::Error> { + Context::try_from_ref(client_header) + .ok_or_else(|| Context::client_type_mismatch_error(&Self::client_type())) + } + + fn into_any_misbehavior(misbehavior: Client::Misbehavior) -> Self::AnyMisbehavior { + Context::into(misbehavior) + } + + fn try_from_any_misbehavior( + misbehavior: Self::AnyMisbehavior, + ) -> Result { + Context::try_from(misbehavior) + .ok_or_else(|| Context::client_type_mismatch_error(&Self::client_type())) + } + + fn try_from_any_misbehavior_ref( + misbehavior: &Self::AnyMisbehavior, + ) -> Result<&Client::Misbehavior, Context::Error> { + Context::try_from_ref(misbehavior) + .ok_or_else(|| Context::client_type_mismatch_error(&Self::client_type())) + } +} + +pub trait ContainsClient: + HasAnyClientTypes + HasClientPrisms + HasClientTypeFor +where + Client: HasClientTypes, +{ +} + +impl ContainsClient for Context +where + Client: HasClientTypes, + Context: HasAnyClientTypes + HasClientPrisms + HasClientTypeFor, +{ +} diff --git a/crates/ibc-framework/src/core/traits/error.rs b/crates/ibc-framework/src/core/traits/error.rs new file mode 100644 index 000000000..2291d07ce --- /dev/null +++ b/crates/ibc-framework/src/core/traits/error.rs @@ -0,0 +1,9 @@ +use crate::core::traits::sync::Async; + +pub trait HasError: Async { + type Error: Async; +} + +pub trait InjectError: HasError { + fn inject_error(error: E) -> Self::Error; +} diff --git a/crates/ibc-framework/src/core/traits/event.rs b/crates/ibc-framework/src/core/traits/event.rs new file mode 100644 index 000000000..c2051f7b1 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/event.rs @@ -0,0 +1,9 @@ +use crate::core::traits::sync::Async; + +pub trait HasEventTypes: Async { + type Event: Async; +} + +pub trait HasEventEmitter: HasEventTypes { + fn emit_event(&self, event: &Self::Event); +} diff --git a/crates/ibc-framework/src/core/traits/events/misbehavior.rs b/crates/ibc-framework/src/core/traits/events/misbehavior.rs new file mode 100644 index 000000000..b2402a98e --- /dev/null +++ b/crates/ibc-framework/src/core/traits/events/misbehavior.rs @@ -0,0 +1,15 @@ +use crate::core::traits::client::HasAnyClientTypes; +use crate::core::traits::event::HasEventTypes; +use crate::core::traits::host::HasHostTypes; +use crate::core::traits::ibc::HasIbcTypes; + +pub trait InjectMisbehaviorEvent: + HasAnyClientTypes + HasEventTypes + HasIbcTypes + HasHostTypes +{ + fn misbehavior_event( + client_id: &Self::ClientId, + client_type: &Self::ClientType, + consensus_height: &Self::Height, + header: &Self::AnyClientHeader, + ) -> Self::Event; +} diff --git a/crates/ibc-framework/src/core/traits/events/mod.rs b/crates/ibc-framework/src/core/traits/events/mod.rs new file mode 100644 index 000000000..b896562ca --- /dev/null +++ b/crates/ibc-framework/src/core/traits/events/mod.rs @@ -0,0 +1,2 @@ +pub mod misbehavior; +pub mod update_client; diff --git a/crates/ibc-framework/src/core/traits/events/update_client.rs b/crates/ibc-framework/src/core/traits/events/update_client.rs new file mode 100644 index 000000000..00fd15d39 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/events/update_client.rs @@ -0,0 +1,15 @@ +use crate::core::traits::client::HasAnyClientTypes; +use crate::core::traits::event::HasEventTypes; +use crate::core::traits::host::HasHostTypes; +use crate::core::traits::ibc::HasIbcTypes; + +pub trait InjectUpdateClientEvent: + HasAnyClientTypes + HasEventTypes + HasIbcTypes + HasHostTypes +{ + fn update_client_event( + client_id: &Self::ClientId, + client_type: &Self::ClientType, + consensus_height: &Self::Height, + header: &Self::AnyClientHeader, + ) -> Self::Event; +} diff --git a/crates/ibc-framework/src/core/traits/handlers/mod.rs b/crates/ibc-framework/src/core/traits/handlers/mod.rs new file mode 100644 index 000000000..4a9b38e37 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/handlers/mod.rs @@ -0,0 +1 @@ +pub mod update_client; diff --git a/crates/ibc-framework/src/core/traits/handlers/update_client.rs b/crates/ibc-framework/src/core/traits/handlers/update_client.rs new file mode 100644 index 000000000..76907af45 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/handlers/update_client.rs @@ -0,0 +1,49 @@ +use crate::core::aliases::client::{ClientHeader, ClientState, ConsensusState}; +use crate::core::traits::client::{HasAnyClientTypes, HasClientTypes}; +use crate::core::traits::error::HasError; +use crate::core::traits::ibc::HasIbcTypes; +use crate::core::traits::sync::Async; + +pub trait HasAnyUpdateClientHandler: HasIbcTypes + HasAnyClientTypes + HasError { + type AnyUpdateClientHandler: AnyUpdateClientHandler; + + fn check_client_header_and_update_state( + &self, + client_id: &Self::ClientId, + client_state: &Self::AnyClientState, + new_client_header: &Self::AnyClientHeader, + ) -> Result<(Self::AnyClientState, Self::AnyConsensusState), Self::Error> { + Self::AnyUpdateClientHandler::check_client_header_and_update_state( + self, + client_id, + client_state, + new_client_header, + ) + } +} + +pub trait AnyUpdateClientHandler: Async +where + Context: HasIbcTypes + HasAnyClientTypes + HasError, +{ + fn check_client_header_and_update_state( + context: &Context, + client_id: &Context::ClientId, + client_state: &Context::AnyClientState, + new_client_header: &Context::AnyClientHeader, + ) -> Result<(Context::AnyClientState, Context::AnyConsensusState), Context::Error>; +} + +pub trait UpdateClientHandler: Async +where + Context: HasIbcTypes + HasError, +{ + type Client: HasClientTypes; + + fn check_client_header_and_update_state( + chain: &Context, + client_id: &Context::ClientId, + client_state: &ClientState, + new_client_header: &ClientHeader, + ) -> Result<(ClientState, ConsensusState), Context::Error>; +} diff --git a/crates/ibc-framework/src/core/traits/host.rs b/crates/ibc-framework/src/core/traits/host.rs new file mode 100644 index 000000000..1e698fa9e --- /dev/null +++ b/crates/ibc-framework/src/core/traits/host.rs @@ -0,0 +1,18 @@ +use crate::core::traits::sync::Async; + +pub trait HasHostTypes: Async { + type Height: Async; + + type Timestamp: Ord + Async; + + // Require non-negative duration + type Duration: Ord + Async; +} + +pub trait HasHostMethods: HasHostTypes { + fn host_height(&self) -> Self::Height; + + fn host_timestamp(&self) -> Self::Timestamp; + + fn add_duration(time: &Self::Timestamp, duration: &Self::Duration) -> Self::Timestamp; +} diff --git a/crates/ibc-framework/src/core/traits/ibc.rs b/crates/ibc-framework/src/core/traits/ibc.rs new file mode 100644 index 000000000..b3301647b --- /dev/null +++ b/crates/ibc-framework/src/core/traits/ibc.rs @@ -0,0 +1,13 @@ +use crate::core::traits::sync::Async; + +pub trait HasIbcTypes { + type ClientId: Async; + + type ConnectionId: Async; + + type ChannelId: Async; + + type Port: Async; + + type MerkleProof: Async; +} diff --git a/crates/ibc-framework/src/core/traits/message.rs b/crates/ibc-framework/src/core/traits/message.rs new file mode 100644 index 000000000..d63b1b222 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/message.rs @@ -0,0 +1,13 @@ +use crate::core::traits::sync::Async; + +pub trait HasMessageTypes { + type Message: Async; + + type MessageType: Eq + Async; + + type Signer: Async; +} + +pub trait HasMessageMethods: HasMessageTypes { + fn message_type(message: &Self::Message) -> Self::MessageType; +} diff --git a/crates/ibc-framework/src/core/traits/message_handler.rs b/crates/ibc-framework/src/core/traits/message_handler.rs new file mode 100644 index 000000000..0c4c98adc --- /dev/null +++ b/crates/ibc-framework/src/core/traits/message_handler.rs @@ -0,0 +1,9 @@ +use crate::core::traits::error::HasError; +use crate::core::traits::message::HasMessageTypes; + +pub trait MessageHandler +where + Context: HasMessageTypes + HasError, +{ + fn handle_message(context: &Context, message: &Context::Message) -> Result<(), Context::Error>; +} diff --git a/crates/ibc-framework/src/core/traits/messages/ibc.rs b/crates/ibc-framework/src/core/traits/messages/ibc.rs new file mode 100644 index 000000000..1d5bb2037 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/messages/ibc.rs @@ -0,0 +1,5 @@ +use crate::core::traits::messages::update_client::HasUpdateClientMessage; + +pub trait HasIbcMessages: HasUpdateClientMessage {} + +impl HasIbcMessages for Context where Context: HasUpdateClientMessage {} diff --git a/crates/ibc-framework/src/core/traits/messages/mod.rs b/crates/ibc-framework/src/core/traits/messages/mod.rs new file mode 100644 index 000000000..27a26e959 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/messages/mod.rs @@ -0,0 +1,2 @@ +pub mod ibc; +pub mod update_client; diff --git a/crates/ibc-framework/src/core/traits/messages/update_client.rs b/crates/ibc-framework/src/core/traits/messages/update_client.rs new file mode 100644 index 000000000..3fbdf64a2 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/messages/update_client.rs @@ -0,0 +1,40 @@ +use crate::core::traits::client::HasAnyClientTypes; +use crate::core::traits::error::HasError; +use crate::core::traits::ibc::HasIbcTypes; +use crate::core::traits::message::HasMessageTypes; +use crate::core::traits::sync::Async; + +pub trait HasUpdateClientMessage: HasAnyClientTypes + HasIbcTypes + HasMessageTypes { + const MESSAGE_TYPE: Self::MessageType; + + type UpdateClientMessage: Async; + + fn try_extract_update_client_message( + message: &Self::Message, + ) -> Option<&Self::UpdateClientMessage>; + + fn message_client_id(message: &Self::UpdateClientMessage) -> &Self::ClientId; + + fn message_client_header(message: &Self::UpdateClientMessage) -> &Self::AnyClientHeader; +} + +pub trait UpdateClientMessageHandler: Async +where + Context: HasUpdateClientMessage + HasError, +{ + fn handle_update_client_message( + context: &Context, + message: &Context::UpdateClientMessage, + ) -> Result<(), Context::Error>; +} + +pub trait HasUpdateClientMessageHandler: HasUpdateClientMessage + HasError { + type UpdateClientMessageHandler: UpdateClientMessageHandler; + + fn handle_update_client_message( + &self, + message: &Self::UpdateClientMessage, + ) -> Result<(), Self::Error> { + Self::UpdateClientMessageHandler::handle_update_client_message(self, message) + } +} diff --git a/crates/ibc-framework/src/core/traits/mod.rs b/crates/ibc-framework/src/core/traits/mod.rs new file mode 100644 index 000000000..9d02097ca --- /dev/null +++ b/crates/ibc-framework/src/core/traits/mod.rs @@ -0,0 +1,13 @@ +pub mod client; +pub mod error; +pub mod event; +pub mod events; +pub mod handlers; +pub mod host; +pub mod ibc; +pub mod message; +pub mod message_handler; +pub mod messages; +pub mod prism; +pub mod stores; +pub mod sync; diff --git a/crates/ibc-framework/src/core/traits/prism.rs b/crates/ibc-framework/src/core/traits/prism.rs new file mode 100644 index 000000000..5360b0a51 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/prism.rs @@ -0,0 +1,9 @@ +use crate::core::traits::sync::Async; + +pub trait Prism: Async { + fn into(subdata: SubData) -> Data; + + fn try_from(data: Data) -> Option; + + fn try_from_ref(data: &Data) -> Option<&SubData>; +} diff --git a/crates/ibc-framework/src/core/traits/stores/client_reader.rs b/crates/ibc-framework/src/core/traits/stores/client_reader.rs new file mode 100644 index 000000000..f37c0ad3f --- /dev/null +++ b/crates/ibc-framework/src/core/traits/stores/client_reader.rs @@ -0,0 +1,172 @@ +use crate::core::traits::client::{ContainsClient, HasAnyClientTypes, HasClientTypes}; +use crate::core::traits::error::HasError; +use crate::core::traits::host::HasHostTypes; +use crate::core::traits::ibc::HasIbcTypes; + +pub trait AnyClientReader +where + Context: HasAnyClientTypes + HasIbcTypes + HasHostTypes + HasError, +{ + fn get_client_type( + context: &Context, + client_id: &Context::ClientId, + ) -> Result; + + fn get_any_client_state( + context: &Context, + client_id: &Context::ClientId, + ) -> Result; + + fn get_latest_any_consensus_state( + context: &Context, + client_id: &Context::ClientId, + ) -> Result; + + fn get_any_consensus_state_at_height( + context: &Context, + client_id: &Context::ClientId, + height: &Context::Height, + ) -> Result, Context::Error>; + + fn get_any_consensus_state_after_height( + context: &Context, + client_id: &Context::ClientId, + height: &Context::Height, + ) -> Result, Context::Error>; + + fn get_any_consensus_state_before_height( + context: &Context, + client_id: &Context::ClientId, + height: &Context::Height, + ) -> Result, Context::Error>; +} + +pub trait HasAnyClientReader: HasAnyClientTypes + HasIbcTypes + HasHostTypes + HasError { + type AnyClientReader: AnyClientReader; + + fn get_client_type(&self, client_id: &Self::ClientId) -> Result { + Self::AnyClientReader::get_client_type(self, client_id) + } + + fn get_any_client_state( + &self, + client_id: &Self::ClientId, + ) -> Result { + Self::AnyClientReader::get_any_client_state(self, client_id) + } + + fn get_latest_any_consensus_state( + &self, + client_id: &Self::ClientId, + ) -> Result { + Self::AnyClientReader::get_latest_any_consensus_state(self, client_id) + } + + fn get_any_consensus_state_at_height( + &self, + client_id: &Self::ClientId, + height: &Self::Height, + ) -> Result, Self::Error> { + Self::AnyClientReader::get_any_consensus_state_at_height(self, client_id, height) + } + + fn get_any_consensus_state_after_height( + &self, + client_id: &Self::ClientId, + height: &Self::Height, + ) -> Result, Self::Error> { + Self::AnyClientReader::get_any_consensus_state_after_height(self, client_id, height) + } + + fn get_any_consensus_state_before_height( + &self, + client_id: &Self::ClientId, + height: &Self::Height, + ) -> Result, Self::Error> { + Self::AnyClientReader::get_any_consensus_state_after_height(self, client_id, height) + } +} + +pub struct MismatchClientFormat { + pub expected_client_type: ClientType, +} + +pub trait ClientReader +where + Context: HasError + HasIbcTypes + HasHostTypes + ContainsClient, + Client: HasClientTypes, +{ + fn get_client_state( + context: &Context, + client_id: &Context::ClientId, + ) -> Result; + + fn get_latest_consensus_state( + context: &Context, + client_id: &Context::ClientId, + ) -> Result; + + fn get_consensus_state_at_height( + context: &Context, + client_id: &Context::ClientId, + height: &Context::Height, + ) -> Result, Context::Error>; + + fn get_consensus_state_after_height( + context: &Context, + client_id: &Context::ClientId, + height: &Context::Height, + ) -> Result, Context::Error>; + + fn get_consensus_state_before_height( + context: &Context, + client_id: &Context::ClientId, + height: &Context::Height, + ) -> Result, Context::Error>; +} + +pub trait HasClientReader: + HasError + HasIbcTypes + HasHostTypes + ContainsClient +where + Client: HasClientTypes, +{ + type ClientReader: ClientReader; + + fn get_client_state( + &self, + client_id: &Self::ClientId, + ) -> Result { + Self::ClientReader::get_client_state(self, client_id) + } + + fn get_latest_consensus_state( + &self, + client_id: &Self::ClientId, + ) -> Result { + Self::ClientReader::get_latest_consensus_state(self, client_id) + } + + fn get_consensus_state_at_height( + &self, + client_id: &Self::ClientId, + height: &Self::Height, + ) -> Result, Self::Error> { + Self::ClientReader::get_consensus_state_at_height(self, client_id, height) + } + + fn get_consensus_state_after_height( + &self, + client_id: &Self::ClientId, + height: &Self::Height, + ) -> Result, Self::Error> { + Self::ClientReader::get_consensus_state_after_height(self, client_id, height) + } + + fn get_consensus_state_before_height( + &self, + client_id: &Self::ClientId, + height: &Self::Height, + ) -> Result, Self::Error> { + Self::ClientReader::get_consensus_state_before_height(self, client_id, height) + } +} diff --git a/crates/ibc-framework/src/core/traits/stores/client_writer.rs b/crates/ibc-framework/src/core/traits/stores/client_writer.rs new file mode 100644 index 000000000..c887260d2 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/stores/client_writer.rs @@ -0,0 +1,40 @@ +use crate::core::traits::client::HasAnyClientTypes; +use crate::core::traits::error::HasError; +use crate::core::traits::ibc::HasIbcTypes; + +pub trait AnyClientWriter +where + Context: HasAnyClientTypes + HasIbcTypes + HasError, +{ + fn set_any_client_state( + context: &Context, + client_id: &Context::ClientId, + client_state: &Context::AnyClientState, + ) -> Result<(), Context::Error>; + + fn set_any_consensus_state( + context: &Context, + client_id: &Context::ClientId, + consensus_state: &Context::AnyConsensusState, + ) -> Result<(), Context::Error>; +} + +pub trait HasAnyClientWriter: HasAnyClientTypes + HasIbcTypes + HasError { + type AnyClientWriter: AnyClientWriter; + + fn set_any_client_state( + &self, + client_id: &Self::ClientId, + client_state: &Self::AnyClientState, + ) -> Result<(), Self::Error> { + Self::AnyClientWriter::set_any_client_state(self, client_id, client_state) + } + + fn set_any_consensus_state( + &self, + client_id: &Self::ClientId, + consensus_state: &Self::AnyConsensusState, + ) -> Result<(), Self::Error> { + Self::AnyClientWriter::set_any_consensus_state(self, client_id, consensus_state) + } +} diff --git a/crates/ibc-framework/src/core/traits/stores/kvstore.rs b/crates/ibc-framework/src/core/traits/stores/kvstore.rs new file mode 100644 index 000000000..05301ea37 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/stores/kvstore.rs @@ -0,0 +1,20 @@ +use crate::core::traits::error::HasError; +use crate::core::traits::sync::Async; + +pub trait ReadOnlyKvStore: HasError +where + Key: Async, + Value: Async, +{ + fn has(key: &Key) -> Result; + + fn get(key: &Key) -> Result, Self::Error>; +} + +pub trait ReadWriteKvStore: ReadOnlyKvStore +where + Key: Async, + Value: Async, +{ + fn set(key: &Key, value: &Value) -> Result<(), Self::Error>; +} diff --git a/crates/ibc-framework/src/core/traits/stores/mod.rs b/crates/ibc-framework/src/core/traits/stores/mod.rs new file mode 100644 index 000000000..7b9b44d52 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/stores/mod.rs @@ -0,0 +1,3 @@ +pub mod client_reader; +pub mod client_writer; +pub mod kvstore; diff --git a/crates/ibc-framework/src/core/traits/sync.rs b/crates/ibc-framework/src/core/traits/sync.rs new file mode 100644 index 000000000..507eb8979 --- /dev/null +++ b/crates/ibc-framework/src/core/traits/sync.rs @@ -0,0 +1,3 @@ +pub trait Async: Sized + Send + Sync + 'static {} + +impl Async for A where A: Sized + Send + Sync + 'static {} diff --git a/crates/ibc-framework/src/lib.rs b/crates/ibc-framework/src/lib.rs new file mode 100644 index 000000000..2bbb094a5 --- /dev/null +++ b/crates/ibc-framework/src/lib.rs @@ -0,0 +1,11 @@ +#![no_std] +#![allow(clippy::type_complexity)] +#![allow(clippy::too_many_arguments)] + +extern crate alloc; + +mod std_prelude; + +pub mod all_for_one; +pub mod core; +pub mod one_for_all; diff --git a/crates/ibc-framework/src/one_for_all/components/default.rs b/crates/ibc-framework/src/one_for_all/components/default.rs new file mode 100644 index 000000000..20096398e --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/components/default.rs @@ -0,0 +1,18 @@ +use crate::core::impls::message_handlers::update_client::BaseUpdateClientMessageHandler; +use crate::one_for_all::impls::stores::{OfaClientReader, OfaClientWriter}; +use crate::one_for_all::traits::chain::OfaChain; +use crate::one_for_all::traits::components::{OfaChainComponents, OfaClientComponents}; + +pub struct DefaultChainComponents; + +impl OfaChainComponents for DefaultChainComponents +where + Chain: OfaChain, + Chain::ClientComponents: OfaClientComponents, +{ + type AnyClientReader = OfaClientReader; + + type AnyClientWriter = OfaClientWriter; + + type UpdateClientMessageHandler = BaseUpdateClientMessageHandler; +} diff --git a/crates/ibc-framework/src/one_for_all/components/mod.rs b/crates/ibc-framework/src/one_for_all/components/mod.rs new file mode 100644 index 000000000..1be8d340b --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/components/mod.rs @@ -0,0 +1 @@ +pub mod default; diff --git a/crates/ibc-framework/src/one_for_all/impls/chain.rs b/crates/ibc-framework/src/one_for_all/impls/chain.rs new file mode 100644 index 000000000..d94ce7608 --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/impls/chain.rs @@ -0,0 +1,162 @@ +use crate::core::traits::client::{HasAnyClientMethods, HasAnyClientTypes}; +use crate::core::traits::error::HasError; +use crate::core::traits::event::{HasEventEmitter, HasEventTypes}; +use crate::core::traits::host::{HasHostMethods, HasHostTypes}; +use crate::core::traits::ibc::HasIbcTypes; +use crate::core::traits::message::{HasMessageMethods, HasMessageTypes}; +use crate::core::traits::messages::update_client::HasUpdateClientMessage; +use crate::one_for_all::traits::chain::OfaChain; +use crate::one_for_all::types::chain::OfaChainWrapper; + +impl HasError for OfaChainWrapper +where + Chain: OfaChain, +{ + type Error = Chain::Error; +} + +impl HasEventTypes for OfaChainWrapper +where + Chain: OfaChain, +{ + type Event = Chain::Event; +} + +impl HasEventEmitter for OfaChainWrapper +where + Chain: OfaChain, +{ + fn emit_event(&self, event: &Self::Event) { + self.chain.emit_event(event) + } +} + +impl HasHostTypes for OfaChainWrapper +where + Chain: OfaChain, +{ + type Height = Chain::Height; + + type Timestamp = Chain::Timestamp; + + type Duration = Chain::Duration; +} + +impl HasHostMethods for OfaChainWrapper +where + Chain: OfaChain, +{ + fn host_height(&self) -> Self::Height { + self.chain.host_height() + } + + fn host_timestamp(&self) -> Self::Timestamp { + self.chain.host_timestamp() + } + + fn add_duration(time: &Self::Timestamp, duration: &Self::Duration) -> Self::Timestamp { + Chain::add_duration(time, duration) + } +} + +impl HasIbcTypes for OfaChainWrapper +where + Chain: OfaChain, +{ + type ClientId = Chain::ClientId; + + type ConnectionId = Chain::ConnectionId; + + type ChannelId = Chain::ChannelId; + + type Port = Chain::Port; + + type MerkleProof = Chain::MerkleProof; +} + +impl HasMessageTypes for OfaChainWrapper +where + Chain: OfaChain, +{ + type Message = Chain::Message; + + type MessageType = Chain::MessageType; + + type Signer = Chain::Signer; +} + +impl HasMessageMethods for OfaChainWrapper +where + Chain: OfaChain, +{ + fn message_type(message: &Self::Message) -> Self::MessageType { + Chain::message_type(message) + } +} + +impl HasAnyClientTypes for OfaChainWrapper +where + Chain: OfaChain, +{ + type ClientType = Chain::ClientType; + + type AnyClientState = Chain::AnyClientState; + + type AnyConsensusState = Chain::AnyConsensusState; + + type AnyClientHeader = Chain::AnyClientHeader; + + type AnyMisbehavior = Chain::AnyMisbehavior; +} + +impl HasAnyClientMethods for OfaChainWrapper +where + Chain: OfaChain, +{ + fn client_state_type(client_state: &Self::AnyClientState) -> Self::ClientType { + Chain::client_state_type(client_state) + } + + fn client_state_is_frozen(client_state: &Self::AnyClientState) -> bool { + Chain::client_state_is_frozen(client_state) + } + + fn client_state_trusting_period(client_state: &Self::AnyClientState) -> Self::Duration { + Chain::client_state_trusting_period(client_state) + } + + fn client_state_latest_height(client_state: &Self::AnyClientState) -> Self::Height { + Chain::client_state_latest_height(client_state) + } + + fn consensus_state_timestamp(consensus_state: &Self::AnyConsensusState) -> Self::Timestamp { + Chain::consensus_state_timestamp(consensus_state) + } + + fn client_header_height(client_header: &Self::AnyClientHeader) -> Self::Height { + Chain::client_header_height(client_header) + } +} + +impl HasUpdateClientMessage for OfaChainWrapper +where + Chain: OfaChain, +{ + const MESSAGE_TYPE: Self::MessageType = Chain::UPDATE_CLIENT_MESSAGE_TYPE; + + type UpdateClientMessage = Chain::UpdateClientMessage; + + fn try_extract_update_client_message( + message: &Self::Message, + ) -> Option<&Self::UpdateClientMessage> { + Chain::try_extract_update_client_message(message) + } + + fn message_client_id(message: &Self::UpdateClientMessage) -> &Self::ClientId { + Chain::update_client_message_client_id(message) + } + + fn message_client_header(message: &Self::UpdateClientMessage) -> &Self::AnyClientHeader { + Chain::update_client_message_client_header(message) + } +} diff --git a/crates/ibc-framework/src/one_for_all/impls/components.rs b/crates/ibc-framework/src/one_for_all/impls/components.rs new file mode 100644 index 000000000..881f843cf --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/impls/components.rs @@ -0,0 +1,41 @@ +use crate::core::traits::handlers::update_client::HasAnyUpdateClientHandler; +use crate::core::traits::messages::update_client::HasUpdateClientMessageHandler; +use crate::core::traits::stores::client_reader::HasAnyClientReader; +use crate::core::traits::stores::client_writer::HasAnyClientWriter; +use crate::one_for_all::traits::chain::OfaChain; +use crate::one_for_all::traits::components::{OfaChainComponents, OfaClientComponents}; +use crate::one_for_all::types::chain::OfaChainWrapper; + +impl HasAnyClientReader for OfaChainWrapper +where + Chain: OfaChain, + Chain::ChainComponents: OfaChainComponents, +{ + type AnyClientReader = >::AnyClientReader; +} + +impl HasAnyClientWriter for OfaChainWrapper +where + Chain: OfaChain, + Chain::ChainComponents: OfaChainComponents, +{ + type AnyClientWriter = >::AnyClientWriter; +} + +impl HasAnyUpdateClientHandler for OfaChainWrapper +where + Chain: OfaChain, + Chain::ClientComponents: OfaClientComponents, +{ + type AnyUpdateClientHandler = + >::AnyUpdateClientHandler; +} + +impl HasUpdateClientMessageHandler for OfaChainWrapper +where + Chain: OfaChain, + Chain::ChainComponents: OfaChainComponents, +{ + type UpdateClientMessageHandler = + >::UpdateClientMessageHandler; +} diff --git a/crates/ibc-framework/src/one_for_all/impls/error.rs b/crates/ibc-framework/src/one_for_all/impls/error.rs new file mode 100644 index 000000000..40f6f9114 --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/impls/error.rs @@ -0,0 +1,44 @@ +use crate::core::impls::message_handlers::dispatch::InjectDispatchError; +use crate::core::impls::message_handlers::update_client::InjectUpdateClientError; +use crate::core::traits::client::InjectClientTypeMismatchError; +use crate::one_for_all::traits::chain::OfaChain; +use crate::one_for_all::types::chain::OfaChainWrapper; + +impl InjectClientTypeMismatchError for OfaChainWrapper +where + Chain: OfaChain, +{ + fn client_type_mismatch_error(expected_client_type: &Self::ClientType) -> Self::Error { + Chain::client_type_mismatch_error(expected_client_type) + } +} + +impl InjectDispatchError for OfaChainWrapper +where + Chain: OfaChain, +{ + fn unknown_message_error(message_type: &Self::MessageType) -> Self::Error { + Chain::unknown_message_error(message_type) + } + + fn parse_message_error(message_type: &Self::MessageType) -> Self::Error { + Chain::parse_message_error(message_type) + } +} + +impl InjectUpdateClientError for OfaChainWrapper +where + Chain: OfaChain, +{ + fn client_frozen_error(client_id: &Self::ClientId) -> Self::Error { + Chain::client_frozen_error(client_id) + } + + fn client_expired_error( + client_id: &Self::ClientId, + current_time: &Self::Timestamp, + latest_allowed_update_time: &Self::Timestamp, + ) -> Self::Error { + Chain::client_expired_error(client_id, current_time, latest_allowed_update_time) + } +} diff --git a/crates/ibc-framework/src/one_for_all/impls/event.rs b/crates/ibc-framework/src/one_for_all/impls/event.rs new file mode 100644 index 000000000..37d828de6 --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/impls/event.rs @@ -0,0 +1,32 @@ +use crate::core::traits::events::misbehavior::InjectMisbehaviorEvent; +use crate::core::traits::events::update_client::InjectUpdateClientEvent; +use crate::one_for_all::traits::chain::OfaChain; +use crate::one_for_all::types::chain::OfaChainWrapper; + +impl InjectUpdateClientEvent for OfaChainWrapper +where + Chain: OfaChain, +{ + fn update_client_event( + client_id: &Self::ClientId, + client_type: &Self::ClientType, + consensus_height: &Self::Height, + header: &Self::AnyClientHeader, + ) -> Self::Event { + Chain::update_client_event(client_id, client_type, consensus_height, header) + } +} + +impl InjectMisbehaviorEvent for OfaChainWrapper +where + Chain: OfaChain, +{ + fn misbehavior_event( + client_id: &Self::ClientId, + client_type: &Self::ClientType, + consensus_height: &Self::Height, + header: &Self::AnyClientHeader, + ) -> Self::Event { + Chain::misbehavior_event(client_id, client_type, consensus_height, header) + } +} diff --git a/crates/ibc-framework/src/one_for_all/impls/mod.rs b/crates/ibc-framework/src/one_for_all/impls/mod.rs new file mode 100644 index 000000000..25c1f2db3 --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/impls/mod.rs @@ -0,0 +1,5 @@ +pub mod chain; +pub mod components; +pub mod error; +pub mod event; +pub mod stores; diff --git a/crates/ibc-framework/src/one_for_all/impls/stores.rs b/crates/ibc-framework/src/one_for_all/impls/stores.rs new file mode 100644 index 000000000..75ca15909 --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/impls/stores.rs @@ -0,0 +1,86 @@ +use crate::core::traits::stores::client_reader::AnyClientReader; +use crate::core::traits::stores::client_writer::AnyClientWriter; +use crate::one_for_all::traits::chain::OfaChain; +use crate::one_for_all::types::chain::OfaChainWrapper; + +pub struct OfaClientReader; +pub struct OfaClientWriter; + +impl AnyClientReader> for OfaClientReader +where + Chain: OfaChain, +{ + fn get_client_type( + context: &OfaChainWrapper, + client_id: &Chain::ClientId, + ) -> Result { + context.chain.get_client_type(client_id) + } + + fn get_any_client_state( + context: &OfaChainWrapper, + client_id: &Chain::ClientId, + ) -> Result { + context.chain.get_any_client_state(client_id) + } + + fn get_latest_any_consensus_state( + context: &OfaChainWrapper, + client_id: &Chain::ClientId, + ) -> Result { + context.chain.get_latest_any_consensus_state(client_id) + } + + fn get_any_consensus_state_at_height( + context: &OfaChainWrapper, + client_id: &Chain::ClientId, + height: &Chain::Height, + ) -> Result, Chain::Error> { + context + .chain + .get_any_consensus_state_at_height(client_id, height) + } + + fn get_any_consensus_state_after_height( + context: &OfaChainWrapper, + client_id: &Chain::ClientId, + height: &Chain::Height, + ) -> Result, Chain::Error> { + context + .chain + .get_any_consensus_state_after_height(client_id, height) + } + + fn get_any_consensus_state_before_height( + context: &OfaChainWrapper, + client_id: &Chain::ClientId, + height: &Chain::Height, + ) -> Result, Chain::Error> { + context + .chain + .get_any_consensus_state_before_height(client_id, height) + } +} + +impl AnyClientWriter> for OfaClientWriter +where + Chain: OfaChain, +{ + fn set_any_client_state( + context: &OfaChainWrapper, + client_id: &Chain::ClientId, + client_state: &Chain::AnyClientState, + ) -> Result<(), Chain::Error> { + context.chain.set_any_client_state(client_id, client_state) + } + + fn set_any_consensus_state( + context: &OfaChainWrapper, + client_id: &Chain::ClientId, + consensus_state: &Chain::AnyConsensusState, + ) -> Result<(), Chain::Error> { + context + .chain + .set_any_consensus_state(client_id, consensus_state) + } +} diff --git a/crates/ibc-framework/src/one_for_all/instances/chain.rs b/crates/ibc-framework/src/one_for_all/instances/chain.rs new file mode 100644 index 000000000..e0a02b93f --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/instances/chain.rs @@ -0,0 +1,13 @@ +use crate::all_for_one::traits::base::AfoChainContext; +use crate::one_for_all::traits::chain::OfaChain; +use crate::one_for_all::traits::components::{OfaChainComponents, OfaClientComponents}; +use crate::one_for_all::types::chain::OfaChainWrapper; + +pub fn ofa_to_afo_chain(chain: Chain) -> impl AfoChainContext +where + Chain: OfaChain, + Chain::ChainComponents: OfaChainComponents, + Chain::ClientComponents: OfaClientComponents, +{ + OfaChainWrapper { chain } +} diff --git a/crates/ibc-framework/src/one_for_all/instances/mod.rs b/crates/ibc-framework/src/one_for_all/instances/mod.rs new file mode 100644 index 000000000..28ac57df5 --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/instances/mod.rs @@ -0,0 +1 @@ +pub mod chain; diff --git a/crates/ibc-framework/src/one_for_all/mod.rs b/crates/ibc-framework/src/one_for_all/mod.rs new file mode 100644 index 000000000..6b148afb0 --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/mod.rs @@ -0,0 +1,5 @@ +pub mod components; +pub mod impls; +pub mod instances; +pub mod traits; +pub mod types; diff --git a/crates/ibc-framework/src/one_for_all/traits/chain.rs b/crates/ibc-framework/src/one_for_all/traits/chain.rs new file mode 100644 index 000000000..8641a6446 --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/traits/chain.rs @@ -0,0 +1,171 @@ +use crate::core::traits::sync::Async; + +pub trait OfaChainTypes: Async { + type Error: Async; + + type Event: Async; + + type Height: Async; + + type Timestamp: Ord + Async; + + type Duration: Ord + Async; + + type Message: Async; + + type MessageType: Eq + Async; + + type Signer: Async; + + type ClientId: Async; + + type ConnectionId: Async; + + type ChannelId: Async; + + type Port: Async; + + type MerkleProof: Async; + + type ClientType: Eq + Async; + + type AnyClientState: Async; + + type AnyConsensusState: Async; + + type AnyClientHeader: Async; + + type AnyMisbehavior: Async; + + type UpdateClientMessage: Async; +} + +pub trait OfaChain: OfaChainTypes { + type ChainComponents; + + type ClientComponents; + + // EventEmitter methods + + fn emit_event(&self, event: &Self::Event); + + // Host methods + + fn host_height(&self) -> Self::Height; + + fn host_timestamp(&self) -> Self::Timestamp; + + fn add_duration(time: &Self::Timestamp, duration: &Self::Duration) -> Self::Timestamp; + + // Message methods + + fn message_type(message: &Self::Message) -> Self::MessageType; + + // AnyClient methods + + fn client_state_type(client_state: &Self::AnyClientState) -> Self::ClientType; + + fn client_state_is_frozen(client_state: &Self::AnyClientState) -> bool; + + fn client_state_trusting_period(client_state: &Self::AnyClientState) -> Self::Duration; + + fn client_state_latest_height(client_state: &Self::AnyClientState) -> Self::Height; + + fn consensus_state_timestamp(consensus_state: &Self::AnyConsensusState) -> Self::Timestamp; + + fn client_header_height(client_header: &Self::AnyClientHeader) -> Self::Height; + + // AnyClientReader methods + + fn get_client_type(&self, client_id: &Self::ClientId) -> Result; + + fn get_any_client_state( + &self, + client_id: &Self::ClientId, + ) -> Result; + + fn get_latest_any_consensus_state( + &self, + client_id: &Self::ClientId, + ) -> Result; + + fn get_any_consensus_state_at_height( + &self, + client_id: &Self::ClientId, + height: &Self::Height, + ) -> Result, Self::Error>; + + fn get_any_consensus_state_after_height( + &self, + client_id: &Self::ClientId, + height: &Self::Height, + ) -> Result, Self::Error>; + + fn get_any_consensus_state_before_height( + &self, + client_id: &Self::ClientId, + height: &Self::Height, + ) -> Result, Self::Error>; + + // AnyClientWriter methods + + fn set_any_client_state( + &self, + client_id: &Self::ClientId, + client_state: &Self::AnyClientState, + ) -> Result<(), Self::Error>; + + fn set_any_consensus_state( + &self, + client_id: &Self::ClientId, + consensus_state: &Self::AnyConsensusState, + ) -> Result<(), Self::Error>; + + // Error methods + + fn client_type_mismatch_error(expected_client_type: &Self::ClientType) -> Self::Error; + + fn unknown_message_error(message_type: &Self::MessageType) -> Self::Error; + + fn parse_message_error(message_type: &Self::MessageType) -> Self::Error; + + fn client_frozen_error(client_id: &Self::ClientId) -> Self::Error; + + fn client_expired_error( + client_id: &Self::ClientId, + current_time: &Self::Timestamp, + latest_allowed_update_time: &Self::Timestamp, + ) -> Self::Error; + + // Event methods + + fn update_client_event( + client_id: &Self::ClientId, + client_type: &Self::ClientType, + consensus_height: &Self::Height, + header: &Self::AnyClientHeader, + ) -> Self::Event; + + fn misbehavior_event( + client_id: &Self::ClientId, + client_type: &Self::ClientType, + consensus_height: &Self::Height, + header: &Self::AnyClientHeader, + ) -> Self::Event; + + // Message methods + + // UpdateClient message + + const UPDATE_CLIENT_MESSAGE_TYPE: Self::MessageType; + + fn try_extract_update_client_message( + message: &Self::Message, + ) -> Option<&Self::UpdateClientMessage>; + + fn update_client_message_client_id(message: &Self::UpdateClientMessage) -> &Self::ClientId; + + fn update_client_message_client_header( + message: &Self::UpdateClientMessage, + ) -> &Self::AnyClientHeader; +} diff --git a/crates/ibc-framework/src/one_for_all/traits/components.rs b/crates/ibc-framework/src/one_for_all/traits/components.rs new file mode 100644 index 000000000..758035bf4 --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/traits/components.rs @@ -0,0 +1,24 @@ +use crate::core::traits::handlers::update_client::AnyUpdateClientHandler; +use crate::core::traits::messages::update_client::UpdateClientMessageHandler; +use crate::core::traits::stores::client_reader::AnyClientReader; +use crate::core::traits::stores::client_writer::AnyClientWriter; +use crate::one_for_all::traits::chain::OfaChain; +use crate::one_for_all::types::chain::OfaChainWrapper; + +pub trait OfaChainComponents +where + Chain: OfaChain, +{ + type AnyClientReader: AnyClientReader>; + + type AnyClientWriter: AnyClientWriter>; + + type UpdateClientMessageHandler: UpdateClientMessageHandler>; +} + +pub trait OfaClientComponents +where + Chain: OfaChain, +{ + type AnyUpdateClientHandler: AnyUpdateClientHandler>; +} diff --git a/crates/ibc-framework/src/one_for_all/traits/mod.rs b/crates/ibc-framework/src/one_for_all/traits/mod.rs new file mode 100644 index 000000000..313c8fb07 --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/traits/mod.rs @@ -0,0 +1,2 @@ +pub mod chain; +pub mod components; diff --git a/crates/ibc-framework/src/one_for_all/types/chain.rs b/crates/ibc-framework/src/one_for_all/types/chain.rs new file mode 100644 index 000000000..e8bab6c0d --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/types/chain.rs @@ -0,0 +1,4 @@ +#[derive(Clone)] +pub struct OfaChainWrapper { + pub chain: Chain, +} diff --git a/crates/ibc-framework/src/one_for_all/types/mod.rs b/crates/ibc-framework/src/one_for_all/types/mod.rs new file mode 100644 index 000000000..28ac57df5 --- /dev/null +++ b/crates/ibc-framework/src/one_for_all/types/mod.rs @@ -0,0 +1 @@ +pub mod chain; diff --git a/crates/ibc-framework/src/std_prelude.rs b/crates/ibc-framework/src/std_prelude.rs new file mode 100644 index 000000000..bdce26208 --- /dev/null +++ b/crates/ibc-framework/src/std_prelude.rs @@ -0,0 +1,15 @@ +pub use core::prelude::v1::*; + +// Re-export according to alloc::prelude::v1 because it is not yet stabilized +// https://doc.rust-lang.org/src/alloc/prelude/v1.rs.html +pub use alloc::borrow::ToOwned; +pub use alloc::boxed::Box; +pub use alloc::string::{String, ToString}; +pub use alloc::vec::Vec; + +pub use alloc::format; +pub use alloc::vec; + +// Those are exported by default in the std prelude in Rust 2021 +pub use core::convert::{TryFrom, TryInto}; +pub use core::iter::FromIterator;