diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5ad00d20b9..1976c07649 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -42,7 +42,7 @@ jobs: command: fmt args: --all -- --check - clippy_check: + clippy_all_features: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -56,6 +56,20 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} args: --all-features --all-targets + clippy_no_default_features: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: clippy + override: true + - uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --no-default-features --all-targets + test-stable: runs-on: ubuntu-latest steps: diff --git a/Cargo.lock b/Cargo.lock index e3a030b14a..aa2baa2153 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + [[package]] name = "aho-corasick" version = "0.7.18" @@ -100,12 +106,24 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + [[package]] name = "arrayvec" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "ascii" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbf56136a5198c7b01a49e3afcbef6cf84597273d298f54432926024107b0109" + [[package]] name = "async-stream" version = "0.3.2" @@ -146,7 +164,7 @@ checksum = "e00550829ef8e2c4115250d0ee43305649b0fa95f78a32ce5b07da0b73d95c5c" dependencies = [ "futures-io", "futures-util", - "log", + "log 0.4.14", "pin-project-lite", "tokio", "tokio-rustls", @@ -165,6 +183,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + [[package]] name = "autocfg" version = "1.0.1" @@ -187,6 +211,15 @@ dependencies = [ "serde", ] +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +dependencies = [ + "byteorder", +] + [[package]] name = "base64" version = "0.13.0" @@ -256,6 +289,17 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2b_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -272,6 +316,36 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +[[package]] +name = "brotli-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "brotli2" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cb036c3eade309815c15ddbacec5b22c4d1f3983a774ab2eac2e3e9ea85568e" +dependencies = [ + "brotli-sys", + "libc", +] + +[[package]] +name = "buf_redux" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" +dependencies = [ + "memchr", + "safemem", +] + [[package]] name = "bumpalo" version = "3.7.0" @@ -328,6 +402,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "chunked_transfer" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" + [[package]] name = "clap" version = "3.0.0-beta.2" @@ -360,6 +440,15 @@ dependencies = [ "syn", ] +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + [[package]] name = "color-backtrace" version = "0.3.0" @@ -377,6 +466,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "279bc8fc53f788a75c7804af68237d1fce02cde1e275a886a4b320604dc2aeda" +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "contracts" version = "0.4.0" @@ -467,7 +562,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg", + "autocfg 1.0.1", "cfg-if 0.1.10", "lazy_static", ] @@ -559,6 +654,27 @@ dependencies = [ "syn", ] +[[package]] +name = "dashmap" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +dependencies = [ + "cfg-if 1.0.0", + "num_cpus", +] + +[[package]] +name = "deflate" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4" +dependencies = [ + "adler32", + "byteorder", + "gzip-header", +] + [[package]] name = "der" version = "0.3.5" @@ -590,6 +706,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "dirs" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" +dependencies = [ + "libc", + "redox_users 0.3.5", + "winapi", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -607,7 +734,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.0", "winapi", ] @@ -708,6 +835,18 @@ dependencies = [ "subtle", ] +[[package]] +name = "filetime" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.8", + "winapi", +] + [[package]] name = "fnv" version = "1.0.7" @@ -749,6 +888,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "funty" version = "1.1.0" @@ -809,7 +954,7 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" dependencies = [ - "autocfg", + "autocfg 1.0.1", "proc-macro-hack", "proc-macro2", "quote", @@ -834,7 +979,7 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" dependencies = [ - "autocfg", + "autocfg 1.0.1", "futures-channel", "futures-core", "futures-io", @@ -874,7 +1019,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" dependencies = [ "typenum", - "version_check", + "version_check 0.9.3", ] [[package]] @@ -956,6 +1101,15 @@ dependencies = [ "syn", ] +[[package]] +name = "gzip-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0131feb3d3bb2a5a238d8a4d09f6353b7ebfdc52e77bccbf4ea6eaa751dde639" +dependencies = [ + "crc32fast", +] + [[package]] name = "h2" version = "0.3.3" @@ -1003,12 +1157,12 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0b7591fb62902706ae8e7aaff416b1b0fa2c0fd0878b46dc13baa3712d8a855" dependencies = [ - "base64", + "base64 0.13.0", "bitflags", "bytes", "headers-core", "http", - "mime", + "mime 0.3.16", "sha-1", "time", ] @@ -1167,7 +1321,7 @@ dependencies = [ "ct-logs", "futures-util", "hyper", - "log", + "log 0.4.14", "rustls", "rustls-native-certs", "tokio", @@ -1248,6 +1402,7 @@ dependencies = [ "humantime-serde", "ibc", "ibc-proto", + "ibc-telemetry", "itertools 0.10.0", "k256", "prost", @@ -1289,6 +1444,7 @@ dependencies = [ "ibc", "ibc-proto", "ibc-relayer", + "ibc-telemetry", "itertools 0.10.0", "once_cell", "prost", @@ -1309,6 +1465,19 @@ dependencies = [ "tracing-subscriber 0.2.18", ] +[[package]] +name = "ibc-telemetry" +version = "0.1.0" +dependencies = [ + "crossbeam-channel 0.5.1", + "ibc", + "once_cell", + "opentelemetry", + "opentelemetry-prometheus", + "prometheus", + "rouille", +] + [[package]] name = "ics23" version = "0.6.5" @@ -1347,7 +1516,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" dependencies = [ - "autocfg", + "autocfg 1.0.1", "hashbrown", ] @@ -1454,6 +1623,15 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "log" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" +dependencies = [ + "log 0.4.14", +] + [[package]] name = "log" version = "0.4.14" @@ -1496,7 +1674,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" dependencies = [ - "autocfg", + "autocfg 1.0.1", +] + +[[package]] +name = "mime" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" +dependencies = [ + "log 0.3.9", ] [[package]] @@ -1505,6 +1692,18 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "mime_guess" +version = "1.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216929a5ee4dd316b1702eedf5e74548c123d370f47841ceaac38ca154690ca3" +dependencies = [ + "mime 0.2.6", + "phf", + "phf_codegen", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.4.4" @@ -1512,7 +1711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ "adler", - "autocfg", + "autocfg 1.0.1", ] [[package]] @@ -1522,7 +1721,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956" dependencies = [ "libc", - "log", + "log 0.4.14", "miow", "ntapi", "winapi", @@ -1551,6 +1750,24 @@ dependencies = [ "tracing-subscriber 0.2.18", ] +[[package]] +name = "multipart" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136eed74cadb9edd2651ffba732b19a450316b680e4f48d6c79e905799e19d01" +dependencies = [ + "buf_redux", + "httparse", + "log 0.4.14", + "mime 0.2.6", + "mime_guess", + "quick-error", + "rand 0.6.5", + "safemem", + "tempfile", + "twoway", +] + [[package]] name = "native-tls" version = "0.2.7" @@ -1559,7 +1776,7 @@ checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4" dependencies = [ "lazy_static", "libc", - "log", + "log 0.4.14", "openssl", "openssl-probe", "openssl-sys", @@ -1579,7 +1796,7 @@ dependencies = [ "funty", "lexical-core", "memchr", - "version_check", + "version_check 0.9.3", ] [[package]] @@ -1608,7 +1825,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg", + "autocfg 1.0.1", "num-traits", ] @@ -1618,7 +1835,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg", + "autocfg 1.0.1", ] [[package]] @@ -1678,13 +1895,43 @@ version = "0.9.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6b0d6fb7d80f877617dfcb014e605e2b5ab2fb0afdf27935219bb6bd984cb98" dependencies = [ - "autocfg", + "autocfg 1.0.1", "cc", "libc", "pkg-config", "vcpkg", ] +[[package]] +name = "opentelemetry" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "492848ff47f11b7f9de0443b404e2c5775f695e1af6b7076ca25f999581d547a" +dependencies = [ + "async-trait", + "crossbeam-channel 0.5.1", + "dashmap", + "fnv", + "futures", + "js-sys", + "lazy_static", + "percent-encoding", + "pin-project", + "rand 0.8.3", + "thiserror", +] + +[[package]] +name = "opentelemetry-prometheus" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f41760047df46012aaf2bb87fec0efed4d97f7a6af6825858c3b4d9438dadb94" +dependencies = [ + "opentelemetry", + "prometheus", + "protobuf", +] + [[package]] name = "os_str_bytes" version = "2.4.0" @@ -1720,7 +1967,7 @@ dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.8", "smallvec 1.6.1", "winapi", ] @@ -1740,6 +1987,45 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "phf" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" +dependencies = [ + "phf_shared", + "rand 0.6.5", +] + +[[package]] +name = "phf_shared" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" +dependencies = [ + "siphasher", + "unicase", +] + [[package]] name = "pin-project" version = "1.0.7" @@ -1804,7 +2090,7 @@ dependencies = [ "proc-macro2", "quote", "syn", - "version_check", + "version_check 0.9.3", ] [[package]] @@ -1815,7 +2101,7 @@ checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", - "version_check", + "version_check 0.9.3", ] [[package]] @@ -1839,6 +2125,21 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "prometheus" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5986aa8d62380092d2f50f8b1cdba9cb9b6731ffd4b25b51fd126b6c3e05b99c" +dependencies = [ + "cfg-if 1.0.0", + "fnv", + "lazy_static", + "memchr", + "parking_lot", + "protobuf", + "thiserror", +] + [[package]] name = "prost" version = "0.7.0" @@ -1872,6 +2173,18 @@ dependencies = [ "prost", ] +[[package]] +name = "protobuf" +version = "2.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45604fc7a88158e7d514d8e22e14ac746081e7a70d7690074dd0029ee37458d6" + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.9" @@ -1893,6 +2206,25 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc 0.1.0", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + [[package]] name = "rand" version = "0.7.3" @@ -1918,6 +2250,16 @@ dependencies = [ "rand_hc 0.3.0", ] +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -1938,6 +2280,21 @@ dependencies = [ "rand_core 0.6.2", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.5.1" @@ -1956,6 +2313,15 @@ dependencies = [ "getrandom 0.2.3", ] +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + [[package]] name = "rand_hc" version = "0.2.0" @@ -1974,6 +2340,74 @@ dependencies = [ "rand_core 0.6.2", ] +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + [[package]] name = "redox_syscall" version = "0.2.8" @@ -1983,6 +2417,17 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +dependencies = [ + "getrandom 0.1.16", + "redox_syscall 0.1.57", + "rust-argon2", +] + [[package]] name = "redox_users" version = "0.4.0" @@ -1990,7 +2435,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom 0.2.3", - "redox_syscall", + "redox_syscall 0.2.8", ] [[package]] @@ -2061,6 +2506,44 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "rouille" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cfaebc11a52b7415f07e69f18f8240a0ea5eedf0dcb888c5fb7b432e7b4729b" +dependencies = [ + "base64 0.10.1", + "brotli2", + "chrono", + "deflate", + "filetime", + "multipart", + "num_cpus", + "percent-encoding", + "rand 0.7.3", + "serde", + "serde_derive", + "serde_json", + "sha1", + "term", + "threadpool", + "time", + "tiny_http", + "url", +] + +[[package]] +name = "rust-argon2" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" +dependencies = [ + "base64 0.13.0", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils 0.8.5", +] + [[package]] name = "rustc-demangle" version = "0.1.19" @@ -2079,8 +2562,8 @@ version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ - "base64", - "log", + "base64 0.13.0", + "log 0.4.14", "ring", "sct", "webpki", @@ -2104,6 +2587,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + [[package]] name = "same-file" version = "1.0.6" @@ -2303,6 +2792,12 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "sha1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" + [[package]] name = "sha2" version = "0.9.5" @@ -2372,6 +2867,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc47a29ce97772ca5c927f75bac34866b16d64e07f330c3248e2d7226623901b" +[[package]] +name = "siphasher" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" + [[package]] name = "slab" version = "0.4.3" @@ -2390,7 +2891,7 @@ dependencies = [ "fs2", "fxhash", "libc", - "log", + "log 0.4.14", "parking_lot", ] @@ -2511,7 +3012,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "rand 0.8.3", - "redox_syscall", + "redox_syscall 0.2.8", "remove_dir_all", "winapi", ] @@ -2636,6 +3137,17 @@ dependencies = [ "tendermint", ] +[[package]] +name = "term" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" +dependencies = [ + "byteorder", + "dirs", + "winapi", +] + [[package]] name = "termcolor" version = "1.1.2" @@ -2683,6 +3195,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + [[package]] name = "time" version = "0.1.44" @@ -2712,6 +3233,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "tiny_http" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce51b50006056f590c9b7c3808c3bd70f0d1101666629713866c227d6e58d39" +dependencies = [ + "ascii", + "chrono", + "chunked_transfer", + "log 0.4.14", + "url", +] + [[package]] name = "tinyvec" version = "1.2.0" @@ -2733,7 +3267,7 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a38d31d7831c6ed7aad00aa4c12d9375fd225a6dd77da1d25b707346319a975" dependencies = [ - "autocfg", + "autocfg 1.0.1", "bytes", "libc", "memchr", @@ -2799,7 +3333,7 @@ dependencies = [ "bytes", "futures-core", "futures-sink", - "log", + "log 0.4.14", "pin-project-lite", "tokio", ] @@ -2821,7 +3355,7 @@ checksum = "2ac42cd97ac6bd2339af5bcabf105540e21e45636ec6fa6aae5e85d44db31be0" dependencies = [ "async-stream", "async-trait", - "base64", + "base64 0.13.0", "bytes", "futures-core", "futures-util", @@ -2881,7 +3415,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" dependencies = [ "cfg-if 1.0.0", - "log", + "log 0.4.14", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2924,7 +3458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" dependencies = [ "lazy_static", - "log", + "log 0.4.14", "tracing-core", ] @@ -2989,25 +3523,43 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24" dependencies = [ - "base64", + "base64 0.13.0", "byteorder", "bytes", "http", "httparse", "input_buffer", - "log", + "log 0.4.14", "rand 0.8.3", "sha-1", "url", "utf-8", ] +[[package]] +name = "twoway" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" +dependencies = [ + "memchr", +] + [[package]] name = "typenum" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +[[package]] +name = "unicase" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" +dependencies = [ + "version_check 0.1.5", +] + [[package]] name = "unicode-bidi" version = "0.3.5" @@ -3086,6 +3638,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" + [[package]] name = "version_check" version = "0.9.3" @@ -3118,7 +3676,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" dependencies = [ - "log", + "log 0.4.14", "try-lock", ] @@ -3152,7 +3710,7 @@ checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" dependencies = [ "bumpalo", "lazy_static", - "log", + "log 0.4.14", "proc-macro2", "quote", "syn", diff --git a/Cargo.toml b/Cargo.toml index b78f2a0226..82a431efe2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,8 @@ members = [ "modules", "relayer", "relayer-cli", - "proto" + "telemetry", + "proto", ] exclude = [ diff --git a/config.toml b/config.toml index b1c1078193..b8aa553f4d 100644 --- a/config.toml +++ b/config.toml @@ -5,6 +5,10 @@ strategy = 'packets' log_level = 'info' +[telemetry] +enabled = true +port = 3001 + [[chains]] id = 'ibc-0' rpc_addr = 'http://127.0.0.1:26657' diff --git a/modules/src/events.rs b/modules/src/events.rs index 3277469251..ee09d360cd 100644 --- a/modules/src/events.rs +++ b/modules/src/events.rs @@ -66,11 +66,11 @@ pub enum IbcEvent { } /// For use in debug messages -pub struct VecIbcEvents(pub Vec); -impl fmt::Display for VecIbcEvents { +pub struct PrettyEvents<'a>(pub &'a [IbcEvent]); +impl<'a> fmt::Display for PrettyEvents<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { writeln!(f, "events:")?; - for v in &self.0 { + for v in self.0 { writeln!(f, "\t{}", v)?; } Ok(()) diff --git a/relayer-cli/Cargo.toml b/relayer-cli/Cargo.toml index 6afb6ae701..1939873211 100644 --- a/relayer-cli/Cargo.toml +++ b/relayer-cli/Cargo.toml @@ -17,12 +17,15 @@ description = """ name = "hermes" [features] +default = ["telemetry"] profiling = ["ibc-relayer/profiling"] +telemetry = ["ibc-relayer/telemetry", "ibc-telemetry"] [dependencies] -ibc = { version = "0.3.2", path = "../modules" } -ibc-relayer = { version = "0.3.2", path = "../relayer" } -ibc-proto = { version = "0.8.0", path = "../proto" } +ibc = { version = "0.3.2", path = "../modules" } +ibc-relayer = { version = "0.3.2", path = "../relayer" } +ibc-proto = { version = "0.8.0", path = "../proto" } +ibc-telemetry = { version = "0.1.0", path = "../telemetry", optional = true } anomaly = "0.2.0" gumdrop = { version = "0.7", features = ["default_expr"] } diff --git a/relayer-cli/src/commands/start.rs b/relayer-cli/src/commands/start.rs index 8b2a0bdca8..8190b776d6 100644 --- a/relayer-cli/src/commands/start.rs +++ b/relayer-cli/src/commands/start.rs @@ -1,5 +1,6 @@ use abscissa_core::{Command, Options, Runnable}; +use ibc_relayer::config::Config; use ibc_relayer::supervisor::Supervisor; use crate::conclude::Output; @@ -11,10 +12,35 @@ pub struct StartCmd {} impl Runnable for StartCmd { fn run(&self) { let config = app_config(); - let supervisor = Supervisor::spawn(config.clone()).expect("failed to spawn supervisor"); + + let supervisor = spawn_supervisor(config.clone()); match supervisor.run() { Ok(()) => Output::success_msg("done").exit(), Err(e) => Output::error(e).exit(), } } } + +#[cfg(feature = "telemetry")] +fn spawn_supervisor(config: Config) -> Supervisor { + let state = ibc_telemetry::new_state(); + + if config.telemetry.enabled { + ibc_telemetry::spawn(config.telemetry.port, state.clone()); + } + + Supervisor::spawn(config, state) +} + +#[cfg(not(feature = "telemetry"))] +fn spawn_supervisor(config: Config) -> Supervisor { + if config.telemetry.enabled { + warn!( + "telemetry enabled in the config but Hermes was built without telemetry support, \ + build Hermes with --features=telemetry to enable telemetry support." + ); + } + + let telemetry = ibc_relayer::telemetry::TelemetryDisabled; + Supervisor::spawn(config, telemetry) +} diff --git a/relayer/Cargo.toml b/relayer/Cargo.toml index 778ebeb0d6..c8369c04c8 100644 --- a/relayer/Cargo.toml +++ b/relayer/Cargo.toml @@ -14,10 +14,12 @@ description = """ [features] profiling = [] +telemetry = ["ibc-telemetry"] [dependencies] -ibc = { version = "0.3.2", path = "../modules" } -ibc-proto = { version = "0.8.0", path = "../proto" } +ibc = { version = "0.3.2", path = "../modules" } +ibc-proto = { version = "0.8.0", path = "../proto" } +ibc-telemetry = { version = "0.1.0", path = "../telemetry", optional = true } subtle-encoding = "0.5" anomaly = "0.2.0" diff --git a/relayer/src/chain/handle.rs b/relayer/src/chain/handle.rs index 4e2be7c4ca..7dd282c9f9 100644 --- a/relayer/src/chain/handle.rs +++ b/relayer/src/chain/handle.rs @@ -1,39 +1,45 @@ -use std::fmt::Debug; -use std::sync::Arc; +use std::{ + fmt::{self, Debug}, + sync::Arc, +}; use crossbeam_channel as channel; use dyn_clone::DynClone; use serde::{Serialize, Serializer}; -use ibc::ics02_client::client_consensus::{AnyConsensusState, AnyConsensusStateWithHeight}; -use ibc::ics02_client::client_state::{AnyClientState, IdentifiedAnyClientState}; -use ibc::ics02_client::events::UpdateClient; -use ibc::ics02_client::misbehaviour::AnyMisbehaviour; -use ibc::ics04_channel::channel::IdentifiedChannelEnd; -use ibc::query::QueryTxRequest; use ibc::{ events::IbcEvent, - ics02_client::header::AnyHeader, + ics02_client::{ + client_consensus::{AnyConsensusState, AnyConsensusStateWithHeight}, + client_state::{AnyClientState, IdentifiedAnyClientState}, + events::UpdateClient, + header::AnyHeader, + misbehaviour::AnyMisbehaviour, + }, ics03_connection::{connection::ConnectionEnd, version::Version}, ics04_channel::{ - channel::ChannelEnd, + channel::{ChannelEnd, IdentifiedChannelEnd}, packet::{PacketMsgType, Sequence}, }, ics23_commitment::commitment::CommitmentPrefix, ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}, proofs::Proofs, + query::QueryTxRequest, signer::Signer, Height, }; -use ibc_proto::ibc::core::channel::v1::{ - PacketState, QueryChannelClientStateRequest, QueryChannelsRequest, - QueryConnectionChannelsRequest, QueryNextSequenceReceiveRequest, - QueryPacketAcknowledgementsRequest, QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, - QueryUnreceivedPacketsRequest, + +use ibc_proto::ibc::core::{ + channel::v1::{ + PacketState, QueryChannelClientStateRequest, QueryChannelsRequest, + QueryConnectionChannelsRequest, QueryNextSequenceReceiveRequest, + QueryPacketAcknowledgementsRequest, QueryPacketCommitmentsRequest, + QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest, + }, + client::v1::{QueryClientStatesRequest, QueryConsensusStatesRequest}, + commitment::v1::MerkleProof, + connection::v1::QueryClientConnectionsRequest, }; -use ibc_proto::ibc::core::client::v1::{QueryClientStatesRequest, QueryConsensusStatesRequest}; -use ibc_proto::ibc::core::commitment::v1::MerkleProof; -use ibc_proto::ibc::core::connection::v1::QueryClientConnectionsRequest; pub use prod::ProdChainHandle; @@ -63,6 +69,15 @@ impl ChainHandlePair { } } +impl Debug for ChainHandlePair { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ChainHandlePair") + .field("a", &self.a.id()) + .field("b", &self.b.id()) + .finish() + } +} + pub type Subscription = channel::Receiver>>; pub type ReplyTo = channel::Sender>; diff --git a/relayer/src/config.rs b/relayer/src/config.rs index b269ae252b..704a1b1248 100644 --- a/relayer/src/config.rs +++ b/relayer/src/config.rs @@ -39,6 +39,8 @@ pub mod default { #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct Config { pub global: GlobalConfig, + #[serde(default)] + pub telemetry: TelemetryConfig, #[serde(default = "Vec::new", skip_serializing_if = "Vec::is_empty")] pub chains: Vec, #[serde(skip_serializing_if = "Option::is_none")] @@ -102,6 +104,21 @@ impl Default for GlobalConfig { } } +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct TelemetryConfig { + pub enabled: bool, + pub port: u16, +} + +impl Default for TelemetryConfig { + fn default() -> Self { + Self { + enabled: false, + port: 3001, + } + } +} + #[derive(Clone, Debug, Deserialize, Serialize)] pub struct ChainConfig { pub id: ChainId, diff --git a/relayer/src/lib.rs b/relayer/src/lib.rs index 8a0f1d53e7..a6be011169 100644 --- a/relayer/src/lib.rs +++ b/relayer/src/lib.rs @@ -30,6 +30,7 @@ pub mod macros; pub mod object; pub mod registry; pub mod supervisor; +pub mod telemetry; pub mod transfer; pub mod upgrade_chain; pub mod util; diff --git a/relayer/src/link.rs b/relayer/src/link.rs index 9b164ac97e..685451c7c1 100644 --- a/relayer/src/link.rs +++ b/relayer/src/link.rs @@ -9,10 +9,9 @@ use prost_types::Any; use thiserror::Error; use tracing::{debug, error, info, trace, warn}; -use ibc::events::VecIbcEvents; use ibc::{ downcast, - events::{IbcEvent, IbcEventType}, + events::{IbcEvent, IbcEventType, PrettyEvents}, ics03_connection::connection::State as ConnectionState, ics04_channel::{ channel::{ChannelEnd, Order, QueryPacketEventDataRequest, State as ChannelState}, @@ -590,7 +589,7 @@ impl RelayPath { fn relay_from_operational_data( &mut self, initial_od: OperationalData, - ) -> Result, LinkError> { + ) -> Result { // We will operate on potentially different operational data if the initial one fails. let mut odata = initial_od; @@ -607,16 +606,17 @@ impl RelayPath { // Consume the operational data by attempting to send its messages match self.send_from_operational_data(odata.clone()) { - Ok(events) => { + Ok(summary) => { // Done with this op. data info!("[{}] success", self); - return Ok(events); + + return Ok(summary); } Err(LinkError::SendError(ev)) => { // This error means we can retry error!("[{}] error {}", self, ev); match self.regenerate_operational_data(odata.clone()) { - None => return Ok(vec![]), // Nothing to retry + None => return Ok(RelaySummary::empty()), // Nothing to retry Some(new_od) => odata = new_od, } } @@ -626,7 +626,8 @@ impl RelayPath { } } } - Ok(vec![]) + + Ok(RelaySummary::empty()) } /// Helper for managing retries of the `relay_from_operational_data` method. @@ -712,10 +713,10 @@ impl RelayPath { fn send_from_operational_data( &mut self, odata: OperationalData, - ) -> Result, LinkError> { + ) -> Result { if odata.batch.is_empty() { error!("[{}] ignoring empty operational data!", self); - return Ok(vec![]); + return Ok(RelaySummary::empty()); } let target = match odata.target { @@ -726,7 +727,7 @@ impl RelayPath { let msgs = odata.assemble_msgs(self)?; let tx_events = target.send_msgs(msgs)?; - info!("[{}] result {}\n", self, VecIbcEvents(tx_events.clone())); + info!("[{}] result {}\n", self, PrettyEvents(&tx_events)); let ev = tx_events .clone() @@ -735,7 +736,7 @@ impl RelayPath { match ev { Some(ev) => Err(LinkError::SendError(Box::new(ev))), - None => Ok(tx_events), + None => Ok(RelaySummary::from_events(tx_events)), } } @@ -822,11 +823,7 @@ impl RelayPath { ); let dst_tx_events = self.dst_chain().send_msgs(dst_update)?; - info!( - "[{}] result {}\n", - self, - VecIbcEvents(dst_tx_events.clone()) - ); + info!("[{}] result {}\n", self, PrettyEvents(&dst_tx_events)); dst_err_ev = dst_tx_events .into_iter() @@ -867,11 +864,7 @@ impl RelayPath { ); let src_tx_events = self.src_chain().send_msgs(src_update)?; - info!( - "[{}] result {}\n", - self, - VecIbcEvents(src_tx_events.clone()) - ); + info!("[{}] result {}\n", self, PrettyEvents(&src_tx_events)); src_err_ev = src_tx_events .into_iter() @@ -1280,17 +1273,20 @@ impl RelayPath { /// Checks if there are any operational data items ready, and if so performs the relaying /// of corresponding packets to the target chain. - pub fn execute_schedule(&mut self) -> Result<(), LinkError> { + pub fn execute_schedule(&mut self) -> Result { let (src_ods, dst_ods) = self.try_fetch_scheduled_operational_data(); + + let mut summary = RelaySummary::empty(); + for od in dst_ods { - self.relay_from_operational_data(od)?; + summary.extend(self.relay_from_operational_data(od)?); } for od in src_ods { - self.relay_from_operational_data(od)?; + summary.extend(self.relay_from_operational_data(od)?); } - Ok(()) + Ok(summary) } /// Refreshes the scheduled batches. @@ -1680,7 +1676,7 @@ impl Link { // Block waiting for all of the scheduled data (until `None` is returned) while let Some(odata) = self.a_to_b.fetch_scheduled_operational_data() { let mut last_res = self.a_to_b.relay_from_operational_data(odata)?; - results.append(&mut last_res); + results.append(&mut last_res.events); } Ok(results) @@ -1694,9 +1690,30 @@ impl Link { // Block waiting for all of the scheduled data while let Some(odata) = self.a_to_b.fetch_scheduled_operational_data() { let mut last_res = self.a_to_b.relay_from_operational_data(odata)?; - results.append(&mut last_res); + results.append(&mut last_res.events); } Ok(results) } } + +#[derive(Clone, Debug)] +pub struct RelaySummary { + pub events: Vec, + // errors: todo!(), + // timings: todo!(), +} + +impl RelaySummary { + pub fn empty() -> Self { + Self { events: vec![] } + } + + pub fn from_events(events: Vec) -> Self { + Self { events } + } + + pub fn extend(&mut self, other: RelaySummary) { + self.events.extend(other.events) + } +} diff --git a/relayer/src/supervisor.rs b/relayer/src/supervisor.rs index 29d4913940..28f4017db2 100644 --- a/relayer/src/supervisor.rs +++ b/relayer/src/supervisor.rs @@ -28,6 +28,7 @@ use crate::{ }, object::{Channel, Client, Object, UnidirectionalChannelPath}, registry::Registry, + telemetry::Telemetry, util::try_recv_multiple, worker::{WorkerMap, WorkerMsg}, }; @@ -43,20 +44,25 @@ pub struct Supervisor { registry: Registry, workers: WorkerMap, worker_msg_rx: Receiver, + + #[allow(dead_code)] + telemetry: Telemetry, } impl Supervisor { /// Spawns a [`Supervisor`] which will listen for events on all the chains in the [`Config`]. - pub fn spawn(config: Config) -> Result { + pub fn spawn(config: Config, telemetry: Telemetry) -> Self { let registry = Registry::new(config.clone()); let (worker_msg_tx, worker_msg_rx) = crossbeam_channel::unbounded(); + let workers = WorkerMap::new(worker_msg_tx, telemetry.clone()); - Ok(Self { + Self { config, registry, - workers: WorkerMap::new(worker_msg_tx), + workers, worker_msg_rx, - }) + telemetry, + } } fn handshake_enabled(&self) -> bool { diff --git a/relayer/src/telemetry.rs b/relayer/src/telemetry.rs new file mode 100644 index 0000000000..fd64b665a0 --- /dev/null +++ b/relayer/src/telemetry.rs @@ -0,0 +1,34 @@ +// If the `telemetry` feature is enabled, re-export the `ibc-telemetry` state. +#[cfg(feature = "telemetry")] +pub type Telemetry = std::sync::Arc; + +// Otherwise, define and export a dummy type. +#[cfg(not(feature = "telemetry"))] +#[derive(Clone, Debug)] +pub struct TelemetryDisabled; + +#[cfg(not(feature = "telemetry"))] +pub type Telemetry = TelemetryDisabled; + +/// A macro to send metric updates via a telemetry handle, +/// only if the `telemetry` feature is enabled. +/// Otherwise, it compiles to a no-op. +/// +/// ## Note +/// Equivalent to `#[cfg(feature = "telemetry")]`, but +/// should be preferred over the latter. +/// +/// ## Example +/// +/// ```rust,ignore +/// telemetry!(self.telemetry.tx_count(1)); +/// ``` +#[macro_export] +macro_rules! telemetry { + ($e:expr) => { + #[cfg(feature = "telemetry")] + { + $e; + } + }; +} diff --git a/relayer/src/worker.rs b/relayer/src/worker.rs index a2ec1c95b0..c99cef81af 100644 --- a/relayer/src/worker.rs +++ b/relayer/src/worker.rs @@ -3,7 +3,7 @@ use std::fmt; use crossbeam_channel::Sender; use tracing::{debug, error, info}; -use crate::{chain::handle::ChainHandlePair, object::Object}; +use crate::{chain::handle::ChainHandlePair, object::Object, telemetry::Telemetry}; pub mod retry_strategy; @@ -49,6 +49,7 @@ impl Worker { chains: ChainHandlePair, object: Object, msg_tx: Sender, + telemetry: Telemetry, ) -> WorkerHandle { let (cmd_tx, cmd_rx) = crossbeam_channel::unbounded(); @@ -61,10 +62,14 @@ impl Worker { ); let worker = match object { - Object::Client(client) => Self::Client(ClientWorker::new(client, chains, cmd_rx)), - Object::Channel(channel) => Self::Channel(ChannelWorker::new(channel, chains, cmd_rx)), + Object::Client(client) => { + Self::Client(ClientWorker::new(client, chains, cmd_rx, telemetry)) + } + Object::Channel(channel) => { + Self::Channel(ChannelWorker::new(channel, chains, cmd_rx, telemetry)) + } Object::UnidirectionalChannelPath(path) => { - Self::UniChanPath(UniChanPathWorker::new(path, chains, cmd_rx)) + Self::UniChanPath(UniChanPathWorker::new(path, chains, cmd_rx, telemetry)) } }; diff --git a/relayer/src/worker/channel.rs b/relayer/src/worker/channel.rs index 3714845a53..78c6ee1f17 100644 --- a/relayer/src/worker/channel.rs +++ b/relayer/src/worker/channel.rs @@ -5,6 +5,7 @@ use crossbeam_channel::Receiver; use tracing::{debug, warn}; use crate::channel::Channel as RelayChannel; +use crate::telemetry::Telemetry; use crate::{ chain::handle::ChainHandlePair, object::Channel, util::retry::retry_with_index, worker::retry_strategy, @@ -16,14 +17,23 @@ pub struct ChannelWorker { channel: Channel, chains: ChainHandlePair, cmd_rx: Receiver, + + #[allow(dead_code)] + telemetry: Telemetry, } impl ChannelWorker { - pub fn new(channel: Channel, chains: ChainHandlePair, cmd_rx: Receiver) -> Self { + pub fn new( + channel: Channel, + chains: ChainHandlePair, + cmd_rx: Receiver, + telemetry: Telemetry, + ) -> Self { Self { channel, chains, cmd_rx, + telemetry, } } @@ -32,8 +42,6 @@ impl ChannelWorker { let a_chain = self.chains.a.clone(); let b_chain = self.chains.b.clone(); - let mut handshake_channel; - // Flag that indicates if the worker should actively resume handshake. // Set on start or when event based handshake fails. let mut resume_handshake = true; @@ -48,13 +56,15 @@ impl ChannelWorker { // process the last event, the one with highest "rank". let last_event = batch.events.last(); debug!("channel worker starts processing {:#?}", last_event); + match last_event { Some(event) => { - handshake_channel = RelayChannel::restore_from_event( + let mut handshake_channel = RelayChannel::restore_from_event( a_chain.clone(), b_chain.clone(), event.clone(), )?; + retry_with_index( retry_strategy::worker_default_strategy(), |index| handshake_channel.step_event(event.clone(), index), @@ -70,6 +80,7 @@ impl ChannelWorker { if !resume_handshake { continue; } + debug!( "channel worker starts processing block event at {:#?}", current_height diff --git a/relayer/src/worker/client.rs b/relayer/src/worker/client.rs index 7dd801d8e4..c9bdcef421 100644 --- a/relayer/src/worker/client.rs +++ b/relayer/src/worker/client.rs @@ -10,6 +10,8 @@ use crate::{ chain::handle::ChainHandlePair, foreign_client::{ForeignClient, ForeignClientError, MisbehaviourResults}, object::Client, + telemetry, + telemetry::Telemetry, }; use super::WorkerCmd; @@ -18,14 +20,23 @@ pub struct ClientWorker { client: Client, chains: ChainHandlePair, cmd_rx: Receiver, + + #[allow(dead_code)] + telemetry: Telemetry, } impl ClientWorker { - pub fn new(client: Client, chains: ChainHandlePair, cmd_rx: Receiver) -> Self { + pub fn new( + client: Client, + chains: ChainHandlePair, + cmd_rx: Receiver, + telemetry: Telemetry, + ) -> Self { Self { client, chains, cmd_rx, + telemetry, } } @@ -54,10 +65,22 @@ impl ClientWorker { thread::sleep(Duration::from_millis(600)); // Run client refresh, exit only if expired or frozen - if let Err(e @ ForeignClientError::ExpiredOrFrozen(..)) = client.refresh() { - error!("failed to refresh client '{}': {}", client, e); - continue; - } + match client.refresh() { + Ok(Some(_)) => { + telemetry! { + self.telemetry.ibc_client_update( + &self.client.dst_chain_id, + &self.client.dst_client_id, + 1 + ) + }; + } + Err(e @ ForeignClientError::ExpiredOrFrozen(..)) => { + error!("failed to refresh client '{}': {}", client, e); + continue; + } + _ => (), + }; if skip_misbehaviour { continue; @@ -72,7 +95,15 @@ impl ClientWorker { // Run misbehaviour. If evidence submitted the loop will exit in next // iteration with frozen client - self.detect_misbehaviour(&client, Some(update)); + if self.detect_misbehaviour(&client, Some(update)) { + telemetry! { + self.telemetry.ibc_client_misbehaviour( + &self.client.dst_chain_id, + &self.client.dst_client_id, + 1 + ) + }; + } } } } diff --git a/relayer/src/worker/map.rs b/relayer/src/worker/map.rs index d9ce4ac892..64538abac2 100644 --- a/relayer/src/worker/map.rs +++ b/relayer/src/worker/map.rs @@ -1,11 +1,14 @@ use std::collections::HashMap; use crossbeam_channel::Sender; + use ibc::ics24_host::identifier::ChainId; use crate::{ chain::handle::{ChainHandle, ChainHandlePair}, object::Object, + telemetry, + telemetry::Telemetry, }; use super::{Worker, WorkerHandle, WorkerMsg}; @@ -15,15 +18,17 @@ use super::{Worker, WorkerHandle, WorkerMsg}; pub struct WorkerMap { workers: HashMap, msg_tx: Sender, + telemetry: Telemetry, } impl WorkerMap { /// Create a new worker map, which will spawn workers with /// the given channel for sending messages back to the [`Supervisor`]. - pub fn new(msg_tx: Sender) -> Self { + pub fn new(msg_tx: Sender, telemetry: Telemetry) -> Self { Self { workers: HashMap::new(), msg_tx, + telemetry, } } @@ -36,6 +41,7 @@ impl WorkerMap { /// the map and wait for its thread to terminate. pub fn remove_stopped(&mut self, object: &Object) -> bool { if let Some(handle) = self.workers.remove(object) { + telemetry!(self.telemetry.worker(metric_type(object), -1)); let _ = handle.join(); true } else { @@ -72,9 +78,34 @@ impl WorkerMap { if self.workers.contains_key(&object) { &self.workers[&object] } else { - let handles = ChainHandlePair { a: src, b: dst }; - let worker = Worker::spawn(handles, object.clone(), self.msg_tx.clone()); + let worker = self.spawn_worker(src, dst, &object); self.workers.entry(object).or_insert(worker) } } + + fn spawn_worker( + &mut self, + src: Box, + dst: Box, + object: &Object, + ) -> WorkerHandle { + telemetry!(self.telemetry.worker(metric_type(object), 1)); + + Worker::spawn( + ChainHandlePair { a: src, b: dst }, + object.clone(), + self.msg_tx.clone(), + self.telemetry.clone(), + ) + } +} + +#[cfg(feature = "telemetry")] +fn metric_type(o: &Object) -> ibc_telemetry::state::WorkerType { + use ibc_telemetry::state::WorkerType::*; + match o { + Object::Client(_) => Client, + Object::Channel(_) => Channel, + Object::UnidirectionalChannelPath(_) => Packet, + } } diff --git a/relayer/src/worker/uni_chan_path.rs b/relayer/src/worker/uni_chan_path.rs index 6a5243edf2..2a8b8540cc 100644 --- a/relayer/src/worker/uni_chan_path.rs +++ b/relayer/src/worker/uni_chan_path.rs @@ -6,18 +6,22 @@ use tracing::{error, warn}; use crate::{ chain::handle::ChainHandlePair, - link::{Link, LinkParameters}, + link::{Link, LinkParameters, RelaySummary}, object::UnidirectionalChannelPath, + telemetry, + telemetry::Telemetry, util::retry::{retry_with_index, RetryResult}, worker::retry_strategy, }; use super::WorkerCmd; +#[derive(Debug)] pub struct UniChanPathWorker { path: UnidirectionalChannelPath, chains: ChainHandlePair, cmd_rx: Receiver, + telemetry: Telemetry, } impl UniChanPathWorker { @@ -25,24 +29,24 @@ impl UniChanPathWorker { path: UnidirectionalChannelPath, chains: ChainHandlePair, cmd_rx: Receiver, + telemetry: Telemetry, ) -> Self { Self { path, chains, cmd_rx, + telemetry, } } /// Run the event loop for events associated with a [`UnidirectionalChannelPath`]. pub fn run(self) -> Result<(), BoxError> { - let rx = self.cmd_rx; - let mut link = Link::new_from_opts( self.chains.a.clone(), self.chains.b.clone(), LinkParameters { - src_port_id: self.path.src_port_id, - src_channel_id: self.path.src_channel_id, + src_port_id: self.path.src_port_id.clone(), + src_channel_id: self.path.src_channel_id.clone(), }, )?; @@ -56,20 +60,26 @@ impl UniChanPathWorker { thread::sleep(Duration::from_millis(200)); let result = retry_with_index(retry_strategy::worker_default_strategy(), |index| { - Self::step(rx.try_recv().ok(), &mut link, index) + Self::step(self.cmd_rx.try_recv().ok(), &mut link, index) }); - if let Err(retries) = result { - return Err(format!( - "UnidirectionalChannelPath worker failed after {} retries", - retries - ) - .into()); + match result { + Ok(_summary) => { + telemetry!(self.packet_metrics(&_summary)); + } + + Err(retries) => { + return Err(format!( + "UnidirectionalChannelPath worker failed after {} retries", + retries + ) + .into()); + } } } } - fn step(cmd: Option, link: &mut Link, index: u64) -> RetryResult<(), u64> { + fn step(cmd: Option, link: &mut Link, index: u64) -> RetryResult { if let Some(cmd) = cmd { let result = match cmd { WorkerCmd::IbcEvents { batch } => { @@ -93,12 +103,13 @@ impl UniChanPathWorker { .refresh_schedule() .and_then(|_| link.a_to_b.execute_schedule()); - if let Err(e) = result { - error!("{}", e); - return RetryResult::Retry(index); + match result { + Ok(summary) => RetryResult::Ok(summary), + Err(e) => { + error!("{}", e); + RetryResult::Retry(index) + } } - - RetryResult::Ok(()) } /// Get a reference to the uni chan path worker's chains. @@ -110,4 +121,64 @@ impl UniChanPathWorker { pub fn object(&self) -> &UnidirectionalChannelPath { &self.path } + + #[cfg(feature = "telemetry")] + fn packet_metrics(&self, summary: &RelaySummary) { + self.receive_packet_metrics(&summary); + self.acknowledgment_metrics(&summary); + self.timeout_metrics(&summary); + } + + #[cfg(feature = "telemetry")] + fn receive_packet_metrics(&self, summary: &RelaySummary) { + use ibc::events::IbcEvent::WriteAcknowledgement; + + let count = summary + .events + .iter() + .filter(|e| matches!(e, WriteAcknowledgement(_))) + .count(); + + self.telemetry.ibc_receive_packets( + &self.path.src_chain_id, + &self.path.src_channel_id, + &self.path.src_port_id, + count as u64, + ) + } + + #[cfg(feature = "telemetry")] + fn acknowledgment_metrics(&self, summary: &RelaySummary) { + use ibc::events::IbcEvent::AcknowledgePacket; + + let count = summary + .events + .iter() + .filter(|e| matches!(e, AcknowledgePacket(_))) + .count(); + + self.telemetry.ibc_acknowledgment_packets( + &self.path.src_chain_id, + &self.path.src_channel_id, + &self.path.src_port_id, + count as u64, + ) + } + + #[cfg(feature = "telemetry")] + fn timeout_metrics(&self, summary: &RelaySummary) { + use ibc::events::IbcEvent::TimeoutPacket; + let count = summary + .events + .iter() + .filter(|e| matches!(e, TimeoutPacket(_))) + .count(); + + self.telemetry.ibc_timeout_packets( + &self.path.src_chain_id, + &self.path.src_channel_id, + &self.path.src_port_id, + count as u64, + ) + } } diff --git a/telemetry/Cargo.toml b/telemetry/Cargo.toml new file mode 100644 index 0000000000..a6992458c8 --- /dev/null +++ b/telemetry/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "ibc-telemetry" +version = "0.1.0" +authors = ["Informal Systems "] +edition = "2018" + +[dependencies] +ibc = { version = "0.3.2", path = "../modules" } + +crossbeam-channel = "0.5.1" +once_cell = "1.7.2" +opentelemetry = "0.14.0" +opentelemetry-prometheus = "0.7.0" +prometheus = "0.12.0" +rouille = "3.1.1" diff --git a/telemetry/src/lib.rs b/telemetry/src/lib.rs new file mode 100644 index 0000000000..446d566761 --- /dev/null +++ b/telemetry/src/lib.rs @@ -0,0 +1,14 @@ +pub mod server; +pub mod state; + +use std::{sync::Arc, thread::JoinHandle}; + +pub use crate::state::TelemetryState; + +pub fn new_state() -> Arc { + Arc::new(TelemetryState::default()) +} + +pub fn spawn(port: u16, state: Arc) -> JoinHandle<()> { + std::thread::spawn(move || server::run(state, port)) +} diff --git a/telemetry/src/server.rs b/telemetry/src/server.rs new file mode 100644 index 0000000000..a0fc153e9d --- /dev/null +++ b/telemetry/src/server.rs @@ -0,0 +1,41 @@ +use std::sync::Arc; + +use prometheus::{Encoder, TextEncoder}; +use rouille::Request; + +use crate::state::TelemetryState; + +enum Route { + Metrics, + Other, +} + +impl Route { + fn from_request(request: &Request) -> Route { + if request.url() == "/metrics" { + Route::Metrics + } else { + Route::Other + } + } +} + +pub fn run(telemetry_state: Arc, port: u16) { + rouille::start_server(("localhost", port), move |request| { + match Route::from_request(request) { + // The prometheus endpoint + Route::Metrics => { + let mut buffer = vec![]; + let encoder = TextEncoder::new(); + let metric_families = telemetry_state.gather(); + encoder.encode(&metric_families, &mut buffer).unwrap(); + + rouille::Response::from_data(encoder.format_type().to_string(), buffer) + } + + // Any other route + // Return an empty response with a 404 status code. + Route::Other => rouille::Response::empty_404(), + } + }) +} diff --git a/telemetry/src/state.rs b/telemetry/src/state.rs new file mode 100644 index 0000000000..b5d9471659 --- /dev/null +++ b/telemetry/src/state.rs @@ -0,0 +1,174 @@ +use std::fmt; + +use opentelemetry::{ + global, + metrics::{Counter, UpDownCounter}, + KeyValue, +}; +use opentelemetry_prometheus::PrometheusExporter; + +use ibc::ics24_host::identifier::{ChainId, ChannelId, ClientId, PortId}; +use prometheus::proto::MetricFamily; + +#[derive(Copy, Clone, Debug)] +pub enum WorkerType { + Client, + Channel, + Packet, +} + +impl fmt::Display for WorkerType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Client => write!(f, "client"), + Self::Channel => write!(f, "channel"), + Self::Packet => write!(f, "packet"), + } + } +} + +#[derive(Debug)] +pub struct TelemetryState { + exporter: PrometheusExporter, + + /// Number of workers per object + workers: UpDownCounter, + + /// Number of client updates per client + ibc_client_updates: Counter, + + /// Number of client misbehaviours per client + ibc_client_misbehaviours: Counter, + + /// Number of receive packets relayed, per channel + receive_packets: Counter, + + /// Number of acknowledgment packets relayed, per channel + acknowledgment_packets: Counter, + + /// Number of timeout packets relayed, per channel + timeout_packets: Counter, +} + +impl TelemetryState { + /// Gather the metrics for export + pub fn gather(&self) -> Vec { + self.exporter.registry().gather() + } + + /// Update the number of workers per object + pub fn worker(&self, worker_type: WorkerType, count: i64) { + let labels = &[KeyValue::new("type", worker_type.to_string())]; + self.workers.add(count, labels); + } + + /// Update the number of client updates per client + pub fn ibc_client_update(&self, chain: &ChainId, client: &ClientId, count: u64) { + let labels = &[ + KeyValue::new("chain", chain.to_string()), + KeyValue::new("client", client.to_string()), + ]; + + self.ibc_client_updates.add(count, labels); + } + + /// Number of client misbehaviours per client + pub fn ibc_client_misbehaviour(&self, chain: &ChainId, client: &ClientId, count: u64) { + let labels = &[ + KeyValue::new("chain", chain.to_string()), + KeyValue::new("client", client.to_string()), + ]; + + self.ibc_client_misbehaviours.add(count, labels); + } + + /// Number of receive packets relayed, per channel + pub fn ibc_receive_packets( + &self, + src_chain: &ChainId, + src_channel: &ChannelId, + src_port: &PortId, + count: u64, + ) { + let labels = &[ + KeyValue::new("src_chain", src_chain.to_string()), + KeyValue::new("src_channel", src_channel.to_string()), + KeyValue::new("src_port", src_port.to_string()), + ]; + + self.receive_packets.add(count, labels); + } + + pub fn ibc_acknowledgment_packets( + &self, + src_chain: &ChainId, + src_channel: &ChannelId, + src_port: &PortId, + count: u64, + ) { + let labels = &[ + KeyValue::new("src_chain", src_chain.to_string()), + KeyValue::new("src_channel", src_channel.to_string()), + KeyValue::new("src_port", src_port.to_string()), + ]; + + self.acknowledgment_packets.add(count, labels); + } + + pub fn ibc_timeout_packets( + &self, + src_chain: &ChainId, + src_channel: &ChannelId, + src_port: &PortId, + count: u64, + ) { + let labels = &[ + KeyValue::new("src_chain", src_chain.to_string()), + KeyValue::new("src_channel", src_channel.to_string()), + KeyValue::new("src_port", src_port.to_string()), + ]; + + self.timeout_packets.add(count, labels); + } +} + +impl Default for TelemetryState { + fn default() -> Self { + let exporter = opentelemetry_prometheus::exporter().init(); + let meter = global::meter("hermes"); + + Self { + exporter, + + workers: meter + .i64_up_down_counter("workers") + .with_description("Number of workers per object") + .init(), + + ibc_client_updates: meter + .u64_counter("ibc_client_updates") + .with_description("Number of client updates performed per client") + .init(), + + ibc_client_misbehaviours: meter + .u64_counter("ibc_client_misbehaviours") + .with_description("Number of misbehaviours detected per client") + .init(), + + receive_packets: meter + .u64_counter("ibc_receive_packets") + .with_description("Number of receive packets relayed per channel") + .init(), + + acknowledgment_packets: meter + .u64_counter("ibc_acknowledgment_packets") + .with_description("Number of acknowledgment packets relayed per channel") + .init(), + + timeout_packets: meter + .u64_counter("ibc_timeout_packets") + .with_description("Number of timeout packets relayed per channel") + .init(), + } + } +}