From 43c47dcc470e5142e4f9138c8278c44d5ba193eb Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Sun, 31 Oct 2021 18:59:14 -0700 Subject: [PATCH 001/115] Remove unused num256 references Only gravity_utils used its direct dependency on num256. This removes the unused num256 dependencies. Explicit uses of num256 are highly tied to clarity, so trying to replace them at the top level is not useful and we should just proceed to replace clarity and web30.. --- orchestrator/Cargo.lock | 5 ----- orchestrator/cosmos_gravity/Cargo.toml | 3 +-- orchestrator/ethereum_gravity/Cargo.toml | 1 - orchestrator/gravity_utils/Cargo.toml | 2 +- orchestrator/orchestrator/Cargo.toml | 1 - orchestrator/relayer/Cargo.toml | 1 - orchestrator/test_runner/Cargo.toml | 1 - 7 files changed, 2 insertions(+), 12 deletions(-) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index 205341bfe..f3c254953 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -994,7 +994,6 @@ dependencies = [ "gravity_proto", "gravity_utils", "log", - "num256", "prost", "prost-types", "rand 0.8.3", @@ -1296,7 +1295,6 @@ dependencies = [ "deep_space 2.4.7", "gravity_utils", "log", - "num256", "sha3", "web30", ] @@ -2380,7 +2378,6 @@ dependencies = [ "hyper", "lazy_static", "log", - "num256", "openssl", "openssl-probe", "prometheus", @@ -2932,7 +2929,6 @@ dependencies = [ "gravity_utils", "lazy_static", "log", - "num256", "openssl-probe", "serde", "serde_derive", @@ -3460,7 +3456,6 @@ dependencies = [ "gravity_utils", "lazy_static", "log", - "num256", "orchestrator", "rand 0.8.3", "serde", diff --git a/orchestrator/cosmos_gravity/Cargo.toml b/orchestrator/cosmos_gravity/Cargo.toml index d54b6c294..870a651e9 100644 --- a/orchestrator/cosmos_gravity/Cargo.toml +++ b/orchestrator/cosmos_gravity/Cargo.toml @@ -14,7 +14,6 @@ gravity_proto = {path = "../gravity_proto/"} deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} clarity = "0.4.11" serde = "1.0" -num256 = "0.3" log = "0.4" sha3 = "0.9" tokio = "1.4" @@ -28,4 +27,4 @@ bytes = "1" [dev-dependencies] env_logger = "0.8" rand = "0.8" -actix = "0.11" \ No newline at end of file +actix = "0.11" diff --git a/orchestrator/ethereum_gravity/Cargo.toml b/orchestrator/ethereum_gravity/Cargo.toml index e9fb8c03c..21ff24f38 100644 --- a/orchestrator/ethereum_gravity/Cargo.toml +++ b/orchestrator/ethereum_gravity/Cargo.toml @@ -12,6 +12,5 @@ gravity_utils = {path = "../gravity_utils"} deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} clarity = "0.4.11" web30 = "0.15.4" -num256 = "0.3" log = "0.4" sha3 = "0.9" diff --git a/orchestrator/gravity_utils/Cargo.toml b/orchestrator/gravity_utils/Cargo.toml index 37bcf6f0a..6479411e8 100644 --- a/orchestrator/gravity_utils/Cargo.toml +++ b/orchestrator/gravity_utils/Cargo.toml @@ -23,4 +23,4 @@ url = "2" sha3 = "0.9" [dev_dependencies] rand = "0.8" -actix = "0.11" \ No newline at end of file +actix = "0.11" diff --git a/orchestrator/orchestrator/Cargo.toml b/orchestrator/orchestrator/Cargo.toml index 2dcde9787..d91d114a2 100644 --- a/orchestrator/orchestrator/Cargo.toml +++ b/orchestrator/orchestrator/Cargo.toml @@ -27,7 +27,6 @@ serde = "1.0" actix-rt = "2.2" lazy_static = "1" web30 = "0.15" -num256 = "0.3" log = "0.4" env_logger = "0.8" serde_json = "1.0" diff --git a/orchestrator/relayer/Cargo.toml b/orchestrator/relayer/Cargo.toml index 53388d3a5..52ef37041 100644 --- a/orchestrator/relayer/Cargo.toml +++ b/orchestrator/relayer/Cargo.toml @@ -26,7 +26,6 @@ serde = "1.0" actix-rt = "2" lazy_static = "1" web30 = "0.15" -num256 = "0.3" log = "0.4" env_logger = "0.8" tokio = "1.4" diff --git a/orchestrator/test_runner/Cargo.toml b/orchestrator/test_runner/Cargo.toml index d2fd98715..dd41f1125 100644 --- a/orchestrator/test_runner/Cargo.toml +++ b/orchestrator/test_runner/Cargo.toml @@ -27,7 +27,6 @@ actix-rt = "2.2" lazy_static = "1" url = "2" web30 = "0.15.4" -num256 = "0.3" log = "0.4" env_logger = "0.8" tokio = "1.4.0" From 4bfc465950016cf62f0ad8fa4fe9801989f22ac1 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 1 Nov 2021 18:28:53 -0700 Subject: [PATCH 002/115] Add ethers to orchestrator --- orchestrator/Cargo.lock | 1459 +++++++++++++++++++++++--- orchestrator/orchestrator/Cargo.toml | 1 + 2 files changed, 1310 insertions(+), 150 deletions(-) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index f3c254953..4bc3dd0a1 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "abscissa_core" version = "0.6.0-beta.1" @@ -62,7 +72,7 @@ dependencies = [ "actix-rt 2.2.0", "actix_derive", "bitflags", - "bytes 1.0.1", + "bytes 1.1.0", "crossbeam-channel", "futures-core", "futures-sink", @@ -100,7 +110,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d5dbeb2d9e51344cb83ca7cc170f1217f9fe25bfc50160e6e200b5c31c1019a" dependencies = [ "bitflags", - "bytes 1.0.1", + "bytes 1.1.0", "futures-core", "futures-sink", "log", @@ -143,7 +153,7 @@ dependencies = [ "actix-threadpool", "actix-tls 2.0.0", "actix-utils 2.0.0", - "base64", + "base64 0.13.0", "bitflags", "brotli2", "bytes 0.5.6", @@ -167,7 +177,7 @@ dependencies = [ "log", "mime", "percent-encoding", - "pin-project 1.0.6", + "pin-project 1.0.8", "rand 0.7.3", "regex", "serde", @@ -190,9 +200,9 @@ dependencies = [ "actix-tls 3.0.0-beta.5", "actix-utils 3.0.0", "ahash", - "base64", + "base64 0.13.0", "bitflags", - "bytes 1.0.1", + "bytes 1.1.0", "bytestring", "derive_more", "encoding_rs", @@ -209,9 +219,9 @@ dependencies = [ "mime", "once_cell", "percent-encoding", - "pin-project 1.0.6", + "pin-project 1.0.8", "pin-project-lite 0.2.6", - "rand 0.8.3", + "rand 0.8.4", "regex", "serde", "sha-1", @@ -442,7 +452,7 @@ dependencies = [ "log", "mime", "openssl", - "pin-project 1.0.6", + "pin-project 1.0.8", "regex", "serde", "serde_json", @@ -490,13 +500,25 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if 1.0.0", + "cipher", + "cpufeatures", + "opaque-debug 0.3.0", +] + [[package]] name = "ahash" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f200cbb1e856866d9eade941cf3aa0c5d7dd36f74311c4273b494f4ef036957" dependencies = [ - "getrandom 0.2.2", + "getrandom 0.2.3", "once_cell", "version_check", ] @@ -546,6 +568,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + [[package]] name = "async-stream" version = "0.3.0" @@ -569,15 +597,26 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.49" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589652ce7ccb335d1e7ecb3be145425702b290dbcb7029bbeaae263fc1d87b48" +checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version 0.4.0", +] + [[package]] name = "atty" version = "0.2.14" @@ -589,6 +628,18 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "auto_impl" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cbf586c80ada5e5ccdecae80d3ef0854f224e2dd74435f8d87e6831b8d0a38" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -605,7 +656,7 @@ dependencies = [ "actix-http 2.2.0", "actix-rt 1.1.1", "actix-service 1.0.6", - "base64", + "base64 0.13.0", "bytes 0.5.6", "cfg-if 1.0.0", "derive_more", @@ -630,8 +681,8 @@ dependencies = [ "actix-http 3.0.0-beta.10", "actix-rt 2.2.0", "actix-service 2.0.0", - "base64", - "bytes 1.0.1", + "base64 0.13.0", + "bytes 1.1.0", "cfg-if 1.0.0", "derive_more", "futures-core", @@ -641,7 +692,7 @@ dependencies = [ "openssl", "percent-encoding", "pin-project-lite 0.2.6", - "rand 0.8.3", + "rand 0.8.4", "serde", "serde_json", "serde_urlencoded", @@ -654,12 +705,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24f143b3839608f1254ac928abeffea9d654d9732162dcb6f0dd92bc022672f1" dependencies = [ "async-trait", - "bytes 1.0.1", + "bytes 1.1.0", "futures-util", "http", "http-body", "hyper", - "pin-project 1.0.6", + "pin-project 1.0.8", "regex", "serde", "serde_json", @@ -690,6 +741,28 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" +[[package]] +name = "base58" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" + +[[package]] +name = "base58check" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee2fe4c9a0c84515f136aaae2466744a721af6d63339c18689d9e995d74d99b" +dependencies = [ + "base58", + "sha2 0.8.2", +] + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + [[package]] name = "base64" version = "0.13.0" @@ -714,6 +787,15 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c7f7096bc256f5e5cb960f60dfc4f4ef979ca65abe7fb9d5a4f77150d3783d4" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bip32" version = "0.2.2" @@ -725,7 +807,7 @@ dependencies = [ "hmac 0.11.0", "k256", "ripemd160", - "sha2", + "sha2 0.9.8", "subtle", "zeroize", ] @@ -736,14 +818,68 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitvec" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +dependencies = [ + "either", + "radium 0.3.0", +] + +[[package]] +name = "bitvec" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" +dependencies = [ + "funty", + "radium 0.6.2", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding 0.1.5", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + [[package]] name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding", - "generic-array", + "block-padding 0.2.1", + "generic-array 0.14.4", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", ] [[package]] @@ -778,7 +914,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" dependencies = [ - "sha2", + "sha2 0.9.8", ] [[package]] @@ -787,6 +923,18 @@ version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" +[[package]] +name = "byte-slice-cast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c751592b77c499e7bce34d99d67c2c11bdc0574e9a488ddade14150a4698" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + [[package]] name = "byteorder" version = "1.4.3" @@ -801,9 +949,12 @@ checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" [[package]] name = "bytes" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +dependencies = [ + "serde", +] [[package]] name = "bytestring" @@ -811,7 +962,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90706ba19e97b90786e19dc0d5e2abd80008d99d4c0c5d1ad0b5e72cec7c494d" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", +] + +[[package]] +name = "camino" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b" +dependencies = [ + "serde", ] [[package]] @@ -820,6 +980,28 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e9e01327e6c86e92ec72b1c798d4a94810f147209bbe3ffab6a86954937a6f" +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba2ae6de944143141f6155a473a6b02f66c7c3f9f47316f802f80204ebfe6e12" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.4", + "serde", + "serde_json", +] + [[package]] name = "cc" version = "1.0.67" @@ -855,6 +1037,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array 0.14.4", +] + [[package]] name = "clap" version = "3.0.0-beta.5" @@ -904,6 +1095,62 @@ dependencies = [ "sha3", ] +[[package]] +name = "coins-bip32" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01b669993c632e5fec4a297085ec57381f53e4646c123cb77a7ca754e005c921" +dependencies = [ + "bincode", + "bs58", + "coins-core", + "digest 0.9.0", + "hmac 0.11.0", + "k256", + "lazy_static", + "serde", + "sha2 0.9.8", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38426029442f91bd49973d6f59f28e3dbb14e633e3019ac4ec6bce402c44f81c" +dependencies = [ + "bitvec 0.17.4", + "coins-bip32", + "getrandom 0.2.3", + "hex", + "hmac 0.11.0", + "pbkdf2 0.8.0", + "rand 0.8.4", + "sha2 0.9.8", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257d975731955ee86fa7f348000c3fea09c262e84c70c11e994a85aa4f467a7" +dependencies = [ + "base58check", + "base64 0.12.3", + "bech32 0.7.3", + "blake2", + "digest 0.9.0", + "generic-array 0.14.4", + "hex", + "ripemd160", + "serde", + "serde_derive", + "sha2 0.9.8", + "sha3", + "thiserror", +] + [[package]] name = "color-eyre" version = "0.5.11" @@ -968,6 +1215,22 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" +[[package]] +name = "core-foundation" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + [[package]] name = "cosmos-sdk-proto" version = "0.6.3" @@ -985,7 +1248,7 @@ name = "cosmos_gravity" version = "0.1.0" dependencies = [ "actix", - "bytes 1.0.1", + "bytes 1.1.0", "clarity", "cosmos-sdk-proto", "deep_space 2.4.7", @@ -996,7 +1259,7 @@ dependencies = [ "log", "prost", "prost-types", - "rand 0.8.3", + "rand 0.8.4", "serde", "sha3", "tokio 1.5.0", @@ -1004,6 +1267,15 @@ dependencies = [ "web30", ] +[[package]] +name = "cpufeatures" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] + [[package]] name = "cpuid-bool" version = "0.1.2" @@ -1040,25 +1312,41 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-bigint" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" dependencies = [ - "generic-array", + "generic-array 0.14.4", "rand_core 0.6.2", "subtle", "zeroize", ] +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array 0.14.4", + "subtle", +] + [[package]] name = "crypto-mac" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" dependencies = [ - "generic-array", + "generic-array 0.14.4", "subtle", ] @@ -1068,10 +1356,19 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25fab6889090c8133f3deb8f73ba3c65a7f456f66436fc012a1b1e272b1e103e" dependencies = [ - "generic-array", + "generic-array 0.14.4", "subtle", ] +[[package]] +name = "ctr" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a232f92a03f37dd7d7dd2adc67166c77e9cd88de5b019b9a9eecfaeaf7bfd481" +dependencies = [ + "cipher", +] + [[package]] name = "darling" version = "0.13.0" @@ -1113,7 +1410,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afd044e670beb23ce6a2007d139ed3787b99c85b5ff3982b8fdfda66c3682e53" dependencies = [ - "base64", + "base64 0.13.0", "bech32 0.7.3", "hmac 0.10.1", "num-bigint 0.3.2", @@ -1126,7 +1423,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "sha2", + "sha2 0.9.8", "unicode-normalization", ] @@ -1135,9 +1432,9 @@ name = "deep_space" version = "2.4.7" source = "git+https://github.com/iqlusioninc/deep_space/?branch=master#c6b31f758a4d4542f1272815be130e0904e2854d" dependencies = [ - "base64", + "base64 0.13.0", "bech32 0.8.0", - "bytes 1.0.1", + "bytes 1.1.0", "cosmos-sdk-proto", "hmac 0.11.0", "log", @@ -1147,14 +1444,14 @@ dependencies = [ "pbkdf2 0.9.0", "prost", "prost-types", - "rand 0.8.3", + "rand 0.8.4", "ripemd160", "rust_decimal", "secp256k1 0.20.1", "serde", "serde_derive", "serde_json", - "sha2", + "sha2 0.9.8", "tendermint-proto", "tokio 1.5.0", "tonic", @@ -1182,13 +1479,22 @@ dependencies = [ "syn", ] +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + [[package]] name = "digest" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array", + "generic-array 0.14.4", ] [[package]] @@ -1235,7 +1541,7 @@ checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b" dependencies = [ "crypto-bigint", "ff", - "generic-array", + "generic-array 0.14.4", "group", "pkcs8", "rand_core 0.6.2", @@ -1287,6 +1593,71 @@ dependencies = [ "typeable", ] +[[package]] +name = "eth-keystore" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d47d900a7dea08593d398104f8288e37858b0ad714c8d08cd03fdb86563e6402" +dependencies = [ + "aes", + "ctr", + "digest 0.9.0", + "hex", + "hmac 0.11.0", + "pbkdf2 0.8.0", + "rand 0.8.4", + "scrypt", + "serde", + "serde_json", + "sha2 0.9.8", + "sha3", + "thiserror", + "uuid", +] + +[[package]] +name = "ethabi" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76ef192b63e8a44b3d08832acebbb984c3fba154b5c26f70037c860202a0d4b" +dependencies = [ + "anyhow", + "ethereum-types", + "hex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb684ac8fa8f6c5759f788862bb22ec6fe3cb392f6bfd08e3c64b603661e3f8" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05136f7057fe789f06e6d41d07b34e6f70d8c86e5693b60f97aaa6553553bdaf" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types", + "uint", +] + [[package]] name = "ethereum_gravity" version = "0.1.0" @@ -1299,6 +1670,182 @@ dependencies = [ "web30", ] +[[package]] +name = "ethers" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3329c24c9cece2606e76f6de9870754283c6f615b0dff2e16809e40ace8a0d" +dependencies = [ + "ethers-contract", + "ethers-core", + "ethers-middleware", + "ethers-providers", + "ethers-signers", +] + +[[package]] +name = "ethers-contract" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d25bee65967910fae113f5beb85c632b14152c2eea209e991605d2a8fbd8531" +dependencies = [ + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "hex", + "once_cell", + "pin-project 1.0.8", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ffd490c3590bb310daaeac902b745a14bfcc1c5cd5e02fc0f3707893d5cf997" +dependencies = [ + "Inflector", + "anyhow", + "cargo_metadata", + "cfg-if 1.0.0", + "ethers-core", + "getrandom 0.2.3", + "hex", + "once_cell", + "proc-macro2", + "quote", + "reqwest", + "serde", + "serde_json", + "syn", + "url", +] + +[[package]] +name = "ethers-contract-derive" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0aabf97b4bc98bc966e296998dfd91724b6d64ca463ec4e10c4cd3450e2289d" +dependencies = [ + "ethers-contract-abigen", + "ethers-core", + "hex", + "proc-macro2", + "quote", + "serde_json", + "syn", +] + +[[package]] +name = "ethers-core" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cf3fa1d6d46f4f0ff62b03d1e8062b80b6fde7138bcca03d6759dab22a9d8d6" +dependencies = [ + "arrayvec 0.7.2", + "bytes 1.1.0", + "convert_case", + "ecdsa", + "elliptic-curve", + "ethabi", + "futures-util", + "generic-array 0.14.4", + "glob", + "hex", + "k256", + "once_cell", + "proc-macro2", + "quote", + "rand 0.8.4", + "rlp", + "rlp-derive", + "semver 1.0.4", + "serde", + "serde_json", + "syn", + "thiserror", + "tiny-keccak", + "tokio 1.5.0", +] + +[[package]] +name = "ethers-middleware" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d24ec324ed07af7d21be7fc9de709566c93d701eec415eee4a34ac5b7ecdd39" +dependencies = [ + "async-trait", + "ethers-contract", + "ethers-core", + "ethers-providers", + "ethers-signers", + "futures-util", + "instant", + "reqwest", + "serde", + "serde-aux", + "serde_json", + "thiserror", + "tokio 1.5.0", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b36bbe42435a740f05f5ed8a136a347411c9961af210d5ef8aceec781a58728" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-core", + "futures-channel", + "futures-core", + "futures-timer", + "futures-util", + "hex", + "parking_lot", + "pin-project 1.0.8", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-timer", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b0b2520fc6290abc5ab20be1f294fc5ac558261f45bb7cd9261b45512a905ea" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "futures-executor", + "futures-util", + "hex", + "rand 0.8.4", + "sha2 0.9.8", + "thiserror", +] + [[package]] name = "eyre" version = "0.6.5" @@ -1309,6 +1856,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + [[package]] name = "ff" version = "0.10.1" @@ -1319,6 +1872,18 @@ dependencies = [ "subtle", ] +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "byteorder", + "rand 0.8.4", + "rustc-hex", + "static_assertions", +] + [[package]] name = "fixedbitset" version = "0.2.0" @@ -1396,6 +1961,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + [[package]] name = "futures" version = "0.3.14" @@ -1413,9 +1984,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.14" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25" +checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" dependencies = [ "futures-core", "futures-sink", @@ -1423,15 +1994,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.14" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815" +checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" [[package]] name = "futures-executor" -version = "0.3.14" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d" +checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" dependencies = [ "futures-core", "futures-task", @@ -1440,16 +2011,17 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.14" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04" +checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" [[package]] name = "futures-macro" -version = "0.3.14" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b" +checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" dependencies = [ + "autocfg", "proc-macro-hack", "proc-macro2", "quote", @@ -1458,22 +2030,29 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.14" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23" +checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" [[package]] name = "futures-task" -version = "0.3.14" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc" +checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.14" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025" +checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" dependencies = [ + "autocfg", "futures-channel", "futures-core", "futures-io", @@ -1497,6 +2076,15 @@ dependencies = [ "byteorder", ] +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + [[package]] name = "generic-array" version = "0.14.4" @@ -1520,13 +2108,15 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if 1.0.0", + "js-sys", "libc", "wasi 0.10.2+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1535,6 +2125,12 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + [[package]] name = "gorc" version = "0.2.23" @@ -1543,7 +2139,7 @@ dependencies = [ "abscissa_tokio", "actix-rt 2.2.0", "bip32", - "bytes 1.0.1", + "bytes 1.1.0", "clap", "clarity", "cosmos_gravity", @@ -1593,7 +2189,7 @@ dependencies = [ name = "gravity_proto" version = "0.1.0" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "cosmos-sdk-proto", "prost", "prost-types", @@ -1612,7 +2208,7 @@ dependencies = [ "log", "num-bigint 0.4.0", "num256", - "rand 0.8.3", + "rand 0.8.4", "serde", "serde_derive", "sha3", @@ -1659,7 +2255,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "825343c4eef0b63f541f8903f395dc5beb362a979b5799a84062527ef1e37726" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "fnv", "futures-core", "futures-sink", @@ -1696,6 +2292,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hkd32" version = "0.6.0" @@ -1706,7 +2308,7 @@ dependencies = [ "once_cell", "pbkdf2 0.8.0", "rand_core 0.6.2", - "sha2", + "sha2 0.9.8", "zeroize", ] @@ -1717,7 +2319,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" dependencies = [ "crypto-mac 0.10.0", - "digest", + "digest 0.9.0", ] [[package]] @@ -1727,7 +2329,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ "crypto-mac 0.11.0", - "digest", + "digest 0.9.0", ] [[package]] @@ -1747,7 +2349,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "fnv", "itoa", ] @@ -1758,7 +2360,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfb77c123b4e2f72a2069aeae0b4b4949cc7e966df277813fc16347e7549737" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "http", "pin-project-lite 0.2.6", ] @@ -1787,7 +2389,7 @@ version = "0.14.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b61cf2d1aebcf6e6352c97b81dc2244ca29194be1b276f5d8ad5c6330fffb11" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "futures-channel", "futures-core", "futures-util", @@ -1805,6 +2407,34 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" +dependencies = [ + "futures-util", + "hyper", + "log", + "rustls", + "tokio 1.5.0", + "tokio-rustls", + "webpki", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes 1.1.0", + "hyper", + "native-tls", + "tokio 1.5.0", + "tokio-native-tls", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1822,6 +2452,44 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "impl-codec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47ca4d2b6931707a55fce5cf66aff80e2178c8b63bbb4ecb5695cbc870ddf6f" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5dacb10c5b3bb92d46ba347505a9041e676bb20ad220101326bffb0c93031ee" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "indenter" version = "0.3.3" @@ -1840,11 +2508,14 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.9" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -1865,9 +2536,15 @@ dependencies = [ "socket2 0.3.19", "widestring", "winapi 0.3.9", - "winreg", + "winreg 0.6.2", ] +[[package]] +name = "ipnet" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" + [[package]] name = "itertools" version = "0.9.0" @@ -1892,6 +2569,15 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "k256" version = "0.9.6" @@ -1901,7 +2587,7 @@ dependencies = [ "cfg-if 1.0.0", "ecdsa", "elliptic-curve", - "sha2", + "sha2 0.9.8", "sha3", ] @@ -1941,9 +2627,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.93" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" +checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" [[package]] name = "linked-hash-map" @@ -2109,6 +2795,24 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +[[package]] +name = "native-tls" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "net2" version = "0.2.37" @@ -2307,9 +3011,15 @@ checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" [[package]] name = "once_cell" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "opaque-debug" @@ -2372,6 +3082,7 @@ dependencies = [ "docopt", "env_logger", "ethereum_gravity", + "ethers", "futures", "gravity_proto", "gravity_utils", @@ -2381,7 +3092,7 @@ dependencies = [ "openssl", "openssl-probe", "prometheus", - "rand 0.8.3", + "rand 0.8.4", "relayer", "serde", "serde_derive", @@ -2406,6 +3117,32 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2386b4ebe91c2f7f51082d4cefa145d030e33a1842a96b12e4885cc3c01f7a55" +[[package]] +name = "parity-scale-codec" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" +dependencies = [ + "arrayvec 0.7.2", + "bitvec 0.20.4", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "parking_lot" version = "0.11.1" @@ -2431,6 +3168,17 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "password-hash" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e0b28ace46c5a396546bcf443bf422b57049617433d8854227352a4a9b24e7" +dependencies = [ + "base64ct", + "rand_core 0.6.2", + "subtle", +] + [[package]] name = "password-hash" version = "0.3.2" @@ -2454,12 +3202,12 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3b8c0d71734018084da0c0354193a5edfb81b20d2d57a92c5b154aefc554a4a" dependencies = [ - "base64", + "base64 0.13.0", "crypto-mac 0.10.0", "hmac 0.10.1", "rand 0.7.3", "rand_core 0.5.1", - "sha2", + "sha2 0.9.8", "subtle", ] @@ -2469,7 +3217,11 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" dependencies = [ + "base64ct", "crypto-mac 0.11.0", + "hmac 0.11.0", + "password-hash 0.2.3", + "sha2 0.9.8", ] [[package]] @@ -2480,8 +3232,8 @@ checksum = "f05894bce6a1ba4be299d0c5f29563e08af2bc18bb7d48313113bed71e904739" dependencies = [ "crypto-mac 0.11.0", "hmac 0.11.0", - "password-hash", - "sha2", + "password-hash 0.3.2", + "sha2 0.9.8", ] [[package]] @@ -2503,10 +3255,20 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" name = "petgraph" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" dependencies = [ - "fixedbitset", - "indexmap", + "futures", + "rustc_version 0.4.0", ] [[package]] @@ -2520,11 +3282,11 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc174859768806e91ae575187ada95c91a29e96a98dc5d2cd9a1fed039501ba6" +checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" dependencies = [ - "pin-project-internal 1.0.6", + "pin-project-internal 1.0.8", ] [[package]] @@ -2540,9 +3302,9 @@ dependencies = [ [[package]] name = "pin-project-internal" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a490329918e856ed1b083f244e3bfe2d8c4f336407e4ea9e1a9f479ff09049e5" +checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" dependencies = [ "proc-macro2", "quote", @@ -2591,6 +3353,29 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +[[package]] +name = "primitive-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" +dependencies = [ + "thiserror", + "toml", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -2629,9 +3414,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.29" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ "unicode-xid", ] @@ -2657,7 +3442,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e6984d2f1a23009bd270b8bb56d0926810a3d483f59c987d77969e9d8e840b2" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "prost-derive", ] @@ -2667,7 +3452,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32d3ebd75ac2679c2af3a92246639f9fcc8a442ee420719cc4fe195b98dd5fa3" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "heck", "itertools", "log", @@ -2698,7 +3483,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b518d7cdd93dab1d1122cf07fa9a60771836c668dde9d9e2a139f957f0d9f1bb" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "prost", ] @@ -2736,6 +3521,18 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" + +[[package]] +name = "radium" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" + [[package]] name = "rand" version = "0.4.6" @@ -2764,9 +3561,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha 0.3.0", @@ -2824,7 +3621,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "getrandom 0.2.2", + "getrandom 0.2.3", ] [[package]] @@ -2906,7 +3703,7 @@ dependencies = [ "lazy_static", "log", "openssl-probe", - "rand 0.8.3", + "rand 0.8.4", "relayer", "serde", "serde_derive", @@ -2946,6 +3743,45 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "reqwest" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d2927ca2f685faf0fc620ac4834690d29e7abb153add10f5812eef20b5e280" +dependencies = [ + "base64 0.13.0", + "bytes 1.1.0", + "encoding_rs", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "hyper-rustls", + "hyper-tls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite 0.2.6", + "rustls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio 1.5.0", + "tokio-native-tls", + "tokio-rustls", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg 0.7.0", +] + [[package]] name = "resolv-conf" version = "0.7.0" @@ -2956,15 +3792,51 @@ dependencies = [ "quick-error", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi 0.3.9", +] + [[package]] name = "ripemd160" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" dependencies = [ - "block-buffer", - "digest", - "opaque-debug", + "block-buffer 0.9.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "rlp" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "999508abb0ae792aabed2460c45b89106d97fe4adac593bdaef433c2605847b5" +dependencies = [ + "bytes 1.1.0", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -2983,7 +3855,7 @@ version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc7f5b8840fb1f83869a3e1dfd06d93db79ea05311ac5b42b8337d3371caa4f1" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "num-traits", "serde", ] @@ -2994,6 +3866,12 @@ version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + [[package]] name = "rustc_version" version = "0.2.3" @@ -3003,12 +3881,43 @@ dependencies = [ "semver 0.9.0", ] +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.4", +] + +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64 0.13.0", + "log", + "ring", + "sct", + "webpki", +] + [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "salsa20" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecbd2eb639fd7cab5804a0837fe373cc2172d15437e804c054a9fb885cb923b0" +dependencies = [ + "cipher", +] + [[package]] name = "same-file" version = "1.0.6" @@ -3018,12 +3927,46 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi 0.3.9", +] + [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scrypt" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879588d8f90906e73302547e20fffefdd240eb3e0e744e142321f5d49dea0518" +dependencies = [ + "base64ct", + "hmac 0.11.0", + "password-hash 0.2.3", + "pbkdf2 0.8.0", + "salsa20", + "sha2 0.9.8", +] + +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "secp256k1" version = "0.19.0" @@ -3070,6 +4013,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23a2ac85147a3a11d77ecf1bc7166ec0b92febfa4461c37944e180f319ece467" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "0.9.0" @@ -3094,6 +4060,12 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "send_wrapper" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "930c0acf610d3fdb5e2ab6213019aaa04e227ebe9547b0649ba599b16d788bd7" + [[package]] name = "serde" version = "1.0.125" @@ -3103,6 +4075,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-aux" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907c320ef8f45ce134b28ca9567ec58ec0d51dcae4e1ffe7ee0cc15517243810" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "serde-rlp" version = "0.1.4" @@ -3164,11 +4146,11 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if 1.0.0", "cpuid-bool", - "digest", - "opaque-debug", + "digest 0.9.0", + "opaque-debug 0.3.0", ] [[package]] @@ -3179,15 +4161,27 @@ checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" [[package]] name = "sha2" -version = "0.9.3" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" +checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if 1.0.0", - "cpuid-bool", - "digest", - "opaque-debug", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", ] [[package]] @@ -3196,10 +4190,10 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" dependencies = [ - "block-buffer", - "digest", + "block-buffer 0.9.0", + "digest 0.9.0", "keccak", - "opaque-debug", + "opaque-debug 0.3.0", ] [[package]] @@ -3238,7 +4232,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" dependencies = [ - "digest", + "digest 0.9.0", "rand_core 0.6.2", ] @@ -3275,6 +4269,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spki" version = "0.4.1" @@ -3293,6 +4293,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stdweb" version = "0.4.20" @@ -3300,7 +4306,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" dependencies = [ "discard", - "rustc_version", + "rustc_version 0.2.3", "stdweb-derive", "stdweb-internal-macros", "stdweb-internal-runtime", @@ -3386,6 +4392,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempdir" version = "0.3.7" @@ -3404,7 +4416,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if 1.0.0", "libc", - "rand 0.8.3", + "rand 0.8.4", "redox_syscall", "remove_dir_all", "winapi 0.3.9", @@ -3417,7 +4429,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfd0371c6b0c7fc4f6b053b8a1bc868a2a47c49a1408c4cd6f595d9f3bd3c238" dependencies = [ "anomaly", - "bytes 1.0.1", + "bytes 1.1.0", "chrono", "num-derive", "num-traits", @@ -3457,7 +4469,7 @@ dependencies = [ "lazy_static", "log", "orchestrator", - "rand 0.8.3", + "rand 0.8.4", "serde", "serde_derive", "tokio 1.5.0", @@ -3477,18 +4489,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.24" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.24" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", "quote", @@ -3561,6 +4573,15 @@ dependencies = [ "syn", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.2.0" @@ -3603,7 +4624,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5" dependencies = [ "autocfg", - "bytes 1.0.1", + "bytes 1.1.0", "libc", "memchr", "mio 0.7.11", @@ -3627,6 +4648,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio 1.5.0", +] + [[package]] name = "tokio-openssl" version = "0.4.0" @@ -3645,8 +4676,19 @@ checksum = "ac1bec5c0a4aa71e3459802c7a12e8912c2091ce2151004f9ce95cc5d1c6124e" dependencies = [ "futures", "openssl", - "pin-project 1.0.6", + "pin-project 1.0.8", + "tokio 1.5.0", +] + +[[package]] +name = "tokio-rustls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +dependencies = [ + "rustls", "tokio 1.5.0", + "webpki", ] [[package]] @@ -3680,7 +4722,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "940a12c99365c31ea8dd9ba04ec1be183ffe4920102bb7122c2f515437601e8e" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "futures-core", "futures-sink", "log", @@ -3705,8 +4747,8 @@ checksum = "556dc31b450f45d18279cfc3d2519280273f460d5387e6b7b24503e65d206f8b" dependencies = [ "async-stream", "async-trait", - "base64", - "bytes 1.0.1", + "base64 0.13.0", + "bytes 1.1.0", "futures-core", "futures-util", "h2 0.3.3", @@ -3714,7 +4756,7 @@ dependencies = [ "http-body", "hyper", "percent-encoding", - "pin-project 1.0.6", + "pin-project 1.0.8", "prost", "prost-derive", "tokio 1.5.0", @@ -3747,8 +4789,8 @@ dependencies = [ "futures-core", "futures-util", "indexmap", - "pin-project 1.0.6", - "rand 0.8.3", + "pin-project 1.0.8", + "rand 0.8.4", "slab", "tokio 1.5.0", "tokio-stream", @@ -3764,12 +4806,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b56efe69aa0ad2b5da6b942e57ea9f6fe683b7a314d4ff48662e2c8838de1" dependencies = [ - "bytes 1.0.1", + "bytes 1.1.0", "futures-core", "futures-util", "http", "http-body", - "pin-project 1.0.6", + "pin-project 1.0.8", "tower-layer", "tower-service", ] @@ -3788,9 +4830,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.25" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" +checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ "cfg-if 1.0.0", "log", @@ -3801,9 +4843,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.15" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" +checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" dependencies = [ "proc-macro2", "quote", @@ -3812,9 +4854,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.17" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" dependencies = [ "lazy_static", ] @@ -3825,7 +4867,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" dependencies = [ - "pin-project 1.0.6", + "pin-project 1.0.8", "tracing", ] @@ -3921,6 +4963,18 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +[[package]] +name = "uint" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unicase" version = "2.6.0" @@ -3966,11 +5020,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "url" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", "idna", @@ -3978,6 +5038,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.3", + "serde", +] + [[package]] name = "vcpkg" version = "0.2.11" @@ -4034,9 +5104,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -4044,9 +5114,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" dependencies = [ "bumpalo", "lazy_static", @@ -4057,11 +5127,23 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4069,9 +5151,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.73" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ "proc-macro2", "quote", @@ -4082,9 +5164,34 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.73" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" + +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] name = "web30" @@ -4105,6 +5212,25 @@ dependencies = [ "tokio 1.5.0", ] +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +dependencies = [ + "webpki", +] + [[package]] name = "which" version = "4.1.0" @@ -4173,6 +5299,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "winreg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -4183,6 +5318,30 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "ws_stream_wasm" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47ca1ab42f5afed7fc332b22b6e932ca5414b209465412c8cdf0ad23bc0de645" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "pharos", + "rustc_version 0.4.0", + "send_wrapper", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" + [[package]] name = "zeroize" version = "1.4.2" diff --git a/orchestrator/orchestrator/Cargo.toml b/orchestrator/orchestrator/Cargo.toml index d91d114a2..7aa51cc17 100644 --- a/orchestrator/orchestrator/Cargo.toml +++ b/orchestrator/orchestrator/Cargo.toml @@ -20,6 +20,7 @@ gravity_utils = { path = "../gravity_utils" } gravity_proto = { path = "../gravity_proto" } deep_space={git="https://github.com/iqlusioninc/deep_space/", branch = "master" } +ethers = { version = "0.5.4", features=["abigen"] } serde_derive = "1.0" clarity = "0.4.11" docopt = "1" From 1c08b914d97c3c7b90d021480cfab46033151473 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 1 Nov 2021 22:03:52 -0700 Subject: [PATCH 003/115] Initial cargo fmt on orchestrator/orchestrator --- orchestrator/orchestrator/src/lib.rs | 2 +- orchestrator/orchestrator/src/metrics.rs | 1 - orchestrator/orchestrator/src/oracle_resync.rs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/orchestrator/orchestrator/src/lib.rs b/orchestrator/orchestrator/src/lib.rs index bd3d695aa..1c363fa52 100644 --- a/orchestrator/orchestrator/src/lib.rs +++ b/orchestrator/orchestrator/src/lib.rs @@ -6,4 +6,4 @@ pub mod oracle_resync; #[macro_use] extern crate log; -extern crate prometheus; \ No newline at end of file +extern crate prometheus; diff --git a/orchestrator/orchestrator/src/metrics.rs b/orchestrator/orchestrator/src/metrics.rs index af92919e4..4923a89ef 100644 --- a/orchestrator/orchestrator/src/metrics.rs +++ b/orchestrator/orchestrator/src/metrics.rs @@ -5,7 +5,6 @@ use hyper::Server; use lazy_static::lazy_static; use prometheus::*; - pub async fn metrics_main_loop(addr: &net::SocketAddr) { let get_metrics = || async { let mut buffer = Vec::new(); diff --git a/orchestrator/orchestrator/src/oracle_resync.rs b/orchestrator/orchestrator/src/oracle_resync.rs index 928a23204..124088db9 100644 --- a/orchestrator/orchestrator/src/oracle_resync.rs +++ b/orchestrator/orchestrator/src/oracle_resync.rs @@ -20,7 +20,7 @@ pub async fn get_last_checked_block( our_cosmos_address: CosmosAddress, gravity_contract_address: Address, web3: &Web3, - blocks_to_search:u128, + blocks_to_search: u128, ) -> Uint256 { let mut grpc_client = grpc_client; From 2243e52db3898761b002d217ee532dc55ac6584b Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 1 Nov 2021 23:47:35 -0700 Subject: [PATCH 004/115] Remove main.rs from orchestrator --- orchestrator/orchestrator/Cargo.toml | 4 - orchestrator/orchestrator/src/main.rs | 165 -------------------------- 2 files changed, 169 deletions(-) delete mode 100644 orchestrator/orchestrator/src/main.rs diff --git a/orchestrator/orchestrator/Cargo.toml b/orchestrator/orchestrator/Cargo.toml index 7aa51cc17..e9929278d 100644 --- a/orchestrator/orchestrator/Cargo.toml +++ b/orchestrator/orchestrator/Cargo.toml @@ -8,10 +8,6 @@ edition = "2018" name = "orchestrator" path = "src/lib.rs" -[[bin]] -name = "orchestrator" -path = "src/main.rs" - [dependencies] relayer = { path = "../relayer" } ethereum_gravity = { path = "../ethereum_gravity" } diff --git a/orchestrator/orchestrator/src/main.rs b/orchestrator/orchestrator/src/main.rs deleted file mode 100644 index 5d30f6b0c..000000000 --- a/orchestrator/orchestrator/src/main.rs +++ /dev/null @@ -1,165 +0,0 @@ -//! Orchestrator is a sort of specialized relayer for Althea-Gravity that runs on every validator. -//! Things this binary is responsible for -//! * Performing all the Ethereum signing required to submit updates and generate batches -//! * Progressing the validator set update generation process. -//! * Observing events on the Ethereum chain and submitting oracle messages for validator consensus -//! Things this binary needs -//! * Access to the validators signing Ethereum key -//! * Access to the validators Cosmos key -//! * Access to an Cosmos chain RPC server -//! * Access to an Ethereum chain RPC server - -#[macro_use] -extern crate serde_derive; -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate log; - -mod ethereum_event_watcher; -mod get_with_retry; -mod main_loop; -mod metrics; -mod oracle_resync; - -use crate::main_loop::orchestrator_main_loop; -use clarity::Address as EthAddress; -use clarity::PrivateKey as EthPrivateKey; -use deep_space::private_key::PrivateKey as CosmosPrivateKey; -use docopt::Docopt; -use env_logger::Env; -use gravity_utils::connection_prep::{ - check_delegate_addresses, check_for_eth, wait_for_cosmos_node_ready, -}; -use gravity_utils::connection_prep::{check_for_fee_denom, create_rpc_connections}; -use main_loop::{ETH_ORACLE_LOOP_SPEED, ETH_SIGNER_LOOP_SPEED}; -use relayer::main_loop::LOOP_SPEED as RELAYER_LOOP_SPEED; -use std::cmp::min; - -#[derive(Debug, Deserialize)] -struct Args { - flag_cosmos_phrase: String, - flag_ethereum_key: String, - flag_cosmos_grpc: String, - flag_address_prefix: String, - flag_ethereum_rpc: String, - flag_contract_address: String, - flag_fees: String, - flag_metrics_listen: String, -} - -lazy_static! { - pub static ref USAGE: String = format!( - "Usage: {} --cosmos-phrase= --ethereum-key= --cosmos-grpc= --address-prefix= --ethereum-rpc= --fees= --contract-address= --metrics-listen= - Options: - -h --help Show this screen. - --cosmos-phrase= The mnenmonic of the Cosmos account key of the validator - --ethereum-key= The Ethereum private key of the validator - --cosmos-grpc= The Cosmos gRPC url, usually the validator - --address-prefix= The prefix for addresses on this Cosmos chain - --ethereum-rpc= The Ethereum RPC url, should be a self hosted node - --fees= The Cosmos Denom in which to pay Cosmos chain fees - --contract-address= The Ethereum contract address for Gravity, this is temporary - --metrics-listen= The address metrics server listens on [default: 127.0.0.1:3000]. - About: - The Validator companion binary for Gravity. This must be run by all Gravity chain validators - and is a mix of a relayer + oracle + ethereum signing infrastructure - Written By: {} - Version {}", - env!("CARGO_PKG_NAME"), - env!("CARGO_PKG_AUTHORS"), - env!("CARGO_PKG_VERSION"), - ); -} - -#[actix_rt::main] -async fn main() { - env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); - // On Linux static builds we need to probe ssl certs path to be able to - // do TLS stuff. - openssl_probe::init_ssl_cert_env_vars(); - - let args: Args = Docopt::new(USAGE.as_str()) - .and_then(|d| d.deserialize()) - .unwrap_or_else(|e| e.exit()); - let cosmos_key = CosmosPrivateKey::from_phrase(&args.flag_cosmos_phrase, "") - .expect("Invalid Private Cosmos Key!"); - let ethereum_key: EthPrivateKey = args - .flag_ethereum_key - .parse() - .expect("Invalid Ethereum private key!"); - let contract_address: EthAddress = args - .flag_contract_address - .parse() - .expect("Invalid contract address!"); - let metrics_listen = args - .flag_metrics_listen - .parse() - .expect("Invalid metrics listen address!"); - - let fee_denom = args.flag_fees; - - let timeout = min( - min(ETH_SIGNER_LOOP_SPEED, ETH_ORACLE_LOOP_SPEED), - RELAYER_LOOP_SPEED, - ); - - trace!("Probing RPC connections"); - // probe all rpc connections and see if they are valid - let connections = create_rpc_connections( - args.flag_address_prefix, - Some(args.flag_cosmos_grpc), - Some(args.flag_ethereum_rpc), - timeout, - ) - .await; - - let mut grpc = connections.grpc.clone().unwrap(); - let contact = connections.contact.clone().unwrap(); - let web3 = connections.web3.clone().unwrap(); - - let public_eth_key = ethereum_key - .to_public_key() - .expect("Invalid Ethereum Private Key!"); - let public_cosmos_key = cosmos_key.to_address(&contact.get_prefix()).unwrap(); - info!("Starting Gravity Validator companion binary Relayer + Oracle + Eth Signer"); - info!( - "Ethereum Address: {} Cosmos Address {}", - public_eth_key, public_cosmos_key - ); - - // check if the cosmos node is syncing, if so wait for it - // we can't move any steps above this because they may fail on an incorrect - // historic chain state while syncing occurs - wait_for_cosmos_node_ready(&contact).await; - - // check if the delegate addresses are correctly configured - check_delegate_addresses( - &mut grpc, - public_eth_key, - public_cosmos_key, - &contact.get_prefix(), - ) - .await; - - // check if we actually have the promised balance of tokens to pay fees - check_for_fee_denom(&fee_denom, public_cosmos_key, &contact).await; - check_for_eth(public_eth_key, &web3).await; - - orchestrator_main_loop( - cosmos_key, - ethereum_key, - connections.web3.unwrap(), - connections.contact.unwrap(), - connections.grpc.unwrap(), - contract_address, - (1f64, fee_denom.to_owned()), - &metrics_listen, - 1f32, - 5000u128, - 1.0f64, - false, - 5, - ) - .await; -} From 759f0d3d4db65687db94f279779edaa33d0c3559 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 2 Nov 2021 20:20:38 -0700 Subject: [PATCH 005/115] Add ethers dependency to gorc --- orchestrator/Cargo.lock | 1 + orchestrator/gorc/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index 4bc3dd0a1..a8e5561b4 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -2146,6 +2146,7 @@ dependencies = [ "deep_space 2.4.7", "env_logger", "ethereum_gravity", + "ethers", "gravity_proto", "gravity_utils", "k256", diff --git a/orchestrator/gorc/Cargo.toml b/orchestrator/gorc/Cargo.toml index 7db2a256b..71919e9f7 100644 --- a/orchestrator/gorc/Cargo.toml +++ b/orchestrator/gorc/Cargo.toml @@ -19,6 +19,7 @@ orchestrator = { path = "../orchestrator" } relayer = { path = "../relayer" } deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} +ethers = { version = "0.5.4", features=["abigen"] } clarity = "0.4.12" actix-rt = "2.2" rpassword = "5" From 140ac48866a82672178f50a58d3daf56f364ead6 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 2 Nov 2021 20:49:39 -0700 Subject: [PATCH 006/115] Add ethers to other Cargo.toml that use clarity --- orchestrator/Cargo.lock | 5 +++++ orchestrator/cosmos_gravity/Cargo.toml | 1 + orchestrator/ethereum_gravity/Cargo.toml | 1 + orchestrator/gravity_utils/Cargo.toml | 1 + orchestrator/register_delegate_keys/Cargo.toml | 1 + orchestrator/relayer/Cargo.toml | 1 + 6 files changed, 10 insertions(+) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index a8e5561b4..268f2d641 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -1254,6 +1254,7 @@ dependencies = [ "deep_space 2.4.7", "env_logger", "ethereum_gravity", + "ethers", "gravity_proto", "gravity_utils", "log", @@ -1664,6 +1665,7 @@ version = "0.1.0" dependencies = [ "clarity", "deep_space 2.4.7", + "ethers", "gravity_utils", "log", "sha3", @@ -2205,6 +2207,7 @@ dependencies = [ "clarity", "cosmos-sdk-proto", "deep_space 2.4.7", + "ethers", "gravity_proto", "log", "num-bigint 0.4.0", @@ -3699,6 +3702,7 @@ dependencies = [ "docopt", "env_logger", "ethereum_gravity", + "ethers", "gravity_proto", "gravity_utils", "lazy_static", @@ -3723,6 +3727,7 @@ dependencies = [ "docopt", "env_logger", "ethereum_gravity", + "ethers", "gravity_proto", "gravity_utils", "lazy_static", diff --git a/orchestrator/cosmos_gravity/Cargo.toml b/orchestrator/cosmos_gravity/Cargo.toml index 870a651e9..f24a00a37 100644 --- a/orchestrator/cosmos_gravity/Cargo.toml +++ b/orchestrator/cosmos_gravity/Cargo.toml @@ -12,6 +12,7 @@ ethereum_gravity = {path = "../ethereum_gravity"} gravity_proto = {path = "../gravity_proto/"} deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} +ethers = { version = "0.5.4", features=["abigen"] } clarity = "0.4.11" serde = "1.0" log = "0.4" diff --git a/orchestrator/ethereum_gravity/Cargo.toml b/orchestrator/ethereum_gravity/Cargo.toml index 21ff24f38..633d1bad8 100644 --- a/orchestrator/ethereum_gravity/Cargo.toml +++ b/orchestrator/ethereum_gravity/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" gravity_utils = {path = "../gravity_utils"} deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} +ethers = { version = "0.5.4", features=["abigen"] } clarity = "0.4.11" web30 = "0.15.4" log = "0.4" diff --git a/orchestrator/gravity_utils/Cargo.toml b/orchestrator/gravity_utils/Cargo.toml index 6479411e8..2e5313aac 100644 --- a/orchestrator/gravity_utils/Cargo.toml +++ b/orchestrator/gravity_utils/Cargo.toml @@ -10,6 +10,7 @@ edition = "2018" gravity_proto = {path = "../gravity_proto/"} cosmos-sdk-proto = "0.6.3" deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} +ethers = { version = "0.5.4", features=["abigen"] } web30 = "0.15" clarity = "0.4.11" num256 = "0.3" diff --git a/orchestrator/register_delegate_keys/Cargo.toml b/orchestrator/register_delegate_keys/Cargo.toml index d7bdd0504..5cd4b4fe3 100644 --- a/orchestrator/register_delegate_keys/Cargo.toml +++ b/orchestrator/register_delegate_keys/Cargo.toml @@ -16,6 +16,7 @@ gravity_utils = {path = "../gravity_utils"} gravity_proto = {path = "../gravity_proto/"} deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} +ethers = { version = "0.5.4", features=["abigen"] } contact = "0.4" serde_derive = "1.0" clarity = "0.4.11" diff --git a/orchestrator/relayer/Cargo.toml b/orchestrator/relayer/Cargo.toml index 52ef37041..93c78bbed 100644 --- a/orchestrator/relayer/Cargo.toml +++ b/orchestrator/relayer/Cargo.toml @@ -19,6 +19,7 @@ gravity_utils = { path = "../gravity_utils" } gravity_proto = { path = "../gravity_proto" } deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} +ethers = { version = "0.5.4", features=["abigen"] } serde_derive = "1.0" clarity = "0.4.11" docopt = "1" From 2151a72d89d72d32b02d01883d21b2d0adf527f1 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 2 Nov 2021 22:20:14 -0700 Subject: [PATCH 007/115] WIP: replace clarity/web30 Since types just get passed down through so many functions, there isn't really a way to break the refactor into commits that compile cleanly. Will keep pushing progress into a broken WIP commit until the types are all statically satisfied. --- .../gorc/src/commands/orchestrator/start.rs | 16 +++--- orchestrator/gorc/src/config.rs | 5 ++ .../gravity_utils/src/connection_prep.rs | 51 +++++++++++-------- orchestrator/gravity_utils/src/error.rs | 11 ++-- .../src/types/ethereum_events.rs | 4 +- orchestrator/orchestrator/src/main_loop.rs | 26 +++++----- .../relayer/src/find_latest_valset.rs | 27 +++++----- orchestrator/relayer/src/main.rs | 21 ++++---- orchestrator/relayer/src/main_loop.rs | 13 +++-- 9 files changed, 95 insertions(+), 79 deletions(-) diff --git a/orchestrator/gorc/src/commands/orchestrator/start.rs b/orchestrator/gorc/src/commands/orchestrator/start.rs index ec1c659f7..4363f7310 100644 --- a/orchestrator/gorc/src/commands/orchestrator/start.rs +++ b/orchestrator/gorc/src/commands/orchestrator/start.rs @@ -1,6 +1,6 @@ use crate::{application::APP, prelude::*}; use abscissa_core::{Clap, Command, Runnable}; -use clarity::address::Address as EthAddress; +use ethers::{prelude::*, types::Address as EthAddress}; use gravity_utils::connection_prep::{ check_delegate_addresses, check_for_eth, check_for_fee_denom, create_rpc_connections, wait_for_cosmos_node_ready, @@ -9,7 +9,7 @@ use orchestrator::main_loop::{ orchestrator_main_loop, ETH_ORACLE_LOOP_SPEED, ETH_SIGNER_LOOP_SPEED, }; use relayer::main_loop::LOOP_SPEED as RELAYER_LOOP_SPEED; -use std::cmp::min; +use std::{cmp::min, sync::Arc}; /// Start the Orchestrator #[derive(Command, Debug, Clap)] @@ -34,8 +34,8 @@ impl Runnable for StartCommand { let cosmos_key = config.load_deep_space_key(self.cosmos_key.clone()); let cosmos_address = cosmos_key.to_address(&cosmos_prefix).unwrap(); - let ethereum_key = config.load_clarity_key(self.ethereum_key.clone()); - let ethereum_address = ethereum_key.to_public_key().unwrap(); + let ethereum_wallet = config.load_ethers_wallet(self.ethereum_key.clone()); + let ethereum_address = ethereum_wallet.address(); let contract_address: EthAddress = config .gravity @@ -61,7 +61,8 @@ impl Runnable for StartCommand { let mut grpc = connections.grpc.clone().unwrap(); let contact = connections.contact.clone().unwrap(); - let web3 = connections.web3.clone().unwrap(); + let eth_client = SignerMiddleware::new(connections.eth_provider.clone().unwrap(), ethereum_wallet.clone()); + let eth_client = Arc::new(eth_client); info!("Starting Relayer + Oracle + Ethereum Signer"); info!("Ethereum Address: {}", ethereum_address); @@ -83,15 +84,14 @@ impl Runnable for StartCommand { // check if we actually have the promised balance of tokens to pay fees check_for_fee_denom(&fees_denom, cosmos_address, &contact).await; - check_for_eth(ethereum_address, &web3).await; + check_for_eth(ethereum_address, ð_client.provider()).await; let gas_price = config.cosmos.gas_price.as_tuple(); orchestrator_main_loop( cosmos_key, - ethereum_key, - web3, contact, + eth_client, grpc, contract_address, gas_price, diff --git a/orchestrator/gorc/src/config.rs b/orchestrator/gorc/src/config.rs index ced60a387..b2775f088 100644 --- a/orchestrator/gorc/src/config.rs +++ b/orchestrator/gorc/src/config.rs @@ -1,3 +1,4 @@ +use ethers::signers::LocalWallet as EthWallet; use serde::{Deserialize, Serialize}; use signatory::FsKeyStore; use std::net::SocketAddr; @@ -27,6 +28,10 @@ impl GorcConfig { return clarity::PrivateKey::from_slice(&key).expect("Could not convert key"); } + pub fn load_ethers_wallet(&self, name: String) -> EthWallet { + EthWallet::from(self.load_secret_key(name)) + } + pub fn load_deep_space_key(&self, name: String) -> deep_space::private_key::PrivateKey { let key = self.load_secret_key(name).to_bytes(); let key = deep_space::utils::bytes_to_hex_str(&key); diff --git a/orchestrator/gravity_utils/src/connection_prep.rs b/orchestrator/gravity_utils/src/connection_prep.rs index ee624b5bb..0d7838e4d 100644 --- a/orchestrator/gravity_utils/src/connection_prep.rs +++ b/orchestrator/gravity_utils/src/connection_prep.rs @@ -2,22 +2,24 @@ //! It's a common problem to have conflicts between ipv4 and ipv6 localhost and this module is first and foremost supposed to resolve that problem //! by trying more than one thing to handle potentially misconfigured inputs. -use clarity::Address as EthAddress; use deep_space::client::ChainStatus; use deep_space::Address as CosmosAddress; use deep_space::Contact; +use ethers::prelude::*; +use ethers::providers::Provider as EthProvider; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_proto::gravity::DelegateKeysByEthereumSignerRequest; use gravity_proto::gravity::DelegateKeysByOrchestratorRequest; +use std::convert::TryFrom; use std::process::exit; use std::time::Duration; use tokio::time::sleep as delay_for; use tonic::transport::Channel; use url::Url; -use web30::client::Web3; pub struct Connections { - pub web3: Option, + pub eth_provider: Option>, pub grpc: Option>, pub contact: Option, } @@ -31,7 +33,7 @@ pub async fn create_rpc_connections( eth_rpc_url: Option, timeout: Duration, ) -> Connections { - let mut web3 = None; + let mut eth_provider = None; let mut grpc = None; let mut contact = None; if let Some(grpc_url) = grpc_url { @@ -114,11 +116,12 @@ pub async fn create_rpc_connections( .unwrap_or_else(|_| panic!("Invalid Ethereum RPC url {}", eth_rpc_url)); check_scheme(&url, ð_rpc_url); let eth_url = eth_rpc_url.trim_end_matches('/'); - let base_web30 = Web3::new(ð_url, timeout); - let try_base = base_web30.eth_block_number().await; + let base_eth_provider = EthProvider::::try_from(eth_url) + .unwrap_or_else(|_| panic!("Could not instantiate Ethereum HTTP provider: {}", eth_url)); + let try_base = base_eth_provider.get_block_number().await; match try_base { // it worked, lets go! - Ok(_) => web3 = Some(base_web30), + Ok(_) => eth_provider = Some(base_eth_provider), // did not work, now we check if it's localhost Err(e) => { warn!( @@ -131,19 +134,21 @@ pub async fn create_rpc_connections( let prefix = url.scheme(); let ipv6_url = format!("{}://::1:{}", prefix, port); let ipv4_url = format!("{}://127.0.0.1:{}", prefix, port); - let ipv6_web3 = Web3::new(&ipv6_url, timeout); - let ipv4_web3 = Web3::new(&ipv4_url, timeout); - let ipv6_test = ipv6_web3.eth_block_number().await; - let ipv4_test = ipv4_web3.eth_block_number().await; + let ipv6_eth_provider = EthProvider::::try_from(ipv6_url.as_str()) + .unwrap_or_else(|_| panic!("Could not instantiate Ethereum HTTP provider: {}", &ipv6_url)); + let ipv4_eth_provider = EthProvider::::try_from(ipv4_url.as_str()) + .unwrap_or_else(|_| panic!("Could not instantiate Ethereum HTTP provider: {}", &ipv4_url)); + let ipv6_test = ipv6_eth_provider.get_block_number().await; + let ipv4_test = ipv4_eth_provider.get_block_number().await; warn!("Trying fallback urls {} {}", ipv6_url, ipv4_url); match (ipv4_test, ipv6_test) { (Ok(_), Err(_)) => { info!("Url fallback succeeded, your Ethereum rpc url {} has been corrected to {}", eth_rpc_url, ipv4_url); - web3 = Some(ipv4_web3) + eth_provider = Some(ipv4_eth_provider) } (Err(_), Ok(_)) => { info!("Url fallback succeeded, your Ethereum rpc url {} has been corrected to {}", eth_rpc_url, ipv6_url); - web3 = Some(ipv6_web3) + eth_provider = Some(ipv6_eth_provider) }, (Ok(_), Ok(_)) => panic!("This should never happen? Why didn't things work the first time?"), (Err(_), Err(_)) => panic!("Could not connect to Ethereum rpc, are you sure it's running and on the specified port? {}", eth_rpc_url) @@ -155,10 +160,12 @@ pub async fn create_rpc_connections( // transparently upgrade to https if available, we can't transparently downgrade for obvious security reasons let https_on_80_url = format!("https://{}:80", body); let https_on_443_url = format!("https://{}:443", body); - let https_on_80_web3 = Web3::new(&https_on_80_url, timeout); - let https_on_443_web3 = Web3::new(&https_on_443_url, timeout); - let https_on_80_test = https_on_80_web3.eth_block_number().await; - let https_on_443_test = https_on_443_web3.eth_block_number().await; + let https_on_80_eth_provider = EthProvider::::try_from(https_on_80_url.as_str()) + .unwrap_or_else(|_| panic!("Could not instantiate Ethereum HTTP provider: {}", &https_on_80_url)); + let https_on_443_eth_provider = EthProvider::::try_from(https_on_443_url.as_str()) + .unwrap_or_else(|_| panic!("Could not instantiate Ethereum HTTP provider: {}", &https_on_443_url)); + let https_on_80_test = https_on_80_eth_provider.get_block_number().await; + let https_on_443_test = https_on_443_eth_provider.get_block_number().await; warn!( "Trying fallback urls {} {}", https_on_443_url, https_on_80_url @@ -166,11 +173,11 @@ pub async fn create_rpc_connections( match (https_on_80_test, https_on_443_test) { (Ok(_), Err(_)) => { info!("Https upgrade succeeded, your Ethereum rpc url {} has been corrected to {}", eth_rpc_url, https_on_80_url); - web3 = Some(https_on_80_web3) + eth_provider = Some(https_on_80_eth_provider) }, (Err(_), Ok(_)) => { info!("Https upgrade succeeded, your Ethereum rpc url {} has been corrected to {}", eth_rpc_url, https_on_443_url); - web3 = Some(https_on_443_web3) + eth_provider = Some(https_on_443_eth_provider) }, (Ok(_), Ok(_)) => panic!("This should never happen? Why didn't things work the first time?"), (Err(_), Err(_)) => panic!("Could not connect to Ethereum rpc, are you sure it's running and on the specified port? {}", eth_rpc_url) @@ -183,7 +190,7 @@ pub async fn create_rpc_connections( } Connections { - web3, + eth_provider, grpc, contact, } @@ -319,8 +326,8 @@ pub async fn check_for_fee_denom(fee_denom: &str, address: CosmosAddress, contac } /// Checks the user has some Ethereum in their address to pay for things -pub async fn check_for_eth(address: EthAddress, web3: &Web3) { - let balance = web3.eth_get_balance(address).await.unwrap(); +pub async fn check_for_eth(address: EthAddress, eth_provider: &EthProvider) { + let balance = eth_provider.get_balance(address, None).await.unwrap(); if balance == 0u8.into() { warn!("You don't have any Ethereum! You will need to send some to {} for this program to work. Dust will do for basic operations, more info about average relaying costs will be presented as the program runs", address); } diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index 64d82addc..a32708a00 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -4,11 +4,14 @@ use clarity::Error as ClarityError; use deep_space::error::AddressError as CosmosAddressError; use deep_space::error::CosmosGrpcError; +use ethers::prelude::*; +use ethers::prelude::signer::SignerMiddlewareError; use num_bigint::ParseBigIntError; use std::fmt::{self, Debug}; use tokio::time::error::Elapsed; use tonic::Status; -use web30::jsonrpc::error::Web3Error; + +pub type EthClientError = SignerMiddlewareError, LocalWallet>; #[derive(Debug)] #[allow(clippy::large_enum_variant)] @@ -16,7 +19,7 @@ pub enum GravityError { InvalidBigInt(ParseBigIntError), CosmosGrpcError(CosmosGrpcError), CosmosAddressError(CosmosAddressError), - EthereumRestError(Web3Error), + EthereumRestError(EthClientError), InvalidBridgeStateError(String), FailedToUpdateValset, EthereumContractError(String), @@ -80,8 +83,8 @@ impl From for GravityError { } } -impl From for GravityError { - fn from(error: Web3Error) -> Self { +impl From for GravityError { + fn from(error: EthClientError) -> Self { GravityError::EthereumRestError(error) } } diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index aece31c46..dfb12ddc1 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -6,12 +6,12 @@ use super::ValsetMember; use crate::error::GravityError; -use clarity::Address as EthAddress; use deep_space::utils::bytes_to_hex_str; use deep_space::Address as CosmosAddress; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; use num256::Uint256; use std::unimplemented; -use web30::types::Log; /// A parsed struct representing the Ethereum event fired by the Gravity contract /// when the validator set is updated. diff --git a/orchestrator/orchestrator/src/main_loop.rs b/orchestrator/orchestrator/src/main_loop.rs index 302098b90..5fcb45555 100644 --- a/orchestrator/orchestrator/src/main_loop.rs +++ b/orchestrator/orchestrator/src/main_loop.rs @@ -7,7 +7,7 @@ use crate::{ ethereum_event_watcher::check_for_events, metrics::metrics_main_loop, oracle_resync::get_last_checked_block, }; -use clarity::{address::Address as EthAddress, Uint256}; +use clarity::Uint256; use clarity::{utils::bytes_to_hex_str, PrivateKey as EthPrivateKey}; use cosmos_gravity::send::send_main_loop; use cosmos_gravity::{ @@ -22,9 +22,11 @@ use deep_space::error::CosmosGrpcError; use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::{Contact, Msg}; use ethereum_gravity::utils::get_gravity_id; +use ethers::{prelude::*, types::Address as EthAddress}; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use relayer::main_loop::relayer_main_loop; use std::convert::TryInto; +use std::sync::Arc; use std::{ net, time::{Duration, Instant}, @@ -34,6 +36,8 @@ use tokio::time::sleep as delay_for; use tonic::transport::Channel; use web30::client::Web3; +pub type EthClient = Arc, LocalWallet>>; + /// The execution speed governing all loops in this file /// which is to say all loops started by Orchestrator main /// loop except the relayer loop @@ -47,9 +51,8 @@ pub const ETH_ORACLE_LOOP_SPEED: Duration = Duration::from_secs(13); /// of all execution time sleeping this shouldn't be an issue at all. pub async fn orchestrator_main_loop( cosmos_key: CosmosPrivateKey, - ethereum_key: EthPrivateKey, - web3: Web3, contact: Contact, + eth_client: EthClient, grpc_client: GravityQueryClient, gravity_contract_address: EthAddress, gas_price: (f64, String), @@ -73,8 +76,8 @@ pub async fn orchestrator_main_loop( let b = eth_oracle_main_loop( cosmos_key, - web3.clone(), contact.clone(), + eth_client.clone(), grpc_client.clone(), gravity_contract_address, blocks_to_search, @@ -83,9 +86,8 @@ pub async fn orchestrator_main_loop( let c = eth_signer_main_loop( cosmos_key, - ethereum_key, - web3.clone(), contact.clone(), + eth_client.clone(), grpc_client.clone(), gravity_contract_address, tx.clone(), @@ -95,8 +97,7 @@ pub async fn orchestrator_main_loop( if !relayer_opt_out { let e = relayer_main_loop( - ethereum_key, - web3, + eth_client.clone(), grpc_client.clone(), gravity_contract_address, eth_gas_multiplier, @@ -113,8 +114,8 @@ const DELAY: Duration = Duration::from_secs(5); /// and ferried over to Cosmos where they will be used to issue tokens or process batches. pub async fn eth_oracle_main_loop( cosmos_key: CosmosPrivateKey, - web3: Web3, contact: Contact, + eth_client: EthClient, grpc_client: GravityQueryClient, gravity_contract_address: EthAddress, blocks_to_search: u128, @@ -218,9 +219,8 @@ pub async fn eth_oracle_main_loop( /// valid and signed off on. pub async fn eth_signer_main_loop( cosmos_key: CosmosPrivateKey, - ethereum_key: EthPrivateKey, - web3: Web3, contact: Contact, + eth_client: EthClient, grpc_client: GravityQueryClient, contract_address: EthAddress, msg_sender: tokio::sync::mpsc::Sender>, @@ -388,8 +388,8 @@ pub async fn eth_signer_main_loop( } } -pub async fn check_for_eth(orchestrator_address: EthAddress, web3: Web3) { - let balance = web3.eth_get_balance(orchestrator_address).await.unwrap(); +pub async fn check_for_eth(orchestrator_address: EthAddress, eth_client: EthClient) { + let balance = eth_client.get_balance(orchestrator_address, None).await.unwrap(); if balance == 0u8.into() { warn!("You don't have any Ethereum! You will need to send some to {} for this program to work. Dust will do for basic operations, more info about average relaying costs will be presented as the program runs", orchestrator_address); } diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index 4a637cfb9..6d781c897 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -1,10 +1,11 @@ +use crate::main_loop::EthClient; use clarity::{Address, Uint256}; use ethereum_gravity::utils::downcast_uint256; +use ethers::prelude::*; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::types::ValsetUpdatedEvent; use gravity_utils::{error::GravityError, types::Valset}; use tonic::transport::Channel; -use web30::client::Web3; /// This function finds the latest valset on the Gravity contract by looking back through the event /// history and finding the most recent ValsetUpdatedEvent. Most of the time this will be very fast @@ -14,11 +15,11 @@ use web30::client::Web3; pub async fn find_latest_valset( grpc_client: &mut GravityQueryClient, gravity_contract_address: Address, - web3: &Web3, + eth_client: EthClient, ) -> Result { - const BLOCKS_TO_SEARCH: u128 = 5_000u128; - let latest_block = web3.eth_block_number().await?; - let mut current_block: Uint256 = latest_block.clone(); + const BLOCKS_TO_SEARCH: u64 = 5_000u64; + let latest_block = eth_client.get_block_number().await?; + let mut current_block = latest_block.clone(); while current_block.clone() > 0u8.into() { trace!( @@ -30,14 +31,14 @@ pub async fn find_latest_valset( } else { current_block.clone() - BLOCKS_TO_SEARCH.into() }; - let mut all_valset_events = web3 - .check_for_events( - end_search.clone(), - Some(current_block.clone()), - vec![gravity_contract_address], - vec!["ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"], - ) - .await?; + + let filter = Filter::new() + .select(end_block..current_block) + .address(gravity_contract_address) + .event("ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"); + + let mut all_valset_events = eth_client.get_logs(&filter).await?; + // by default the lowest found valset goes first, we want the highest. all_valset_events.reverse(); diff --git a/orchestrator/relayer/src/main.rs b/orchestrator/relayer/src/main.rs index f7ec3c4fe..a641a9ad2 100644 --- a/orchestrator/relayer/src/main.rs +++ b/orchestrator/relayer/src/main.rs @@ -1,9 +1,12 @@ +use std::sync::Arc; + use crate::main_loop::relayer_main_loop; use crate::main_loop::LOOP_SPEED; -use clarity::Address as EthAddress; -use clarity::PrivateKey as EthPrivateKey; use docopt::Docopt; use env_logger::Env; +use ethers::prelude::*; +use ethers::signers::LocalWallet as EthWallet; +use ethers::types::Address as EthAddress; use gravity_utils::connection_prep::{ check_for_eth, create_rpc_connections, wait_for_cosmos_node_ready, }; @@ -63,7 +66,7 @@ async fn main() { let args: Args = Docopt::new(USAGE.as_str()) .and_then(|d| d.deserialize()) .unwrap_or_else(|e| e.exit()); - let ethereum_key: EthPrivateKey = args + let ethereum_wallet: EthWallet = args .flag_ethereum_key .parse() .expect("Invalid Ethereum private key!"); @@ -79,25 +82,23 @@ async fn main() { LOOP_SPEED, ) .await; + let eth_client = SignerMiddleware::new(connections.eth_provider.clone().unwrap(), ethereum_wallet.clone()); + let eth_client = Arc::new(eth_client); - let public_eth_key = ethereum_key - .to_public_key() - .expect("Invalid Ethereum Private Key!"); + let public_eth_key = eth_client.address(); info!("Starting Gravity Relayer"); info!("Ethereum Address: {}", public_eth_key); let contact = connections.contact.clone().unwrap(); - let web3 = connections.web3.clone().unwrap(); // check if the cosmos node is syncing, if so wait for it // we can't move any steps above this because they may fail on an incorrect // historic chain state while syncing occurs wait_for_cosmos_node_ready(&contact).await; - check_for_eth(public_eth_key, &web3).await; + check_for_eth(public_eth_key, ð_client.provider()).await; relayer_main_loop( - ethereum_key, - connections.web3.unwrap(), + eth_client, connections.grpc.unwrap(), gravity_contract_address, 1f32, diff --git a/orchestrator/relayer/src/main_loop.rs b/orchestrator/relayer/src/main_loop.rs index 976ddd636..82499a5f6 100644 --- a/orchestrator/relayer/src/main_loop.rs +++ b/orchestrator/relayer/src/main_loop.rs @@ -2,22 +2,21 @@ use crate::{ batch_relaying::relay_batches, find_latest_valset::find_latest_valset, logic_call_relaying::relay_logic_calls, valset_relaying::relay_valsets, }; -use clarity::address::Address as EthAddress; -use clarity::PrivateKey as EthPrivateKey; use ethereum_gravity::utils::get_gravity_id; +use ethers::{prelude::*, types::Address as EthAddress}; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use std::time::{Duration, Instant}; +use std::{sync::Arc, time::{Duration, Instant}}; use tokio::time::sleep as delay_for; use tonic::transport::Channel; -use web30::client::Web3; + +pub type EthClient = Arc, LocalWallet>>; pub const LOOP_SPEED: Duration = Duration::from_secs(17); /// This function contains the orchestrator primary loop, it is broken out of the main loop so that /// it can be called in the test runner for easier orchestration of multi-node tests pub async fn relayer_main_loop( - ethereum_key: EthPrivateKey, - web3: Web3, + eth_client: EthClient, grpc_client: GravityQueryClient, gravity_contract_address: EthAddress, gas_multiplier: f32, @@ -26,7 +25,7 @@ pub async fn relayer_main_loop( loop { let loop_start = Instant::now(); - let our_ethereum_address = ethereum_key.to_public_key().unwrap(); + let our_ethereum_address = eth_client.address(); let current_eth_valset = find_latest_valset(&mut grpc_client, gravity_contract_address, &web3).await; if current_eth_valset.is_err() { From 61a08fd36caacfab6aae55214a7bab44d1a68a2e Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 3 Nov 2021 17:01:13 -0700 Subject: [PATCH 008/115] Move old orchestrator doc comment to lib.rs --- orchestrator/orchestrator/src/lib.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/orchestrator/orchestrator/src/lib.rs b/orchestrator/orchestrator/src/lib.rs index 1c363fa52..c5bb6ecf5 100644 --- a/orchestrator/orchestrator/src/lib.rs +++ b/orchestrator/orchestrator/src/lib.rs @@ -1,3 +1,14 @@ +//! Orchestrator is a sort of specialized relayer for the Gravity bridge that runs on every validator. +//! Things this library is responsible for +//! * Performing all the Ethereum signing required to submit updates and generate batches +//! * Progressing the validator set update generation process. +//! * Observing events on the Ethereum chain and submitting oracle messages for validator consensus +//! Things this library needs +//! * Access to the validators signing Ethereum key +//! * Access to the validators Cosmos key +//! * Access to an Cosmos chain RPC server +//! * Access to an Ethereum chain RPC server + pub mod ethereum_event_watcher; pub mod get_with_retry; pub mod main_loop; From aa320940e9a34110c47b149dd58207dbe13d1e33 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 3 Nov 2021 20:40:01 -0700 Subject: [PATCH 009/115] Make orchestrator main_loop.rs doc comment readable --- orchestrator/orchestrator/src/main_loop.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/orchestrator/orchestrator/src/main_loop.rs b/orchestrator/orchestrator/src/main_loop.rs index 5fcb45555..5cdd9a007 100644 --- a/orchestrator/orchestrator/src/main_loop.rs +++ b/orchestrator/orchestrator/src/main_loop.rs @@ -1,6 +1,7 @@ -//! This file contains the main loops for two distinct functions that just happen to reside int his same binary for ease of use. The Ethereum Signer and the Ethereum Oracle are both roles in Gravity -//! that can only be run by a validator. This single binary the 'Orchestrator' runs not only these two rules but also the untrusted role of a relayer, that does not need any permissions and has it's -//! own crate and binary so that anyone may run it. +//! This file contains the main loops for two distinct functions that just happen to reside in this same binary for ease of use. +//! The Ethereum Signer and the Ethereum Oracle are both roles in Gravity that can only be run by a validator. This single binary +//! the 'Orchestrator' runs not only these two roles but also the untrusted role of a relayer, that does not need any permissions +//! and has its own crate and binary so that anyone may run it. use crate::metrics; use crate::{ From 53aa2c2201cbf09220f7aa0cae4c154691340712 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 4 Nov 2021 18:41:04 -0700 Subject: [PATCH 010/115] WIP: rewrite find_latest_valset --- orchestrator/ethereum_gravity/src/utils.rs | 16 ----- .../src/types/ethereum_events.rs | 6 +- .../relayer/src/find_latest_valset.rs | 59 +++++++++---------- 3 files changed, 31 insertions(+), 50 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index ce2ce9a8a..03f6caa69 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -44,22 +44,6 @@ pub fn get_checkpoint_hash(valset: &Valset, gravity_id: &str) -> Result, Ok(locally_computed_digest.to_vec()) } -pub fn downcast_uint256(input: Uint256) -> Option { - if input >= U64MAX.into() { - None - } else { - let mut val = input.to_bytes_be(); - // pad to 8 bytes - while val.len() < 8 { - val.insert(0, 0); - } - let mut lower_bytes: [u8; 8] = [0; 8]; - // get the 'lowest' 8 bytes from a 256 bit integer - lower_bytes.copy_from_slice(&val[0..val.len()]); - Some(u64::from_be_bytes(lower_bytes)) - } -} - pub fn downcast_to_u128(input: Uint256) -> Option { if input >= U128MAX.into() { None diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index dfb12ddc1..1188da85b 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -17,9 +17,9 @@ use std::unimplemented; /// when the validator set is updated. #[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Hash)] pub struct ValsetUpdatedEvent { - pub valset_nonce: Uint256, - pub event_nonce: Uint256, - pub block_height: Uint256, + pub valset_nonce: U256, + pub event_nonce: U256, + pub block_height: U256, pub members: Vec, } diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index 6d781c897..5cd23f8c3 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -1,12 +1,14 @@ use crate::main_loop::EthClient; use clarity::{Address, Uint256}; -use ethereum_gravity::utils::downcast_uint256; use ethers::prelude::*; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::types::ValsetUpdatedEvent; use gravity_utils::{error::GravityError, types::Valset}; +use std::panic; use tonic::transport::Channel; +pub const VALSET_UPDATED_EVENT_STRING: str = "ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"; + /// This function finds the latest valset on the Gravity contract by looking back through the event /// history and finding the most recent ValsetUpdatedEvent. Most of the time this will be very fast /// as the latest update will be in recent blockchain history and the search moves from the present @@ -18,51 +20,46 @@ pub async fn find_latest_valset( eth_client: EthClient, ) -> Result { const BLOCKS_TO_SEARCH: u64 = 5_000u64; - let latest_block = eth_client.get_block_number().await?; - let mut current_block = latest_block.clone(); + const ZERO: u64 = 0u64; - while current_block.clone() > 0u8.into() { - trace!( - "About to submit a Valset or Batch looking back into the history to find the last Valset Update, on block {}", - current_block - ); - let end_search = if current_block.clone() < BLOCKS_TO_SEARCH.into() { - 0u8.into() - } else { - current_block.clone() - BLOCKS_TO_SEARCH.into() - }; + let mut filter = Filter::new() + .address(gravity_contract_address) + .event(&VALSET_UPDATED_EVENT_STRING); + let mut end_filter_block = eth_client.get_block_number().await?; + + while end_filter_block > ZERO { + trace!("About to submit a Valset or Batch, looking back into the history to find the last Valset Update, on block {}", end_filter_block); - let filter = Filter::new() - .select(end_block..current_block) - .address(gravity_contract_address) - .event("ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"); + let start_filter_block = end_filter_block.saturating_sub(BLOCKS_TO_SEARCH); + filter.select(start_filter_block..end_filter_block); - let mut all_valset_events = eth_client.get_logs(&filter).await?; + let logged_event = eth_client.get_logs(&filter).await?.last(); // we only need the most recent (last) one - // by default the lowest found valset goes first, we want the highest. - all_valset_events.reverse(); + if logged_event.is_some() { + trace!("Found event {:?}", logged_event); - trace!("Found events {:?}", all_valset_events); + match ValsetUpdatedEvent::from_log(logged_event.unwrap()) { + Ok(valset_updated_event) => { + let downcast_nonce = panic::catch_unwind(|| valset_updated_event.event_nonce.as_u64()); + if let Err(_) = downcast_nonce { + error!("ValsetUpdatedEvent contained nonce larger than u64: {:?}", valset_updated_event); + continue; + } - // we take only the first event if we find any at all. - if !all_valset_events.is_empty() { - let event = &all_valset_events[0]; - match ValsetUpdatedEvent::from_log(event) { - Ok(event) => { let latest_eth_valset = Valset { - nonce: downcast_uint256(event.valset_nonce.clone()).unwrap(), + nonce: downcast_nonce.unwrap(), members: event.members, }; let cosmos_chain_valset = cosmos_gravity::query::get_valset(grpc_client, latest_eth_valset.nonce) .await?; - check_if_valsets_differ(cosmos_chain_valset, &&latest_eth_valset); + check_if_valsets_differ(cosmos_chain_valset, &latest_eth_valset); return Ok(latest_eth_valset); } Err(e) => error!("Got valset event that we can't parse {}", e), } } - current_block = end_search; + end_filter_block = start_filter_block.saturating_sub(1); // filter ranges are inclusive, avoid searching same block } panic!("Could not find the last validator set for contract {}, probably not a valid Gravity contract!", gravity_contract_address) @@ -96,12 +93,12 @@ fn check_if_valsets_differ(cosmos_valset: Option, ethereum_valset: &Vals c_valset.sort(); e_valset.sort(); if c_valset == e_valset { - info!( + warn!( "Sorting disagreement between Cosmos and Ethereum on Valset nonce {}", ethereum_valset.nonce ); } else { - info!("Validator sets for nonce {} Cosmos and Ethereum differ. Possible bridge highjacking!", ethereum_valset.nonce) + error!("Validator sets for nonce {} Cosmos and Ethereum differ. Possible bridge highjacking!", ethereum_valset.nonce) } } } From f8995eb834547aa243a48588d5b19b40ae529f7a Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 4 Nov 2021 22:30:02 -0700 Subject: [PATCH 011/115] Use static strings for eth event prototypes --- .../gravity_utils/src/types/ethereum_events.rs | 6 ++++++ .../orchestrator/src/ethereum_event_watcher.rs | 12 +++++++----- orchestrator/orchestrator/src/oracle_resync.rs | 16 +++++++++------- orchestrator/relayer/src/find_latest_valset.rs | 7 +++---- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 1188da85b..7505bd44b 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -13,6 +13,12 @@ use ethers::types::Address as EthAddress; use num256::Uint256; use std::unimplemented; +pub const ERC20_DEPLOYED_EVENT_STR: &'static str = "ERC20DeployedEvent(string,address,string,string,uint8,uint256)"; +pub const LOGIC_CALL_EVENT_STR: &'static str = "LogicCallEvent(bytes32,uint256,bytes,uint256)"; +pub const SEND_TO_COSMOS_EVENT_STR: &'static str = "SendToCosmosEvent(address,address,bytes32,uint256,uint256)"; +pub const TRANSACTION_BATCH_EXECUTED_EVENT_STR: &'static str = "TransactionBatchExecutedEvent(uint256,address,uint256)"; +pub const VALSET_UPDATED_EVENT_STR: &'static str = "ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"; + /// A parsed struct representing the Ethereum event fired by the Gravity contract /// when the validator set is updated. #[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Hash)] diff --git a/orchestrator/orchestrator/src/ethereum_event_watcher.rs b/orchestrator/orchestrator/src/ethereum_event_watcher.rs index 571345dc6..33dc591dc 100644 --- a/orchestrator/orchestrator/src/ethereum_event_watcher.rs +++ b/orchestrator/orchestrator/src/ethereum_event_watcher.rs @@ -13,6 +13,8 @@ use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::{ error::GravityError, types::{ + ERC20_DEPLOYED_EVENT_STR, LOGIC_CALL_EVENT_STR, SEND_TO_COSMOS_EVENT_STR, + TRANSACTION_BATCH_EXECUTED_EVENT_STR, VALSET_UPDATED_EVENT_STR, Erc20DeployedEvent, LogicCallExecutedEvent, SendToCosmosEvent, TransactionBatchExecutedEvent, ValsetUpdatedEvent, }, @@ -44,7 +46,7 @@ pub async fn check_for_events( starting_block.clone(), Some(latest_block.clone()), vec![gravity_contract_address], - vec!["SendToCosmosEvent(address,address,bytes32,uint256,uint256)"], + vec![SEND_TO_COSMOS_EVENT_STR], ) .await; debug!("Deposit events detected {:?}", deposits); @@ -54,7 +56,7 @@ pub async fn check_for_events( starting_block.clone(), Some(latest_block.clone()), vec![gravity_contract_address], - vec!["TransactionBatchExecutedEvent(uint256,address,uint256)"], + vec![TRANSACTION_BATCH_EXECUTED_EVENT_STR], ) .await; debug!("Batche events detected {:?}", batches); @@ -64,7 +66,7 @@ pub async fn check_for_events( starting_block.clone(), Some(latest_block.clone()), vec![gravity_contract_address], - vec!["ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"], + vec![VALSET_UPDATED_EVENT_STR], ) .await; debug!("Valset events detected {:?}", valsets); @@ -74,7 +76,7 @@ pub async fn check_for_events( starting_block.clone(), Some(latest_block.clone()), vec![gravity_contract_address], - vec!["ERC20DeployedEvent(string,address,string,string,uint8,uint256)"], + vec![ERC20_DEPLOYED_EVENT_STR], ) .await; debug!("ERC20 events detected {:?}", erc20_deployed); @@ -84,7 +86,7 @@ pub async fn check_for_events( starting_block.clone(), Some(latest_block.clone()), vec![gravity_contract_address], - vec!["LogicCallEvent(bytes32,uint256,bytes,uint256)"], + vec![LOGIC_CALL_EVENT_STR], ) .await; debug!("Logic call events detected {:?}", logic_calls); diff --git a/orchestrator/orchestrator/src/oracle_resync.rs b/orchestrator/orchestrator/src/oracle_resync.rs index 124088db9..8bb366d1a 100644 --- a/orchestrator/orchestrator/src/oracle_resync.rs +++ b/orchestrator/orchestrator/src/oracle_resync.rs @@ -2,8 +2,10 @@ use clarity::{Address, Uint256}; use deep_space::address::Address as CosmosAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::types::{ - Erc20DeployedEvent, LogicCallExecutedEvent, SendToCosmosEvent, TransactionBatchExecutedEvent, - ValsetUpdatedEvent, + ERC20_DEPLOYED_EVENT_STR, LOGIC_CALL_EVENT_STR, SEND_TO_COSMOS_EVENT_STR, + TRANSACTION_BATCH_EXECUTED_EVENT_STR, VALSET_UPDATED_EVENT_STR, + Erc20DeployedEvent, LogicCallExecutedEvent, SendToCosmosEvent, + TransactionBatchExecutedEvent, ValsetUpdatedEvent, }; use tokio::time::sleep as delay_for; use tonic::transport::Channel; @@ -54,7 +56,7 @@ pub async fn get_last_checked_block( end_search.clone(), Some(current_block.clone()), vec![gravity_contract_address], - vec!["TransactionBatchExecutedEvent(uint256,address,uint256)"], + vec![TRANSACTION_BATCH_EXECUTED_EVENT_STR], ) .await; let send_to_cosmos_events = web3 @@ -62,7 +64,7 @@ pub async fn get_last_checked_block( end_search.clone(), Some(current_block.clone()), vec![gravity_contract_address], - vec!["SendToCosmosEvent(address,address,bytes32,uint256,uint256)"], + vec![SEND_TO_COSMOS_EVENT_STR], ) .await; let erc20_deployed_events = web3 @@ -70,7 +72,7 @@ pub async fn get_last_checked_block( end_search.clone(), Some(current_block.clone()), vec![gravity_contract_address], - vec!["ERC20DeployedEvent(string,address,string,string,uint8,uint256)"], + vec![ERC20_DEPLOYED_EVENT_STR], ) .await; let logic_call_executed_events = web3 @@ -78,7 +80,7 @@ pub async fn get_last_checked_block( end_search.clone(), Some(current_block.clone()), vec![gravity_contract_address], - vec!["LogicCallEvent(bytes32,uint256,bytes,uint256)"], + vec![LOGIC_CALL_EVENT_STR], ) .await; @@ -92,7 +94,7 @@ pub async fn get_last_checked_block( end_search.clone(), Some(current_block.clone()), vec![gravity_contract_address], - vec!["ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"], + vec![VALSET_UPDATED_EVENT_STR], ) .await; if batch_events.is_err() diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index 5cd23f8c3..93b38a84c 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -1,14 +1,13 @@ use crate::main_loop::EthClient; use clarity::{Address, Uint256}; +use ethereum_gravity::utils::downcast_to_u64; use ethers::prelude::*; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use gravity_utils::types::ValsetUpdatedEvent; +use gravity_utils::types::{VALSET_UPDATED_EVENT_STR, ValsetUpdatedEvent}; use gravity_utils::{error::GravityError, types::Valset}; use std::panic; use tonic::transport::Channel; -pub const VALSET_UPDATED_EVENT_STRING: str = "ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"; - /// This function finds the latest valset on the Gravity contract by looking back through the event /// history and finding the most recent ValsetUpdatedEvent. Most of the time this will be very fast /// as the latest update will be in recent blockchain history and the search moves from the present @@ -24,7 +23,7 @@ pub async fn find_latest_valset( let mut filter = Filter::new() .address(gravity_contract_address) - .event(&VALSET_UPDATED_EVENT_STRING); + .event(&VALSET_UPDATED_EVENT_STR); let mut end_filter_block = eth_client.get_block_number().await?; while end_filter_block > ZERO { From 9c42c2d256f1f989d5df0808be3ed340ea03e1af Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 4 Nov 2021 22:31:06 -0700 Subject: [PATCH 012/115] WIP: start migration of downcasting methodology --- orchestrator/ethereum_gravity/src/utils.rs | 56 +++++++------------ .../relayer/src/find_latest_valset.rs | 12 ++-- 2 files changed, 26 insertions(+), 42 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 03f6caa69..3610841c5 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -1,29 +1,13 @@ use clarity::abi::{Token, encode_call}; use clarity::Uint256; use clarity::{abi::encode_tokens, Address as EthAddress}; +use ethers::prelude::*; use gravity_utils::error::GravityError; use gravity_utils::types::*; use sha3::{Digest, Keccak256}; -use std::u128::MAX as U128MAX; -use std::u64::MAX as U64MAX; +use std::panic; use web30::{client::Web3, jsonrpc::error::Web3Error}; -// pub fn get_correct_sig_for_address( -// address: CosmosAddress, -// confirms: &[ValsetConfirmResponse], -// ) -> (Uint256, Uint256, Uint256) { -// for sig in confirms { -// if sig.eth_signer == address { -// return ( -// sig.eth_signature.v.clone(), -// sig.eth_signature.r.clone(), -// sig.eth_signature.s.clone(), -// ); -// } -// } -// panic!("Could not find that address!"); -// } - pub fn get_checkpoint_abi_encode( valset: &Valset, gravity_id: &str, @@ -44,19 +28,17 @@ pub fn get_checkpoint_hash(valset: &Valset, gravity_id: &str) -> Result, Ok(locally_computed_digest.to_vec()) } -pub fn downcast_to_u128(input: Uint256) -> Option { - if input >= U128MAX.into() { - None - } else { - let mut val = input.to_bytes_be(); - // pad to 8 bytes - while val.len() < 16 { - val.insert(0, 0); - } - let mut lower_bytes: [u8; 16] = [0; 16]; - // get the 'lowest' 16 bytes from a 256 bit integer - lower_bytes.copy_from_slice(&val[0..val.len()]); - Some(u128::from_be_bytes(lower_bytes)) +pub fn downcast_to_u64(input: U256) -> Option { + match panic::catch_unwind(|| input.as_u64()) { + Ok(downcasted) => Some(downcasted), + Err(_) => None, + } +} + +pub fn downcast_to_u128(input: U256) -> Option { + match panic::catch_unwind(|| input.as_u128()) { + Ok(downcasted) => Some(downcasted), + Err(_) => None, } } @@ -64,14 +46,14 @@ pub fn downcast_to_u128(input: Uint256) -> Option { fn test_downcast_nonce() { let mut i = 0u64; while i < 100_000 { - assert_eq!(i, downcast_uint256(i.into()).unwrap()); + assert_eq!(i, downcast_to_u64(i.into()).unwrap()); i += 1 } let mut i: u64 = std::u32::MAX.into(); i -= 100; let end = i + 100_000; while i < end { - assert_eq!(i, downcast_uint256(i.into()).unwrap()); + assert_eq!(i, downcast_to_u64(i.into()).unwrap()); i += 1 } } @@ -110,7 +92,7 @@ pub async fn get_valset_nonce( // worth of transactions. But we properly check and // handle that case here. let real_num = Uint256::from_bytes_be(&val); - Ok(downcast_uint256(real_num).expect("Valset nonce overflow! Bridge Halt!")) + Ok(downcast_to_u64(real_num).expect("Valset nonce overflow! Bridge Halt!")) } /// Gets the latest transaction batch nonce @@ -136,7 +118,7 @@ pub async fn get_tx_batch_nonce( // worth of transactions. But we properly check and // handle that case here. let real_num = Uint256::from_bytes_be(&val); - Ok(downcast_uint256(real_num).expect("TxBatch nonce overflow! Bridge Halt!")) + Ok(downcast_to_u64(real_num).expect("TxBatch nonce overflow! Bridge Halt!")) } /// Gets the latest transaction batch nonce @@ -166,7 +148,7 @@ pub async fn get_logic_call_nonce( // worth of transactions. But we properly check and // handle that case here. let real_num = Uint256::from_bytes_be(&val); - Ok(downcast_uint256(real_num).expect("LogicCall nonce overflow! Bridge Halt!")) + Ok(downcast_to_u64(real_num).expect("LogicCall nonce overflow! Bridge Halt!")) } /// Gets the latest transaction batch nonce @@ -191,7 +173,7 @@ pub async fn get_event_nonce( // worth of transactions. But we properly check and // handle that case here. let real_num = Uint256::from_bytes_be(&val); - Ok(downcast_uint256(real_num).expect("EventNonce nonce overflow! Bridge Halt!")) + Ok(downcast_to_u64(real_num).expect("EventNonce nonce overflow! Bridge Halt!")) } /// Gets the gravityID diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index 93b38a84c..aef564248 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -37,12 +37,13 @@ pub async fn find_latest_valset( if logged_event.is_some() { trace!("Found event {:?}", logged_event); - match ValsetUpdatedEvent::from_log(logged_event.unwrap()) { + let valset_updated_event = ValsetUpdatedEvent::from_log(logged_event.unwrap()); + if let Result() + { Ok(valset_updated_event) => { - let downcast_nonce = panic::catch_unwind(|| valset_updated_event.event_nonce.as_u64()); - if let Err(_) = downcast_nonce { - error!("ValsetUpdatedEvent contained nonce larger than u64: {:?}", valset_updated_event); - continue; + let downcast_nonce = downcast_to_u64(valset_updated_event.valset_nonce); + if downcast_nonce.is_none() { + error!("ValsetUpdatedEvent has nonce larger than u64: {:?}", valset_updated_event); } let latest_eth_valset = Valset { @@ -53,6 +54,7 @@ pub async fn find_latest_valset( cosmos_gravity::query::get_valset(grpc_client, latest_eth_valset.nonce) .await?; check_if_valsets_differ(cosmos_chain_valset, &latest_eth_valset); + return Ok(latest_eth_valset); } Err(e) => error!("Got valset event that we can't parse {}", e), From b93222d3fa911a42ec63285c5f221caa9ca26fa0 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 4 Nov 2021 22:48:23 -0700 Subject: [PATCH 013/115] WIP: fixing up valset update filter logic --- orchestrator/relayer/src/find_latest_valset.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index aef564248..d8e7851d1 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -32,18 +32,21 @@ pub async fn find_latest_valset( let start_filter_block = end_filter_block.saturating_sub(BLOCKS_TO_SEARCH); filter.select(start_filter_block..end_filter_block); - let logged_event = eth_client.get_logs(&filter).await?.last(); // we only need the most recent (last) one + let mut filtered_logged_events = eth_client.get_logs(&filter).await?; + filtered_logged_events.reverse(); // we'll process these in reverse order to start from the most recent and work backwards - if logged_event.is_some() { + // TODO(bolten): the original logic only checked one valset event, even if there may have been multiple within the + // filtered blockspace...need more clarity on how severe an error it is if one of these events is malformed, and if + // we should return early with an error or just log it the way the previous version did + for logged_event in filtered_logged_events { trace!("Found event {:?}", logged_event); - let valset_updated_event = ValsetUpdatedEvent::from_log(logged_event.unwrap()); - if let Result() - { + match ValsetUpdatedEvent::from_log(logged_event.unwrap()) { Ok(valset_updated_event) => { let downcast_nonce = downcast_to_u64(valset_updated_event.valset_nonce); if downcast_nonce.is_none() { error!("ValsetUpdatedEvent has nonce larger than u64: {:?}", valset_updated_event); + continue; } let latest_eth_valset = Valset { @@ -60,6 +63,7 @@ pub async fn find_latest_valset( Err(e) => error!("Got valset event that we can't parse {}", e), } } + end_filter_block = start_filter_block.saturating_sub(1); // filter ranges are inclusive, avoid searching same block } From db3dcd6670eac2b0a74714b2c44de71be51e5f45 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 4 Nov 2021 22:48:52 -0700 Subject: [PATCH 014/115] Dropping unnecessary type from GravityError --- orchestrator/gravity_utils/src/error.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index a32708a00..a074faefb 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -11,15 +11,13 @@ use std::fmt::{self, Debug}; use tokio::time::error::Elapsed; use tonic::Status; -pub type EthClientError = SignerMiddlewareError, LocalWallet>; - #[derive(Debug)] #[allow(clippy::large_enum_variant)] pub enum GravityError { InvalidBigInt(ParseBigIntError), CosmosGrpcError(CosmosGrpcError), CosmosAddressError(CosmosAddressError), - EthereumRestError(EthClientError), + EthereumRestError(SignerMiddlewareError, LocalWallet>), InvalidBridgeStateError(String), FailedToUpdateValset, EthereumContractError(String), @@ -83,8 +81,8 @@ impl From for GravityError { } } -impl From for GravityError { - fn from(error: EthClientError) -> Self { +impl From, LocalWallet>> for GravityError { + fn from(error: SignerMiddlewareError, LocalWallet>) -> Self { GravityError::EthereumRestError(error) } } From 20b674f5eeeada0344ebf2c934b3bfa63580fc43 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 4 Nov 2021 22:54:56 -0700 Subject: [PATCH 015/115] Leaving a TODO around use of abigen --- orchestrator/gravity_utils/src/types/ethereum_events.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 7505bd44b..0633b31ce 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -10,7 +10,6 @@ use deep_space::utils::bytes_to_hex_str; use deep_space::Address as CosmosAddress; use ethers::prelude::*; use ethers::types::Address as EthAddress; -use num256::Uint256; use std::unimplemented; pub const ERC20_DEPLOYED_EVENT_STR: &'static str = "ERC20DeployedEvent(string,address,string,string,uint8,uint256)"; @@ -19,6 +18,8 @@ pub const SEND_TO_COSMOS_EVENT_STR: &'static str = "SendToCosmosEvent(address,ad pub const TRANSACTION_BATCH_EXECUTED_EVENT_STR: &'static str = "TransactionBatchExecutedEvent(uint256,address,uint256)"; pub const VALSET_UPDATED_EVENT_STR: &'static str = "ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"; +// TODO(bolten): can we replace a bunch of this functionality using ethers abigen? + /// A parsed struct representing the Ethereum event fired by the Gravity contract /// when the validator set is updated. #[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Hash)] From 22a39525e64268b5587481ed2c9a0355cfd876ea Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 5 Nov 2021 17:12:45 -0700 Subject: [PATCH 016/115] Provider interval TODO, rustfmt --- .../gravity_utils/src/connection_prep.rs | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/orchestrator/gravity_utils/src/connection_prep.rs b/orchestrator/gravity_utils/src/connection_prep.rs index 0d7838e4d..83cd64f55 100644 --- a/orchestrator/gravity_utils/src/connection_prep.rs +++ b/orchestrator/gravity_utils/src/connection_prep.rs @@ -116,8 +116,11 @@ pub async fn create_rpc_connections( .unwrap_or_else(|_| panic!("Invalid Ethereum RPC url {}", eth_rpc_url)); check_scheme(&url, ð_rpc_url); let eth_url = eth_rpc_url.trim_end_matches('/'); - let base_eth_provider = EthProvider::::try_from(eth_url) - .unwrap_or_else(|_| panic!("Could not instantiate Ethereum HTTP provider: {}", eth_url)); + // TODO(bolten): should probably set a non-default interval, but what is the appropriate + // value? + let base_eth_provider = EthProvider::::try_from(eth_url).unwrap_or_else(|_| { + panic!("Could not instantiate Ethereum HTTP provider: {}", eth_url) + }); let try_base = base_eth_provider.get_block_number().await; match try_base { // it worked, lets go! @@ -135,9 +138,19 @@ pub async fn create_rpc_connections( let ipv6_url = format!("{}://::1:{}", prefix, port); let ipv4_url = format!("{}://127.0.0.1:{}", prefix, port); let ipv6_eth_provider = EthProvider::::try_from(ipv6_url.as_str()) - .unwrap_or_else(|_| panic!("Could not instantiate Ethereum HTTP provider: {}", &ipv6_url)); + .unwrap_or_else(|_| { + panic!( + "Could not instantiate Ethereum HTTP provider: {}", + &ipv6_url + ) + }); let ipv4_eth_provider = EthProvider::::try_from(ipv4_url.as_str()) - .unwrap_or_else(|_| panic!("Could not instantiate Ethereum HTTP provider: {}", &ipv4_url)); + .unwrap_or_else(|_| { + panic!( + "Could not instantiate Ethereum HTTP provider: {}", + &ipv4_url + ) + }); let ipv6_test = ipv6_eth_provider.get_block_number().await; let ipv4_test = ipv4_eth_provider.get_block_number().await; warn!("Trying fallback urls {} {}", ipv6_url, ipv4_url); @@ -160,10 +173,24 @@ pub async fn create_rpc_connections( // transparently upgrade to https if available, we can't transparently downgrade for obvious security reasons let https_on_80_url = format!("https://{}:80", body); let https_on_443_url = format!("https://{}:443", body); - let https_on_80_eth_provider = EthProvider::::try_from(https_on_80_url.as_str()) - .unwrap_or_else(|_| panic!("Could not instantiate Ethereum HTTP provider: {}", &https_on_80_url)); - let https_on_443_eth_provider = EthProvider::::try_from(https_on_443_url.as_str()) - .unwrap_or_else(|_| panic!("Could not instantiate Ethereum HTTP provider: {}", &https_on_443_url)); + let https_on_80_eth_provider = EthProvider::::try_from( + https_on_80_url.as_str(), + ) + .unwrap_or_else(|_| { + panic!( + "Could not instantiate Ethereum HTTP provider: {}", + &https_on_80_url + ) + }); + let https_on_443_eth_provider = EthProvider::::try_from( + https_on_443_url.as_str(), + ) + .unwrap_or_else(|_| { + panic!( + "Could not instantiate Ethereum HTTP provider: {}", + &https_on_443_url + ) + }); let https_on_80_test = https_on_80_eth_provider.get_block_number().await; let https_on_443_test = https_on_443_eth_provider.get_block_number().await; warn!( From 1900c2c6360300ed6f1884126dcda85f57453ba6 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Sun, 7 Nov 2021 21:18:58 -0800 Subject: [PATCH 017/115] Remove unnecessary ZERO const --- orchestrator/relayer/src/find_latest_valset.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index d8e7851d1..661cd4672 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -19,14 +19,13 @@ pub async fn find_latest_valset( eth_client: EthClient, ) -> Result { const BLOCKS_TO_SEARCH: u64 = 5_000u64; - const ZERO: u64 = 0u64; let mut filter = Filter::new() .address(gravity_contract_address) .event(&VALSET_UPDATED_EVENT_STR); let mut end_filter_block = eth_client.get_block_number().await?; - while end_filter_block > ZERO { + while end_filter_block > 0u64 { trace!("About to submit a Valset or Batch, looking back into the history to find the last Valset Update, on block {}", end_filter_block); let start_filter_block = end_filter_block.saturating_sub(BLOCKS_TO_SEARCH); From 88b3efbfdbc8abb29df871912287f86daf59e327 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Sun, 7 Nov 2021 22:47:25 -0800 Subject: [PATCH 018/115] ABI JSON for Gravity.sol from Hardhat compile --- orchestrator/abi/Gravity.json | 669 ++++++++++++++++++++++++++++++++++ 1 file changed, 669 insertions(+) create mode 100644 orchestrator/abi/Gravity.json diff --git a/orchestrator/abi/Gravity.json b/orchestrator/abi/Gravity.json new file mode 100644 index 000000000..e3def9e98 --- /dev/null +++ b/orchestrator/abi/Gravity.json @@ -0,0 +1,669 @@ +[ + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_gravityId", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "_powerThreshold", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "_validators", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_powers", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "_cosmosDenom", + "type": "string" + }, + { + "indexed": true, + "internalType": "address", + "name": "_tokenContract", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "_name", + "type": "string" + }, + { + "indexed": false, + "internalType": "string", + "name": "_symbol", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "_decimals", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_eventNonce", + "type": "uint256" + } + ], + "name": "ERC20DeployedEvent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "_invalidationId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_invalidationNonce", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "_returnData", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_eventNonce", + "type": "uint256" + } + ], + "name": "LogicCallEvent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_tokenContract", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "_destination", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_eventNonce", + "type": "uint256" + } + ], + "name": "SendToCosmosEvent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_batchNonce", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_eventNonce", + "type": "uint256" + } + ], + "name": "TransactionBatchExecutedEvent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "_newValsetNonce", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_eventNonce", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "_validators", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "_powers", + "type": "uint256[]" + } + ], + "name": "ValsetUpdatedEvent", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_cosmosDenom", + "type": "string" + }, + { + "internalType": "string", + "name": "_name", + "type": "string" + }, + { + "internalType": "string", + "name": "_symbol", + "type": "string" + }, + { + "internalType": "uint8", + "name": "_decimals", + "type": "uint8" + } + ], + "name": "deployERC20", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_erc20Address", + "type": "address" + } + ], + "name": "lastBatchNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_invalidation_id", + "type": "bytes32" + } + ], + "name": "lastLogicCallNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_tokenContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "_destination", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "sendToCosmos", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "state_gravityId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "state_invalidationMapping", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "state_lastBatchNonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "state_lastEventNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "state_lastValsetCheckpoint", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "state_lastValsetNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "state_powerThreshold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_currentValidators", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_currentPowers", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_currentValsetNonce", + "type": "uint256" + }, + { + "internalType": "uint8[]", + "name": "_v", + "type": "uint8[]" + }, + { + "internalType": "bytes32[]", + "name": "_r", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "_s", + "type": "bytes32[]" + }, + { + "internalType": "uint256[]", + "name": "_amounts", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "_destinations", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_fees", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_batchNonce", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_tokenContract", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_batchTimeout", + "type": "uint256" + } + ], + "name": "submitBatch", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_currentValidators", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_currentPowers", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_currentValsetNonce", + "type": "uint256" + }, + { + "internalType": "uint8[]", + "name": "_v", + "type": "uint8[]" + }, + { + "internalType": "bytes32[]", + "name": "_r", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "_s", + "type": "bytes32[]" + }, + { + "components": [ + { + "internalType": "uint256[]", + "name": "transferAmounts", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "transferTokenContracts", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "feeAmounts", + "type": "uint256[]" + }, + { + "internalType": "address[]", + "name": "feeTokenContracts", + "type": "address[]" + }, + { + "internalType": "address", + "name": "logicContractAddress", + "type": "address" + }, + { + "internalType": "bytes", + "name": "payload", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "timeOut", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "invalidationId", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "invalidationNonce", + "type": "uint256" + } + ], + "internalType": "struct LogicCallArgs", + "name": "_args", + "type": "tuple" + } + ], + "name": "submitLogicCall", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_currentValidators", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_currentPowers", + "type": "uint256[]" + }, + { + "internalType": "uint8[]", + "name": "_v", + "type": "uint8[]" + }, + { + "internalType": "bytes32[]", + "name": "_r", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "_s", + "type": "bytes32[]" + }, + { + "internalType": "bytes32", + "name": "_theHash", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "_powerThreshold", + "type": "uint256" + } + ], + "name": "testCheckValidatorSignatures", + "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_validators", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_powers", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_valsetNonce", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "_gravityId", + "type": "bytes32" + } + ], + "name": "testMakeCheckpoint", + "outputs": [], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_newValidators", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_newPowers", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_newValsetNonce", + "type": "uint256" + }, + { + "internalType": "address[]", + "name": "_currentValidators", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "_currentPowers", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "_currentValsetNonce", + "type": "uint256" + }, + { + "internalType": "uint8[]", + "name": "_v", + "type": "uint8[]" + }, + { + "internalType": "bytes32[]", + "name": "_r", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "_s", + "type": "bytes32[]" + } + ], + "name": "updateValset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] From 498e3a023a8a984ff09e41f84ead5d58df6d91ce Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Sun, 7 Nov 2021 22:48:30 -0800 Subject: [PATCH 019/115] Add serde_json, call abigen! on Gravity.json --- orchestrator/Cargo.lock | 5 +++-- orchestrator/gravity_utils/Cargo.toml | 1 + orchestrator/gravity_utils/src/types/ethereum_events.rs | 7 ++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index 268f2d641..716751478 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -2215,6 +2215,7 @@ dependencies = [ "rand 0.8.4", "serde", "serde_derive", + "serde_json", "sha3", "tokio 1.5.0", "tonic", @@ -4125,9 +4126,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8" dependencies = [ "itoa", "ryu", diff --git a/orchestrator/gravity_utils/Cargo.toml b/orchestrator/gravity_utils/Cargo.toml index 2e5313aac..6cc85b369 100644 --- a/orchestrator/gravity_utils/Cargo.toml +++ b/orchestrator/gravity_utils/Cargo.toml @@ -15,6 +15,7 @@ web30 = "0.15" clarity = "0.4.11" num256 = "0.3" serde_derive = "1.0" +serde_json = "1.0.69" serde = "1.0" tokio = "1.4" tonic = "0.4" diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 0633b31ce..279d59682 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -8,6 +8,7 @@ use super::ValsetMember; use crate::error::GravityError; use deep_space::utils::bytes_to_hex_str; use deep_space::Address as CosmosAddress; +use ethers::contract::abigen; use ethers::prelude::*; use ethers::types::Address as EthAddress; use std::unimplemented; @@ -18,7 +19,11 @@ pub const SEND_TO_COSMOS_EVENT_STR: &'static str = "SendToCosmosEvent(address,ad pub const TRANSACTION_BATCH_EXECUTED_EVENT_STR: &'static str = "TransactionBatchExecutedEvent(uint256,address,uint256)"; pub const VALSET_UPDATED_EVENT_STR: &'static str = "ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"; -// TODO(bolten): can we replace a bunch of this functionality using ethers abigen? +abigen!( + Gravity, + "abi/Gravity.json", + event_derives(serde::Deserialize, serde::Serialize) +); /// A parsed struct representing the Ethereum event fired by the Gravity contract /// when the validator set is updated. From 3a0eacc86c81dd6eb4aeebbd7fee7884f783b194 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 8 Nov 2021 00:18:52 -0800 Subject: [PATCH 020/115] WIP: use Gravity.sol ABI directly Starting the process of directly using the ABI by removing the custom parsing for ValsetUpdatedEvent and using functionality from ethers abigen instead. Debating whether or not to leave it as a macro (which makes it kind of difficult to introspect) or to check in a version of the generated code. Also moved the downcasting functions to the generic gravity_utils package so other code can easily pull it in. --- orchestrator/gravity_utils/src/error.rs | 10 ++ orchestrator/gravity_utils/src/ethereum.rs | 16 +++ orchestrator/gravity_utils/src/lib.rs | 1 + .../src/types/ethereum_events.rs | 105 ++++-------------- .../gravity_utils/src/types/valsets.rs | 2 +- .../relayer/src/find_latest_valset.rs | 7 +- 6 files changed, 55 insertions(+), 86 deletions(-) create mode 100644 orchestrator/gravity_utils/src/ethereum.rs diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index a074faefb..63eb9fb59 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -4,6 +4,7 @@ use clarity::Error as ClarityError; use deep_space::error::AddressError as CosmosAddressError; use deep_space::error::CosmosGrpcError; +use ethers::abi::Error as EthersAbiError; use ethers::prelude::*; use ethers::prelude::signer::SignerMiddlewareError; use num_bigint::ParseBigIntError; @@ -18,6 +19,7 @@ pub enum GravityError { CosmosGrpcError(CosmosGrpcError), CosmosAddressError(CosmosAddressError), EthereumRestError(SignerMiddlewareError, LocalWallet>), + EthersAbiError(EthersAbiError), InvalidBridgeStateError(String), FailedToUpdateValset, EthereumContractError(String), @@ -40,6 +42,7 @@ impl fmt::Display for GravityError { } GravityError::CosmosAddressError(val) => write!(f, "Cosmos Address error {}", val), GravityError::EthereumRestError(val) => write!(f, "Ethereum REST error {}", val), + GravityError::EthersAbiError(val) => write!(f, "Ethers ABI error {}", val), GravityError::InvalidOptionsError(val) => { write!(f, "Invalid TX options for this call {}", val) } @@ -86,6 +89,13 @@ impl From, LocalWallet>> for GravityError { GravityError::EthereumRestError(error) } } + +impl From for GravityError { + fn from(error: EthersAbiError) -> Self { + GravityError::EthersAbiError(error) + } +} + impl From for GravityError { fn from(error: Status) -> Self { GravityError::GravityGrpcError(error) diff --git a/orchestrator/gravity_utils/src/ethereum.rs b/orchestrator/gravity_utils/src/ethereum.rs new file mode 100644 index 000000000..5e85cc716 --- /dev/null +++ b/orchestrator/gravity_utils/src/ethereum.rs @@ -0,0 +1,16 @@ +use ethers::prelude::*; +use std::panic; + +pub fn downcast_to_u64(input: U256) -> Option { + match panic::catch_unwind(|| input.as_u64()) { + Ok(downcasted) => Some(downcasted), + Err(_) => None, + } +} + +pub fn downcast_to_u128(input: U256) -> Option { + match panic::catch_unwind(|| input.as_u128()) { + Ok(downcasted) => Some(downcasted), + Err(_) => None, + } +} \ No newline at end of file diff --git a/orchestrator/gravity_utils/src/lib.rs b/orchestrator/gravity_utils/src/lib.rs index 13f655786..55f465d56 100644 --- a/orchestrator/gravity_utils/src/lib.rs +++ b/orchestrator/gravity_utils/src/lib.rs @@ -7,5 +7,6 @@ extern crate log; pub mod connection_prep; pub mod error; +pub mod ethereum; pub mod message_signatures; pub mod types; diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 279d59682..a94d8492b 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -6,8 +6,10 @@ use super::ValsetMember; use crate::error::GravityError; +use crate::ethereum::downcast_to_u64; use deep_space::utils::bytes_to_hex_str; use deep_space::Address as CosmosAddress; +use ethers::abi::RawLog; use ethers::contract::abigen; use ethers::prelude::*; use ethers::types::Address as EthAddress; @@ -25,6 +27,13 @@ abigen!( event_derives(serde::Deserialize, serde::Serialize) ); +fn log_to_ethers_event(log: &Log) -> Result { + T::decode_log(&RawLog { + topics: log.topics, + data: log.data.to_vec(), + }).map_err(From::from) +} + /// A parsed struct representing the Ethereum event fired by the Gravity contract /// when the validator set is updated. #[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Hash)] @@ -39,85 +48,18 @@ impl ValsetUpdatedEvent { /// This function is not an abi compatible bytes parser, but it's actually /// not hard at all to extract data like this by hand. pub fn from_log(input: &Log) -> Result { - // we have one indexed event so we should fined two indexes, one the event itself - // and one the indexed nonce - if input.topics.get(1).is_none() { - return Err(GravityError::InvalidEventLogError( - "Too few topics".to_string(), - )); - } - let valset_nonce_data = &input.topics[1]; - let valset_nonce = Uint256::from_bytes_be(valset_nonce_data); - if valset_nonce > u64::MAX.into() { - return Err(GravityError::InvalidEventLogError( - "Nonce overflow, probably incorrect parsing".to_string(), - )); - } - let valset_nonce: u64 = valset_nonce.to_string().parse().unwrap(); + let event: ValsetUpdatedEventFilter = log_to_ethers_event(input)?; - // first index is the event nonce, following two have event data we don't - // care about, fourth index contains the length of the eth address array - let index_start = 0; - let index_end = index_start + 32; - let nonce_data = &input.data[index_start..index_end]; - let event_nonce = Uint256::from_bytes_be(nonce_data); - if event_nonce > u64::MAX.into() { - return Err(GravityError::InvalidEventLogError( - "Nonce overflow, probably incorrect parsing".to_string(), - )); - } - let event_nonce: u64 = event_nonce.to_string().parse().unwrap(); - // first index is the event nonce, following two have event data we don't - // care about, fourth index contains the length of the eth address array - let index_start = 3 * 32; - let index_end = index_start + 32; - let eth_addresses_offset = index_start + 32; - let len_eth_addresses = Uint256::from_bytes_be(&input.data[index_start..index_end]); - if len_eth_addresses > usize::MAX.into() { - return Err(GravityError::InvalidEventLogError( - "Ethereum array len overflow, probably incorrect parsing".to_string(), - )); - } - let len_eth_addresses: usize = len_eth_addresses.to_string().parse().unwrap(); - let index_start = (4 + len_eth_addresses) * 32; - let index_end = index_start + 32; - let powers_offset = index_start + 32; - let len_powers = Uint256::from_bytes_be(&input.data[index_start..index_end]); - if len_powers > usize::MAX.into() { - return Err(GravityError::InvalidEventLogError( - "Powers array len overflow, probably incorrect parsing".to_string(), - )); - } - let len_powers: usize = len_eth_addresses.to_string().parse().unwrap(); - if len_powers != len_eth_addresses { - return Err(GravityError::InvalidEventLogError( - "Array len mismatch, probably incorrect parsing".to_string(), - )); - } - - let mut validators = Vec::new(); - for i in 0..len_eth_addresses { - let power_start = (i * 32) + powers_offset; - let power_end = power_start + 32; - let address_start = (i * 32) + eth_addresses_offset; - let address_end = address_start + 32; - let power = Uint256::from_bytes_be(&input.data[power_start..power_end]); - // an eth address at 20 bytes is 12 bytes shorter than the Uint256 it's stored in. - let eth_address = EthAddress::from_slice(&input.data[address_start + 12..address_end]); - if eth_address.is_err() { - return Err(GravityError::InvalidEventLogError( - "Ethereum Address parsing error, probably incorrect parsing".to_string(), - )); - } - let eth_address = Some(eth_address.unwrap()); - if power > u64::MAX.into() { - return Err(GravityError::InvalidEventLogError( - "Power greater than u64::MAX, probably incorrect parsing".to_string(), - )); - } - let power: u64 = power.to_string().parse().unwrap(); - validators.push(ValsetMember { power, eth_address }) - } + let mut validators: Vec = event.powers.iter() + .zip(event.validators.iter()) + .map(|(power, validator)| { + ValsetMember { + power: downcast_to_u64(*power).unwrap(), + eth_address: Some(*validator), + } + }) + .collect(); + // validators.push(ValsetMember { power, eth_address }) let mut check = validators.clone(); check.sort(); check.reverse(); @@ -128,6 +70,7 @@ impl ValsetUpdatedEvent { validators, check ); } + let block_height = if let Some(bn) = input.block_number.clone() { bn } else { @@ -138,9 +81,9 @@ impl ValsetUpdatedEvent { }; Ok(ValsetUpdatedEvent { - valset_nonce: valset_nonce.into(), - event_nonce: event_nonce.into(), - block_height, + valset_nonce: event.new_valset_nonce, + event_nonce: event.event_nonce, + block_height: block_height.into(), members: validators, }) } diff --git a/orchestrator/gravity_utils/src/types/valsets.rs b/orchestrator/gravity_utils/src/types/valsets.rs index 1eef52e74..7f87bba5b 100644 --- a/orchestrator/gravity_utils/src/types/valsets.rs +++ b/orchestrator/gravity_utils/src/types/valsets.rs @@ -1,6 +1,6 @@ use super::*; use crate::error::GravityError; -use clarity::Address as EthAddress; +use ethers::types::Address as EthAddress; use clarity::Signature as EthSignature; use deep_space::error::CosmosGrpcError; use std::fmt::Debug; diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index 661cd4672..d5350638f 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -1,10 +1,9 @@ use crate::main_loop::EthClient; use clarity::{Address, Uint256}; -use ethereum_gravity::utils::downcast_to_u64; use ethers::prelude::*; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use gravity_utils::types::{VALSET_UPDATED_EVENT_STR, ValsetUpdatedEvent}; -use gravity_utils::{error::GravityError, types::Valset}; +use gravity_utils::types::{VALSET_UPDATED_EVENT_STR, ValsetUpdatedEvent, ValsetUpdatedEventFilter}; +use gravity_utils::{error::GravityError, ethereum::downcast_to_u64, types::Valset}; use std::panic; use tonic::transport::Channel; @@ -40,7 +39,7 @@ pub async fn find_latest_valset( for logged_event in filtered_logged_events { trace!("Found event {:?}", logged_event); - match ValsetUpdatedEvent::from_log(logged_event.unwrap()) { + match ValsetUpdatedEvent::from_log(&logged_event) { Ok(valset_updated_event) => { let downcast_nonce = downcast_to_u64(valset_updated_event.valset_nonce); if downcast_nonce.is_none() { From edd4e37635f5b57ee55cbec4be289ad683bdec84 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 8 Nov 2021 08:44:34 -0800 Subject: [PATCH 021/115] Move downcast tests, small fixes --- orchestrator/ethereum_gravity/src/utils.rs | 46 ------------------- orchestrator/gravity_utils/src/error.rs | 2 + orchestrator/gravity_utils/src/ethereum.rs | 32 +++++++++++++ .../src/types/ethereum_events.rs | 4 +- 4 files changed, 36 insertions(+), 48 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 3610841c5..a02ca21ee 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -28,52 +28,6 @@ pub fn get_checkpoint_hash(valset: &Valset, gravity_id: &str) -> Result, Ok(locally_computed_digest.to_vec()) } -pub fn downcast_to_u64(input: U256) -> Option { - match panic::catch_unwind(|| input.as_u64()) { - Ok(downcasted) => Some(downcasted), - Err(_) => None, - } -} - -pub fn downcast_to_u128(input: U256) -> Option { - match panic::catch_unwind(|| input.as_u128()) { - Ok(downcasted) => Some(downcasted), - Err(_) => None, - } -} - -#[test] -fn test_downcast_nonce() { - let mut i = 0u64; - while i < 100_000 { - assert_eq!(i, downcast_to_u64(i.into()).unwrap()); - i += 1 - } - let mut i: u64 = std::u32::MAX.into(); - i -= 100; - let end = i + 100_000; - while i < end { - assert_eq!(i, downcast_to_u64(i.into()).unwrap()); - i += 1 - } -} - -#[test] -fn test_downcast_to_u128() { - let mut i = 0u128; - while i < 100_000 { - assert_eq!(i, downcast_to_u128(i.into()).unwrap()); - i += 1 - } - let mut i: u128 = std::u64::MAX.into(); - i -= 100; - let end = i + 100_000; - while i < end { - assert_eq!(i, downcast_to_u128(i.into()).unwrap()); - i += 1 - } -} - /// Gets the latest validator set nonce pub async fn get_valset_nonce( contract_address: EthAddress, diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index 63eb9fb59..fda2c4d72 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -101,11 +101,13 @@ impl From for GravityError { GravityError::GravityGrpcError(error) } } + impl From for GravityError { fn from(error: CosmosAddressError) -> Self { GravityError::CosmosAddressError(error) } } + impl From for GravityError { fn from(error: ParseBigIntError) -> Self { GravityError::InvalidBigInt(error) diff --git a/orchestrator/gravity_utils/src/ethereum.rs b/orchestrator/gravity_utils/src/ethereum.rs index 5e85cc716..28e6858bf 100644 --- a/orchestrator/gravity_utils/src/ethereum.rs +++ b/orchestrator/gravity_utils/src/ethereum.rs @@ -13,4 +13,36 @@ pub fn downcast_to_u128(input: U256) -> Option { Ok(downcasted) => Some(downcasted), Err(_) => None, } +} + +#[test] +fn test_downcast_to_u64() { + let mut i = 0u64; + while i < 100_000 { + assert_eq!(i, downcast_to_u64(i.into()).unwrap()); + i += 1 + } + let mut i: u64 = std::u32::MAX.into(); + i -= 100; + let end = i + 100_000; + while i < end { + assert_eq!(i, downcast_to_u64(i.into()).unwrap()); + i += 1 + } +} + +#[test] +fn test_downcast_to_u128() { + let mut i = 0u128; + while i < 100_000 { + assert_eq!(i, downcast_to_u128(i.into()).unwrap()); + i += 1 + } + let mut i: u128 = std::u64::MAX.into(); + i -= 100; + let end = i + 100_000; + while i < end { + assert_eq!(i, downcast_to_u128(i.into()).unwrap()); + i += 1 + } } \ No newline at end of file diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index a94d8492b..e9e9b2096 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -50,7 +50,7 @@ impl ValsetUpdatedEvent { pub fn from_log(input: &Log) -> Result { let event: ValsetUpdatedEventFilter = log_to_ethers_event(input)?; - let mut validators: Vec = event.powers.iter() + let validators: Vec = event.powers.iter() .zip(event.validators.iter()) .map(|(power, validator)| { ValsetMember { @@ -59,7 +59,7 @@ impl ValsetUpdatedEvent { } }) .collect(); - // validators.push(ValsetMember { power, eth_address }) + let mut check = validators.clone(); check.sort(); check.reverse(); From 0f236dda0949752b40dc0bf3f1d395702ba63eee Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 8 Nov 2021 21:32:45 -0800 Subject: [PATCH 022/115] Fix block height conversion, remove unused import --- orchestrator/gravity_utils/src/types/ethereum_events.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index e9e9b2096..41a294541 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -13,7 +13,6 @@ use ethers::abi::RawLog; use ethers::contract::abigen; use ethers::prelude::*; use ethers::types::Address as EthAddress; -use std::unimplemented; pub const ERC20_DEPLOYED_EVENT_STR: &'static str = "ERC20DeployedEvent(string,address,string,string,uint8,uint256)"; pub const LOGIC_CALL_EVENT_STR: &'static str = "LogicCallEvent(bytes32,uint256,bytes,uint256)"; @@ -83,7 +82,7 @@ impl ValsetUpdatedEvent { Ok(ValsetUpdatedEvent { valset_nonce: event.new_valset_nonce, event_nonce: event.event_nonce, - block_height: block_height.into(), + block_height: U256::from(block_height.as_u64()), members: validators, }) } From 8b37d8b44e64503476e154246ddd7509463811db Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 8 Nov 2021 22:39:32 -0800 Subject: [PATCH 023/115] Complete conversion of ethereum_events.rs All event types are now using abigen versions. Additionally, it appears that the conversion of LogicCallExecutedEvent from a log was just marked as "unimplemented" but now has been added as well. Also rewrote the event nonce filtering using iterators and adaptors. There's probably a way of further using traits to reduce code duplication here but it's not a huge issue that it's not super DRY right now. --- .../src/types/ethereum_events.rs | 346 +++++------------- 1 file changed, 95 insertions(+), 251 deletions(-) diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 41a294541..b5d2d9922 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -26,6 +26,8 @@ abigen!( event_derives(serde::Deserialize, serde::Serialize) ); +// given a Log retrieved by querying the Ethereum chain, decode it into one of +// the types we are generating using abigen! above for the Gravity contract fn log_to_ethers_event(log: &Log) -> Result { T::decode_log(&RawLog { topics: log.topics, @@ -33,6 +35,17 @@ fn log_to_ethers_event(log: &Log) -> Result Result { + match log.block_number.clone() { + Some(block_height) => Ok(U256::from(block_height.as_u64())), + None => Err(GravityError::InvalidEventLogError( + "Log does not have block number, we only search logs already in blocks?".to_string()) + ) + } +} + /// A parsed struct representing the Ethereum event fired by the Gravity contract /// when the validator set is updated. #[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Hash)] @@ -70,22 +83,14 @@ impl ValsetUpdatedEvent { ); } - let block_height = if let Some(bn) = input.block_number.clone() { - bn - } else { - return Err(GravityError::InvalidEventLogError( - "Log does not have block number, we only search logs already in blocks?" - .to_string(), - )); - }; - Ok(ValsetUpdatedEvent { valset_nonce: event.new_valset_nonce, event_nonce: event.event_nonce, - block_height: U256::from(block_height.as_u64()), + block_height: block_height_from_log(&input)?, members: validators, }) } + pub fn from_logs(input: &[Log]) -> Result, GravityError> { let mut res = Vec::new(); for item in input { @@ -93,16 +98,14 @@ impl ValsetUpdatedEvent { } Ok(res) } + /// returns all values in the array with event nonces greater /// than the provided value pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { - let mut ret = Vec::new(); - for item in input { - if item.event_nonce > event_nonce.into() { - ret.push(item.clone()) - } - } - ret + input.iter() + .filter(|item| item.event_nonce > event_nonce.into()) + .map(|item| item.clone()) + .collect() } } @@ -112,55 +115,30 @@ impl ValsetUpdatedEvent { pub struct TransactionBatchExecutedEvent { /// the nonce attached to the transaction batch that follows /// it throughout it's lifecycle - pub batch_nonce: Uint256, + pub batch_nonce: U256, /// The block height this event occurred at - pub block_height: Uint256, + pub block_height: U256, /// The ERC20 token contract address for the batch executed, since batches are uniform /// in token type there is only one pub erc20: EthAddress, /// the event nonce representing a unique ordering of events coming out /// of the Gravity solidity contract. Ensuring that these events can only be played /// back in order - pub event_nonce: Uint256, + pub event_nonce: U256, } impl TransactionBatchExecutedEvent { pub fn from_log(input: &Log) -> Result { - if let (Some(batch_nonce_data), Some(erc20_data)) = - (input.topics.get(1), input.topics.get(2)) - { - let batch_nonce = Uint256::from_bytes_be(batch_nonce_data); - let erc20 = EthAddress::from_slice(&erc20_data[12..32])?; - let event_nonce = Uint256::from_bytes_be(&input.data); - let block_height = if let Some(bn) = input.block_number.clone() { - bn - } else { - return Err(GravityError::InvalidEventLogError( - "Log does not have block number, we only search logs already in blocks?" - .to_string(), - )); - }; - if event_nonce > u64::MAX.into() - || batch_nonce > u64::MAX.into() - || block_height > u64::MAX.into() - { - Err(GravityError::InvalidEventLogError( - "Event nonce overflow, probably incorrect parsing".to_string(), - )) - } else { - Ok(TransactionBatchExecutedEvent { - batch_nonce, - block_height, - erc20, - event_nonce, - }) - } - } else { - Err(GravityError::InvalidEventLogError( - "Too few topics".to_string(), - )) - } + let event: TransactionBatchExecutedEventFilter = log_to_ethers_event(input)?; + + Ok(TransactionBatchExecutedEvent { + batch_nonce: event.batch_nonce, + block_height: block_height_from_log(&input)?, + erc20: event.token, + event_nonce: event.event_nonce, + }) } + pub fn from_logs(input: &[Log]) -> Result, GravityError> { let mut res = Vec::new(); for item in input { @@ -168,16 +146,14 @@ impl TransactionBatchExecutedEvent { } Ok(res) } + /// returns all values in the array with event nonces greater /// than the provided value pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { - let mut ret = Vec::new(); - for item in input { - if item.event_nonce > event_nonce.into() { - ret.push(item.clone()) - } - } - ret + input.iter() + .filter(|item| item.event_nonce > event_nonce.into()) + .map(|item| item.clone()) + .collect() } } @@ -192,58 +168,28 @@ pub struct SendToCosmosEvent { /// The Cosmos destination pub destination: CosmosAddress, /// The amount of the erc20 token that is being sent - pub amount: Uint256, + pub amount: U256, /// The transaction's nonce, used to make sure there can be no accidental duplication - pub event_nonce: Uint256, + pub event_nonce: U256, /// The block height this event occurred at - pub block_height: Uint256, + pub block_height: U256, } impl SendToCosmosEvent { pub fn from_log(input: &Log, prefix: &str) -> Result { - let topics = ( - input.topics.get(1), - input.topics.get(2), - input.topics.get(3), - ); - if let (Some(erc20_data), Some(sender_data), Some(destination_data)) = topics { - let erc20 = EthAddress::from_slice(&erc20_data[12..32])?; - let sender = EthAddress::from_slice(&sender_data[12..32])?; - // this is required because deep_space requires a fixed length slice to - // create an address from bytes. - let mut c_address_bytes: [u8; 20] = [0; 20]; - c_address_bytes.copy_from_slice(&destination_data[12..32]); - let destination = CosmosAddress::from_bytes(c_address_bytes, prefix).unwrap(); - let amount = Uint256::from_bytes_be(&input.data[..32]); - let event_nonce = Uint256::from_bytes_be(&input.data[32..]); - let block_height = if let Some(bn) = input.block_number.clone() { - bn - } else { - return Err(GravityError::InvalidEventLogError( - "Log does not have block number, we only search logs already in blocks?" - .to_string(), - )); - }; - if event_nonce > u64::MAX.into() || block_height > u64::MAX.into() { - Err(GravityError::InvalidEventLogError( - "Event nonce overflow, probably incorrect parsing".to_string(), - )) - } else { - Ok(SendToCosmosEvent { - erc20, - sender, - destination, - amount, - event_nonce, - block_height, - }) - } - } else { - Err(GravityError::InvalidEventLogError( - "Too few topics".to_string(), - )) - } + let event: SendToCosmosEventFilter = log_to_ethers_event(input)?; + + // TODO(bolten): verify this method of retrieval for Cosmos addresses works as expected + Ok(SendToCosmosEvent { + erc20: event.token_contract, + sender: event.sender, + destination: CosmosAddress::from_slice(&event.destination[12..32], prefix)?, + amount: event.amount, + event_nonce: event.event_nonce, + block_height: block_height_from_log(&input)?, + }) } + pub fn from_logs( input: &[Log], prefix: &str, @@ -254,16 +200,14 @@ impl SendToCosmosEvent { } Ok(res) } + /// returns all values in the array with event nonces greater /// than the provided value pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { - let mut ret = Vec::new(); - for item in input { - if item.event_nonce > event_nonce.into() { - ret.push(item.clone()) - } - } - ret + input.iter() + .filter(|item| item.event_nonce > event_nonce.into()) + .map(|item| item.clone()) + .collect() } } @@ -283,130 +227,25 @@ pub struct Erc20DeployedEvent { pub symbol: String, /// The number of decimals required to represent the smallest unit of this token pub decimals: u8, - pub event_nonce: Uint256, - pub block_height: Uint256, + pub event_nonce: U256, + pub block_height: U256, } impl Erc20DeployedEvent { pub fn from_log(input: &Log) -> Result { - let token_contract = input.topics.get(1); - if let Some(new_token_contract_data) = token_contract { - let erc20 = EthAddress::from_slice(&new_token_contract_data[12..32])?; - let index_start = 3 * 32; - let index_end = index_start + 32; - let decimals = Uint256::from_bytes_be(&input.data[index_start..index_end]); - if decimals > u8::MAX.into() { - return Err(GravityError::InvalidEventLogError( - "Decimals overflow, probably incorrect parsing".to_string(), - )); - } - let decimals: u8 = decimals.to_string().parse().unwrap(); - - let index_start = 4 * 32; - let index_end = index_start + 32; - let nonce = Uint256::from_bytes_be(&input.data[index_start..index_end]); - if nonce > u64::MAX.into() { - return Err(GravityError::InvalidEventLogError( - "Nonce overflow, probably incorrect parsing".to_string(), - )); - } - - let index_start = 5 * 32; - let index_end = index_start + 32; - let denom_len = Uint256::from_bytes_be(&input.data[index_start..index_end]); - // it's not probable that we have 4+ gigabytes of event data - if denom_len > u32::MAX.into() { - return Err(GravityError::InvalidEventLogError( - "denom length overflow, probably incorrect parsing".to_string(), - )); - } - let denom_len: usize = denom_len.to_string().parse().unwrap(); - let index_start = 6 * 32; - let index_end = index_start + denom_len; - let denom = String::from_utf8(input.data[index_start..index_end].to_vec()); - trace!("Denom {:?}", denom); - if denom.is_err() { - return Err(GravityError::InvalidEventLogError(format!( - "{:?} is not valid utf8, probably incorrect parsing", - denom - ))); - } - let denom = denom.unwrap(); - - // beyond this point we are parsing strings placed - // after a variable length string and we will need to compute offsets - - // this trick computes the next 32 byte (256 bit) word index, then multiplies by - // 32 to get the bytes offset, this is required since we have dynamic length types but - // the next entry always starts on a round 32 byte word. - let index_start = ((index_end + 31) / 32) * 32; - let index_end = index_start + 32; - let erc20_name_len = Uint256::from_bytes_be(&input.data[index_start..index_end]); - // it's not probable that we have 4+ gigabytes of event data - if erc20_name_len > u32::MAX.into() { - return Err(GravityError::InvalidEventLogError( - "ERC20 Name length overflow, probably incorrect parsing".to_string(), - )); - } - let erc20_name_len: usize = erc20_name_len.to_string().parse().unwrap(); - let index_start = index_end; - let index_end = index_start + erc20_name_len; - let erc20_name = String::from_utf8(input.data[index_start..index_end].to_vec()); - if erc20_name.is_err() { - return Err(GravityError::InvalidEventLogError(format!( - "{:?} is not valid utf8, probably incorrect parsing", - erc20_name - ))); - } - trace!("ERC20 Name {:?}", erc20_name); - let erc20_name = erc20_name.unwrap(); - - let index_start = ((index_end + 31) / 32) * 32; - let index_end = index_start + 32; - let symbol_len = Uint256::from_bytes_be(&input.data[index_start..index_end]); - // it's not probable that we have 4+ gigabytes of event data - if symbol_len > u32::MAX.into() { - return Err(GravityError::InvalidEventLogError( - "Symbol length overflow, probably incorrect parsing".to_string(), - )); - } - let symbol_len: usize = symbol_len.to_string().parse().unwrap(); - let index_start = index_end; - let index_end = index_start + symbol_len; - let symbol = String::from_utf8(input.data[index_start..index_end].to_vec()); - trace!("Symbol {:?}", symbol); - if symbol.is_err() { - return Err(GravityError::InvalidEventLogError(format!( - "{:?} is not valid utf8, probably incorrect parsing", - symbol - ))); - } - let symbol = symbol.unwrap(); - - let block_height = if let Some(bn) = input.block_number.clone() { - bn - } else { - return Err(GravityError::InvalidEventLogError( - "Log does not have block number, we only search logs already in blocks?" - .to_string(), - )); - }; - - Ok(Erc20DeployedEvent { - cosmos_denom: denom, - name: erc20_name, - decimals, - event_nonce: nonce, - erc20_address: erc20, - symbol, - block_height, - }) - } else { - Err(GravityError::InvalidEventLogError( - "Too few topics".to_string(), - )) - } + let event: Erc20DeployedEventFilter = log_to_ethers_event(input)?; + + Ok(Erc20DeployedEvent { + cosmos_denom: event.cosmos_denom, + erc20_address: event.token_contract, + name: event.name, + symbol: event.symbol, + decimals: event.decimals, + event_nonce: event.event_nonce, + block_height: block_height_from_log(&input)?, + }) } + pub fn from_logs(input: &[Log]) -> Result, GravityError> { let mut res = Vec::new(); for item in input { @@ -414,16 +253,14 @@ impl Erc20DeployedEvent { } Ok(res) } + /// returns all values in the array with event nonces greater /// than the provided value pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { - let mut ret = Vec::new(); - for item in input { - if item.event_nonce > event_nonce.into() { - ret.push(item.clone()) - } - } - ret + input.iter() + .filter(|item| item.event_nonce > event_nonce.into()) + .map(|item| item.clone()) + .collect() } } /// A parsed struct representing the Ethereum event fired when someone uses the Gravity @@ -431,16 +268,25 @@ impl Erc20DeployedEvent { #[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Hash)] pub struct LogicCallExecutedEvent { pub invalidation_id: Vec, - pub invalidation_nonce: Uint256, + pub invalidation_nonce: U256, pub return_data: Vec, - pub event_nonce: Uint256, - pub block_height: Uint256, + pub event_nonce: U256, + pub block_height: U256, } impl LogicCallExecutedEvent { - pub fn from_log(_input: &Log) -> Result { - unimplemented!("foo") + pub fn from_log(input: &Log) -> Result { + let event: LogicCallEventFilter = log_to_ethers_event(input)?; + + Ok(LogicCallExecutedEvent { + invalidation_id: event.invalidation_id.into(), + invalidation_nonce: event.invalidation_nonce, + return_data: event.return_data.into(), + event_nonce: event.event_nonce, + block_height: block_height_from_log(&input)?, + }) } + pub fn from_logs(input: &[Log]) -> Result, GravityError> { let mut res = Vec::new(); for item in input { @@ -448,16 +294,14 @@ impl LogicCallExecutedEvent { } Ok(res) } + /// returns all values in the array with event nonces greater /// than the provided value pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { - let mut ret = Vec::new(); - for item in input { - if item.event_nonce > event_nonce.into() { - ret.push(item.clone()) - } - } - ret + input.iter() + .filter(|item| item.event_nonce > event_nonce.into()) + .map(|item| item.clone()) + .collect() } } From 35cafea2dd88093e280f4ffb2123d15df814a00e Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 8 Nov 2021 22:59:59 -0800 Subject: [PATCH 024/115] Ensure powers can be downcast, fix up some errors --- .../src/types/ethereum_events.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index b5d2d9922..06fd7c46c 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -41,7 +41,7 @@ fn block_height_from_log(log: &Log) -> Result { match log.block_number.clone() { Some(block_height) => Ok(U256::from(block_height.as_u64())), None => Err(GravityError::InvalidEventLogError( - "Log does not have block number, we only search logs already in blocks?".to_string()) + format!("Log does not have block number, we only search logs already in blocks? {:?}", log)) ) } } @@ -61,12 +61,23 @@ impl ValsetUpdatedEvent { /// not hard at all to extract data like this by hand. pub fn from_log(input: &Log) -> Result { let event: ValsetUpdatedEventFilter = log_to_ethers_event(input)?; + let powers: Vec = event.powers.iter() + .map(|power| downcast_to_u64(*power)) + .filter(|power_result| power_result.is_some()) + .map(Option::unwrap) + .collect(); + + if powers.len() < event.powers.len() { + return Err(GravityError::InvalidEventLogError( + format!("ValsetUpdatedEvent contains powers that cannot be downcast to u64: {:?}", event)) + ) + } - let validators: Vec = event.powers.iter() + let validators: Vec = powers.iter() .zip(event.validators.iter()) .map(|(power, validator)| { ValsetMember { - power: downcast_to_u64(*power).unwrap(), + power: *power, eth_address: Some(*validator), } }) @@ -77,7 +88,7 @@ impl ValsetUpdatedEvent { check.reverse(); // if the validator set is not sorted we're in a bad spot if validators != check { - trace!( + warn!( "Someone submitted an unsorted validator set, this means all updates will fail until someone feeds in this unsorted value by hand {:?} instead of {:?}", validators, check ); From 4a82a28237e5e0306ae691199ec3352d562002db Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 8 Nov 2021 23:04:07 -0800 Subject: [PATCH 025/115] Downcasting the powers in a simpler way --- .../gravity_utils/src/types/ethereum_events.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 06fd7c46c..7bf748979 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -61,16 +61,16 @@ impl ValsetUpdatedEvent { /// not hard at all to extract data like this by hand. pub fn from_log(input: &Log) -> Result { let event: ValsetUpdatedEventFilter = log_to_ethers_event(input)?; - let powers: Vec = event.powers.iter() - .map(|power| downcast_to_u64(*power)) - .filter(|power_result| power_result.is_some()) - .map(Option::unwrap) - .collect(); - if powers.len() < event.powers.len() { - return Err(GravityError::InvalidEventLogError( - format!("ValsetUpdatedEvent contains powers that cannot be downcast to u64: {:?}", event)) - ) + let powers: Vec = Vec::new(); + for power in event.powers { + if let Some(downcast_power) = downcast_to_u64(power) { + powers.push(downcast_power); + } else { + return Err(GravityError::InvalidEventLogError( + format!("ValsetUpdatedEvent contains powers that cannot be downcast to u64: {:?}", event)) + ) + } } let validators: Vec = powers.iter() From d86598345b8c23f9e88e7bfb1b4e0a3fdba7265d Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 8 Nov 2021 23:06:11 -0800 Subject: [PATCH 026/115] Make sure powers is mutable, add a TODO --- orchestrator/gravity_utils/src/types/ethereum_events.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 7bf748979..294448143 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -62,7 +62,7 @@ impl ValsetUpdatedEvent { pub fn from_log(input: &Log) -> Result { let event: ValsetUpdatedEventFilter = log_to_ethers_event(input)?; - let powers: Vec = Vec::new(); + let mut powers: Vec = Vec::new(); for power in event.powers { if let Some(downcast_power) = downcast_to_u64(power) { powers.push(downcast_power); @@ -87,6 +87,8 @@ impl ValsetUpdatedEvent { check.sort(); check.reverse(); // if the validator set is not sorted we're in a bad spot + // TODO(bolten): perhaps there is a better way to handle this than logging the event? + // what would the downstream effects of not returning a ValsetUpdatedEvent here? if validators != check { warn!( "Someone submitted an unsorted validator set, this means all updates will fail until someone feeds in this unsorted value by hand {:?} instead of {:?}", From d6d81c6d8c64c6c40b564f1771dffba001d7238f Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 9 Nov 2021 17:59:15 -0800 Subject: [PATCH 027/115] Move EthClient type and replace some uses of web3 --- orchestrator/ethereum_gravity/src/utils.rs | 2 ++ orchestrator/orchestrator/src/main_loop.rs | 4 +--- orchestrator/relayer/src/main_loop.rs | 17 ++++++----------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index a02ca21ee..7b785bd27 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -8,6 +8,8 @@ use sha3::{Digest, Keccak256}; use std::panic; use web30::{client::Web3, jsonrpc::error::Web3Error}; +pub type EthClient = Arc, LocalWallet>>; + pub fn get_checkpoint_abi_encode( valset: &Valset, gravity_id: &str, diff --git a/orchestrator/orchestrator/src/main_loop.rs b/orchestrator/orchestrator/src/main_loop.rs index 5cdd9a007..d71b42c3f 100644 --- a/orchestrator/orchestrator/src/main_loop.rs +++ b/orchestrator/orchestrator/src/main_loop.rs @@ -22,7 +22,7 @@ use deep_space::client::ChainStatus; use deep_space::error::CosmosGrpcError; use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::{Contact, Msg}; -use ethereum_gravity::utils::get_gravity_id; +use ethereum_gravity::utils::{EthClient, get_gravity_id}; use ethers::{prelude::*, types::Address as EthAddress}; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use relayer::main_loop::relayer_main_loop; @@ -37,8 +37,6 @@ use tokio::time::sleep as delay_for; use tonic::transport::Channel; use web30::client::Web3; -pub type EthClient = Arc, LocalWallet>>; - /// The execution speed governing all loops in this file /// which is to say all loops started by Orchestrator main /// loop except the relayer loop diff --git a/orchestrator/relayer/src/main_loop.rs b/orchestrator/relayer/src/main_loop.rs index 82499a5f6..5ba7da697 100644 --- a/orchestrator/relayer/src/main_loop.rs +++ b/orchestrator/relayer/src/main_loop.rs @@ -2,15 +2,13 @@ use crate::{ batch_relaying::relay_batches, find_latest_valset::find_latest_valset, logic_call_relaying::relay_logic_calls, valset_relaying::relay_valsets, }; -use ethereum_gravity::utils::get_gravity_id; +use ethereum_gravity::utils::{EthClient, get_gravity_id}; use ethers::{prelude::*, types::Address as EthAddress}; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use std::{sync::Arc, time::{Duration, Instant}}; use tokio::time::sleep as delay_for; use tonic::transport::Channel; -pub type EthClient = Arc, LocalWallet>>; - pub const LOOP_SPEED: Duration = Duration::from_secs(17); /// This function contains the orchestrator primary loop, it is broken out of the main loop so that @@ -27,7 +25,7 @@ pub async fn relayer_main_loop( let our_ethereum_address = eth_client.address(); let current_eth_valset = - find_latest_valset(&mut grpc_client, gravity_contract_address, &web3).await; + find_latest_valset(&mut grpc_client, gravity_contract_address, eth_client.clone()).await; if current_eth_valset.is_err() { error!("Could not get current valset! {:?}", current_eth_valset); continue; @@ -35,7 +33,7 @@ pub async fn relayer_main_loop( let current_eth_valset = current_eth_valset.unwrap(); let gravity_id = - get_gravity_id(gravity_contract_address, our_ethereum_address, &web3).await; + get_gravity_id(gravity_contract_address, our_ethereum_address, eth_client.clone()).await; if gravity_id.is_err() { error!("Failed to get GravityID, check your Eth node"); return; @@ -44,8 +42,7 @@ pub async fn relayer_main_loop( relay_valsets( current_eth_valset.clone(), - ethereum_key, - &web3, + eth_client.clone(), &mut grpc_client, gravity_contract_address, gravity_id.clone(), @@ -55,8 +52,7 @@ pub async fn relayer_main_loop( relay_batches( current_eth_valset.clone(), - ethereum_key, - &web3, + eth_client.clone(), &mut grpc_client, gravity_contract_address, gravity_id.clone(), @@ -67,8 +63,7 @@ pub async fn relayer_main_loop( relay_logic_calls( current_eth_valset, - ethereum_key, - &web3, + eth_client.clone(), &mut grpc_client, gravity_contract_address, gravity_id.clone(), From fbdeba00e24ace6fcfcdc15a0d7c282d2bd6babf Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 9 Nov 2021 18:00:16 -0800 Subject: [PATCH 028/115] Get the gravity_id using ethers contract --- orchestrator/ethereum_gravity/src/utils.rs | 28 +++++++++++++--------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 7b785bd27..c7c95b326 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -136,17 +136,23 @@ pub async fn get_event_nonce( pub async fn get_gravity_id( contract_address: EthAddress, caller_address: EthAddress, - web3: &Web3, -) -> Result { - let payload = encode_call("state_gravityId()", &[]).unwrap(); - let val = web3 - .simulate_transaction(contract_address, 0u8.into(), payload, caller_address, None) - .await?; - let gravity_id = String::from_utf8(val); - match gravity_id { - Ok(val) => Ok(val), - Err(e) => Err(Web3Error::BadResponse(e.to_string())), - } + eth_client: EthClient, +) -> Result { + const GAS_LIMIT: u128 = 12450000; // the most Hardhat will allow, will work on Geth + + let caller_balance = eth_client.get_balance(caller_address, None).await?; + let latest_block = eth_client.get_block(BlockNumber::Latest).await?; + let price = latest_block.base_fee_per_gas.ok_or(1u8.into()); // shouldn't happen unless pre-London + let limit = min(GAS_LIMIT.into(), caller_balance / price.clone()); + + let contract = Gravity::new(contract_address, eth_client); + let contract_call = contract.state_gravityId() + .from(caller_address) + .gas(limit.into()) + .gas_price(price.into()) + .value(0u8.into()); + + String::from_utf8(contract_call.call().await?) } /// Gets the ERC20 symbol, should maybe be upstreamed From 7e2a23c4c42dcd57c97b69c137c561ee0aaeffbc Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 9 Nov 2021 18:33:59 -0800 Subject: [PATCH 029/115] Make ethereum events DRY with traits, rustfmt --- .../src/types/ethereum_events.rs | 208 +++++++++--------- 1 file changed, 108 insertions(+), 100 deletions(-) diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 294448143..648ac316e 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -4,7 +4,7 @@ //! mirror Serde and perhaps even become a serde crate for Ethereum ABI decoding //! For now reference the ABI encoding document here https://docs.soliditylang.org/en/v0.8.3/abi-spec.html -use super::ValsetMember; +use super::{Valset, ValsetMember}; use crate::error::GravityError; use crate::ethereum::downcast_to_u64; use deep_space::utils::bytes_to_hex_str; @@ -14,11 +14,15 @@ use ethers::contract::abigen; use ethers::prelude::*; use ethers::types::Address as EthAddress; -pub const ERC20_DEPLOYED_EVENT_STR: &'static str = "ERC20DeployedEvent(string,address,string,string,uint8,uint256)"; +pub const ERC20_DEPLOYED_EVENT_STR: &'static str = + "ERC20DeployedEvent(string,address,string,string,uint8,uint256)"; pub const LOGIC_CALL_EVENT_STR: &'static str = "LogicCallEvent(bytes32,uint256,bytes,uint256)"; -pub const SEND_TO_COSMOS_EVENT_STR: &'static str = "SendToCosmosEvent(address,address,bytes32,uint256,uint256)"; -pub const TRANSACTION_BATCH_EXECUTED_EVENT_STR: &'static str = "TransactionBatchExecutedEvent(uint256,address,uint256)"; -pub const VALSET_UPDATED_EVENT_STR: &'static str = "ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"; +pub const SEND_TO_COSMOS_EVENT_STR: &'static str = + "SendToCosmosEvent(address,address,bytes32,uint256,uint256)"; +pub const TRANSACTION_BATCH_EXECUTED_EVENT_STR: &'static str = + "TransactionBatchExecutedEvent(uint256,address,uint256)"; +pub const VALSET_UPDATED_EVENT_STR: &'static str = + "ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"; abigen!( Gravity, @@ -32,7 +36,8 @@ fn log_to_ethers_event(log: &Log) -> Result(log: &Log) -> Result Result { match log.block_number.clone() { Some(block_height) => Ok(U256::from(block_height.as_u64())), - None => Err(GravityError::InvalidEventLogError( - format!("Log does not have block number, we only search logs already in blocks? {:?}", log)) - ) + None => Err(GravityError::InvalidEventLogError(format!( + "Log does not have block number, we only search logs already in blocks? {:?}", + log + ))), + } +} + +// some traits to avoid code duplication + +pub trait FromLog: Sized { + fn from_log(input: &Log) -> Result; +} + +pub trait FromLogWithPrefix: Sized { + fn from_log(input: &Log, prefix: &str) -> Result; +} + +pub trait EventNonce { + fn get_event_nonce(&self) -> U256; +} + +pub trait FromLogs { + fn from_logs(input: &[Log]) -> Result, GravityError> { + let mut res = Vec::new(); + for item in input { + res.push(T::from_log(item)?); + } + Ok(res) + } +} + +pub trait FromLogsWithPrefix { + fn from_logs( + input: &[Log], + prefix: &str, + ) -> Result, GravityError> { + let mut res = Vec::new(); + for item in input { + res.push(T::from_log(item, prefix)?); + } + Ok(res) + } +} + +pub trait EventNonceFilter: Sized { + /// returns all values in the array with event nonces greater + /// than the provided value + fn filter_by_event_nonce(event_nonce: u64, input: &[T]) -> Vec { + input + .iter() + .filter(|item| item.get_event_nonce() > event_nonce.into()) + .map(|item| *item.clone()) + .collect() } } @@ -56,10 +111,10 @@ pub struct ValsetUpdatedEvent { pub members: Vec, } -impl ValsetUpdatedEvent { +impl FromLog for ValsetUpdatedEvent { /// This function is not an abi compatible bytes parser, but it's actually /// not hard at all to extract data like this by hand. - pub fn from_log(input: &Log) -> Result { + fn from_log(input: &Log) -> Result { let event: ValsetUpdatedEventFilter = log_to_ethers_event(input)?; let mut powers: Vec = Vec::new(); @@ -67,19 +122,19 @@ impl ValsetUpdatedEvent { if let Some(downcast_power) = downcast_to_u64(power) { powers.push(downcast_power); } else { - return Err(GravityError::InvalidEventLogError( - format!("ValsetUpdatedEvent contains powers that cannot be downcast to u64: {:?}", event)) - ) + return Err(GravityError::InvalidEventLogError(format!( + "ValsetUpdatedEvent contains powers that cannot be downcast to u64: {:?}", + event + ))); } } - let validators: Vec = powers.iter() + let validators: Vec = powers + .iter() .zip(event.validators.iter()) - .map(|(power, validator)| { - ValsetMember { - power: *power, - eth_address: Some(*validator), - } + .map(|(power, validator)| ValsetMember { + power: *power, + eth_address: Some(*validator), }) .collect(); @@ -103,24 +158,15 @@ impl ValsetUpdatedEvent { members: validators, }) } +} - pub fn from_logs(input: &[Log]) -> Result, GravityError> { - let mut res = Vec::new(); - for item in input { - res.push(ValsetUpdatedEvent::from_log(item)?); - } - Ok(res) - } - - /// returns all values in the array with event nonces greater - /// than the provided value - pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { - input.iter() - .filter(|item| item.event_nonce > event_nonce.into()) - .map(|item| item.clone()) - .collect() +impl FromLogs for ValsetUpdatedEvent {} +impl EventNonce for ValsetUpdatedEvent { + fn get_event_nonce(&self) -> U256 { + self.event_nonce } } +impl EventNonceFilter for ValsetUpdatedEvent {} /// A parsed struct representing the Ethereum event fired by the Gravity contract when /// a transaction batch is executed. @@ -151,24 +197,15 @@ impl TransactionBatchExecutedEvent { event_nonce: event.event_nonce, }) } +} - pub fn from_logs(input: &[Log]) -> Result, GravityError> { - let mut res = Vec::new(); - for item in input { - res.push(TransactionBatchExecutedEvent::from_log(item)?); - } - Ok(res) - } - - /// returns all values in the array with event nonces greater - /// than the provided value - pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { - input.iter() - .filter(|item| item.event_nonce > event_nonce.into()) - .map(|item| item.clone()) - .collect() +impl FromLogs for TransactionBatchExecutedEvent {} +impl EventNonce for TransactionBatchExecutedEvent { + fn get_event_nonce(&self) -> U256 { + self.event_nonce } } +impl EventNonceFilter for TransactionBatchExecutedEvent {} /// A parsed struct representing the Ethereum event fired when someone makes a deposit /// on the Gravity contract @@ -188,8 +225,8 @@ pub struct SendToCosmosEvent { pub block_height: U256, } -impl SendToCosmosEvent { - pub fn from_log(input: &Log, prefix: &str) -> Result { +impl FromLogWithPrefix for SendToCosmosEvent { + fn from_log(input: &Log, prefix: &str) -> Result { let event: SendToCosmosEventFilter = log_to_ethers_event(input)?; // TODO(bolten): verify this method of retrieval for Cosmos addresses works as expected @@ -202,27 +239,15 @@ impl SendToCosmosEvent { block_height: block_height_from_log(&input)?, }) } +} - pub fn from_logs( - input: &[Log], - prefix: &str, - ) -> Result, GravityError> { - let mut res = Vec::new(); - for item in input { - res.push(Self::from_log(item, prefix)?); - } - Ok(res) - } - - /// returns all values in the array with event nonces greater - /// than the provided value - pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { - input.iter() - .filter(|item| item.event_nonce > event_nonce.into()) - .map(|item| item.clone()) - .collect() +impl FromLogsWithPrefix for SendToCosmosEvent {} +impl EventNonce for SendToCosmosEvent { + fn get_event_nonce(&self) -> U256 { + self.event_nonce } } +impl EventNonceFilter for SendToCosmosEvent {} /// A parsed struct representing the Ethereum event fired when someone uses the Gravity /// contract to deploy a new ERC20 contract representing a Cosmos asset @@ -258,24 +283,16 @@ impl Erc20DeployedEvent { block_height: block_height_from_log(&input)?, }) } +} - pub fn from_logs(input: &[Log]) -> Result, GravityError> { - let mut res = Vec::new(); - for item in input { - res.push(Erc20DeployedEvent::from_log(item)?); - } - Ok(res) - } - - /// returns all values in the array with event nonces greater - /// than the provided value - pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { - input.iter() - .filter(|item| item.event_nonce > event_nonce.into()) - .map(|item| item.clone()) - .collect() +impl FromLogs for Erc20DeployedEvent {} +impl EventNonce for Erc20DeployedEvent { + fn get_event_nonce(&self) -> U256 { + self.event_nonce } } +impl EventNonceFilter for Erc20DeployedEvent {} + /// A parsed struct representing the Ethereum event fired when someone uses the Gravity /// contract to deploy a new ERC20 contract representing a Cosmos asset #[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Hash)] @@ -299,24 +316,15 @@ impl LogicCallExecutedEvent { block_height: block_height_from_log(&input)?, }) } +} - pub fn from_logs(input: &[Log]) -> Result, GravityError> { - let mut res = Vec::new(); - for item in input { - res.push(LogicCallExecutedEvent::from_log(item)?); - } - Ok(res) - } - - /// returns all values in the array with event nonces greater - /// than the provided value - pub fn filter_by_event_nonce(event_nonce: u64, input: &[Self]) -> Vec { - input.iter() - .filter(|item| item.event_nonce > event_nonce.into()) - .map(|item| item.clone()) - .collect() +impl FromLogs for LogicCallExecutedEvent {} +impl EventNonce for LogicCallExecutedEvent { + fn get_event_nonce(&self) -> U256 { + self.event_nonce } } +impl EventNonceFilter for LogicCallExecutedEvent {} /// Function used for debug printing hex dumps /// of ethereum events From 7071604ceebe14718dd1cbae79683fa249ab2025 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 9 Nov 2021 19:09:46 -0800 Subject: [PATCH 030/115] Swap out abigen! for generated code from Gravity --- orchestrator/ethereum_gravity/src/utils.rs | 10 +- orchestrator/gravity_utils/src/gravity.rs | 514 ++++++++++++++++++ orchestrator/gravity_utils/src/lib.rs | 1 + .../src/types/ethereum_events.rs | 8 +- 4 files changed, 522 insertions(+), 11 deletions(-) create mode 100644 orchestrator/gravity_utils/src/gravity.rs diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index c7c95b326..57706c767 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -3,12 +3,14 @@ use clarity::Uint256; use clarity::{abi::encode_tokens, Address as EthAddress}; use ethers::prelude::*; use gravity_utils::error::GravityError; +use gravity_utils::gravity::*; use gravity_utils::types::*; use sha3::{Digest, Keccak256}; use std::panic; use web30::{client::Web3, jsonrpc::error::Web3Error}; -pub type EthClient = Arc, LocalWallet>>; +pub type EthSignerMiddleware = SignerMiddleware, LocalWallet>; +pub type EthClient = Arc; pub fn get_checkpoint_abi_encode( valset: &Valset, @@ -145,14 +147,14 @@ pub async fn get_gravity_id( let price = latest_block.base_fee_per_gas.ok_or(1u8.into()); // shouldn't happen unless pre-London let limit = min(GAS_LIMIT.into(), caller_balance / price.clone()); - let contract = Gravity::new(contract_address, eth_client); - let contract_call = contract.state_gravityId() + let contract: Gravity = Gravity::new(contract_address, eth_client); + let contract_call = contract.state_gravity_id() .from(caller_address) .gas(limit.into()) .gas_price(price.into()) .value(0u8.into()); - String::from_utf8(contract_call.call().await?) + String::from_utf8(contract_call.call().await?.to_vec()) } /// Gets the ERC20 symbol, should maybe be upstreamed diff --git a/orchestrator/gravity_utils/src/gravity.rs b/orchestrator/gravity_utils/src/gravity.rs new file mode 100644 index 000000000..4ead5a8f9 --- /dev/null +++ b/orchestrator/gravity_utils/src/gravity.rs @@ -0,0 +1,514 @@ +pub use gravity_mod::*; +#[allow(clippy::too_many_arguments)] +mod gravity_mod { + #![allow(clippy::enum_variant_names)] + #![allow(dead_code)] + #![allow(clippy::type_complexity)] + #![allow(unused_imports)] + use ethers::contract::{ + builders::{ContractCall, Event}, + Contract, Lazy, + }; + use ethers::core::{ + abi::{Abi, Detokenize, InvalidOutputType, Token, Tokenizable}, + types::*, + }; + use ethers::providers::Middleware; + #[doc = "Gravity was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs"] + use std::sync::Arc; + pub static GRAVITY_ABI: ethers::contract::Lazy = + ethers::contract::Lazy::new(|| { + serde_json :: from_str ("[\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"_gravityId\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"_powerThreshold\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"_validators\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"_powers\",\n \"type\": \"uint256[]\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"constructor\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"string\",\n \"name\": \"_cosmosDenom\",\n \"type\": \"string\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"_tokenContract\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"string\",\n \"name\": \"_name\",\n \"type\": \"string\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"string\",\n \"name\": \"_symbol\",\n \"type\": \"string\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"_decimals\",\n \"type\": \"uint8\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"_eventNonce\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"ERC20DeployedEvent\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": false,\n \"internalType\": \"bytes32\",\n \"name\": \"_invalidationId\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"_invalidationNonce\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes\",\n \"name\": \"_returnData\",\n \"type\": \"bytes\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"_eventNonce\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"LogicCallEvent\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"_tokenContract\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"_sender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"bytes32\",\n \"name\": \"_destination\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"_amount\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"_eventNonce\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"SendToCosmosEvent\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"_batchNonce\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"_token\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"_eventNonce\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"TransactionBatchExecutedEvent\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"uint256\",\n \"name\": \"_newValsetNonce\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"_eventNonce\",\n \"type\": \"uint256\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address[]\",\n \"name\": \"_validators\",\n \"type\": \"address[]\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256[]\",\n \"name\": \"_powers\",\n \"type\": \"uint256[]\"\n }\n ],\n \"name\": \"ValsetUpdatedEvent\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"_cosmosDenom\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"_name\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"_symbol\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"_decimals\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"deployERC20\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"_erc20Address\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"lastBatchNonce\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"_invalidation_id\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"lastLogicCallNonce\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"_tokenContract\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"_destination\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"_amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"sendToCosmos\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"state_gravityId\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"state_invalidationMapping\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"state_lastBatchNonces\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"state_lastEventNonce\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"state_lastValsetCheckpoint\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"\",\n \"type\": \"bytes32\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"state_lastValsetNonce\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"state_powerThreshold\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"_currentValidators\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"_currentPowers\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"_currentValsetNonce\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint8[]\",\n \"name\": \"_v\",\n \"type\": \"uint8[]\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"_r\",\n \"type\": \"bytes32[]\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"_s\",\n \"type\": \"bytes32[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"_amounts\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"_destinations\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"_fees\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"_batchNonce\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"_tokenContract\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"_batchTimeout\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"submitBatch\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"_currentValidators\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"_currentPowers\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"_currentValsetNonce\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint8[]\",\n \"name\": \"_v\",\n \"type\": \"uint8[]\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"_r\",\n \"type\": \"bytes32[]\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"_s\",\n \"type\": \"bytes32[]\"\n },\n {\n \"components\": [\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"transferAmounts\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"transferTokenContracts\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"feeAmounts\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"feeTokenContracts\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"logicContractAddress\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"bytes\",\n \"name\": \"payload\",\n \"type\": \"bytes\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"timeOut\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"invalidationId\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"invalidationNonce\",\n \"type\": \"uint256\"\n }\n ],\n \"internalType\": \"struct LogicCallArgs\",\n \"name\": \"_args\",\n \"type\": \"tuple\"\n }\n ],\n \"name\": \"submitLogicCall\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"_currentValidators\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"_currentPowers\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint8[]\",\n \"name\": \"_v\",\n \"type\": \"uint8[]\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"_r\",\n \"type\": \"bytes32[]\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"_s\",\n \"type\": \"bytes32[]\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"_theHash\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"_powerThreshold\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"testCheckValidatorSignatures\",\n \"outputs\": [],\n \"stateMutability\": \"pure\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"_validators\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"_powers\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"_valsetNonce\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"bytes32\",\n \"name\": \"_gravityId\",\n \"type\": \"bytes32\"\n }\n ],\n \"name\": \"testMakeCheckpoint\",\n \"outputs\": [],\n \"stateMutability\": \"pure\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"_newValidators\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"_newPowers\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"_newValsetNonce\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"address[]\",\n \"name\": \"_currentValidators\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"uint256[]\",\n \"name\": \"_currentPowers\",\n \"type\": \"uint256[]\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"_currentValsetNonce\",\n \"type\": \"uint256\"\n },\n {\n \"internalType\": \"uint8[]\",\n \"name\": \"_v\",\n \"type\": \"uint8[]\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"_r\",\n \"type\": \"bytes32[]\"\n },\n {\n \"internalType\": \"bytes32[]\",\n \"name\": \"_s\",\n \"type\": \"bytes32[]\"\n }\n ],\n \"name\": \"updateValset\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n]\n") . expect ("invalid abi") + }); + #[derive(Clone)] + pub struct Gravity(ethers::contract::Contract); + impl std::ops::Deref for Gravity { + type Target = ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl std::fmt::Debug for Gravity { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_tuple(stringify!(Gravity)) + .field(&self.address()) + .finish() + } + } + impl<'a, M: ethers::providers::Middleware> Gravity { + #[doc = r" Creates a new contract instance with the specified `ethers`"] + #[doc = r" client at the given `Address`. The contract derefs to a `ethers::Contract`"] + #[doc = r" object"] + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + let contract = + ethers::contract::Contract::new(address.into(), GRAVITY_ABI.clone(), client); + Self(contract) + } + #[doc = "Calls the contract's `deployERC20` (0xf7955637) function"] + pub fn deploy_erc20( + &self, + cosmos_denom: String, + name: String, + symbol: String, + decimals: u8, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([247, 149, 86, 55], (cosmos_denom, name, symbol, decimals)) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `lastBatchNonce` (0x011b2174) function"] + pub fn last_batch_nonce( + &self, + erc_20_address: ethers::core::types::Address, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([1, 27, 33, 116], erc_20_address) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `lastLogicCallNonce` (0xc9d194d5) function"] + pub fn last_logic_call_nonce( + &self, + invalidation_id: [u8; 32], + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([201, 209, 148, 213], invalidation_id) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `sendToCosmos` (0x1ffbe7f9) function"] + pub fn send_to_cosmos( + &self, + token_contract: ethers::core::types::Address, + destination: [u8; 32], + amount: ethers::core::types::U256, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([31, 251, 231, 249], (token_contract, destination, amount)) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `state_gravityId` (0xbdda81d4) function"] + pub fn state_gravity_id(&self) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([189, 218, 129, 212], ()) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `state_invalidationMapping` (0x7dfb6f86) function"] + pub fn state_invalidation_mapping( + &self, + p0: [u8; 32], + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([125, 251, 111, 134], p0) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `state_lastBatchNonces` (0xdf97174b) function"] + pub fn state_last_batch_nonces( + &self, + p0: ethers::core::types::Address, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([223, 151, 23, 75], p0) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `state_lastEventNonce` (0x73b20547) function"] + pub fn state_last_event_nonce( + &self, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([115, 178, 5, 71], ()) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `state_lastValsetCheckpoint` (0xf2b53307) function"] + pub fn state_last_valset_checkpoint( + &self, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([242, 181, 51, 7], ()) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `state_lastValsetNonce` (0xb56561fe) function"] + pub fn state_last_valset_nonce( + &self, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([181, 101, 97, 254], ()) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `state_powerThreshold` (0xe5a2b5d2) function"] + pub fn state_power_threshold( + &self, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([229, 162, 181, 210], ()) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `submitBatch` (0x83b435db) function"] + pub fn submit_batch( + &self, + current_validators: ::std::vec::Vec, + current_powers: ::std::vec::Vec, + current_valset_nonce: ethers::core::types::U256, + v: ::std::vec::Vec, + r: ::std::vec::Vec<[u8; 32]>, + s: ::std::vec::Vec<[u8; 32]>, + amounts: ::std::vec::Vec, + destinations: ::std::vec::Vec, + fees: ::std::vec::Vec, + batch_nonce: ethers::core::types::U256, + token_contract: ethers::core::types::Address, + batch_timeout: ethers::core::types::U256, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash( + [131, 180, 53, 219], + ( + current_validators, + current_powers, + current_valset_nonce, + v, + r, + s, + amounts, + destinations, + fees, + batch_nonce, + token_contract, + batch_timeout, + ), + ) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `submitLogicCall` (0x0c246c82) function"] + pub fn submit_logic_call( + &self, + current_validators: ::std::vec::Vec, + current_powers: ::std::vec::Vec, + current_valset_nonce: ethers::core::types::U256, + v: ::std::vec::Vec, + r: ::std::vec::Vec<[u8; 32]>, + s: ::std::vec::Vec<[u8; 32]>, + args: LogicCallArgs, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash( + [12, 36, 108, 130], + ( + current_validators, + current_powers, + current_valset_nonce, + v, + r, + s, + args, + ), + ) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `testCheckValidatorSignatures` (0xdb7c4e57) function"] + pub fn test_check_validator_signatures( + &self, + current_validators: ::std::vec::Vec, + current_powers: ::std::vec::Vec, + v: ::std::vec::Vec, + r: ::std::vec::Vec<[u8; 32]>, + s: ::std::vec::Vec<[u8; 32]>, + the_hash: [u8; 32], + power_threshold: ethers::core::types::U256, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash( + [219, 124, 78, 87], + ( + current_validators, + current_powers, + v, + r, + s, + the_hash, + power_threshold, + ), + ) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `testMakeCheckpoint` (0xc227c30b) function"] + pub fn test_make_checkpoint( + &self, + validators: ::std::vec::Vec, + powers: ::std::vec::Vec, + valset_nonce: ethers::core::types::U256, + gravity_id: [u8; 32], + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash( + [194, 39, 195, 11], + (validators, powers, valset_nonce, gravity_id), + ) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `updateValset` (0xe3cb9f62) function"] + pub fn update_valset( + &self, + new_validators: ::std::vec::Vec, + new_powers: ::std::vec::Vec, + new_valset_nonce: ethers::core::types::U256, + current_validators: ::std::vec::Vec, + current_powers: ::std::vec::Vec, + current_valset_nonce: ethers::core::types::U256, + v: ::std::vec::Vec, + r: ::std::vec::Vec<[u8; 32]>, + s: ::std::vec::Vec<[u8; 32]>, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash( + [227, 203, 159, 98], + ( + new_validators, + new_powers, + new_valset_nonce, + current_validators, + current_powers, + current_valset_nonce, + v, + r, + s, + ), + ) + .expect("method not found (this should never happen)") + } + #[doc = "Gets the contract's `ERC20DeployedEvent` event"] + pub fn erc20_deployed_event_filter( + &self, + ) -> ethers::contract::builders::Event { + self.0.event() + } + #[doc = "Gets the contract's `LogicCallEvent` event"] + pub fn logic_call_event_filter( + &self, + ) -> ethers::contract::builders::Event { + self.0.event() + } + #[doc = "Gets the contract's `SendToCosmosEvent` event"] + pub fn send_to_cosmos_event_filter( + &self, + ) -> ethers::contract::builders::Event { + self.0.event() + } + #[doc = "Gets the contract's `TransactionBatchExecutedEvent` event"] + pub fn transaction_batch_executed_event_filter( + &self, + ) -> ethers::contract::builders::Event { + self.0.event() + } + #[doc = "Gets the contract's `ValsetUpdatedEvent` event"] + pub fn valset_updated_event_filter( + &self, + ) -> ethers::contract::builders::Event { + self.0.event() + } + #[doc = r" Returns an [`Event`](#ethers_contract::builders::Event) builder for all events of this contract"] + pub fn events(&self) -> ethers::contract::builders::Event { + self.0.event_with_filter(Default::default()) + } + } + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthEvent, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethevent( + name = "ERC20DeployedEvent", + abi = "ERC20DeployedEvent(string,address,string,string,uint8,uint256)" + )] + pub struct Erc20DeployedEventFilter { + pub cosmos_denom: String, + #[ethevent(indexed)] + pub token_contract: ethers::core::types::Address, + pub name: String, + pub symbol: String, + pub decimals: u8, + pub event_nonce: ethers::core::types::U256, + } + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthEvent, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethevent( + name = "LogicCallEvent", + abi = "LogicCallEvent(bytes32,uint256,bytes,uint256)" + )] + pub struct LogicCallEventFilter { + pub invalidation_id: [u8; 32], + pub invalidation_nonce: ethers::core::types::U256, + pub return_data: Vec, + pub event_nonce: ethers::core::types::U256, + } + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthEvent, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethevent( + name = "SendToCosmosEvent", + abi = "SendToCosmosEvent(address,address,bytes32,uint256,uint256)" + )] + pub struct SendToCosmosEventFilter { + #[ethevent(indexed)] + pub token_contract: ethers::core::types::Address, + #[ethevent(indexed)] + pub sender: ethers::core::types::Address, + #[ethevent(indexed)] + pub destination: [u8; 32], + pub amount: ethers::core::types::U256, + pub event_nonce: ethers::core::types::U256, + } + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthEvent, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethevent( + name = "TransactionBatchExecutedEvent", + abi = "TransactionBatchExecutedEvent(uint256,address,uint256)" + )] + pub struct TransactionBatchExecutedEventFilter { + #[ethevent(indexed)] + pub batch_nonce: ethers::core::types::U256, + #[ethevent(indexed)] + pub token: ethers::core::types::Address, + pub event_nonce: ethers::core::types::U256, + } + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthEvent, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethevent( + name = "ValsetUpdatedEvent", + abi = "ValsetUpdatedEvent(uint256,uint256,address[],uint256[])" + )] + pub struct ValsetUpdatedEventFilter { + #[ethevent(indexed)] + pub new_valset_nonce: ethers::core::types::U256, + pub event_nonce: ethers::core::types::U256, + pub validators: Vec, + pub powers: Vec, + } + #[derive(Debug, Clone, PartialEq, Eq)] + pub enum GravityEvents { + Erc20DeployedEventFilter(Erc20DeployedEventFilter), + LogicCallEventFilter(LogicCallEventFilter), + SendToCosmosEventFilter(SendToCosmosEventFilter), + TransactionBatchExecutedEventFilter(TransactionBatchExecutedEventFilter), + ValsetUpdatedEventFilter(ValsetUpdatedEventFilter), + } + impl ethers::core::abi::Tokenizable for GravityEvents { + fn from_token( + token: ethers::core::abi::Token, + ) -> Result + where + Self: Sized, + { + if let Ok(decoded) = Erc20DeployedEventFilter::from_token(token.clone()) { + return Ok(GravityEvents::Erc20DeployedEventFilter(decoded)); + } + if let Ok(decoded) = LogicCallEventFilter::from_token(token.clone()) { + return Ok(GravityEvents::LogicCallEventFilter(decoded)); + } + if let Ok(decoded) = SendToCosmosEventFilter::from_token(token.clone()) { + return Ok(GravityEvents::SendToCosmosEventFilter(decoded)); + } + if let Ok(decoded) = TransactionBatchExecutedEventFilter::from_token(token.clone()) { + return Ok(GravityEvents::TransactionBatchExecutedEventFilter(decoded)); + } + if let Ok(decoded) = ValsetUpdatedEventFilter::from_token(token.clone()) { + return Ok(GravityEvents::ValsetUpdatedEventFilter(decoded)); + } + Err(ethers::core::abi::InvalidOutputType( + "Failed to decode all event variants".to_string(), + )) + } + fn into_token(self) -> ethers::core::abi::Token { + match self { + GravityEvents::Erc20DeployedEventFilter(element) => element.into_token(), + GravityEvents::LogicCallEventFilter(element) => element.into_token(), + GravityEvents::SendToCosmosEventFilter(element) => element.into_token(), + GravityEvents::TransactionBatchExecutedEventFilter(element) => element.into_token(), + GravityEvents::ValsetUpdatedEventFilter(element) => element.into_token(), + } + } + } + impl ethers::core::abi::TokenizableItem for GravityEvents {} + impl ethers::contract::EthLogDecode for GravityEvents { + fn decode_log(log: ðers::core::abi::RawLog) -> Result + where + Self: Sized, + { + if let Ok(decoded) = Erc20DeployedEventFilter::decode_log(log) { + return Ok(GravityEvents::Erc20DeployedEventFilter(decoded)); + } + if let Ok(decoded) = LogicCallEventFilter::decode_log(log) { + return Ok(GravityEvents::LogicCallEventFilter(decoded)); + } + if let Ok(decoded) = SendToCosmosEventFilter::decode_log(log) { + return Ok(GravityEvents::SendToCosmosEventFilter(decoded)); + } + if let Ok(decoded) = TransactionBatchExecutedEventFilter::decode_log(log) { + return Ok(GravityEvents::TransactionBatchExecutedEventFilter(decoded)); + } + if let Ok(decoded) = ValsetUpdatedEventFilter::decode_log(log) { + return Ok(GravityEvents::ValsetUpdatedEventFilter(decoded)); + } + Err(ethers::core::abi::Error::InvalidData) + } + } + #[doc = "`LogicCallArgs(uint256[],address[],uint256[],address[],address,bytes,uint256,bytes32,uint256)`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthAbiType, + serde :: Deserialize, + serde :: Serialize, + )] + pub struct LogicCallArgs { + pub transfer_amounts: Vec, + pub transfer_token_contracts: Vec, + pub fee_amounts: Vec, + pub fee_token_contracts: Vec, + pub logic_contract_address: ethers::core::types::Address, + pub payload: Vec, + pub time_out: ethers::core::types::U256, + pub invalidation_id: [u8; 32], + pub invalidation_nonce: ethers::core::types::U256, + } +} diff --git a/orchestrator/gravity_utils/src/lib.rs b/orchestrator/gravity_utils/src/lib.rs index 55f465d56..f1247857c 100644 --- a/orchestrator/gravity_utils/src/lib.rs +++ b/orchestrator/gravity_utils/src/lib.rs @@ -8,5 +8,6 @@ extern crate log; pub mod connection_prep; pub mod error; pub mod ethereum; +pub mod gravity; pub mod message_signatures; pub mod types; diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 648ac316e..3023a3dba 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -7,10 +7,10 @@ use super::{Valset, ValsetMember}; use crate::error::GravityError; use crate::ethereum::downcast_to_u64; +use crate::gravity::*; use deep_space::utils::bytes_to_hex_str; use deep_space::Address as CosmosAddress; use ethers::abi::RawLog; -use ethers::contract::abigen; use ethers::prelude::*; use ethers::types::Address as EthAddress; @@ -24,12 +24,6 @@ pub const TRANSACTION_BATCH_EXECUTED_EVENT_STR: &'static str = pub const VALSET_UPDATED_EVENT_STR: &'static str = "ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"; -abigen!( - Gravity, - "abi/Gravity.json", - event_derives(serde::Deserialize, serde::Serialize) -); - // given a Log retrieved by querying the Ethereum chain, decode it into one of // the types we are generating using abigen! above for the Gravity contract fn log_to_ethers_event(log: &Log) -> Result { From c7180c4060d61a2189eb3b314c4b9286088cf29c Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 9 Nov 2021 22:14:52 -0800 Subject: [PATCH 031/115] Add module for building the gravity.rs file --- orchestrator/Cargo.lock | 11 +++++++++++ orchestrator/Cargo.toml | 4 +++- orchestrator/abi_build/Cargo.toml | 12 ++++++++++++ orchestrator/abi_build/src/main.rs | 29 +++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 orchestrator/abi_build/Cargo.toml create mode 100644 orchestrator/abi_build/src/main.rs diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index 716751478..4f5498377 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -12,6 +12,16 @@ dependencies = [ "regex", ] +[[package]] +name = "abi_build" +version = "0.1.0" +dependencies = [ + "ethers", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "abscissa_core" version = "0.6.0-beta.1" @@ -2176,6 +2186,7 @@ dependencies = [ name = "gravity_bridge" version = "0.1.0" dependencies = [ + "abi_build", "cosmos_gravity", "ethereum_gravity", "gorc", diff --git a/orchestrator/Cargo.toml b/orchestrator/Cargo.toml index e1918c182..14376c51d 100644 --- a/orchestrator/Cargo.toml +++ b/orchestrator/Cargo.toml @@ -24,6 +24,7 @@ members = [ "relayer", "register_delegate_keys", "gorc", + "abi_build", ] [dependencies] @@ -36,4 +37,5 @@ test_runner = { path = "./test_runner" } gravity_proto = { path = "./gravity_proto" } register_delegate_keys = { path = "./register_delegate_keys" } gorc = { path = "./gorc" } -relayer = { path = "./relayer" } \ No newline at end of file +relayer = { path = "./relayer" } +abi_build = { path = "./abi_build" } diff --git a/orchestrator/abi_build/Cargo.toml b/orchestrator/abi_build/Cargo.toml new file mode 100644 index 000000000..02f1f3d9a --- /dev/null +++ b/orchestrator/abi_build/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "abi_build" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ethers = { version = "0.5.4", features=["abigen"] } +serde_derive = "1.0" +serde_json = "1.0.69" +serde = "1.0" diff --git a/orchestrator/abi_build/src/main.rs b/orchestrator/abi_build/src/main.rs new file mode 100644 index 000000000..d4c13bca4 --- /dev/null +++ b/orchestrator/abi_build/src/main.rs @@ -0,0 +1,29 @@ +use ethers::contract::Abigen; +use std::process; + +fn main() { + let abigen = match Abigen::new("Gravity", "../abi/Gravity.json") { + Ok(abigen) => abigen, + Err(e) => { + println!("Could not open Gravity.json: {}", e); + process::exit(1); + } + }; + + let abi = match abigen + .add_event_derive("serde::Deserialize") + .add_event_derive("serde::Serialize") + .generate() + { + Ok(abi) => abi, + Err(e) => { + println!("Could not generate abi from Gravity.json: {}", e); + process::exit(1); + } + }; + + match abi.write_to_file("../gravity_utils/src/gravity.rs") { + Ok(_) => (), + Err(e) => println!("Error writing gravity.rs: {}", e), + } +} From fc4cfd557a7590a394fef72c2f0d655b4157b6f3 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 9 Nov 2021 23:15:14 -0800 Subject: [PATCH 032/115] WIP: Start converting relay_valsets Also, implement the tokenization of the valset checkpoint message using ethers --- orchestrator/cosmos_gravity/src/query.rs | 2 +- .../ethereum_gravity/src/valset_update.rs | 3 +-- .../gravity_utils/src/message_signatures.rs | 20 +++++++++++-------- .../gravity_utils/src/types/valsets.rs | 2 +- orchestrator/relayer/src/valset_relaying.rs | 13 +++++------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/orchestrator/cosmos_gravity/src/query.rs b/orchestrator/cosmos_gravity/src/query.rs index e40eb7144..dac78bd57 100644 --- a/orchestrator/cosmos_gravity/src/query.rs +++ b/orchestrator/cosmos_gravity/src/query.rs @@ -1,5 +1,5 @@ -use clarity::Address as EthAddress; use deep_space::address::Address; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_proto::gravity::*; use gravity_utils::error::GravityError; diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index b99dc238a..c4159e725 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -72,10 +72,9 @@ pub async fn estimate_valset_cost( new_valset: &Valset, old_valset: &Valset, confirms: &[ValsetConfirmResponse], - web3: &Web3, + eth_client: EthClient, gravity_contract_address: EthAddress, gravity_id: String, - our_eth_key: EthPrivateKey, ) -> Result { let our_eth_address = our_eth_key.to_public_key().unwrap(); let our_balance = web3.eth_get_balance(our_eth_address).await?; diff --git a/orchestrator/gravity_utils/src/message_signatures.rs b/orchestrator/gravity_utils/src/message_signatures.rs index 91b96e3b5..23d8bcff0 100644 --- a/orchestrator/gravity_utils/src/message_signatures.rs +++ b/orchestrator/gravity_utils/src/message_signatures.rs @@ -1,6 +1,7 @@ use crate::types::{LogicCall, TransactionBatch, Valset}; -use clarity::abi::{encode_tokens, Token}; use clarity::utils::get_ethereum_msg_hash; +use ethers::core::abi::{self, Token}; +use ethers::utils::hash_message; /// takes the required input data and produces the required signature to confirm a validator /// set update on the Gravity Ethereum contract. This value will then be signed before being @@ -9,18 +10,21 @@ use clarity::utils::get_ethereum_msg_hash; /// digest that is normally signed or may be used as a 'hash of the message' pub fn encode_valset_confirm(gravity_id: String, valset: Valset) -> Vec { let (eth_addresses, powers) = valset.filter_empty_addresses(); - encode_tokens(&[ - Token::FixedString(gravity_id), - Token::FixedString("checkpoint".to_string()), - valset.nonce.into(), - eth_addresses.into(), - powers.into(), + let eth_addresses = eth_addresses.iter().map (|address| Token::Address(*address)).collect(); + let powers = powers.iter().map(|power| Token::Uint((*power).into())).collect(); + + abi::encode(&[ + Token::FixedBytes(gravity_id.into_bytes()), + Token::FixedBytes("checkpoint".to_string().into_bytes()), + Token::Uint(valset.nonce.into()), + Token::Array(eth_addresses), + Token::Array(powers), ]) } pub fn encode_valset_confirm_hashed(gravity_id: String, valset: Valset) -> Vec { let digest = encode_valset_confirm(gravity_id, valset); - get_ethereum_msg_hash(&digest) + hash_message(digest).as_bytes().to_vec() } #[test] diff --git a/orchestrator/gravity_utils/src/types/valsets.rs b/orchestrator/gravity_utils/src/types/valsets.rs index 7f87bba5b..d0c885c32 100644 --- a/orchestrator/gravity_utils/src/types/valsets.rs +++ b/orchestrator/gravity_utils/src/types/valsets.rs @@ -101,7 +101,7 @@ impl Valset { powers.push(val.power); } None => { - addresses.push(EthAddress::default()); + addresses.push(EthAddress::zero()); powers.push(val.power); } } diff --git a/orchestrator/relayer/src/valset_relaying.rs b/orchestrator/relayer/src/valset_relaying.rs index 9e011a05f..0478cb283 100644 --- a/orchestrator/relayer/src/valset_relaying.rs +++ b/orchestrator/relayer/src/valset_relaying.rs @@ -3,14 +3,13 @@ use std::time::Duration; -use clarity::address::Address as EthAddress; use clarity::utils::bytes_to_hex_str; -use clarity::PrivateKey as EthPrivateKey; use cosmos_gravity::query::get_latest_valset; use cosmos_gravity::query::{get_all_valset_confirms, get_valset}; -use ethereum_gravity::{one_eth, utils::downcast_to_u128, valset_update::send_eth_valset_update}; +use ethereum_gravity::{one_eth, valset_update::send_eth_valset_update}; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use gravity_utils::{message_signatures::encode_valset_confirm_hashed, types::Valset}; +use gravity_utils::{ethereum::downcast_to_u128, message_signatures::encode_valset_confirm_hashed, types::Valset}; use tonic::transport::Channel; use web30::client::Web3; @@ -19,8 +18,7 @@ use web30::client::Web3; pub async fn relay_valsets( // the validator set currently in the contract on Ethereum current_eth_valset: Valset, - ethereum_key: EthPrivateKey, - web3: &Web3, + eth_client: EthClient, grpc_client: &mut GravityQueryClient, gravity_contract_address: EthAddress, gravity_id: String, @@ -132,10 +130,9 @@ pub async fn relay_valsets( &latest_cosmos_valset, ¤t_eth_valset, &latest_cosmos_confirmed, - web3, + eth_client.clone(), gravity_contract_address, gravity_id.clone(), - ethereum_key, ) .await; if cost.is_err() { From f6a573d12064a302690b0f63c6eb5f3048c0e438 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 10 Nov 2021 21:56:13 -0800 Subject: [PATCH 033/115] WIP: message signature enconding, erc 20 token --- orchestrator/Cargo.lock | 1 + orchestrator/gravity_utils/Cargo.toml | 1 + orchestrator/gravity_utils/src/error.rs | 18 ++++++ .../gravity_utils/src/message_signatures.rs | 64 +++++++++---------- .../gravity_utils/src/types/batches.rs | 15 +++-- .../gravity_utils/src/types/logic_call.rs | 3 +- orchestrator/gravity_utils/src/types/mod.rs | 11 ++-- 7 files changed, 66 insertions(+), 47 deletions(-) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index 4f5498377..8319608d7 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -2220,6 +2220,7 @@ dependencies = [ "deep_space 2.4.7", "ethers", "gravity_proto", + "hex", "log", "num-bigint 0.4.0", "num256", diff --git a/orchestrator/gravity_utils/Cargo.toml b/orchestrator/gravity_utils/Cargo.toml index 6cc85b369..9652a8e4f 100644 --- a/orchestrator/gravity_utils/Cargo.toml +++ b/orchestrator/gravity_utils/Cargo.toml @@ -23,6 +23,7 @@ num-bigint = "0.4" log = "0.4" url = "2" sha3 = "0.9" +hex = { version = "0.4.3", default-features = false, features = ["std"] } [dev_dependencies] rand = "0.8" actix = "0.11" diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index fda2c4d72..c51f8afb5 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -5,8 +5,10 @@ use clarity::Error as ClarityError; use deep_space::error::AddressError as CosmosAddressError; use deep_space::error::CosmosGrpcError; use ethers::abi::Error as EthersAbiError; +use ethers::abi::ethereum_types::FromDecStrErr as EthersParseUintError; use ethers::prelude::*; use ethers::prelude::signer::SignerMiddlewareError; +use hex::FromHexError; use num_bigint::ParseBigIntError; use std::fmt::{self, Debug}; use tokio::time::error::Elapsed; @@ -20,6 +22,8 @@ pub enum GravityError { CosmosAddressError(CosmosAddressError), EthereumRestError(SignerMiddlewareError, LocalWallet>), EthersAbiError(EthersAbiError), + EthersParseAddressError(FromHexError), + EthersParseUintError(EthersParseUintError), InvalidBridgeStateError(String), FailedToUpdateValset, EthereumContractError(String), @@ -43,6 +47,8 @@ impl fmt::Display for GravityError { GravityError::CosmosAddressError(val) => write!(f, "Cosmos Address error {}", val), GravityError::EthereumRestError(val) => write!(f, "Ethereum REST error {}", val), GravityError::EthersAbiError(val) => write!(f, "Ethers ABI error {}", val), + GravityError::EthersParseAddressError(val) => write!(f, "Ethers H160 address parse error {}", val), + GravityError::EthersParseUintError(val) => write!(f, "Ethers U256 parse error {}", val), GravityError::InvalidOptionsError(val) => { write!(f, "Invalid TX options for this call {}", val) } @@ -96,6 +102,18 @@ impl From for GravityError { } } +impl From for GravityError { + fn from(error: EthersParseAddressError) -> Self { + GravityError::EthersParseAddressError(error) + } +} + +impl From for GravityError { + fn from(error: EthersParseUintError) -> Self { + GravityError::EthersParseUintError(error) + } +} + impl From for GravityError { fn from(error: Status) -> Self { GravityError::GravityGrpcError(error) diff --git a/orchestrator/gravity_utils/src/message_signatures.rs b/orchestrator/gravity_utils/src/message_signatures.rs index 23d8bcff0..b8efc0fef 100644 --- a/orchestrator/gravity_utils/src/message_signatures.rs +++ b/orchestrator/gravity_utils/src/message_signatures.rs @@ -1,5 +1,4 @@ use crate::types::{LogicCall, TransactionBatch, Valset}; -use clarity::utils::get_ethereum_msg_hash; use ethers::core::abi::{self, Token}; use ethers::utils::hash_message; @@ -113,21 +112,22 @@ fn test_valset_signature() { /// digest that is normally signed or may be used as a 'hash of the message' pub fn encode_tx_batch_confirm(gravity_id: String, batch: TransactionBatch) -> Vec { let (amounts, destinations, fees) = batch.get_checkpoint_values(); - encode_tokens(&[ - Token::FixedString(gravity_id), - Token::FixedString("transactionBatch".to_string()), + + abi::encode(&[ + Token::FixedBytes(gravity_id.into_bytes()), + Token::FixedBytes("transactionBatch".to_string().into_bytes()), amounts, destinations, fees, - batch.nonce.into(), - batch.token_contract.into(), - batch.batch_timeout.into(), + Token::Uint(batch.nonce.into()), + Token::Address(batch.token_contract), + Token::Uint(batch.batch_timeout.into()), ]) } pub fn encode_tx_batch_confirm_hashed(gravity_id: String, batch: TransactionBatch) -> Vec { let digest = encode_tx_batch_confirm(gravity_id, batch); - get_ethereum_msg_hash(&digest) + hash_message(digest).as_bytes().to_vec() } #[test] @@ -241,37 +241,33 @@ fn test_specific_batch_signature() { /// Note: This is the message, you need to run Keccak256::digest() in order to get the 32byte /// digest that is normally signed or may be used as a 'hash of the message' pub fn encode_logic_call_confirm(gravity_id: String, call: LogicCall) -> Vec { - let mut transfer_amounts = Vec::new(); - let mut transfer_token_contracts = Vec::new(); - let mut fee_amounts = Vec::new(); - let mut fee_token_contracts = Vec::new(); - for item in call.transfers.iter() { - transfer_amounts.push(Token::Uint(item.amount.clone())); - transfer_token_contracts.push(item.token_contract_address); - } - for item in call.fees.iter() { - fee_amounts.push(Token::Uint(item.amount.clone())); - fee_token_contracts.push(item.token_contract_address); - } - - encode_tokens(&[ - Token::FixedString(gravity_id), // Gravity Instance ID - Token::FixedString("logicCall".to_string()), //Function Name - Token::Dynamic(transfer_amounts), //Array of Transfer amounts - transfer_token_contracts.into(), //ERC-20 contract for transfers - Token::Dynamic(fee_amounts), // Array of Fees - fee_token_contracts.into(), // ERC-20 contract for fee payments - call.logic_contract_address.into(), // Address of a logic contract - Token::UnboundedBytes(call.payload), // Encoded arguments to logic contract - call.timeout.into(), // Timeout on batch - Token::Bytes(call.invalidation_id), // Scope of logic batch - call.invalidation_nonce.into(), // Nonce of logic batch. See 2-d nonce scheme. + let transfer_amounts = call.transfers.iter() + .map(|transfer| Token::Uint(transfer.amount)).collect(); + let transfer_token_contracts = call.transfers.iter() + .map(|transfer| Token::Address(transfer.token_contract_address)).collect(); + let fee_amounts = call.fees.iter() + .map(|fee| Token::Uint(fee.amount)).collect(); + let fee_token_contracts = call.fees.iter() + .map(|fee| Token::Address(fee.token_contract_address)).collect(); + + abi::encode(&[ + Token::FixedBytes(gravity_id.into_bytes()), // Gravity Instance ID + Token::FixedBytes("logicCall".to_string().into_bytes()), // Function Name + Token::Array(transfer_amounts), // Array of Transfer amounts + Token::Array(transfer_token_contracts), // ERC-20 contract for transfers + Token::Array(fee_amounts), // Array of Fees + Token::Array(fee_token_contracts), // ERC-20 contract for fee payments + Token::Address(call.logic_contract_address), // Address of a logic contract + Token::Bytes(call.payload), // Encoded arguments to logic contract + Token::Uint(call.timeout.into()), // Timeout on batch + Token::FixedBytes(call.invalidation_id), // Scope of logic batch + Token::Uint(call.invalidation_nonce.into()), // Nonce of logic batch. See 2-d nonce scheme. ]) } pub fn encode_logic_call_confirm_hashed(gravity_id: String, call: LogicCall) -> Vec { let digest = encode_logic_call_confirm(gravity_id, call); - get_ethereum_msg_hash(&digest) + hash_message(digest).as_bytes().to_vec() } #[test] diff --git a/orchestrator/gravity_utils/src/types/batches.rs b/orchestrator/gravity_utils/src/types/batches.rs index e6127e5fd..9f9ff24cc 100644 --- a/orchestrator/gravity_utils/src/types/batches.rs +++ b/orchestrator/gravity_utils/src/types/batches.rs @@ -1,7 +1,8 @@ use super::*; use crate::error::GravityError; use clarity::Signature as EthSignature; -use clarity::{abi::Token, Address as EthAddress}; +use ethers::core::abi::Token; +use ethers::types::Address as EthAddress; use deep_space::Address as CosmosAddress; /// This represents an individual transaction being bridged over to Ethereum @@ -50,16 +51,16 @@ impl TransactionBatch { let mut destinations = Vec::new(); let mut fees = Vec::new(); for item in self.transactions.iter() { - amounts.push(Token::Uint(item.erc20_token.amount.clone())); - fees.push(Token::Uint(item.erc20_fee.amount.clone())); - destinations.push(item.ethereum_recipient) + amounts.push(Token::Uint(item.erc20_token.amount)); + fees.push(Token::Uint(item.erc20_fee.amount)); + destinations.push(Token::Address(item.ethereum_recipient)) } assert_eq!(amounts.len(), destinations.len()); assert_eq!(fees.len(), destinations.len()); ( - Token::Dynamic(amounts), - destinations.into(), - Token::Dynamic(fees), + Token::Array(amounts), + Token::Array(destinations), + Token::Array(fees), ) } diff --git a/orchestrator/gravity_utils/src/types/logic_call.rs b/orchestrator/gravity_utils/src/types/logic_call.rs index 9486ea3a1..45723e644 100644 --- a/orchestrator/gravity_utils/src/types/logic_call.rs +++ b/orchestrator/gravity_utils/src/types/logic_call.rs @@ -1,6 +1,7 @@ use super::*; use crate::error::GravityError; -use clarity::{Address as EthAddress, Signature as EthSignature}; +use clarity::Signature as EthSignature; +use ethers::types::Address as EthAddress; /// the response we get when querying for a valset confirmation #[derive(Serialize, Deserialize, Debug, Default, Clone)] diff --git a/orchestrator/gravity_utils/src/types/mod.rs b/orchestrator/gravity_utils/src/types/mod.rs index b84cfe0b5..c869602a6 100644 --- a/orchestrator/gravity_utils/src/types/mod.rs +++ b/orchestrator/gravity_utils/src/types/mod.rs @@ -1,11 +1,12 @@ -use clarity::Address as EthAddress; -use num256::Uint256; mod batches; mod ethereum_events; mod logic_call; mod signatures; mod valsets; use crate::error::GravityError; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; +use std::str::FromStr; pub use batches::*; pub use ethereum_events::*; @@ -15,7 +16,7 @@ pub use valsets::*; #[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Hash)] pub struct Erc20Token { - pub amount: Uint256, + pub amount: U256, #[serde(rename = "contract")] pub token_contract_address: EthAddress, } @@ -23,8 +24,8 @@ pub struct Erc20Token { impl Erc20Token { pub fn from_proto(input: gravity_proto::gravity::Erc20Token) -> Result { Ok(Erc20Token { - amount: input.amount.parse()?, - token_contract_address: EthAddress::parse_and_validate(&input.contract)?, + amount: U256::from_dec_str(input.amount.as_str())?, + token_contract_address: EthAddress::from_str(&input.contract)?, }) } } From 87700cb8c5fd4c4804bcd34741132ac89f272d47 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 10 Nov 2021 22:12:28 -0800 Subject: [PATCH 034/115] Extract bytes_to_hex_str from clarity --- orchestrator/gravity_utils/src/ethereum.rs | 17 +++++++++++++++++ orchestrator/relayer/src/valset_relaying.rs | 6 +++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/orchestrator/gravity_utils/src/ethereum.rs b/orchestrator/gravity_utils/src/ethereum.rs index 28e6858bf..9b87b23c3 100644 --- a/orchestrator/gravity_utils/src/ethereum.rs +++ b/orchestrator/gravity_utils/src/ethereum.rs @@ -15,6 +15,13 @@ pub fn downcast_to_u128(input: U256) -> Option { } } +pub fn bytes_to_hex_str(bytes: &[u8]) -> String { + bytes + .iter() + .map(|b| format!("{:0>2x?}", b)) + .fold(String::new(), |acc, x| acc + &x) +} + #[test] fn test_downcast_to_u64() { let mut i = 0u64; @@ -45,4 +52,14 @@ fn test_downcast_to_u128() { assert_eq!(i, downcast_to_u128(i.into()).unwrap()); i += 1 } +} + +#[test] +fn encode_bytes() { + assert_eq!(bytes_to_hex_str(&[0xf]), "0f".to_owned()); + assert_eq!(bytes_to_hex_str(&[0xff]), "ff".to_owned()); + assert_eq!( + bytes_to_hex_str(&[0xde, 0xad, 0xbe, 0xef]), + "deadbeef".to_owned() + ); } \ No newline at end of file diff --git a/orchestrator/relayer/src/valset_relaying.rs b/orchestrator/relayer/src/valset_relaying.rs index 0478cb283..0365bf934 100644 --- a/orchestrator/relayer/src/valset_relaying.rs +++ b/orchestrator/relayer/src/valset_relaying.rs @@ -3,13 +3,13 @@ use std::time::Duration; -use clarity::utils::bytes_to_hex_str; use cosmos_gravity::query::get_latest_valset; use cosmos_gravity::query::{get_all_valset_confirms, get_valset}; use ethereum_gravity::{one_eth, valset_update::send_eth_valset_update}; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use gravity_utils::{ethereum::downcast_to_u128, message_signatures::encode_valset_confirm_hashed, types::Valset}; +use gravity_utils::{ethereum::downcast_to_u128, ethereum::bytes_to_hex_str, + message_signatures::encode_valset_confirm_hashed, types::Valset}; use tonic::transport::Channel; use web30::client::Web3; @@ -73,7 +73,7 @@ pub async fn relay_valsets( // there are two possible encoding problems that could cause the very rare sig failure bug, // one of them is that the hash is incorrect, that's not probable considering that // both Geth and Clarity agree on it. but this lets us check - info!("New valset hash {}", bytes_to_hex_str(&hash),); + info!("New valset hash {}", bytes_to_hex_str(&hash)); // order valset sigs prepares signatures for submission, notice we compare // them to the 'current' set in the bridge, this confirms for us that the validator set From 78510a02ac11da9cbae6862c0c8c32e403e596d6 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 10 Nov 2021 23:10:11 -0800 Subject: [PATCH 035/115] Convert to using ethers signature type We don't appear to be using Default or Hash for the signature-containing types, and since ethers doesn't implement them like clarity does, I removed those derives. Also removed a bunch of clones because ethers U256, Address, and Signature types all implement Copy. ethers also uses u64 for their v value in the sig, so we're mirroring that here. --- .../gravity_utils/src/types/batches.rs | 28 +++++++------- .../gravity_utils/src/types/logic_call.rs | 8 ++-- .../gravity_utils/src/types/signatures.rs | 38 ++++++++----------- .../gravity_utils/src/types/valsets.rs | 18 ++++----- 4 files changed, 43 insertions(+), 49 deletions(-) diff --git a/orchestrator/gravity_utils/src/types/batches.rs b/orchestrator/gravity_utils/src/types/batches.rs index 9f9ff24cc..3ed697a57 100644 --- a/orchestrator/gravity_utils/src/types/batches.rs +++ b/orchestrator/gravity_utils/src/types/batches.rs @@ -1,9 +1,9 @@ use super::*; use crate::error::GravityError; -use clarity::Signature as EthSignature; use ethers::core::abi::Token; -use ethers::types::Address as EthAddress; +use ethers::types::{Address as EthAddress, Signature as EthSignature}; use deep_space::Address as CosmosAddress; +use std::convert::TryFrom; /// This represents an individual transaction being bridged over to Ethereum /// parallel is the OutgoingTransferTx in x/gravity/types/batch.go @@ -23,6 +23,7 @@ impl BatchTransaction { "Can not have tx with null erc20_token!".to_string(), )); } + Ok(BatchTransaction { id: input.id, sender: input.sender.parse()?, @@ -47,16 +48,16 @@ impl TransactionBatch { /// extracts the amounts, destinations and fees as submitted to the Ethereum contract /// and used for signatures pub fn get_checkpoint_values(&self) -> (Token, Token, Token) { - let mut amounts = Vec::new(); - let mut destinations = Vec::new(); - let mut fees = Vec::new(); - for item in self.transactions.iter() { - amounts.push(Token::Uint(item.erc20_token.amount)); - fees.push(Token::Uint(item.erc20_fee.amount)); - destinations.push(Token::Address(item.ethereum_recipient)) - } + let amounts: Vec = + self.transactions.iter().map(|tx| Token::Uint(tx.erc20_token.amount)).collect(); + let destinations: Vec = + self.transactions.iter().map(|tx| Token::Address(tx.ethereum_recipient)).collect(); + let fees: Vec = + self.transactions.iter().map(|tx| Token::Uint(tx.erc20_fee.amount)).collect(); + assert_eq!(amounts.len(), destinations.len()); assert_eq!(fees.len(), destinations.len()); + ( Token::Array(amounts), Token::Array(destinations), @@ -72,13 +73,14 @@ impl TransactionBatch { if let Some(total_fee) = running_total_fee { running_total_fee = Some(Erc20Token { token_contract_address: total_fee.token_contract_address, - amount: total_fee.amount + tx.erc20_fee.amount.clone(), + amount: total_fee.amount + tx.erc20_fee.amount, }); } else { running_total_fee = Some(tx.erc20_fee.clone()) } transactions.push(tx); } + if let Some(total_fee) = running_total_fee { Ok(TransactionBatch { batch_timeout: input.timeout, @@ -112,7 +114,7 @@ impl BatchConfirmResponse { nonce: input.batch_nonce, token_contract: input.token_contract.parse()?, ethereum_signer: input.ethereum_signer.parse()?, - eth_signature: EthSignature::from_bytes(&input.signature)?, + eth_signature: EthSignature::try_from(input.signature.as_slice())?, }) } } @@ -122,6 +124,6 @@ impl Confirm for BatchConfirmResponse { self.ethereum_signer } fn get_signature(&self) -> EthSignature { - self.eth_signature.clone() + self.eth_signature } } diff --git a/orchestrator/gravity_utils/src/types/logic_call.rs b/orchestrator/gravity_utils/src/types/logic_call.rs index 45723e644..5a5cbf429 100644 --- a/orchestrator/gravity_utils/src/types/logic_call.rs +++ b/orchestrator/gravity_utils/src/types/logic_call.rs @@ -1,7 +1,7 @@ use super::*; use crate::error::GravityError; -use clarity::Signature as EthSignature; -use ethers::types::Address as EthAddress; +use ethers::types::{Address as EthAddress, Signature as EthSignature}; +use std::convert::TryFrom; /// the response we get when querying for a valset confirmation #[derive(Serialize, Deserialize, Debug, Default, Clone)] @@ -60,7 +60,7 @@ impl LogicCallConfirmResponse { invalidation_id: input.invalidation_scope, invalidation_nonce: input.invalidation_nonce, ethereum_signer: input.ethereum_signer.parse()?, - eth_signature: EthSignature::from_bytes(&input.signature)?, + eth_signature: EthSignature::try_from(input.signature.as_slice())?, }) } } @@ -70,6 +70,6 @@ impl Confirm for LogicCallConfirmResponse { self.ethereum_signer } fn get_signature(&self) -> EthSignature { - self.eth_signature.clone() + self.eth_signature } } diff --git a/orchestrator/gravity_utils/src/types/signatures.rs b/orchestrator/gravity_utils/src/types/signatures.rs index 8f95d81d9..4b257e333 100644 --- a/orchestrator/gravity_utils/src/types/signatures.rs +++ b/orchestrator/gravity_utils/src/types/signatures.rs @@ -1,6 +1,6 @@ -use clarity::Signature as EthSignature; -use clarity::{abi::Token, Address as EthAddress}; -use num256::Uint256; +use ethers::abi::Token; +use ethers::prelude::*; +use ethers::types::{Address as EthAddress, Signature as EthSignature}; use std::cmp::Ordering; /// A sortable struct of a validator and it's signatures @@ -10,9 +10,9 @@ use std::cmp::Ordering; pub struct GravitySignature { pub power: u64, pub eth_address: EthAddress, - pub v: Uint256, - pub r: Uint256, - pub s: Uint256, + pub v: u64, + pub r: U256, + pub s: U256, } impl Ord for GravitySignature { @@ -53,28 +53,22 @@ pub struct GravitySignatureArrays { /// submittable arrays, including the finicky token encoding tricks you need to /// perform in order to distinguish between a uint8[] and bytes32[] pub fn to_arrays(input: Vec) -> GravitySignatureArrays { - let mut addresses = Vec::new(); - let mut powers = Vec::new(); - let mut v = Vec::new(); - let mut r = Vec::new(); - let mut s = Vec::new(); - for val in input { - addresses.push(val.eth_address); - powers.push(val.power); - v.push(val.v); - r.push(val.r); - s.push(val.s); - } + let addresses = input.iter().map(|sig| sig.eth_address).collect(); + let powers = input.iter().map(|sig| sig.power).collect(); + let v = input.iter().map(|sig| Token::Uint(sig.v.into())).collect(); + let r = input.iter().map(|sig| Token::Uint(sig.r)).collect(); + let s = input.iter().map(|sig| Token::Uint(sig.s)).collect(); + GravitySignatureArrays { addresses, powers, - v: v.into(), - r: r.into(), - s: s.into(), + v: Token::Array(v), + r: Token::Array(r), + s: Token::Array(s), } } -#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq, Hash)] +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] pub struct SigWithAddress { pub eth_address: EthAddress, pub eth_signature: EthSignature, diff --git a/orchestrator/gravity_utils/src/types/valsets.rs b/orchestrator/gravity_utils/src/types/valsets.rs index d0c885c32..9f8cfec8f 100644 --- a/orchestrator/gravity_utils/src/types/valsets.rs +++ b/orchestrator/gravity_utils/src/types/valsets.rs @@ -1,15 +1,14 @@ use super::*; use crate::error::GravityError; -use ethers::types::Address as EthAddress; -use clarity::Signature as EthSignature; +use ethers::types::{Address as EthAddress, Signature as EthSignature}; use deep_space::error::CosmosGrpcError; +use std::convert::TryFrom; use std::fmt::Debug; use std::{ cmp::Ordering, collections::{HashMap, HashSet}, fmt, str, - // str::FromStr, }; /// The total power in the Gravity bridge is normalized to u32 max every @@ -66,7 +65,7 @@ impl ValsetConfirmResponse { Ok(ValsetConfirmResponse { eth_signer: input.ethereum_signer.parse()?, nonce: input.signer_set_nonce, - eth_signature: EthSignature::from_bytes(&input.signature)?, + eth_signature: EthSignature::try_from(input.signature.as_slice())?, }) } } @@ -76,7 +75,7 @@ impl Confirm for ValsetConfirmResponse { self.eth_signer } fn get_signature(&self) -> EthSignature { - self.eth_signature.clone() + self.eth_signature } } @@ -149,15 +148,14 @@ impl Valset { if let Some(eth_address) = member.eth_address { if let Some(sig) = signatures_hashmap.get(ð_address) { assert_eq!(sig.get_eth_address(), eth_address); - assert!(sig.get_signature().is_valid()); - let recover_key = sig.get_signature().recover(signed_message).unwrap(); + let recover_key = sig.get_signature().recover(signed_message)?; if recover_key == sig.get_eth_address() { out.push(GravitySignature { power: member.power, eth_address: sig.get_eth_address(), - v: sig.get_signature().v.clone(), - r: sig.get_signature().r.clone(), - s: sig.get_signature().s.clone(), + v: sig.get_signature().v, + r: sig.get_signature().r, + s: sig.get_signature().s, }); power_of_good_sigs += member.power; } else { From 10d2ca780be6068b7882ec69f38fa60712825dc0 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 11 Nov 2021 00:00:54 -0800 Subject: [PATCH 036/115] WIP: convert all the contract "calls" The ERC20 symbol function was unused, so it was removed. A bunch of other small fixes in here too. --- orchestrator/ethereum_gravity/src/utils.rs | 165 +++++++++--------- .../ethereum_gravity/src/valset_update.rs | 10 +- orchestrator/gravity_utils/src/types/mod.rs | 3 +- 3 files changed, 84 insertions(+), 94 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 57706c767..999620e65 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -1,13 +1,12 @@ -use clarity::abi::{Token, encode_call}; -use clarity::Uint256; -use clarity::{abi::encode_tokens, Address as EthAddress}; +use ethers::core::abi::{self, Token}; use ethers::prelude::*; +use ethers::types::Address as EthAddress; +use ethers::utils::keccak256; use gravity_utils::error::GravityError; +use gravity_utils::ethereum::downcast_to_u64; use gravity_utils::gravity::*; use gravity_utils::types::*; -use sha3::{Digest, Keccak256}; use std::panic; -use web30::{client::Web3, jsonrpc::error::Web3Error}; pub type EthSignerMiddleware = SignerMiddleware, LocalWallet>; pub type EthClient = Arc; @@ -17,18 +16,21 @@ pub fn get_checkpoint_abi_encode( gravity_id: &str, ) -> Result, GravityError> { let (eth_addresses, powers) = valset.filter_empty_addresses(); - Ok(encode_tokens(&[ - Token::FixedString(gravity_id.to_string()), - Token::FixedString("checkpoint".to_string()), - valset.nonce.into(), - eth_addresses.into(), - powers.into(), + let eth_addresses = eth_addresses.iter().map (|address| Token::Address(*address)).collect(); + let powers = powers.iter().map(|power| Token::Uint((*power).into())).collect(); + + Ok(abi::encode(&[ + Token::FixedBytes(gravity_id.into_bytes()), + Token::FixedBytes("checkpoint".to_string().into_bytes()), + Token::Uint(valset.nonce.into()), + Token::Array(eth_addresses), + Token::Array(powers), ])) } pub fn get_checkpoint_hash(valset: &Valset, gravity_id: &str) -> Result, GravityError> { - let locally_computed_abi_encode = get_checkpoint_abi_encode(&valset, &gravity_id); - let locally_computed_digest = Keccak256::digest(&locally_computed_abi_encode?); + let locally_computed_abi_encode = get_checkpoint_abi_encode(&valset, &gravity_id)?; + let locally_computed_digest = keccak256(locally_computed_abi_encode.as_slice()); Ok(locally_computed_digest.to_vec()) } @@ -36,21 +38,25 @@ pub fn get_checkpoint_hash(valset: &Valset, gravity_id: &str) -> Result, pub async fn get_valset_nonce( contract_address: EthAddress, caller_address: EthAddress, - web3: &Web3, -) -> Result { + eth_client: EthClient, +) -> Result { + let (price, limit) = get_contract_call_gas(eth_client, caller_address).await?; + let contract: Gravity = Gravity::new(contract_address, eth_client); + let contract_call = contract.state_lastValsetNonce() + .from(caller_address) + .gas(limit) + .gas_price(price) + .value(0u8.into()); - let payload = encode_call("state_lastValsetNonce()", &[]).unwrap(); + let val = contract_call.call().await?; - let val = web3 - .simulate_transaction(contract_address, 0u8.into(), payload, caller_address, None) - .await?; + // TODO (bolten): do we actually want to halt the bridge as the original comment implies? // the go represents all nonces as u64, there's no // reason they should ever overflow without a user // submitting millions or tens of millions of dollars // worth of transactions. But we properly check and // handle that case here. - let real_num = Uint256::from_bytes_be(&val); - Ok(downcast_to_u64(real_num).expect("Valset nonce overflow! Bridge Halt!")) + Ok(downcast_to_u64(val).expect("Valset nonce overflow! Bridge Halt!")) } /// Gets the latest transaction batch nonce @@ -58,25 +64,25 @@ pub async fn get_tx_batch_nonce( gravity_contract_address: EthAddress, erc20_contract_address: EthAddress, caller_address: EthAddress, - web3: &Web3, -) -> Result { - let payload = encode_call("lastBatchNonce(address)", &[erc20_contract_address.into()]).unwrap(); - let val = web3 - .simulate_transaction( - gravity_contract_address, - 0u8.into(), - payload, - caller_address, - None, - ) - .await?; + eth_client: EthClient, +) -> Result { + let (price, limit) = get_contract_call_gas(eth_client, caller_address).await?; + let contract: Gravity = Gravity::new(contract_address, eth_client); + let contract_call = contract.last_batch_nonce(erc20_contract_address) + .from(caller_address) + .gas(limit) + .gas_price(price) + .value(0u8.into()); + + let val = contract_call.call().await?; + + // TODO (bolten): do we actually want to halt the bridge as the original comment implies? // the go represents all nonces as u64, there's no // reason they should ever overflow without a user // submitting millions or tens of millions of dollars // worth of transactions. But we properly check and // handle that case here. - let real_num = Uint256::from_bytes_be(&val); - Ok(downcast_to_u64(real_num).expect("TxBatch nonce overflow! Bridge Halt!")) + Ok(downcast_to_u64(val).expect("TxBatch nonce overflow! Bridge Halt!")) } /// Gets the latest transaction batch nonce @@ -84,29 +90,25 @@ pub async fn get_logic_call_nonce( gravity_contract_address: EthAddress, invalidation_id: Vec, caller_address: EthAddress, - web3: &Web3, -) -> Result { - let payload = encode_call( - "lastLogicCallNonce(bytes32)", - &[Token::Bytes(invalidation_id)], - ) - .unwrap(); - let val = web3 - .simulate_transaction( - gravity_contract_address, - 0u8.into(), - payload, - caller_address, - None, - ) - .await?; + eth_client: EthClient, +) -> Result { + let (price, limit) = get_contract_call_gas(eth_client, caller_address).await?; + let contract: Gravity = Gravity::new(contract_address, eth_client); + let contract_call = contract.last_logic_call_nonce(invalidation_id.as_slice()) + .from(caller_address) + .gas(limit) + .gas_price(price) + .value(0u8.into()); + + let val = contract_call.call().await?; + + // TODO (bolten): do we actually want to halt the bridge as the original comment implies? // the go represents all nonces as u64, there's no // reason they should ever overflow without a user // submitting millions or tens of millions of dollars // worth of transactions. But we properly check and // handle that case here. - let real_num = Uint256::from_bytes_be(&val); - Ok(downcast_to_u64(real_num).expect("LogicCall nonce overflow! Bridge Halt!")) + Ok(downcast_to_u64(val).expect("LogicCall nonce overflow! Bridge Halt!")) } /// Gets the latest transaction batch nonce @@ -115,22 +117,22 @@ pub async fn get_event_nonce( caller_address: EthAddress, web3: &Web3, ) -> Result { - let payload = encode_call("state_lastEventNonce()", &[]).unwrap(); - let val = web3 - .simulate_transaction( - gravity_contract_address, - 0u8.into(), - payload, - caller_address, - None, - ) - .await?; + let (price, limit) = get_contract_call_gas(eth_client, caller_address).await?; + let contract: Gravity = Gravity::new(contract_address, eth_client); + let contract_call = contract.state_last_event_nonce() + .from(caller_address) + .gas(limit) + .gas_price(price) + .value(0u8.into()); + + let val = contract_call.call().await?; + + // TODO (bolten): do we actually want to halt the bridge as the original comment implies? // the go represents all nonces as u64, there's no // reason they should ever overflow without a user // submitting millions or tens of millions of dollars // worth of transactions. But we properly check and // handle that case here. - let real_num = Uint256::from_bytes_be(&val); Ok(downcast_to_u64(real_num).expect("EventNonce nonce overflow! Bridge Halt!")) } @@ -140,38 +142,29 @@ pub async fn get_gravity_id( caller_address: EthAddress, eth_client: EthClient, ) -> Result { - const GAS_LIMIT: u128 = 12450000; // the most Hardhat will allow, will work on Geth - - let caller_balance = eth_client.get_balance(caller_address, None).await?; - let latest_block = eth_client.get_block(BlockNumber::Latest).await?; - let price = latest_block.base_fee_per_gas.ok_or(1u8.into()); // shouldn't happen unless pre-London - let limit = min(GAS_LIMIT.into(), caller_balance / price.clone()); - + let (price, limit) = get_contract_call_gas(eth_client, caller_address).await?; let contract: Gravity = Gravity::new(contract_address, eth_client); let contract_call = contract.state_gravity_id() .from(caller_address) - .gas(limit.into()) - .gas_price(price.into()) + .gas(limit) + .gas_price(price) .value(0u8.into()); String::from_utf8(contract_call.call().await?.to_vec()) } -/// Gets the ERC20 symbol, should maybe be upstreamed -pub async fn get_erc20_symbol( - contract_address: EthAddress, - caller_address: EthAddress, - web3: &Web3, -) -> Result { +pub async fn get_contract_call_gas( + eth_client: EthClient, + caller_address: EthAddress +) -> Result<(price, limit), GravityError> { + const GAS_LIMIT: u128 = 12450000; // the most Hardhat will allow, will work on Geth - let payload = encode_call("symbol()", &[]).unwrap(); + let caller_balance = eth_client.get_balance(caller_address, None).await?; + let latest_block = eth_client.get_block(BlockNumber::Latest).await?; + let price = latest_block.base_fee_per_gas.ok_or(1u8.into()); // shouldn't happen unless pre-London + let limit = min(GAS_LIMIT.into(), caller_balance / price.clone()); - let val_symbol = web3 - .simulate_transaction(contract_address, 0u8.into(), payload, caller_address, None) - .await?; - // Pardon the unwrap, but this is temporary code, intended only for the tests, to help them - // deal with a deprecated feature (the symbol), which will be removed soon - Ok(String::from_utf8(val_symbol).unwrap()) + Ok((price, limit)) } /// Just a helper struct to represent the cost of actions on Ethereum diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index c4159e725..2748f959c 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -1,10 +1,9 @@ use crate::utils::{get_valset_nonce, GasCost}; -use clarity::PrivateKey as EthPrivateKey; -use clarity::{Address as EthAddress, Uint256}; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; use gravity_utils::types::*; use gravity_utils::{error::GravityError, message_signatures::encode_valset_confirm_hashed}; use std::{cmp::min, time::Duration}; -use web30::{client::Web3, types::TransactionRequest}; /// this function generates an appropriate Ethereum transaction /// to submit the provided validator set and signatures. @@ -13,16 +12,15 @@ pub async fn send_eth_valset_update( new_valset: Valset, old_valset: Valset, confirms: &[ValsetConfirmResponse], - web3: &Web3, timeout: Duration, gravity_contract_address: EthAddress, gravity_id: String, - our_eth_key: EthPrivateKey, + eth_client: EthClient, ) -> Result<(), GravityError> { let old_nonce = old_valset.nonce; let new_nonce = new_valset.nonce; assert!(new_nonce > old_nonce); - let eth_address = our_eth_key.to_public_key().unwrap(); + let eth_address = eth_client.address(); info!( "Ordering signatures and submitting validator set {} -> {} update to Ethereum", old_nonce, new_nonce diff --git a/orchestrator/gravity_utils/src/types/mod.rs b/orchestrator/gravity_utils/src/types/mod.rs index c869602a6..68cdd208e 100644 --- a/orchestrator/gravity_utils/src/types/mod.rs +++ b/orchestrator/gravity_utils/src/types/mod.rs @@ -6,7 +6,6 @@ mod valsets; use crate::error::GravityError; use ethers::prelude::*; use ethers::types::Address as EthAddress; -use std::str::FromStr; pub use batches::*; pub use ethereum_events::*; @@ -25,7 +24,7 @@ impl Erc20Token { pub fn from_proto(input: gravity_proto::gravity::Erc20Token) -> Result { Ok(Erc20Token { amount: U256::from_dec_str(input.amount.as_str())?, - token_contract_address: EthAddress::from_str(&input.contract)?, + token_contract_address: input.contract.parse()?, }) } } From 74debb2c266c35e59a63a82a69354436b31cbdd1 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 11 Nov 2021 14:42:13 -0800 Subject: [PATCH 037/115] Add doc comment and change name for gas get_contract_call_gas -> get_contract_eth_call_gas Trying to ensure it is well explained what the function is intended for and how it should be used. --- orchestrator/ethereum_gravity/src/utils.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 999620e65..b1ef0240c 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -40,7 +40,7 @@ pub async fn get_valset_nonce( caller_address: EthAddress, eth_client: EthClient, ) -> Result { - let (price, limit) = get_contract_call_gas(eth_client, caller_address).await?; + let (price, limit) = get_contract_eth_call_gas(eth_client, caller_address).await?; let contract: Gravity = Gravity::new(contract_address, eth_client); let contract_call = contract.state_lastValsetNonce() .from(caller_address) @@ -66,7 +66,7 @@ pub async fn get_tx_batch_nonce( caller_address: EthAddress, eth_client: EthClient, ) -> Result { - let (price, limit) = get_contract_call_gas(eth_client, caller_address).await?; + let (price, limit) = get_contract_eth_call_gas(eth_client, caller_address).await?; let contract: Gravity = Gravity::new(contract_address, eth_client); let contract_call = contract.last_batch_nonce(erc20_contract_address) .from(caller_address) @@ -92,7 +92,7 @@ pub async fn get_logic_call_nonce( caller_address: EthAddress, eth_client: EthClient, ) -> Result { - let (price, limit) = get_contract_call_gas(eth_client, caller_address).await?; + let (price, limit) = get_contract_eth_call_gas(eth_client, caller_address).await?; let contract: Gravity = Gravity::new(contract_address, eth_client); let contract_call = contract.last_logic_call_nonce(invalidation_id.as_slice()) .from(caller_address) @@ -117,7 +117,7 @@ pub async fn get_event_nonce( caller_address: EthAddress, web3: &Web3, ) -> Result { - let (price, limit) = get_contract_call_gas(eth_client, caller_address).await?; + let (price, limit) = get_contract_eth_call_gas(eth_client, caller_address).await?; let contract: Gravity = Gravity::new(contract_address, eth_client); let contract_call = contract.state_last_event_nonce() .from(caller_address) @@ -142,7 +142,7 @@ pub async fn get_gravity_id( caller_address: EthAddress, eth_client: EthClient, ) -> Result { - let (price, limit) = get_contract_call_gas(eth_client, caller_address).await?; + let (price, limit) = get_contract_eth_call_gas(eth_client, caller_address).await?; let contract: Gravity = Gravity::new(contract_address, eth_client); let contract_call = contract.state_gravity_id() .from(caller_address) @@ -153,7 +153,12 @@ pub async fn get_gravity_id( String::from_utf8(contract_call.call().await?.to_vec()) } -pub async fn get_contract_call_gas( +/// Retrieve gas price and limit in a similar fashion to web30's simulate_transaction. +/// These values are intended to be used in conjunection with eth_call rather than +/// eth_sendtransaction. In ethers this is represented by `call()` on a ContractCall rather +/// than `send()`. Using `call()` will not send a transaction from the caller account or +/// spend gas. +pub async fn get_contract_eth_call_gas( eth_client: EthClient, caller_address: EthAddress ) -> Result<(price, limit), GravityError> { From 95647eb3496e61bfc3a14dceeb37b9b207005680 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 11 Nov 2021 14:45:10 -0800 Subject: [PATCH 038/115] Update GasCost struct --- orchestrator/ethereum_gravity/src/utils.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index b1ef0240c..af7304aa8 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -175,12 +175,12 @@ pub async fn get_contract_eth_call_gas( /// Just a helper struct to represent the cost of actions on Ethereum #[derive(Debug, Default, Clone)] pub struct GasCost { - pub gas: Uint256, - pub gas_price: Uint256, + pub gas: U256, + pub gas_price: U256, } impl GasCost { - pub fn get_total(&self) -> Uint256 { - self.gas.clone() * self.gas_price.clone() + pub fn get_total(&self) -> U256 { + self.gas * self.gas_price } } From bbe942a84f9c896bc553b0b4de01fc8c4984ad6c Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 11 Nov 2021 18:42:09 -0800 Subject: [PATCH 039/115] Convert valset update transactions Important TODO here to address around whether we need to try to manually set the nonce value when estimating gas --- .../ethereum_gravity/src/valset_update.rs | 165 +++++++----------- .../gravity_utils/src/types/signatures.rs | 25 +-- 2 files changed, 81 insertions(+), 109 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index 2748f959c..950310f15 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -1,8 +1,9 @@ -use crate::utils::{get_valset_nonce, GasCost}; +use crate::utils::{EthSignerMiddleware, get_valset_nonce, GasCost}; +use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_utils::types::*; -use gravity_utils::{error::GravityError, message_signatures::encode_valset_confirm_hashed}; +use gravity_utils::{error::GravityError, gravity::*, message_signatures::encode_valset_confirm_hashed}; use std::{cmp::min, time::Duration}; /// this function generates an appropriate Ethereum transaction @@ -17,40 +18,20 @@ pub async fn send_eth_valset_update( gravity_id: String, eth_client: EthClient, ) -> Result<(), GravityError> { - let old_nonce = old_valset.nonce; - let new_nonce = new_valset.nonce; - assert!(new_nonce > old_nonce); - let eth_address = eth_client.address(); - info!( - "Ordering signatures and submitting validator set {} -> {} update to Ethereum", - old_nonce, new_nonce - ); - let before_nonce = get_valset_nonce(gravity_contract_address, eth_address, web3).await?; - if before_nonce != old_nonce { - info!( - "Someone else updated the valset to {}, exiting early", - before_nonce - ); - return Ok(()); - } - - let payload = encode_valset_payload(new_valset, old_valset, confirms, gravity_id)?; + let contract_call = build_valset_update_contract_call( + new_valset, old_valset, confirms, gravity_contract_address, gravity_id, eth_client + ).await?; + let pending_tx = contract_call.send().await?; + info!("Sent valset update with txid {:#066x}", pending_tx); + // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? + // additionally we are mirroring only waiting for 1 confirmation by leaving that as default + pending_tx.interval(Duration::from_secs(1)); - let tx = web3 - .send_transaction( - gravity_contract_address, - payload, - 0u32.into(), - eth_address, - our_eth_key, - vec![], - ) - .await?; - info!("Sent valset update with txid {:#066x}", tx); + if let Err(tx_error) = tokio::time::timeout(timeout, async { pending_tx.await? }).await { + return Err(tx_error); + }; - web3.wait_for_transaction(tx, timeout, None).await?; - - let last_nonce = get_valset_nonce(gravity_contract_address, eth_address, web3).await?; + let last_nonce = get_valset_nonce(gravity_contract_address, eth_address, eth_client).await?; if last_nonce != new_nonce { error!( "Current nonce is {} expected to update to nonce {}", @@ -62,6 +43,7 @@ pub async fn send_eth_valset_update( last_nonce ); } + Ok(()) } @@ -74,50 +56,60 @@ pub async fn estimate_valset_cost( gravity_contract_address: EthAddress, gravity_id: String, ) -> Result { - let our_eth_address = our_eth_key.to_public_key().unwrap(); - let our_balance = web3.eth_get_balance(our_eth_address).await?; - let our_nonce = web3.eth_get_transaction_count(our_eth_address).await?; - let gas_limit = min((u64::MAX - 1).into(), our_balance.clone()); - let gas_price = web3.eth_gas_price().await?; - let zero: Uint256 = 0u8.into(); - let val = web3 - .eth_estimate_gas(TransactionRequest { - from: Some(our_eth_address), - to: gravity_contract_address, - nonce: Some(our_nonce.clone().into()), - gas_price: Some(gas_price.clone().into()), - gas: Some(gas_limit.into()), - value: Some(zero.into()), - data: Some( - encode_valset_payload( - new_valset.clone(), - old_valset.clone(), - confirms, - gravity_id, - )? - .into(), - ), - }) - .await?; + let our_eth_address = eth_client.address(); + let our_balance = eth_client.get_balance(our_eth_address, None).await?; + let gas_limit = min((u64::MAX - 1).into(), our_balance); + let gas_price = eth_client.get_gas_price().await?; + + let contract_call = build_valset_update_contract_call( + new_valset, old_valset, confirms, gravity_contract_address, gravity_id, eth_client + ).await?; + let contract_call = contract_call.gas(gas_limit).gas_price(gas_price); + + // TODO(bolten): estimate gas only takes a transaction request, and doesn't + // care if a specific block is passed as a parameter when creating the contract + // call...the old code set the nonce manually...I think that the value that + // ContractCall will put in the TransactionRequest is by default the next + // available nonce, and the only way to change it would be to reach directly into + // the object as the ContractCall has no method for setting the nonce...is the + // default behavior acceptable? + // + //let our_nonce = eth_client.get_transaction_count(our_eth_address, None).await?; + //contract_call.tx.set_nonce(our_nonce); Ok(GasCost { - gas: val, - gas_price, + gas: contract_call.estimate_gas().await?, + gas_price }) } -/// Encodes the payload bytes for the validator set update call, useful for -/// estimating the cost of submitting a validator set -pub fn encode_valset_payload( +pub async fn build_valset_update_contract_call( new_valset: Valset, old_valset: Valset, confirms: &[ValsetConfirmResponse], + gravity_contract_address: EthAddress, gravity_id: String, -) -> Result, GravityError> { - let (old_addresses, old_powers) = old_valset.filter_empty_addresses(); - let (new_addresses, new_powers) = new_valset.filter_empty_addresses(); + eth_client: EthClient, +) -> Result, GravityError> { let old_nonce = old_valset.nonce; let new_nonce = new_valset.nonce; + assert!(new_nonce > old_nonce); + let eth_address = eth_client.address(); + info!( + "Ordering signatures and submitting validator set {} -> {} update to Ethereum", + old_nonce, new_nonce + ); + let before_nonce = get_valset_nonce(gravity_contract_address, eth_address, eth_client).await?; + if before_nonce != old_nonce { + info!( + "Someone else updated the valset to {}, exiting early", + before_nonce + ); + return Ok(()); + } + + let (old_addresses, old_powers) = old_valset.filter_empty_addresses(); + let (new_addresses, new_powers) = new_valset.filter_empty_addresses(); // remember the signatures are over the new valset and therefore this is the value we must encode // the old valset exists only as a hash in the ethereum store @@ -127,36 +119,11 @@ pub fn encode_valset_payload( let sig_data = old_valset.order_sigs(&hash, confirms)?; let sig_arrays = to_arrays(sig_data); - // Solidity function signature - // function updateValset( - // // The new version of the validator set - // address[] memory _newValidators, - // uint256[] memory _newPowers, - // uint256 _newValsetNonce, - // // The current validators that approve the change - // address[] memory _currentValidators, - // uint256[] memory _currentPowers, - // uint256 _currentValsetNonce, - // // These are arrays of the parts of the current validator's signatures - // uint8[] memory _v, - // bytes32[] memory _r, - // bytes32[] memory _s - let tokens = &[ - new_addresses.into(), - new_powers.into(), - new_nonce.into(), - old_addresses.into(), - old_powers.into(), - old_nonce.into(), - sig_arrays.v, - sig_arrays.r, - sig_arrays.s, - ]; - - let payload = clarity::abi::encode_call( - "updateValset(address[],uint256[],uint256,address[],uint256[],uint256,uint8[],bytes32[],bytes32[])", - tokens, - ).unwrap(); - - Ok(payload) + let contract = Gravity::new(gravity_contract_address, eth_client); + Ok(contract.update_valset( + new_addresses, new_powers, new_nonce.into(), + old_addresses, old_powers, old_nonce.into(), + sig_arrays.v, sig_arrays.r, sig_arrays.s) + .from(eth_address) + .value(0u8.into())) } diff --git a/orchestrator/gravity_utils/src/types/signatures.rs b/orchestrator/gravity_utils/src/types/signatures.rs index 4b257e333..8a5272fe2 100644 --- a/orchestrator/gravity_utils/src/types/signatures.rs +++ b/orchestrator/gravity_utils/src/types/signatures.rs @@ -1,7 +1,7 @@ -use ethers::abi::Token; use ethers::prelude::*; use ethers::types::{Address as EthAddress, Signature as EthSignature}; use std::cmp::Ordering; +use std::convert::TryFrom; /// A sortable struct of a validator and it's signatures /// this can be used for either transaction batch or validator @@ -44,9 +44,9 @@ impl PartialOrd for GravitySignature { pub struct GravitySignatureArrays { pub addresses: Vec, pub powers: Vec, - pub v: Token, - pub r: Token, - pub s: Token, + pub v: Vec, + pub r: Vec<[u8; 32]>, + pub s: Vec<[u8; 32]>, } /// This function handles converting the GravitySignature type into an Ethereum @@ -55,16 +55,21 @@ pub struct GravitySignatureArrays { pub fn to_arrays(input: Vec) -> GravitySignatureArrays { let addresses = input.iter().map(|sig| sig.eth_address).collect(); let powers = input.iter().map(|sig| sig.power).collect(); - let v = input.iter().map(|sig| Token::Uint(sig.v.into())).collect(); - let r = input.iter().map(|sig| Token::Uint(sig.r)).collect(); - let s = input.iter().map(|sig| Token::Uint(sig.s)).collect(); + // TODO(bolten): we're also throwing panics if we encounter downcast errors in + // ethereum_gravity/src/utils.rs, we should consider broadly how to handle + // these sorts of error conditions + let v = input.iter().map(|sig| + u8::try_from(sig.v).expect("Gravity Signature v overflow! Bridge halt!")) + .collect(); + let r = input.iter().map(|sig| sig.r.into()).collect(); + let s = input.iter().map(|sig| sig.s.into()).collect(); GravitySignatureArrays { addresses, powers, - v: Token::Array(v), - r: Token::Array(r), - s: Token::Array(s), + v, + r, + s, } } From 18a5158aef89c86c1456e92cde3a356be819850f Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 11 Nov 2021 18:43:23 -0800 Subject: [PATCH 040/115] Simplify and fix our contract eth_calls --- orchestrator/ethereum_gravity/src/utils.rs | 84 ++++++++++------------ 1 file changed, 38 insertions(+), 46 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index af7304aa8..fbd4bb400 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -1,3 +1,4 @@ +use ethers::contract::builders::ContractCall; use ethers::core::abi::{self, Token}; use ethers::prelude::*; use ethers::types::Address as EthAddress; @@ -40,15 +41,10 @@ pub async fn get_valset_nonce( caller_address: EthAddress, eth_client: EthClient, ) -> Result { - let (price, limit) = get_contract_eth_call_gas(eth_client, caller_address).await?; - let contract: Gravity = Gravity::new(contract_address, eth_client); - let contract_call = contract.state_lastValsetNonce() - .from(caller_address) - .gas(limit) - .gas_price(price) - .value(0u8.into()); - - let val = contract_call.call().await?; + let contract_call = Gravity::new(contract_address, eth_client) + .state_last_valset_nonce(); + let contract_call = build_contract_eth_call(contract_call, eth_client, caller_address).await?; + let valset_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? // the go represents all nonces as u64, there's no @@ -56,7 +52,7 @@ pub async fn get_valset_nonce( // submitting millions or tens of millions of dollars // worth of transactions. But we properly check and // handle that case here. - Ok(downcast_to_u64(val).expect("Valset nonce overflow! Bridge Halt!")) + Ok(downcast_to_u64(valset_nonce).expect("Valset nonce overflow! Bridge Halt!")) } /// Gets the latest transaction batch nonce @@ -66,15 +62,10 @@ pub async fn get_tx_batch_nonce( caller_address: EthAddress, eth_client: EthClient, ) -> Result { - let (price, limit) = get_contract_eth_call_gas(eth_client, caller_address).await?; - let contract: Gravity = Gravity::new(contract_address, eth_client); - let contract_call = contract.last_batch_nonce(erc20_contract_address) - .from(caller_address) - .gas(limit) - .gas_price(price) - .value(0u8.into()); - - let val = contract_call.call().await?; + let contract_call = Gravity::new(contract_address, eth_client).state_last_batch_nonces(p0) + .last_batch_nonce(erc20_contract_address); + let contract_call = build_contract_eth_call(contract_call, eth_client, caller_address).await?; + let tx_batch_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? // the go represents all nonces as u64, there's no @@ -82,7 +73,7 @@ pub async fn get_tx_batch_nonce( // submitting millions or tens of millions of dollars // worth of transactions. But we properly check and // handle that case here. - Ok(downcast_to_u64(val).expect("TxBatch nonce overflow! Bridge Halt!")) + Ok(downcast_to_u64(tx_batch_nonce).expect("TxBatch nonce overflow! Bridge Halt!")) } /// Gets the latest transaction batch nonce @@ -92,15 +83,10 @@ pub async fn get_logic_call_nonce( caller_address: EthAddress, eth_client: EthClient, ) -> Result { - let (price, limit) = get_contract_eth_call_gas(eth_client, caller_address).await?; - let contract: Gravity = Gravity::new(contract_address, eth_client); - let contract_call = contract.last_logic_call_nonce(invalidation_id.as_slice()) - .from(caller_address) - .gas(limit) - .gas_price(price) - .value(0u8.into()); - - let val = contract_call.call().await?; + let contract_call = Gravity::new(contract_address, eth_client) + .last_logic_call_nonce(invalidation_id.as_slice()); + let contract_call = build_contract_eth_call(contract_call, eth_client, caller_address).await?; + let logic_call_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? // the go represents all nonces as u64, there's no @@ -108,7 +94,7 @@ pub async fn get_logic_call_nonce( // submitting millions or tens of millions of dollars // worth of transactions. But we properly check and // handle that case here. - Ok(downcast_to_u64(val).expect("LogicCall nonce overflow! Bridge Halt!")) + Ok(downcast_to_u64(logic_call_nonce).expect("LogicCall nonce overflow! Bridge Halt!")) } /// Gets the latest transaction batch nonce @@ -117,15 +103,10 @@ pub async fn get_event_nonce( caller_address: EthAddress, web3: &Web3, ) -> Result { - let (price, limit) = get_contract_eth_call_gas(eth_client, caller_address).await?; - let contract: Gravity = Gravity::new(contract_address, eth_client); - let contract_call = contract.state_last_event_nonce() - .from(caller_address) - .gas(limit) - .gas_price(price) - .value(0u8.into()); - - let val = contract_call.call().await?; + let contract_call = Gravity::new(contract_address, eth_client) + .state_last_event_nonce(); + let contract_call = build_contract_eth_call(contract_call, eth_client, caller_address).await?; + let event_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? // the go represents all nonces as u64, there's no @@ -133,7 +114,7 @@ pub async fn get_event_nonce( // submitting millions or tens of millions of dollars // worth of transactions. But we properly check and // handle that case here. - Ok(downcast_to_u64(real_num).expect("EventNonce nonce overflow! Bridge Halt!")) + Ok(downcast_to_u64(event_nonce).expect("EventNonce nonce overflow! Bridge Halt!")) } /// Gets the gravityID @@ -142,15 +123,26 @@ pub async fn get_gravity_id( caller_address: EthAddress, eth_client: EthClient, ) -> Result { + let contract_call = Gravity::new(contract_address, eth_client) + .state_gravity_id(); + let contract_call = build_contract_eth_call(contract_call, eth_client, caller_address).await?; + + String::from_utf8(contract_call.call().await?.to_vec()) +} + +/// Since all the contract eth_calls here use the same gas and value settings, use a common +/// function to append them to the ContractCall builder. +pub async fn build_contract_eth_call( + contract_call: ContractCall, + eth_client: EthClient, + caller_address: EthAddress, +) -> Result, GravityError> { let (price, limit) = get_contract_eth_call_gas(eth_client, caller_address).await?; - let contract: Gravity = Gravity::new(contract_address, eth_client); - let contract_call = contract.state_gravity_id() - .from(caller_address) + + Ok(contract_call.from(caller_address) .gas(limit) .gas_price(price) - .value(0u8.into()); - - String::from_utf8(contract_call.call().await?.to_vec()) + .value(0u8.into())) } /// Retrieve gas price and limit in a similar fashion to web30's simulate_transaction. From 9bfb4bc36b71781e5172356709a8d97083e48f33 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 11 Nov 2021 18:43:52 -0800 Subject: [PATCH 041/115] Misc fixes --- orchestrator/gravity_utils/src/types/ethereum_events.rs | 4 ++-- orchestrator/relayer/src/find_latest_valset.rs | 2 +- orchestrator/relayer/src/valset_relaying.rs | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 3023a3dba..2bc7c7110 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -4,7 +4,7 @@ //! mirror Serde and perhaps even become a serde crate for Ethereum ABI decoding //! For now reference the ABI encoding document here https://docs.soliditylang.org/en/v0.8.3/abi-spec.html -use super::{Valset, ValsetMember}; +use super::ValsetMember; use crate::error::GravityError; use crate::ethereum::downcast_to_u64; use crate::gravity::*; @@ -38,7 +38,7 @@ fn log_to_ethers_event(log: &Log) -> Result Result { match log.block_number.clone() { - Some(block_height) => Ok(U256::from(block_height.as_u64())), + Some(block_height) => Ok(block_height.as_u64().into()), None => Err(GravityError::InvalidEventLogError(format!( "Log does not have block number, we only search logs already in blocks? {:?}", log diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index d5350638f..f5274262d 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -2,7 +2,7 @@ use crate::main_loop::EthClient; use clarity::{Address, Uint256}; use ethers::prelude::*; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use gravity_utils::types::{VALSET_UPDATED_EVENT_STR, ValsetUpdatedEvent, ValsetUpdatedEventFilter}; +use gravity_utils::types::{VALSET_UPDATED_EVENT_STR, ValsetUpdatedEvent}; use gravity_utils::{error::GravityError, ethereum::downcast_to_u64, types::Valset}; use std::panic; use tonic::transport::Channel; diff --git a/orchestrator/relayer/src/valset_relaying.rs b/orchestrator/relayer/src/valset_relaying.rs index 0365bf934..a168dab7e 100644 --- a/orchestrator/relayer/src/valset_relaying.rs +++ b/orchestrator/relayer/src/valset_relaying.rs @@ -11,7 +11,6 @@ use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::{ethereum::downcast_to_u128, ethereum::bytes_to_hex_str, message_signatures::encode_valset_confirm_hashed, types::Valset}; use tonic::transport::Channel; -use web30::client::Web3; /// Check the last validator set on Ethereum, if it's lower than our latest validator /// set then we should package and submit the update as an Ethereum transaction From 2bc566e084164e1f96b3f38d1dd2556d28d5c1a8 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 11 Nov 2021 18:47:29 -0800 Subject: [PATCH 042/115] Merge the gas function into the builder --- orchestrator/ethereum_gravity/src/utils.rs | 28 ++++++++-------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index fbd4bb400..148ea2a69 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -132,28 +132,17 @@ pub async fn get_gravity_id( /// Since all the contract eth_calls here use the same gas and value settings, use a common /// function to append them to the ContractCall builder. -pub async fn build_contract_eth_call( - contract_call: ContractCall, - eth_client: EthClient, - caller_address: EthAddress, -) -> Result, GravityError> { - let (price, limit) = get_contract_eth_call_gas(eth_client, caller_address).await?; - - Ok(contract_call.from(caller_address) - .gas(limit) - .gas_price(price) - .value(0u8.into())) -} - +/// /// Retrieve gas price and limit in a similar fashion to web30's simulate_transaction. -/// These values are intended to be used in conjunection with eth_call rather than +/// These values are intended to be used in conjunction with eth_call rather than /// eth_sendtransaction. In ethers this is represented by `call()` on a ContractCall rather /// than `send()`. Using `call()` will not send a transaction from the caller account or /// spend gas. -pub async fn get_contract_eth_call_gas( +pub async fn build_contract_eth_call( + contract_call: ContractCall, eth_client: EthClient, - caller_address: EthAddress -) -> Result<(price, limit), GravityError> { + caller_address: EthAddress, +) -> Result, GravityError> { const GAS_LIMIT: u128 = 12450000; // the most Hardhat will allow, will work on Geth let caller_balance = eth_client.get_balance(caller_address, None).await?; @@ -161,7 +150,10 @@ pub async fn get_contract_eth_call_gas( let price = latest_block.base_fee_per_gas.ok_or(1u8.into()); // shouldn't happen unless pre-London let limit = min(GAS_LIMIT.into(), caller_balance / price.clone()); - Ok((price, limit)) + Ok(contract_call.from(caller_address) + .gas(limit) + .gas_price(price) + .value(0u8.into())) } /// Just a helper struct to represent the cost of actions on Ethereum From 1f361745cc9e79d8c0920ce672824b86eec817df Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 11 Nov 2021 18:50:57 -0800 Subject: [PATCH 043/115] Finish conversion of valset_relaying.rs --- orchestrator/ethereum_gravity/src/valset_update.rs | 2 +- orchestrator/relayer/src/valset_relaying.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index 950310f15..5ba9fffb6 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -52,9 +52,9 @@ pub async fn estimate_valset_cost( new_valset: &Valset, old_valset: &Valset, confirms: &[ValsetConfirmResponse], - eth_client: EthClient, gravity_contract_address: EthAddress, gravity_id: String, + eth_client: EthClient, ) -> Result { let our_eth_address = eth_client.address(); let our_balance = eth_client.get_balance(our_eth_address, None).await?; diff --git a/orchestrator/relayer/src/valset_relaying.rs b/orchestrator/relayer/src/valset_relaying.rs index a168dab7e..8ce65f82b 100644 --- a/orchestrator/relayer/src/valset_relaying.rs +++ b/orchestrator/relayer/src/valset_relaying.rs @@ -129,9 +129,9 @@ pub async fn relay_valsets( &latest_cosmos_valset, ¤t_eth_valset, &latest_cosmos_confirmed, - eth_client.clone(), gravity_contract_address, gravity_id.clone(), + eth_client.clone(), ) .await; if cost.is_err() { @@ -155,11 +155,10 @@ pub async fn relay_valsets( latest_cosmos_valset.clone(), current_eth_valset.clone(), &latest_cosmos_confirmed, - web3, timeout, gravity_contract_address, gravity_id, - ethereum_key, + eth_client.clone(), ) .await; From 24ead91e7f4f2784b5d75647e1bc5320ca27665b Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 11 Nov 2021 22:45:42 -0800 Subject: [PATCH 044/115] WIP: Convert batch submission, contract call fixes As of yet, still have to figure out the gas multiplier implementation. Likely using the Gas Escalator ethers middleware. --- .../ethereum_gravity/src/submit_batch.rs | 130 +++++++----------- orchestrator/ethereum_gravity/src/utils.rs | 28 ++-- .../ethereum_gravity/src/valset_update.rs | 63 ++++----- .../gravity_utils/src/message_signatures.rs | 2 +- .../gravity_utils/src/types/batches.rs | 32 +++-- orchestrator/relayer/src/batch_relaying.rs | 42 +++--- 6 files changed, 129 insertions(+), 168 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/submit_batch.rs b/orchestrator/ethereum_gravity/src/submit_batch.rs index ab18cba46..b02157fb7 100644 --- a/orchestrator/ethereum_gravity/src/submit_batch.rs +++ b/orchestrator/ethereum_gravity/src/submit_batch.rs @@ -1,10 +1,13 @@ -use crate::utils::{get_tx_batch_nonce, GasCost}; -use clarity::PrivateKey as EthPrivateKey; -use clarity::{Address as EthAddress, Uint256}; +use crate::utils::{EthSignerMiddleware, GasCost, get_tx_batch_nonce, set_contract_call_gas_for_estimate}; +use ethers::contract::builders::ContractCall; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; use gravity_utils::error::GravityError; +use gravity_utils::gravity::*; use gravity_utils::message_signatures::encode_tx_batch_confirm_hashed; use gravity_utils::types::*; use web30::types::SendTxOption; +use std::ops::Add; use std::{cmp::min, time::Duration}; use web30::{client::Web3, types::TransactionRequest}; @@ -15,15 +18,14 @@ pub async fn send_eth_transaction_batch( current_valset: Valset, batch: TransactionBatch, confirms: &[BatchConfirmResponse], - web3: &Web3, timeout: Duration, gravity_contract_address: EthAddress, gravity_id: String, - our_eth_key: EthPrivateKey, - options:Vec, + options: Vec, + eth_client: EthClient, ) -> Result<(), GravityError> { let new_batch_nonce = batch.nonce; - let eth_address = our_eth_key.to_public_key().unwrap(); + let eth_address = eth_client.address(); info!( "Ordering signatures and submitting TransactionBatch {}:{} to Ethereum", batch.token_contract, new_batch_nonce @@ -34,10 +36,11 @@ pub async fn send_eth_transaction_batch( gravity_contract_address, batch.token_contract, eth_address, - &web3, + eth_client, ) .await?; - let current_block_height = web3.eth_block_number().await?; + + let current_block_height = eth_client.get_block_number().await?; if before_nonce >= new_batch_nonce { info!( "Someone else updated the batch to {}, exiting early", @@ -52,29 +55,28 @@ pub async fn send_eth_transaction_batch( return Ok(()); } - let payload = encode_batch_payload(current_valset, &batch, confirms, gravity_id)?; - - let tx = web3 - .send_transaction( - gravity_contract_address, - payload, - 0u32.into(), - eth_address, - our_eth_key, - options, - ) - .await?; + let contract_call = build_submit_batch_contract_call( + current_valset, batch, confirms, gravity_contract_address, gravity_id, eth_client + ); + // TODO(bolten): we need to implement the gas multiplier being passed as a TxOption + let pending_tx = contract_call.send().await?; info!("Sent batch update with txid {:#066x}", tx); + // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? + // additionally we are mirroring only waiting for 1 confirmation by leaving that as default + pending_tx.interval(Duration::from_secs(1)); - web3.wait_for_transaction(tx.clone(), timeout, None).await?; + if let Err(tx_error) = tokio::time::timeout(timeout, async { pending_tx.await? }).await { + return Err(tx_error); + }; let last_nonce = get_tx_batch_nonce( gravity_contract_address, batch.token_contract, eth_address, - &web3, + eth_client, ) .await?; + if last_nonce != new_batch_nonce { error!( "Current nonce is {} expected to update to nonce {}", @@ -83,6 +85,7 @@ pub async fn send_eth_transaction_batch( } else { info!("Successfully updated Batch with new Nonce {:?}", last_nonce); } + Ok(()) } @@ -91,42 +94,29 @@ pub async fn estimate_tx_batch_cost( current_valset: Valset, batch: TransactionBatch, confirms: &[BatchConfirmResponse], - web3: &Web3, gravity_contract_address: EthAddress, gravity_id: String, - our_eth_key: EthPrivateKey, + eth_client: EthClient, ) -> Result { - let our_eth_address = our_eth_key.to_public_key().unwrap(); - let our_balance = web3.eth_get_balance(our_eth_address).await?; - let our_nonce = web3.eth_get_transaction_count(our_eth_address).await?; - let gas_limit = min((u64::MAX - 1).into(), our_balance.clone()); - let gas_price = web3.eth_gas_price().await?; - let zero: Uint256 = 0u8.into(); - let val = web3 - .eth_estimate_gas(TransactionRequest { - from: Some(our_eth_address), - to: gravity_contract_address, - nonce: Some(our_nonce.clone().into()), - gas_price: Some(gas_price.clone().into()), - gas: Some(gas_limit.into()), - value: Some(zero.into()), - data: Some(encode_batch_payload(current_valset, &batch, confirms, gravity_id)?.into()), - }) - .await?; + let contract_call = build_submit_batch_contract_call( + current_valset, batch, confirms, gravity_contract_address, gravity_id, eth_client + ); + let contract_call = set_contract_call_gas_for_estimate(contract_call, eth_client); Ok(GasCost { - gas: val, - gas_price, + gas: contract_call.estimate_gas().await?, + gas_price }) } -/// Encodes the batch payload for both estimate_tx_batch_cost and send_eth_transaction_batch -fn encode_batch_payload( +pub fn build_submit_batch_contract_call( current_valset: Valset, - batch: &TransactionBatch, + batch: TransactionBatch, confirms: &[BatchConfirmResponse], + gravity_contract_address: EthAddress, gravity_id: String, -) -> Result, GravityError> { + eth_client: EthClient, +) -> Result, GravityError> { let (current_addresses, current_powers) = current_valset.filter_empty_addresses(); let current_valset_nonce = current_valset.nonce; let new_batch_nonce = batch.nonce; @@ -135,40 +125,12 @@ fn encode_batch_payload( let sig_arrays = to_arrays(sig_data); let (amounts, destinations, fees) = batch.get_checkpoint_values(); - // Solidity function signature - // function submitBatch( - // // The validators that approve the batch and new valset - // address[] memory _currentValidators, - // uint256[] memory _currentPowers, - // uint256 _currentValsetNonce, - // // These are arrays of the parts of the validators signatures - // uint8[] memory _v, - // bytes32[] memory _r, - // bytes32[] memory _s, - // // The batch of transactions - // uint256[] memory _amounts, - // address[] memory _destinations, - // uint256[] memory _fees, - // uint256 _batchNonce, - // address _tokenContract, - // uint256 _batchTimeout - let tokens = &[ - current_addresses.into(), - current_powers.into(), - current_valset_nonce.into(), - sig_arrays.v, - sig_arrays.r, - sig_arrays.s, - amounts, - destinations, - fees, - new_batch_nonce.clone().into(), - batch.token_contract.into(), - batch.batch_timeout.into(), - ]; - let payload = clarity::abi::encode_call("submitBatch(address[],uint256[],uint256,uint8[],bytes32[],bytes32[],uint256[],address[],uint256[],uint256,address,uint256)", - tokens).unwrap(); - trace!("Tokens {:?}", tokens); - - Ok(payload) + let contract = Gravity::new(gravity_contract_address, eth_client); + Ok(contract.submit_batch( + current_addresses, current_powers.into(), current_valset_nonce.into(), + sig_arrays.v, sig_arrays.r, sig_arrays.s, + amounts, destinations, fees, + new_batch_nonce.into(), batch.token_contract, batch.batch_timeout.into() + .from(eth_client.address()) + .value(0u8.into()))) } diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 148ea2a69..927e5fe7f 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -43,7 +43,7 @@ pub async fn get_valset_nonce( ) -> Result { let contract_call = Gravity::new(contract_address, eth_client) .state_last_valset_nonce(); - let contract_call = build_contract_eth_call(contract_call, eth_client, caller_address).await?; + let contract_call = build_contract_eth_call(contract_call, eth_client).await?; let valset_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? @@ -62,9 +62,9 @@ pub async fn get_tx_batch_nonce( caller_address: EthAddress, eth_client: EthClient, ) -> Result { - let contract_call = Gravity::new(contract_address, eth_client).state_last_batch_nonces(p0) + let contract_call = Gravity::new(contract_address, eth_client) .last_batch_nonce(erc20_contract_address); - let contract_call = build_contract_eth_call(contract_call, eth_client, caller_address).await?; + let contract_call = build_contract_eth_call(contract_call, eth_client).await?; let tx_batch_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? @@ -85,7 +85,7 @@ pub async fn get_logic_call_nonce( ) -> Result { let contract_call = Gravity::new(contract_address, eth_client) .last_logic_call_nonce(invalidation_id.as_slice()); - let contract_call = build_contract_eth_call(contract_call, eth_client, caller_address).await?; + let contract_call = build_contract_eth_call(contract_call, eth_client).await?; let logic_call_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? @@ -105,7 +105,7 @@ pub async fn get_event_nonce( ) -> Result { let contract_call = Gravity::new(contract_address, eth_client) .state_last_event_nonce(); - let contract_call = build_contract_eth_call(contract_call, eth_client, caller_address).await?; + let contract_call = build_contract_eth_call(contract_call, eth_client).await?; let event_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? @@ -125,7 +125,7 @@ pub async fn get_gravity_id( ) -> Result { let contract_call = Gravity::new(contract_address, eth_client) .state_gravity_id(); - let contract_call = build_contract_eth_call(contract_call, eth_client, caller_address).await?; + let contract_call = build_contract_eth_call(contract_call, eth_client).await?; String::from_utf8(contract_call.call().await?.to_vec()) } @@ -141,11 +141,10 @@ pub async fn get_gravity_id( pub async fn build_contract_eth_call( contract_call: ContractCall, eth_client: EthClient, - caller_address: EthAddress, ) -> Result, GravityError> { const GAS_LIMIT: u128 = 12450000; // the most Hardhat will allow, will work on Geth - let caller_balance = eth_client.get_balance(caller_address, None).await?; + let caller_balance = eth_client.get_balance(eth_client.get_address(), None).await?; let latest_block = eth_client.get_block(BlockNumber::Latest).await?; let price = latest_block.base_fee_per_gas.ok_or(1u8.into()); // shouldn't happen unless pre-London let limit = min(GAS_LIMIT.into(), caller_balance / price.clone()); @@ -156,6 +155,19 @@ pub async fn build_contract_eth_call( .value(0u8.into())) } +/// Take a ContractCall to be used with eth_estimateGas and set the gas limit and price +/// based on the caller's state. +pub async fn set_contract_call_gas_for_estimate( + contract_call: ContractCall, + eth_client: EthClient, +) -> Result, GravityError> { + let our_balance = eth_client.get_balance(eth_client.get_address(), None).await?; + let gas_limit = min((u64::MAX - 1).into(), our_balance); + let gas_price = eth_client.get_gas_price().await?; + + Ok(contract_call.gas(gas_limit).gas_price(gas_price)) +} + /// Just a helper struct to represent the cost of actions on Ethereum #[derive(Debug, Default, Clone)] pub struct GasCost { diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index 5ba9fffb6..706ac01bf 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -1,4 +1,4 @@ -use crate::utils::{EthSignerMiddleware, get_valset_nonce, GasCost}; +use crate::utils::{EthSignerMiddleware, get_valset_nonce, GasCost, set_contract_call_gas_for_estimate}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; @@ -18,9 +18,26 @@ pub async fn send_eth_valset_update( gravity_id: String, eth_client: EthClient, ) -> Result<(), GravityError> { + let old_nonce = old_valset.nonce; + let new_nonce = new_valset.nonce; + assert!(new_nonce > old_nonce); + let eth_address = eth_client.address(); + info!( + "Ordering signatures and submitting validator set {} -> {} update to Ethereum", + old_nonce, new_nonce + ); + let before_nonce = get_valset_nonce(gravity_contract_address, eth_address, eth_client).await?; + if before_nonce != old_nonce { + info!( + "Someone else updated the valset to {}, exiting early", + before_nonce + ); + return Ok(()); + } + let contract_call = build_valset_update_contract_call( new_valset, old_valset, confirms, gravity_contract_address, gravity_id, eth_client - ).await?; + )?; let pending_tx = contract_call.send().await?; info!("Sent valset update with txid {:#066x}", pending_tx); // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? @@ -56,26 +73,11 @@ pub async fn estimate_valset_cost( gravity_id: String, eth_client: EthClient, ) -> Result { - let our_eth_address = eth_client.address(); - let our_balance = eth_client.get_balance(our_eth_address, None).await?; - let gas_limit = min((u64::MAX - 1).into(), our_balance); - let gas_price = eth_client.get_gas_price().await?; - let contract_call = build_valset_update_contract_call( new_valset, old_valset, confirms, gravity_contract_address, gravity_id, eth_client - ).await?; - let contract_call = contract_call.gas(gas_limit).gas_price(gas_price); - - // TODO(bolten): estimate gas only takes a transaction request, and doesn't - // care if a specific block is passed as a parameter when creating the contract - // call...the old code set the nonce manually...I think that the value that - // ContractCall will put in the TransactionRequest is by default the next - // available nonce, and the only way to change it would be to reach directly into - // the object as the ContractCall has no method for setting the nonce...is the - // default behavior acceptable? - // - //let our_nonce = eth_client.get_transaction_count(our_eth_address, None).await?; - //contract_call.tx.set_nonce(our_nonce); + )?; + let contract_call = + set_contract_call_gas_for_estimate(contract_call, eth_client).await?; Ok(GasCost { gas: contract_call.estimate_gas().await?, @@ -83,7 +85,7 @@ pub async fn estimate_valset_cost( }) } -pub async fn build_valset_update_contract_call( +pub fn build_valset_update_contract_call( new_valset: Valset, old_valset: Valset, confirms: &[ValsetConfirmResponse], @@ -91,23 +93,6 @@ pub async fn build_valset_update_contract_call( gravity_id: String, eth_client: EthClient, ) -> Result, GravityError> { - let old_nonce = old_valset.nonce; - let new_nonce = new_valset.nonce; - assert!(new_nonce > old_nonce); - let eth_address = eth_client.address(); - info!( - "Ordering signatures and submitting validator set {} -> {} update to Ethereum", - old_nonce, new_nonce - ); - let before_nonce = get_valset_nonce(gravity_contract_address, eth_address, eth_client).await?; - if before_nonce != old_nonce { - info!( - "Someone else updated the valset to {}, exiting early", - before_nonce - ); - return Ok(()); - } - let (old_addresses, old_powers) = old_valset.filter_empty_addresses(); let (new_addresses, new_powers) = new_valset.filter_empty_addresses(); @@ -124,6 +109,6 @@ pub async fn build_valset_update_contract_call( new_addresses, new_powers, new_nonce.into(), old_addresses, old_powers, old_nonce.into(), sig_arrays.v, sig_arrays.r, sig_arrays.s) - .from(eth_address) + .from(eth_client.address()) .value(0u8.into())) } diff --git a/orchestrator/gravity_utils/src/message_signatures.rs b/orchestrator/gravity_utils/src/message_signatures.rs index b8efc0fef..7f032d1c6 100644 --- a/orchestrator/gravity_utils/src/message_signatures.rs +++ b/orchestrator/gravity_utils/src/message_signatures.rs @@ -111,7 +111,7 @@ fn test_valset_signature() { /// Note: This is the message, you need to run Keccak256::digest() in order to get the 32byte /// digest that is normally signed or may be used as a 'hash of the message' pub fn encode_tx_batch_confirm(gravity_id: String, batch: TransactionBatch) -> Vec { - let (amounts, destinations, fees) = batch.get_checkpoint_values(); + let (amounts, destinations, fees) = batch.get_checkpoint_values_tokens(); abi::encode(&[ Token::FixedBytes(gravity_id.into_bytes()), diff --git a/orchestrator/gravity_utils/src/types/batches.rs b/orchestrator/gravity_utils/src/types/batches.rs index 3ed697a57..4bde1944c 100644 --- a/orchestrator/gravity_utils/src/types/batches.rs +++ b/orchestrator/gravity_utils/src/types/batches.rs @@ -47,21 +47,33 @@ pub struct TransactionBatch { impl TransactionBatch { /// extracts the amounts, destinations and fees as submitted to the Ethereum contract /// and used for signatures - pub fn get_checkpoint_values(&self) -> (Token, Token, Token) { - let amounts: Vec = - self.transactions.iter().map(|tx| Token::Uint(tx.erc20_token.amount)).collect(); - let destinations: Vec = - self.transactions.iter().map(|tx| Token::Address(tx.ethereum_recipient)).collect(); - let fees: Vec = - self.transactions.iter().map(|tx| Token::Uint(tx.erc20_fee.amount)).collect(); + pub fn get_checkpoint_values(&self) -> (Vec, Vec, Vec) { + let amounts: Vec = + self.transactions.iter().map(|tx| tx.erc20_token.amount).collect(); + let destinations: Vec = + self.transactions.iter().map(|tx| tx.ethereum_recipient).collect(); + let fees: Vec = + self.transactions.iter().map(|tx| tx.erc20_fee.amount).collect(); assert_eq!(amounts.len(), destinations.len()); assert_eq!(fees.len(), destinations.len()); + (amounts, destinations, fees) + } + + pub fn get_checkpoint_values_tokens(&self) -> (Token, Token, Token) { + let (amounts, destinations, fees) = self.get_checkpoint_values(); + let amounts_tokens = + amounts.iter().map(|amount| Token::Uint(*amount)).collect(); + let destinations_tokens = + destinations.iter().map(|destination| Token::Address(*destination)).collect(); + let fees_tokens = + fees.iter().map(|fee| Token::Uint(*fee)).collect(); + ( - Token::Array(amounts), - Token::Array(destinations), - Token::Array(fees), + Token::Array(amounts_tokens), + Token::Array(destinations_tokens), + Token::Array(fees_tokens), ) } diff --git a/orchestrator/relayer/src/batch_relaying.rs b/orchestrator/relayer/src/batch_relaying.rs index 2335dc26b..0518c2721 100644 --- a/orchestrator/relayer/src/batch_relaying.rs +++ b/orchestrator/relayer/src/batch_relaying.rs @@ -1,20 +1,17 @@ -use clarity::address::Address as EthAddress; -use clarity::PrivateKey as EthPrivateKey; -use clarity::Uint256; - use cosmos_gravity::query::get_latest_transaction_batches; use cosmos_gravity::query::get_transaction_batch_signatures; -use ethereum_gravity::utils::{downcast_to_u128, get_tx_batch_nonce}; -use ethereum_gravity::{one_eth, submit_batch::send_eth_transaction_batch}; +use ethereum_gravity::{one_eth, submit_batch::send_eth_transaction_batch, utils::EthClient, + utils::get_tx_batch_nonce}; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; +use gravity_utils::ethereum::downcast_to_u128; use gravity_utils::message_signatures::encode_tx_batch_confirm_hashed; -use gravity_utils::types::Valset; -use gravity_utils::types::{BatchConfirmResponse, TransactionBatch}; +use gravity_utils::types::{BatchConfirmResponse, TransactionBatch, Valset}; use web30::types::SendTxOption; use std::collections::HashMap; use std::time::Duration; use tonic::transport::Channel; -use web30::client::Web3; #[derive(Debug, Clone)] struct SubmittableBatch { @@ -32,8 +29,7 @@ struct SubmittableBatch { pub async fn relay_batches( // the validator set currently in the contract on Ethereum current_valset: Valset, - ethereum_key: EthPrivateKey, - web3: &Web3, + eth_client: EthClient, grpc_client: &mut GravityQueryClient, gravity_contract_address: EthAddress, gravity_id: String, @@ -45,11 +41,9 @@ pub async fn relay_batches( trace!("possible batches {:?}", possible_batches); - submit_batches( current_valset, - ethereum_key, - web3, + eth_client, gravity_contract_address, gravity_id, timeout, @@ -132,19 +126,18 @@ async fn get_batches_and_signatures( /// submit individual batches but also batches in different orders async fn submit_batches( current_valset: Valset, - ethereum_key: EthPrivateKey, - web3: &Web3, + eth_client: EthClient, gravity_contract_address: EthAddress, gravity_id: String, timeout: Duration, gas_multiplier: f32, possible_batches: HashMap>, ) { - let our_ethereum_address = ethereum_key.to_public_key().unwrap(); - let ethereum_block_height = if let Ok(bn) = web3.eth_block_number().await { + let our_ethereum_address = eth_client.address(); + let ethereum_block_height = if let Ok(bn) = eth_client.get_block_number().await { bn } else { - warn!("Failed to get eth block height, is your eth node working?"); + error!("Failed to get eth block height, is your eth node working?"); return; }; @@ -158,7 +151,7 @@ async fn submit_batches( gravity_contract_address, erc20_contract, our_ethereum_address, - web3, + eth_client, ) .await; if latest_ethereum_batch.is_err() { @@ -174,8 +167,7 @@ async fn submit_batches( let oldest_signed_batch = batch.batch; let oldest_signatures = batch.sigs; - let timeout_height: Uint256 = oldest_signed_batch.batch_timeout.into(); - if timeout_height < ethereum_block_height { + if oldest_signed_batch.batch_timeout < ethereum_block_height.as_u64() { warn!( "Batch {}/{} has timed out and can not be submitted", oldest_signed_batch.nonce, oldest_signed_batch.token_contract @@ -189,10 +181,9 @@ async fn submit_batches( current_valset.clone(), oldest_signed_batch.clone(), &oldest_signatures, - web3, gravity_contract_address, gravity_id.clone(), - ethereum_key, + eth_client, ) .await; if cost.is_err() { @@ -215,12 +206,11 @@ async fn submit_batches( current_valset.clone(), oldest_signed_batch, &oldest_signatures, - web3, timeout, gravity_contract_address, gravity_id.clone(), - ethereum_key, tx_options, + eth_client, ) .await; if res.is_err() { From f66ec6f7bb345a790dcb22b4c561783cdc6c14f0 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 12 Nov 2021 22:26:19 -0800 Subject: [PATCH 045/115] Remove dead power_diff code --- .../gravity_utils/src/types/valsets.rs | 46 ------------------- 1 file changed, 46 deletions(-) diff --git a/orchestrator/gravity_utils/src/types/valsets.rs b/orchestrator/gravity_utils/src/types/valsets.rs index 9f8cfec8f..5e7000cf5 100644 --- a/orchestrator/gravity_utils/src/types/valsets.rs +++ b/orchestrator/gravity_utils/src/types/valsets.rs @@ -274,52 +274,6 @@ impl Valset { } res } - - /// This function takes the current valset and compares it to a provided one - /// returning a percentage difference in their power allocation. This is a very - /// important function as it's used to decide when the validator sets are updated - /// on the Ethereum chain and when new validator sets are requested on the Cosmos - /// side. In theory an error here, if unnoticed for long enough, could allow funds - /// to be stolen from the bridge without the validators in question still having stake - /// to lose. - /// Returned value must be less than or equal to two - pub fn power_diff(&self, other: &Valset) -> f32 { - let mut total_power_diff = 0u64; - let a = self.to_hashmap(); - let b = other.to_hashmap(); - let a_map = self.to_hashset(); - let b_map = other.to_hashset(); - // items in A and B, we go through these and compute the absolute value of the - // difference in power and sum it. - let intersection = a_map.intersection(&b_map); - // items in A but not in B or vice versa, since we're just trying to compute the difference - // we can simply sum all of these up. - let symmetric_difference = a_map.symmetric_difference(&b_map); - for item in symmetric_difference { - let mut power = None; - if let Some(val) = a.get(item) { - power = Some(val); - } else if let Some(val) = b.get(item) { - power = Some(val); - } - // impossible for this to panic without a failure in the logic - // of the symmetric difference function - let power = power.unwrap(); - total_power_diff += power; - } - for item in intersection { - // can't panic since there must be an entry for both. - let power_a = a[item]; - let power_b = b[item]; - if power_a > power_b { - total_power_diff += power_a - power_b; - } else { - total_power_diff += power_b - power_a; - } - } - - (total_power_diff as f32) / (u32::MAX as f32) - } } impl From for Valset { From 9596f2ca2f304483f863288d990167e02e72bbbe Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 12 Nov 2021 22:49:15 -0800 Subject: [PATCH 046/115] Move gravity ABI to its own package --- orchestrator/Cargo.lock | 12 ++++++++++++ orchestrator/Cargo.toml | 2 ++ orchestrator/abi_build/src/main.rs | 4 ++-- orchestrator/ethereum_gravity/Cargo.toml | 5 +++-- orchestrator/ethereum_gravity/src/submit_batch.rs | 2 +- orchestrator/ethereum_gravity/src/utils.rs | 2 +- orchestrator/ethereum_gravity/src/valset_update.rs | 4 ++-- orchestrator/gravity_abi/Cargo.toml | 12 ++++++++++++ orchestrator/{abi => gravity_abi}/Gravity.json | 0 .../{gravity_utils => gravity_abi}/src/gravity.rs | 0 orchestrator/gravity_abi/src/lib.rs | 1 + orchestrator/gravity_utils/src/lib.rs | 1 - 12 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 orchestrator/gravity_abi/Cargo.toml rename orchestrator/{abi => gravity_abi}/Gravity.json (100%) rename orchestrator/{gravity_utils => gravity_abi}/src/gravity.rs (100%) create mode 100644 orchestrator/gravity_abi/src/lib.rs diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index 8319608d7..eb942bcf8 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -1676,6 +1676,7 @@ dependencies = [ "clarity", "deep_space 2.4.7", "ethers", + "gravity_abi", "gravity_utils", "log", "sha3", @@ -2182,6 +2183,16 @@ dependencies = [ "web30", ] +[[package]] +name = "gravity_abi" +version = "0.1.0" +dependencies = [ + "ethers", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "gravity_bridge" version = "0.1.0" @@ -2190,6 +2201,7 @@ dependencies = [ "cosmos_gravity", "ethereum_gravity", "gorc", + "gravity_abi", "gravity_proto", "gravity_utils", "orchestrator", diff --git a/orchestrator/Cargo.toml b/orchestrator/Cargo.toml index 14376c51d..20a32ff5f 100644 --- a/orchestrator/Cargo.toml +++ b/orchestrator/Cargo.toml @@ -25,6 +25,7 @@ members = [ "register_delegate_keys", "gorc", "abi_build", + "gravity_abi", ] [dependencies] @@ -39,3 +40,4 @@ register_delegate_keys = { path = "./register_delegate_keys" } gorc = { path = "./gorc" } relayer = { path = "./relayer" } abi_build = { path = "./abi_build" } +gravity_abi = { path = "./gravity_abi" } diff --git a/orchestrator/abi_build/src/main.rs b/orchestrator/abi_build/src/main.rs index d4c13bca4..0a4dedf9c 100644 --- a/orchestrator/abi_build/src/main.rs +++ b/orchestrator/abi_build/src/main.rs @@ -2,7 +2,7 @@ use ethers::contract::Abigen; use std::process; fn main() { - let abigen = match Abigen::new("Gravity", "../abi/Gravity.json") { + let abigen = match Abigen::new("Gravity", "../gravity_abi/Gravity.json") { Ok(abigen) => abigen, Err(e) => { println!("Could not open Gravity.json: {}", e); @@ -22,7 +22,7 @@ fn main() { } }; - match abi.write_to_file("../gravity_utils/src/gravity.rs") { + match abi.write_to_file("../gravity_abi/src/gravity.rs") { Ok(_) => (), Err(e) => println!("Error writing gravity.rs: {}", e), } diff --git a/orchestrator/ethereum_gravity/Cargo.toml b/orchestrator/ethereum_gravity/Cargo.toml index 633d1bad8..1f8942c76 100644 --- a/orchestrator/ethereum_gravity/Cargo.toml +++ b/orchestrator/ethereum_gravity/Cargo.toml @@ -7,9 +7,10 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -gravity_utils = {path = "../gravity_utils"} +gravity_abi = { path = "../gravity_abi" } +gravity_utils = { path = "../gravity_utils" } -deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} +deep_space = { git="https://github.com/iqlusioninc/deep_space/", branch="master" } ethers = { version = "0.5.4", features=["abigen"] } clarity = "0.4.11" web30 = "0.15.4" diff --git a/orchestrator/ethereum_gravity/src/submit_batch.rs b/orchestrator/ethereum_gravity/src/submit_batch.rs index b02157fb7..d6387a47b 100644 --- a/orchestrator/ethereum_gravity/src/submit_batch.rs +++ b/orchestrator/ethereum_gravity/src/submit_batch.rs @@ -2,8 +2,8 @@ use crate::utils::{EthSignerMiddleware, GasCost, get_tx_batch_nonce, set_contrac use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; +use gravity_abi::gravity::*; use gravity_utils::error::GravityError; -use gravity_utils::gravity::*; use gravity_utils::message_signatures::encode_tx_batch_confirm_hashed; use gravity_utils::types::*; use web30::types::SendTxOption; diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 927e5fe7f..4455beaed 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -3,9 +3,9 @@ use ethers::core::abi::{self, Token}; use ethers::prelude::*; use ethers::types::Address as EthAddress; use ethers::utils::keccak256; +use gravity_abi::gravity::*; use gravity_utils::error::GravityError; use gravity_utils::ethereum::downcast_to_u64; -use gravity_utils::gravity::*; use gravity_utils::types::*; use std::panic; diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index 706ac01bf..d5bf7337b 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -2,8 +2,8 @@ use crate::utils::{EthSignerMiddleware, get_valset_nonce, GasCost, set_contract_ use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; -use gravity_utils::types::*; -use gravity_utils::{error::GravityError, gravity::*, message_signatures::encode_valset_confirm_hashed}; +use gravity_abi::gravity::*; +use gravity_utils::{error::GravityError, message_signatures::encode_valset_confirm_hashed, types::*}; use std::{cmp::min, time::Duration}; /// this function generates an appropriate Ethereum transaction diff --git a/orchestrator/gravity_abi/Cargo.toml b/orchestrator/gravity_abi/Cargo.toml new file mode 100644 index 000000000..8e8379e0b --- /dev/null +++ b/orchestrator/gravity_abi/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "gravity_abi" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ethers = { version = "0.5.4", features=["abigen"] } +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0.69" \ No newline at end of file diff --git a/orchestrator/abi/Gravity.json b/orchestrator/gravity_abi/Gravity.json similarity index 100% rename from orchestrator/abi/Gravity.json rename to orchestrator/gravity_abi/Gravity.json diff --git a/orchestrator/gravity_utils/src/gravity.rs b/orchestrator/gravity_abi/src/gravity.rs similarity index 100% rename from orchestrator/gravity_utils/src/gravity.rs rename to orchestrator/gravity_abi/src/gravity.rs diff --git a/orchestrator/gravity_abi/src/lib.rs b/orchestrator/gravity_abi/src/lib.rs new file mode 100644 index 000000000..28701a439 --- /dev/null +++ b/orchestrator/gravity_abi/src/lib.rs @@ -0,0 +1 @@ +pub mod gravity; diff --git a/orchestrator/gravity_utils/src/lib.rs b/orchestrator/gravity_utils/src/lib.rs index f1247857c..55f465d56 100644 --- a/orchestrator/gravity_utils/src/lib.rs +++ b/orchestrator/gravity_utils/src/lib.rs @@ -8,6 +8,5 @@ extern crate log; pub mod connection_prep; pub mod error; pub mod ethereum; -pub mod gravity; pub mod message_signatures; pub mod types; From 3e84d28ca484c9f7386c64ba85de347a91934938 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 12 Nov 2021 22:59:23 -0800 Subject: [PATCH 047/115] Fix gravity ABI reference in ethereum_events --- orchestrator/Cargo.lock | 1 + orchestrator/gravity_utils/Cargo.toml | 5 +++-- orchestrator/gravity_utils/src/types/ethereum_events.rs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index eb942bcf8..bbb99be32 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -2231,6 +2231,7 @@ dependencies = [ "cosmos-sdk-proto", "deep_space 2.4.7", "ethers", + "gravity_abi", "gravity_proto", "hex", "log", diff --git a/orchestrator/gravity_utils/Cargo.toml b/orchestrator/gravity_utils/Cargo.toml index 9652a8e4f..606b838e0 100644 --- a/orchestrator/gravity_utils/Cargo.toml +++ b/orchestrator/gravity_utils/Cargo.toml @@ -7,9 +7,10 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -gravity_proto = {path = "../gravity_proto/"} +gravity_abi = { path = "../gravity_abi" } +gravity_proto = { path = "../gravity_proto/" } cosmos-sdk-proto = "0.6.3" -deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} +deep_space = { git="https://github.com/iqlusioninc/deep_space/", branch="master" } ethers = { version = "0.5.4", features=["abigen"] } web30 = "0.15" clarity = "0.4.11" diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 2bc7c7110..fe2d693d7 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -7,12 +7,12 @@ use super::ValsetMember; use crate::error::GravityError; use crate::ethereum::downcast_to_u64; -use crate::gravity::*; use deep_space::utils::bytes_to_hex_str; use deep_space::Address as CosmosAddress; use ethers::abi::RawLog; use ethers::prelude::*; use ethers::types::Address as EthAddress; +use gravity_abi::gravity::*; pub const ERC20_DEPLOYED_EVENT_STR: &'static str = "ERC20DeployedEvent(string,address,string,string,uint8,uint256)"; From 268a1805277e5f4144c1270ea762552b1fde223f Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 12 Nov 2021 23:00:28 -0800 Subject: [PATCH 048/115] Fix EthersParseAddressError --- orchestrator/gravity_utils/src/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index c51f8afb5..c297ec6ac 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -8,7 +8,7 @@ use ethers::abi::Error as EthersAbiError; use ethers::abi::ethereum_types::FromDecStrErr as EthersParseUintError; use ethers::prelude::*; use ethers::prelude::signer::SignerMiddlewareError; -use hex::FromHexError; +use hex::FromHexError as EthersParseAddressError; use num_bigint::ParseBigIntError; use std::fmt::{self, Debug}; use tokio::time::error::Elapsed; @@ -22,7 +22,7 @@ pub enum GravityError { CosmosAddressError(CosmosAddressError), EthereumRestError(SignerMiddlewareError, LocalWallet>), EthersAbiError(EthersAbiError), - EthersParseAddressError(FromHexError), + EthersParseAddressError(EthersParseAddressError), EthersParseUintError(EthersParseUintError), InvalidBridgeStateError(String), FailedToUpdateValset, From e2bc98fcbd92f31642afaf066933846a91055633 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 12 Nov 2021 23:21:37 -0800 Subject: [PATCH 049/115] Various fixes --- orchestrator/Cargo.lock | 2 +- orchestrator/gravity_utils/Cargo.toml | 2 +- orchestrator/gravity_utils/src/error.rs | 11 ++++++++++- .../gravity_utils/src/types/ethereum_events.rs | 10 +++++----- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index bbb99be32..35955c579 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -2233,11 +2233,11 @@ dependencies = [ "ethers", "gravity_abi", "gravity_proto", - "hex", "log", "num-bigint 0.4.0", "num256", "rand 0.8.4", + "rustc-hex", "serde", "serde_derive", "serde_json", diff --git a/orchestrator/gravity_utils/Cargo.toml b/orchestrator/gravity_utils/Cargo.toml index 606b838e0..0f02ff252 100644 --- a/orchestrator/gravity_utils/Cargo.toml +++ b/orchestrator/gravity_utils/Cargo.toml @@ -24,7 +24,7 @@ num-bigint = "0.4" log = "0.4" url = "2" sha3 = "0.9" -hex = { version = "0.4.3", default-features = false, features = ["std"] } +rustc-hex = "2.1.0" [dev_dependencies] rand = "0.8" actix = "0.11" diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index c297ec6ac..631c97784 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -8,7 +8,8 @@ use ethers::abi::Error as EthersAbiError; use ethers::abi::ethereum_types::FromDecStrErr as EthersParseUintError; use ethers::prelude::*; use ethers::prelude::signer::SignerMiddlewareError; -use hex::FromHexError as EthersParseAddressError; +use ethers::types::SignatureError as EthersSignatureError; +use rustc_hex::FromHexError as EthersParseAddressError; use num_bigint::ParseBigIntError; use std::fmt::{self, Debug}; use tokio::time::error::Elapsed; @@ -24,6 +25,7 @@ pub enum GravityError { EthersAbiError(EthersAbiError), EthersParseAddressError(EthersParseAddressError), EthersParseUintError(EthersParseUintError), + EthersSignatureError(EthersSignatureError), InvalidBridgeStateError(String), FailedToUpdateValset, EthereumContractError(String), @@ -49,6 +51,7 @@ impl fmt::Display for GravityError { GravityError::EthersAbiError(val) => write!(f, "Ethers ABI error {}", val), GravityError::EthersParseAddressError(val) => write!(f, "Ethers H160 address parse error {}", val), GravityError::EthersParseUintError(val) => write!(f, "Ethers U256 parse error {}", val), + GravityError::EthersSignatureError(val) => write!(f, "Ethers signature error {}", val), GravityError::InvalidOptionsError(val) => { write!(f, "Invalid TX options for this call {}", val) } @@ -114,6 +117,12 @@ impl From for GravityError { } } +impl From for GravityError { + fn from(error: EthersSignatureError) -> Self { + GravityError::EthersSignatureError(error) + } +} + impl From for GravityError { fn from(error: Status) -> Self { GravityError::GravityGrpcError(error) diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index fe2d693d7..6d6e51818 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -28,7 +28,7 @@ pub const VALSET_UPDATED_EVENT_STR: &'static str = // the types we are generating using abigen! above for the Gravity contract fn log_to_ethers_event(log: &Log) -> Result { T::decode_log(&RawLog { - topics: log.topics, + topics: log.topics.clone(), data: log.data.to_vec(), }) .map_err(From::from) @@ -86,11 +86,11 @@ pub trait FromLogsWithPrefix { pub trait EventNonceFilter: Sized { /// returns all values in the array with event nonces greater /// than the provided value - fn filter_by_event_nonce(event_nonce: u64, input: &[T]) -> Vec { + fn filter_by_event_nonce(event_nonce: u64, input: &[T]) -> Vec { input .iter() .filter(|item| item.get_event_nonce() > event_nonce.into()) - .map(|item| *item.clone()) + .map(|item| (*item).clone()) .collect() } } @@ -112,8 +112,8 @@ impl FromLog for ValsetUpdatedEvent { let event: ValsetUpdatedEventFilter = log_to_ethers_event(input)?; let mut powers: Vec = Vec::new(); - for power in event.powers { - if let Some(downcast_power) = downcast_to_u64(power) { + for power in &event.powers { + if let Some(downcast_power) = downcast_to_u64(*power) { powers.push(downcast_power); } else { return Err(GravityError::InvalidEventLogError(format!( From c3d5997ed46529b1977b8230ab422b6f2ad6f43b Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 12 Nov 2021 23:34:13 -0800 Subject: [PATCH 050/115] Add tokio to ethereum_gravity --- orchestrator/Cargo.lock | 61 ++++++++++++------------ orchestrator/ethereum_gravity/Cargo.toml | 1 + 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index 35955c579..ecabda67c 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -70,7 +70,7 @@ checksum = "4f38df9084daf34a7822ccc39e85598f23fd80e8451003ea41441ed5123fc012" dependencies = [ "abscissa_core", "actix-rt 2.2.0", - "tokio 1.5.0", + "tokio 1.13.0", ] [[package]] @@ -93,7 +93,7 @@ dependencies = [ "parking_lot", "pin-project-lite 0.2.6", "smallvec", - "tokio 1.5.0", + "tokio 1.13.0", "tokio-util 0.6.6", ] @@ -125,7 +125,7 @@ dependencies = [ "futures-sink", "log", "pin-project-lite 0.2.6", - "tokio 1.5.0", + "tokio 1.13.0", "tokio-util 0.6.6", ] @@ -237,7 +237,7 @@ dependencies = [ "sha-1", "smallvec", "time 0.2.26", - "tokio 1.5.0", + "tokio 1.13.0", "zstd", ] @@ -297,7 +297,7 @@ checksum = "bc7d7cd957c9ed92288a7c3c96af81fa5291f65247a76a34dac7b6af74e52ba0" dependencies = [ "actix-macros 0.2.0", "futures-core", - "tokio 1.5.0", + "tokio 1.13.0", ] [[package]] @@ -725,7 +725,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "tokio 1.5.0", + "tokio 1.13.0", "tokio-util 0.6.6", "tower", "tower-http", @@ -1273,7 +1273,7 @@ dependencies = [ "rand 0.8.4", "serde", "sha3", - "tokio 1.5.0", + "tokio 1.13.0", "tonic", "web30", ] @@ -1464,7 +1464,7 @@ dependencies = [ "serde_json", "sha2 0.9.8", "tendermint-proto", - "tokio 1.5.0", + "tokio 1.13.0", "tonic", "unicode-normalization", ] @@ -1680,6 +1680,7 @@ dependencies = [ "gravity_utils", "log", "sha3", + "tokio 1.13.0", "web30", ] @@ -1782,7 +1783,7 @@ dependencies = [ "syn", "thiserror", "tiny-keccak", - "tokio 1.5.0", + "tokio 1.13.0", ] [[package]] @@ -1803,7 +1804,7 @@ dependencies = [ "serde-aux", "serde_json", "thiserror", - "tokio 1.5.0", + "tokio 1.13.0", "tracing", "tracing-futures", "url", @@ -2177,7 +2178,7 @@ dependencies = [ "serde", "signatory", "thiserror", - "tokio 1.5.0", + "tokio 1.13.0", "toml", "tonic", "web30", @@ -2242,7 +2243,7 @@ dependencies = [ "serde_derive", "serde_json", "sha3", - "tokio 1.5.0", + "tokio 1.13.0", "tonic", "url", "web30", @@ -2293,7 +2294,7 @@ dependencies = [ "http", "indexmap", "slab", - "tokio 1.5.0", + "tokio 1.13.0", "tokio-util 0.6.6", "tracing", ] @@ -2431,7 +2432,7 @@ dependencies = [ "itoa", "pin-project-lite 0.2.6", "socket2 0.4.0", - "tokio 1.5.0", + "tokio 1.13.0", "tower-service", "tracing", "want", @@ -2447,7 +2448,7 @@ dependencies = [ "hyper", "log", "rustls", - "tokio 1.5.0", + "tokio 1.13.0", "tokio-rustls", "webpki", ] @@ -2461,7 +2462,7 @@ dependencies = [ "bytes 1.1.0", "hyper", "native-tls", - "tokio 1.5.0", + "tokio 1.13.0", "tokio-native-tls", ] @@ -3127,7 +3128,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "tokio 1.5.0", + "tokio 1.13.0", "tonic", "web30", ] @@ -3761,7 +3762,7 @@ dependencies = [ "openssl-probe", "serde", "serde_derive", - "tokio 1.5.0", + "tokio 1.13.0", "tonic", "web30", ] @@ -3803,7 +3804,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "tokio 1.5.0", + "tokio 1.13.0", "tokio-native-tls", "tokio-rustls", "url", @@ -4504,7 +4505,7 @@ dependencies = [ "rand 0.8.4", "serde", "serde_derive", - "tokio 1.5.0", + "tokio 1.13.0", "tonic", "url", "web30", @@ -4651,9 +4652,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.5.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5" +checksum = "588b2d10a336da58d877567cd8fb8a14b463e2104910f8132cd054b4b96e29ee" dependencies = [ "autocfg", "bytes 1.1.0", @@ -4687,7 +4688,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" dependencies = [ "native-tls", - "tokio 1.5.0", + "tokio 1.13.0", ] [[package]] @@ -4709,7 +4710,7 @@ dependencies = [ "futures", "openssl", "pin-project 1.0.8", - "tokio 1.5.0", + "tokio 1.13.0", ] [[package]] @@ -4719,7 +4720,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ "rustls", - "tokio 1.5.0", + "tokio 1.13.0", "webpki", ] @@ -4731,7 +4732,7 @@ checksum = "e177a5d8c3bf36de9ebe6d58537d8879e964332f93fb3339e43f618c81361af0" dependencies = [ "futures-core", "pin-project-lite 0.2.6", - "tokio 1.5.0", + "tokio 1.13.0", ] [[package]] @@ -4759,7 +4760,7 @@ dependencies = [ "futures-sink", "log", "pin-project-lite 0.2.6", - "tokio 1.5.0", + "tokio 1.13.0", ] [[package]] @@ -4791,7 +4792,7 @@ dependencies = [ "pin-project 1.0.8", "prost", "prost-derive", - "tokio 1.5.0", + "tokio 1.13.0", "tokio-stream", "tokio-util 0.6.6", "tower", @@ -4824,7 +4825,7 @@ dependencies = [ "pin-project 1.0.8", "rand 0.8.4", "slab", - "tokio 1.5.0", + "tokio 1.13.0", "tokio-stream", "tokio-util 0.6.6", "tower-layer", @@ -5241,7 +5242,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "tokio 1.5.0", + "tokio 1.13.0", ] [[package]] diff --git a/orchestrator/ethereum_gravity/Cargo.toml b/orchestrator/ethereum_gravity/Cargo.toml index 1f8942c76..da616360b 100644 --- a/orchestrator/ethereum_gravity/Cargo.toml +++ b/orchestrator/ethereum_gravity/Cargo.toml @@ -16,3 +16,4 @@ clarity = "0.4.11" web30 = "0.15.4" log = "0.4" sha3 = "0.9" +tokio = "1.13.0" From 9d84ee7cfc55e1689aa091be39e6c1338b23e1dd Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 12 Nov 2021 23:34:38 -0800 Subject: [PATCH 051/115] More small fixes --- orchestrator/ethereum_gravity/src/utils.rs | 23 ++++++++++--------- .../ethereum_gravity/src/valset_update.rs | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 4455beaed..9043c0e77 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -7,7 +7,8 @@ use gravity_abi::gravity::*; use gravity_utils::error::GravityError; use gravity_utils::ethereum::downcast_to_u64; use gravity_utils::types::*; -use std::panic; +use std::cmp::min; +use std::sync::Arc; pub type EthSignerMiddleware = SignerMiddleware, LocalWallet>; pub type EthClient = Arc; @@ -21,8 +22,8 @@ pub fn get_checkpoint_abi_encode( let powers = powers.iter().map(|power| Token::Uint((*power).into())).collect(); Ok(abi::encode(&[ - Token::FixedBytes(gravity_id.into_bytes()), - Token::FixedBytes("checkpoint".to_string().into_bytes()), + Token::FixedBytes(gravity_id.as_bytes().to_vec()), + Token::FixedBytes("checkpoint".as_bytes().to_vec()), Token::Uint(valset.nonce.into()), Token::Array(eth_addresses), Token::Array(powers), @@ -40,7 +41,7 @@ pub async fn get_valset_nonce( contract_address: EthAddress, caller_address: EthAddress, eth_client: EthClient, -) -> Result { +) -> Result { let contract_call = Gravity::new(contract_address, eth_client) .state_last_valset_nonce(); let contract_call = build_contract_eth_call(contract_call, eth_client).await?; @@ -61,7 +62,7 @@ pub async fn get_tx_batch_nonce( erc20_contract_address: EthAddress, caller_address: EthAddress, eth_client: EthClient, -) -> Result { +) -> Result { let contract_call = Gravity::new(contract_address, eth_client) .last_batch_nonce(erc20_contract_address); let contract_call = build_contract_eth_call(contract_call, eth_client).await?; @@ -82,7 +83,7 @@ pub async fn get_logic_call_nonce( invalidation_id: Vec, caller_address: EthAddress, eth_client: EthClient, -) -> Result { +) -> Result { let contract_call = Gravity::new(contract_address, eth_client) .last_logic_call_nonce(invalidation_id.as_slice()); let contract_call = build_contract_eth_call(contract_call, eth_client).await?; @@ -101,8 +102,8 @@ pub async fn get_logic_call_nonce( pub async fn get_event_nonce( gravity_contract_address: EthAddress, caller_address: EthAddress, - web3: &Web3, -) -> Result { + eth_client: EthClient, +) -> Result { let contract_call = Gravity::new(contract_address, eth_client) .state_last_event_nonce(); let contract_call = build_contract_eth_call(contract_call, eth_client).await?; @@ -144,12 +145,12 @@ pub async fn build_contract_eth_call( ) -> Result, GravityError> { const GAS_LIMIT: u128 = 12450000; // the most Hardhat will allow, will work on Geth - let caller_balance = eth_client.get_balance(eth_client.get_address(), None).await?; + let caller_balance = eth_client.get_balance(eth_client.address(), None).await?; let latest_block = eth_client.get_block(BlockNumber::Latest).await?; let price = latest_block.base_fee_per_gas.ok_or(1u8.into()); // shouldn't happen unless pre-London let limit = min(GAS_LIMIT.into(), caller_balance / price.clone()); - Ok(contract_call.from(caller_address) + Ok(contract_call.from(eth_client.address()) .gas(limit) .gas_price(price) .value(0u8.into())) @@ -161,7 +162,7 @@ pub async fn set_contract_call_gas_for_estimate( contract_call: ContractCall, eth_client: EthClient, ) -> Result, GravityError> { - let our_balance = eth_client.get_balance(eth_client.get_address(), None).await?; + let our_balance = eth_client.get_balance(eth_client.address(), None).await?; let gas_limit = min((u64::MAX - 1).into(), our_balance); let gas_price = eth_client.get_gas_price().await?; diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index d5bf7337b..2839d8ce8 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -1,4 +1,4 @@ -use crate::utils::{EthSignerMiddleware, get_valset_nonce, GasCost, set_contract_call_gas_for_estimate}; +use crate::utils::{EthClient, EthSignerMiddleware, get_valset_nonce, GasCost, set_contract_call_gas_for_estimate}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; From 8782ffd672100ddc0f1ab3544209cfa1eb9041c3 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 15 Nov 2021 23:08:35 -0800 Subject: [PATCH 052/115] WIP: even more bugfixes --- .../ethereum_gravity/src/submit_batch.rs | 18 ++--- orchestrator/ethereum_gravity/src/utils.rs | 70 ++++++++++++------- orchestrator/gravity_utils/src/error.rs | 25 +++++-- 3 files changed, 74 insertions(+), 39 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/submit_batch.rs b/orchestrator/ethereum_gravity/src/submit_batch.rs index d6387a47b..414639dc4 100644 --- a/orchestrator/ethereum_gravity/src/submit_batch.rs +++ b/orchestrator/ethereum_gravity/src/submit_batch.rs @@ -1,4 +1,4 @@ -use crate::utils::{EthSignerMiddleware, GasCost, get_tx_batch_nonce, set_contract_call_gas_for_estimate}; +use crate::utils::{EthClient, EthSignerMiddleware, GasCost, get_tx_batch_nonce, set_contract_call_gas_for_estimate}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; @@ -7,8 +7,7 @@ use gravity_utils::error::GravityError; use gravity_utils::message_signatures::encode_tx_batch_confirm_hashed; use gravity_utils::types::*; use web30::types::SendTxOption; -use std::ops::Add; -use std::{cmp::min, time::Duration}; +use std::time::Duration; use web30::{client::Web3, types::TransactionRequest}; /// this function generates an appropriate Ethereum transaction @@ -57,7 +56,7 @@ pub async fn send_eth_transaction_batch( let contract_call = build_submit_batch_contract_call( current_valset, batch, confirms, gravity_contract_address, gravity_id, eth_client - ); + )?; // TODO(bolten): we need to implement the gas multiplier being passed as a TxOption let pending_tx = contract_call.send().await?; info!("Sent batch update with txid {:#066x}", tx); @@ -100,8 +99,8 @@ pub async fn estimate_tx_batch_cost( ) -> Result { let contract_call = build_submit_batch_contract_call( current_valset, batch, confirms, gravity_contract_address, gravity_id, eth_client - ); - let contract_call = set_contract_call_gas_for_estimate(contract_call, eth_client); + )?; + let contract_call = set_contract_call_gas_for_estimate(contract_call, eth_client).await?; Ok(GasCost { gas: contract_call.estimate_gas().await?, @@ -118,6 +117,7 @@ pub fn build_submit_batch_contract_call( eth_client: EthClient, ) -> Result, GravityError> { let (current_addresses, current_powers) = current_valset.filter_empty_addresses(); + let current_powers: Vec = current_powers.iter().map(|power| (*power).into()).collect(); let current_valset_nonce = current_valset.nonce; let new_batch_nonce = batch.nonce; let hash = encode_tx_batch_confirm_hashed(gravity_id, batch.clone()); @@ -127,10 +127,10 @@ pub fn build_submit_batch_contract_call( let contract = Gravity::new(gravity_contract_address, eth_client); Ok(contract.submit_batch( - current_addresses, current_powers.into(), current_valset_nonce.into(), + current_addresses, current_powers, current_valset_nonce.into(), sig_arrays.v, sig_arrays.r, sig_arrays.s, amounts, destinations, fees, - new_batch_nonce.into(), batch.token_contract, batch.batch_timeout.into() + new_batch_nonce.into(), batch.token_contract, batch.batch_timeout.into()) .from(eth_client.address()) - .value(0u8.into()))) + .value(U256::zero())) } diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 9043c0e77..c112d2911 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -1,3 +1,4 @@ +use ethers::abi::Detokenize; use ethers::contract::builders::ContractCall; use ethers::core::abi::{self, Token}; use ethers::prelude::*; @@ -38,13 +39,13 @@ pub fn get_checkpoint_hash(valset: &Valset, gravity_id: &str) -> Result, /// Gets the latest validator set nonce pub async fn get_valset_nonce( - contract_address: EthAddress, + gravity_contract_address: EthAddress, caller_address: EthAddress, eth_client: EthClient, ) -> Result { - let contract_call = Gravity::new(contract_address, eth_client) + let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) .state_last_valset_nonce(); - let contract_call = build_contract_eth_call(contract_call, eth_client).await?; + let contract_call = build_contract_eth_call(contract_call, eth_client.clone()).await?; let valset_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? @@ -63,9 +64,9 @@ pub async fn get_tx_batch_nonce( caller_address: EthAddress, eth_client: EthClient, ) -> Result { - let contract_call = Gravity::new(contract_address, eth_client) + let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) .last_batch_nonce(erc20_contract_address); - let contract_call = build_contract_eth_call(contract_call, eth_client).await?; + let contract_call = build_contract_eth_call(contract_call, eth_client.clone()).await?; let tx_batch_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? @@ -84,9 +85,17 @@ pub async fn get_logic_call_nonce( caller_address: EthAddress, eth_client: EthClient, ) -> Result { - let contract_call = Gravity::new(contract_address, eth_client) - .last_logic_call_nonce(invalidation_id.as_slice()); - let contract_call = build_contract_eth_call(contract_call, eth_client).await?; + if invalidation_id.len() != 32 { + return Err(GravityError::InvalidArgumentError(format!( + "Error getting logic call nonce, invalidation id is not 32 bytes: {:?}", invalidation_id))) + } + + let mut invalidation_id_slice: [u8; 32] = Default::default(); + invalidation_id_slice.copy_from_slice(&invalidation_id[..]); + + let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) + .last_logic_call_nonce(invalidation_id_slice); + let contract_call = build_contract_eth_call(contract_call, eth_client.clone()).await?; let logic_call_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? @@ -104,9 +113,9 @@ pub async fn get_event_nonce( caller_address: EthAddress, eth_client: EthClient, ) -> Result { - let contract_call = Gravity::new(contract_address, eth_client) + let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) .state_last_event_nonce(); - let contract_call = build_contract_eth_call(contract_call, eth_client).await?; + let contract_call = build_contract_eth_call(contract_call, eth_client.clone()).await?; let event_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? @@ -120,15 +129,22 @@ pub async fn get_event_nonce( /// Gets the gravityID pub async fn get_gravity_id( - contract_address: EthAddress, + gravity_contract_address: EthAddress, caller_address: EthAddress, eth_client: EthClient, ) -> Result { - let contract_call = Gravity::new(contract_address, eth_client) + let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) .state_gravity_id(); - let contract_call = build_contract_eth_call(contract_call, eth_client).await?; - - String::from_utf8(contract_call.call().await?.to_vec()) + let contract_call = build_contract_eth_call(contract_call, eth_client.clone()).await?; + let gravity_id = contract_call.call().await?; + let id_as_string = String::from_utf8(gravity_id.to_vec()); + + match id_as_string { + Ok(id) => Ok(id), + Err(err) => Err(GravityError::GravityContractError(format!( + "Received invalid utf8 when getting gravity id: {:?}", &gravity_id + ))) + } } /// Since all the contract eth_calls here use the same gas and value settings, use a common @@ -139,29 +155,33 @@ pub async fn get_gravity_id( /// eth_sendtransaction. In ethers this is represented by `call()` on a ContractCall rather /// than `send()`. Using `call()` will not send a transaction from the caller account or /// spend gas. -pub async fn build_contract_eth_call( - contract_call: ContractCall, +pub async fn build_contract_eth_call( + contract_call: ContractCall, eth_client: EthClient, -) -> Result, GravityError> { +) -> Result, GravityError> { const GAS_LIMIT: u128 = 12450000; // the most Hardhat will allow, will work on Geth let caller_balance = eth_client.get_balance(eth_client.address(), None).await?; - let latest_block = eth_client.get_block(BlockNumber::Latest).await?; - let price = latest_block.base_fee_per_gas.ok_or(1u8.into()); // shouldn't happen unless pre-London - let limit = min(GAS_LIMIT.into(), caller_balance / price.clone()); + let latest_block = eth_client.get_block(BlockNumber::Latest).await?.unwrap(); + let price = latest_block.base_fee_per_gas.unwrap_or(1u8.into()); // "or" clause shouldn't happen unless pre-London + if price == U256::zero() { + return Err(GravityError::EthereumBadDataError("Latest block returned base fee per gas of zero".to_string())); + } + + let limit = min(GAS_LIMIT.into(), caller_balance.div_mod(price).0); Ok(contract_call.from(eth_client.address()) .gas(limit) .gas_price(price) - .value(0u8.into())) + .value(U256::zero())) } /// Take a ContractCall to be used with eth_estimateGas and set the gas limit and price /// based on the caller's state. -pub async fn set_contract_call_gas_for_estimate( - contract_call: ContractCall, +pub async fn set_contract_call_gas_for_estimate( + contract_call: ContractCall, eth_client: EthClient, -) -> Result, GravityError> { +) -> Result, GravityError> { let our_balance = eth_client.get_balance(eth_client.address(), None).await?; let gas_limit = min((u64::MAX - 1).into(), our_balance); let gas_price = eth_client.get_gas_price().await?; diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index 631c97784..7a8249615 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -7,6 +7,7 @@ use deep_space::error::CosmosGrpcError; use ethers::abi::Error as EthersAbiError; use ethers::abi::ethereum_types::FromDecStrErr as EthersParseUintError; use ethers::prelude::*; +use ethers::prelude::ContractError; use ethers::prelude::signer::SignerMiddlewareError; use ethers::types::SignatureError as EthersSignatureError; use rustc_hex::FromHexError as EthersParseAddressError; @@ -21,11 +22,15 @@ pub enum GravityError { InvalidBigInt(ParseBigIntError), CosmosGrpcError(CosmosGrpcError), CosmosAddressError(CosmosAddressError), + EthereumBadDataError(String), EthereumRestError(SignerMiddlewareError, LocalWallet>), EthersAbiError(EthersAbiError), + EthersContractError(ContractError, LocalWallet>>), EthersParseAddressError(EthersParseAddressError), EthersParseUintError(EthersParseUintError), EthersSignatureError(EthersSignatureError), + GravityContractError(String), + InvalidArgumentError(String), InvalidBridgeStateError(String), FailedToUpdateValset, EthereumContractError(String), @@ -47,11 +52,15 @@ impl fmt::Display for GravityError { write!(f, "Got invalid BigInt from cosmos! {}", val) } GravityError::CosmosAddressError(val) => write!(f, "Cosmos Address error {}", val), - GravityError::EthereumRestError(val) => write!(f, "Ethereum REST error {}", val), - GravityError::EthersAbiError(val) => write!(f, "Ethers ABI error {}", val), - GravityError::EthersParseAddressError(val) => write!(f, "Ethers H160 address parse error {}", val), - GravityError::EthersParseUintError(val) => write!(f, "Ethers U256 parse error {}", val), - GravityError::EthersSignatureError(val) => write!(f, "Ethers signature error {}", val), + GravityError::EthereumBadDataError(val) => write!(f, "Received unexpected data from Ethereum: {}", val), + GravityError::EthereumRestError(val) => write!(f, "Ethereum REST error: {}", val), + GravityError::EthersAbiError(val) => write!(f, "Ethers ABI error: {}", val), + GravityError::EthersContractError(val) => write!(f, "Ethers contract error: {}", val), + GravityError::EthersParseAddressError(val) => write!(f, "Ethers H160 address parse error: {}", val), + GravityError::EthersParseUintError(val) => write!(f, "Ethers U256 parse error: {}", val), + GravityError::EthersSignatureError(val) => write!(f, "Ethers signature error: {}", val), + GravityError::GravityContractError(val) => write!(f, "Gravity contract error: {}", val), + GravityError::InvalidArgumentError(val) => write!(f, "Invalid argument error: {}", val), GravityError::InvalidOptionsError(val) => { write!(f, "Invalid TX options for this call {}", val) } @@ -105,6 +114,12 @@ impl From for GravityError { } } +impl From, LocalWallet>>> for GravityError { + fn from(error: ContractError, LocalWallet>>) -> Self { + GravityError::EthersContractError(error) + } +} + impl From for GravityError { fn from(error: EthersParseAddressError) -> Self { GravityError::EthersParseAddressError(error) From 316f718fcf743951ed39d82feb0222ed3926f365 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 15 Nov 2021 23:57:36 -0800 Subject: [PATCH 053/115] WIP: even more bugfixes --- orchestrator/ethereum_gravity/src/utils.rs | 14 +++----- .../ethereum_gravity/src/valset_update.rs | 34 ++++++++++--------- orchestrator/gravity_utils/src/error.rs | 9 +++++ 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index c112d2911..0f924a0df 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -176,17 +176,13 @@ pub async fn build_contract_eth_call( .value(U256::zero())) } -/// Take a ContractCall to be used with eth_estimateGas and set the gas limit and price -/// based on the caller's state. -pub async fn set_contract_call_gas_for_estimate( - contract_call: ContractCall, - eth_client: EthClient, -) -> Result, GravityError> { +pub async fn get_max_gas_cost(eth_client: EthClient) -> Result { let our_balance = eth_client.get_balance(eth_client.address(), None).await?; - let gas_limit = min((u64::MAX - 1).into(), our_balance); - let gas_price = eth_client.get_gas_price().await?; - Ok(contract_call.gas(gas_limit).gas_price(gas_price)) + Ok(GasCost { + gas: min((u64::MAX - 1).into(), our_balance), + gas_price: eth_client.get_gas_price().await?, + }) } /// Just a helper struct to represent the cost of actions on Ethereum diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index 2839d8ce8..b92226cfb 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -1,4 +1,4 @@ -use crate::utils::{EthClient, EthSignerMiddleware, get_valset_nonce, GasCost, set_contract_call_gas_for_estimate}; +use crate::utils::{EthClient, EthSignerMiddleware, get_max_gas_cost, get_valset_nonce, GasCost}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; @@ -26,7 +26,7 @@ pub async fn send_eth_valset_update( "Ordering signatures and submitting validator set {} -> {} update to Ethereum", old_nonce, new_nonce ); - let before_nonce = get_valset_nonce(gravity_contract_address, eth_address, eth_client).await?; + let before_nonce = get_valset_nonce(gravity_contract_address, eth_address, eth_client.clone()).await?; if before_nonce != old_nonce { info!( "Someone else updated the valset to {}, exiting early", @@ -36,19 +36,21 @@ pub async fn send_eth_valset_update( } let contract_call = build_valset_update_contract_call( - new_valset, old_valset, confirms, gravity_contract_address, gravity_id, eth_client + &new_valset, &old_valset, confirms, gravity_contract_address, gravity_id, eth_client.clone() )?; let pending_tx = contract_call.send().await?; - info!("Sent valset update with txid {:#066x}", pending_tx); + let tx_hash = *pending_tx; + info!("Sent valset update with txid {}", tx_hash); // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? // additionally we are mirroring only waiting for 1 confirmation by leaving that as default - pending_tx.interval(Duration::from_secs(1)); + let pending_tx = pending_tx.interval(Duration::from_secs(1)); - if let Err(tx_error) = tokio::time::timeout(timeout, async { pending_tx.await? }).await { - return Err(tx_error); - }; + match tokio::time::timeout(timeout, pending_tx).await?? { + Some(receipt) => (), + None => error!("Did not receive transaction receipt when sending valset update: {}", tx_hash), + } - let last_nonce = get_valset_nonce(gravity_contract_address, eth_address, eth_client).await?; + let last_nonce = get_valset_nonce(gravity_contract_address, eth_address, eth_client.clone()).await?; if last_nonce != new_nonce { error!( "Current nonce is {} expected to update to nonce {}", @@ -73,21 +75,21 @@ pub async fn estimate_valset_cost( gravity_id: String, eth_client: EthClient, ) -> Result { + let max_gas_cost = get_max_gas_cost(eth_client.clone()).await?; let contract_call = build_valset_update_contract_call( - new_valset, old_valset, confirms, gravity_contract_address, gravity_id, eth_client + new_valset, old_valset, confirms, gravity_contract_address, gravity_id, eth_client.clone() )?; - let contract_call = - set_contract_call_gas_for_estimate(contract_call, eth_client).await?; + let contract_call = contract_call.gas(max_gas_cost.gas).gas_price(max_gas_cost.gas_price); Ok(GasCost { gas: contract_call.estimate_gas().await?, - gas_price + gas_price: max_gas_cost.gas_price, }) } pub fn build_valset_update_contract_call( - new_valset: Valset, - old_valset: Valset, + new_valset: &Valset, + old_valset: &Valset, confirms: &[ValsetConfirmResponse], gravity_contract_address: EthAddress, gravity_id: String, @@ -110,5 +112,5 @@ pub fn build_valset_update_contract_call( old_addresses, old_powers, old_nonce.into(), sig_arrays.v, sig_arrays.r, sig_arrays.s) .from(eth_client.address()) - .value(0u8.into())) + .value(U256::zero())) } diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index 7a8249615..8d5445071 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -8,6 +8,7 @@ use ethers::abi::Error as EthersAbiError; use ethers::abi::ethereum_types::FromDecStrErr as EthersParseUintError; use ethers::prelude::*; use ethers::prelude::ContractError; +use ethers::prelude::ProviderError as EthersProviderError; use ethers::prelude::signer::SignerMiddlewareError; use ethers::types::SignatureError as EthersSignatureError; use rustc_hex::FromHexError as EthersParseAddressError; @@ -28,6 +29,7 @@ pub enum GravityError { EthersContractError(ContractError, LocalWallet>>), EthersParseAddressError(EthersParseAddressError), EthersParseUintError(EthersParseUintError), + EthersProviderError(EthersProviderError), EthersSignatureError(EthersSignatureError), GravityContractError(String), InvalidArgumentError(String), @@ -58,6 +60,7 @@ impl fmt::Display for GravityError { GravityError::EthersContractError(val) => write!(f, "Ethers contract error: {}", val), GravityError::EthersParseAddressError(val) => write!(f, "Ethers H160 address parse error: {}", val), GravityError::EthersParseUintError(val) => write!(f, "Ethers U256 parse error: {}", val), + GravityError::EthersProviderError(val) => write!(f, "Ethers provider error: {}", val), GravityError::EthersSignatureError(val) => write!(f, "Ethers signature error: {}", val), GravityError::GravityContractError(val) => write!(f, "Gravity contract error: {}", val), GravityError::InvalidArgumentError(val) => write!(f, "Invalid argument error: {}", val), @@ -132,6 +135,12 @@ impl From for GravityError { } } +impl From for GravityError { + fn from(error: EthersProviderError) -> Self { + GravityError::EthersProviderError(error) + } +} + impl From for GravityError { fn from(error: EthersSignatureError) -> Self { GravityError::EthersSignatureError(error) From 2e9c0aaa23d7fadcf44f67324b0f6c14e72172a0 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 16 Nov 2021 01:13:56 -0800 Subject: [PATCH 054/115] WIP: working on fixing handling of gas costs --- orchestrator/ethereum_gravity/src/lib.rs | 8 +++-- .../ethereum_gravity/src/submit_batch.rs | 34 ++++++++++--------- .../ethereum_gravity/src/valset_update.rs | 12 ++++--- orchestrator/gravity_utils/src/ethereum.rs | 11 ++++++ orchestrator/relayer/src/batch_relaying.rs | 34 +++++++++++-------- 5 files changed, 62 insertions(+), 37 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/lib.rs b/orchestrator/ethereum_gravity/src/lib.rs index 44ded6091..105e8bd3e 100644 --- a/orchestrator/ethereum_gravity/src/lib.rs +++ b/orchestrator/ethereum_gravity/src/lib.rs @@ -1,6 +1,6 @@ //! This crate contains various components and utilities for interacting with the Gravity Ethereum contract. -use clarity::Uint256; +use ethers::types::U256; #[macro_use] extern crate log; @@ -12,6 +12,10 @@ pub mod submit_batch; pub mod utils; pub mod valset_update; -pub fn one_eth() -> Uint256 { +pub fn one_eth() -> U256 { 1000000000000000000u128.into() } + +pub fn one_eth_f32() -> f32 { + 1000000000000000000u128 as f32 +} diff --git a/orchestrator/ethereum_gravity/src/submit_batch.rs b/orchestrator/ethereum_gravity/src/submit_batch.rs index 414639dc4..25611470a 100644 --- a/orchestrator/ethereum_gravity/src/submit_batch.rs +++ b/orchestrator/ethereum_gravity/src/submit_batch.rs @@ -1,4 +1,4 @@ -use crate::utils::{EthClient, EthSignerMiddleware, GasCost, get_tx_batch_nonce, set_contract_call_gas_for_estimate}; +use crate::utils::{EthClient, EthSignerMiddleware, GasCost, get_max_gas_cost, get_tx_batch_nonce}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; @@ -6,9 +6,7 @@ use gravity_abi::gravity::*; use gravity_utils::error::GravityError; use gravity_utils::message_signatures::encode_tx_batch_confirm_hashed; use gravity_utils::types::*; -use web30::types::SendTxOption; use std::time::Duration; -use web30::{client::Web3, types::TransactionRequest}; /// this function generates an appropriate Ethereum transaction /// to submit the provided transaction batch @@ -20,7 +18,7 @@ pub async fn send_eth_transaction_batch( timeout: Duration, gravity_contract_address: EthAddress, gravity_id: String, - options: Vec, + gas_cost: GasCost, eth_client: EthClient, ) -> Result<(), GravityError> { let new_batch_nonce = batch.nonce; @@ -35,7 +33,7 @@ pub async fn send_eth_transaction_batch( gravity_contract_address, batch.token_contract, eth_address, - eth_client, + eth_client.clone(), ) .await?; @@ -55,24 +53,26 @@ pub async fn send_eth_transaction_batch( } let contract_call = build_submit_batch_contract_call( - current_valset, batch, confirms, gravity_contract_address, gravity_id, eth_client + current_valset, &batch, confirms, gravity_contract_address, gravity_id, eth_client.clone() )?; // TODO(bolten): we need to implement the gas multiplier being passed as a TxOption let pending_tx = contract_call.send().await?; - info!("Sent batch update with txid {:#066x}", tx); + let tx_hash = *pending_tx; + info!("Sent batch update with txid {}", tx_hash); // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? // additionally we are mirroring only waiting for 1 confirmation by leaving that as default - pending_tx.interval(Duration::from_secs(1)); + let pending_tx = pending_tx.interval(Duration::from_secs(1)); - if let Err(tx_error) = tokio::time::timeout(timeout, async { pending_tx.await? }).await { - return Err(tx_error); - }; + match tokio::time::timeout(timeout, pending_tx).await?? { + Some(receipt) => (), + None => error!("Did not receive transaction receipt when submitting batch: {}", tx_hash), + } let last_nonce = get_tx_batch_nonce( gravity_contract_address, batch.token_contract, eth_address, - eth_client, + eth_client.clone(), ) .await?; @@ -97,20 +97,22 @@ pub async fn estimate_tx_batch_cost( gravity_id: String, eth_client: EthClient, ) -> Result { + let max_gas_cost = get_max_gas_cost(eth_client.clone()).await?; + let contract_call = build_submit_batch_contract_call( - current_valset, batch, confirms, gravity_contract_address, gravity_id, eth_client + current_valset, &batch, confirms, gravity_contract_address, gravity_id, eth_client )?; - let contract_call = set_contract_call_gas_for_estimate(contract_call, eth_client).await?; + let contract_call = contract_call.gas(max_gas_cost.gas).gas_price(max_gas_cost.gas_price); Ok(GasCost { gas: contract_call.estimate_gas().await?, - gas_price + gas_price: max_gas_cost.gas_price, }) } pub fn build_submit_batch_contract_call( current_valset: Valset, - batch: TransactionBatch, + batch: &TransactionBatch, confirms: &[BatchConfirmResponse], gravity_contract_address: EthAddress, gravity_id: String, diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index b92226cfb..b0cb5c439 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -1,10 +1,10 @@ -use crate::utils::{EthClient, EthSignerMiddleware, get_max_gas_cost, get_valset_nonce, GasCost}; +use crate::utils::{EthClient, EthSignerMiddleware, GasCost, get_max_gas_cost, get_valset_nonce}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_abi::gravity::*; use gravity_utils::{error::GravityError, message_signatures::encode_valset_confirm_hashed, types::*}; -use std::{cmp::min, time::Duration}; +use std::time::Duration; /// this function generates an appropriate Ethereum transaction /// to submit the provided validator set and signatures. @@ -97,10 +97,12 @@ pub fn build_valset_update_contract_call( ) -> Result, GravityError> { let (old_addresses, old_powers) = old_valset.filter_empty_addresses(); let (new_addresses, new_powers) = new_valset.filter_empty_addresses(); + let old_powers: Vec = old_powers.iter().map(|power| (*power).into()).collect(); + let new_powers: Vec = new_powers.iter().map(|power| (*power).into()).collect(); // remember the signatures are over the new valset and therefore this is the value we must encode // the old valset exists only as a hash in the ethereum store - let hash = encode_valset_confirm_hashed(gravity_id, new_valset); + let hash = encode_valset_confirm_hashed(gravity_id, new_valset.clone()); // we need to use the old valset here because our signatures need to match the current // members of the validator set in the contract. let sig_data = old_valset.order_sigs(&hash, confirms)?; @@ -108,8 +110,8 @@ pub fn build_valset_update_contract_call( let contract = Gravity::new(gravity_contract_address, eth_client); Ok(contract.update_valset( - new_addresses, new_powers, new_nonce.into(), - old_addresses, old_powers, old_nonce.into(), + new_addresses, new_powers, new_valset.nonce.into(), + old_addresses, old_powers, old_valset.nonce.into(), sig_arrays.v, sig_arrays.r, sig_arrays.s) .from(eth_client.address()) .value(U256::zero())) diff --git a/orchestrator/gravity_utils/src/ethereum.rs b/orchestrator/gravity_utils/src/ethereum.rs index 9b87b23c3..c89ff8f01 100644 --- a/orchestrator/gravity_utils/src/ethereum.rs +++ b/orchestrator/gravity_utils/src/ethereum.rs @@ -1,6 +1,17 @@ use ethers::prelude::*; use std::panic; +pub fn downcast_to_f32(input: U256) -> Option { + // technically the max value of u128 is larger than f32, but + // in practicality this won't matter for any of the cases we + // would care about downcasting from a U256, and Rust will + // gracefully saturate the cast + match panic::catch_unwind(|| input.as_u128() as f32) { + Ok(downcasted) => Some(downcasted), + Err(_) => None, + } +} + pub fn downcast_to_u64(input: U256) -> Option { match panic::catch_unwind(|| input.as_u64()) { Ok(downcasted) => Some(downcasted), diff --git a/orchestrator/relayer/src/batch_relaying.rs b/orchestrator/relayer/src/batch_relaying.rs index 0518c2721..cfea11ee0 100644 --- a/orchestrator/relayer/src/batch_relaying.rs +++ b/orchestrator/relayer/src/batch_relaying.rs @@ -1,11 +1,11 @@ use cosmos_gravity::query::get_latest_transaction_batches; use cosmos_gravity::query::get_transaction_batch_signatures; -use ethereum_gravity::{one_eth, submit_batch::send_eth_transaction_batch, utils::EthClient, +use ethereum_gravity::{one_eth_f32, submit_batch::send_eth_transaction_batch, utils::EthClient, utils::get_tx_batch_nonce}; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use gravity_utils::ethereum::downcast_to_u128; +use gravity_utils::ethereum::downcast_to_f32; use gravity_utils::message_signatures::encode_tx_batch_confirm_hashed; use gravity_utils::types::{BatchConfirmResponse, TransactionBatch, Valset}; use web30::types::SendTxOption; @@ -43,7 +43,7 @@ pub async fn relay_batches( submit_batches( current_valset, - eth_client, + eth_client.clone(), gravity_contract_address, gravity_id, timeout, @@ -183,24 +183,30 @@ async fn submit_batches( &oldest_signatures, gravity_contract_address, gravity_id.clone(), - eth_client, + eth_client.clone(), ) .await; if cost.is_err() { error!("Batch cost estimate failed with {:?}", cost); continue; } - let cost = cost.unwrap(); + let mut cost = cost.unwrap(); + let total_cost = downcast_to_f32(cost.get_total()); + if total_cost.is_none() { + error!("Total gas cost greater than f32 max, skipping batch submission: {}", oldest_signed_batch.nonce); + continue; + } + let gas_as_f32 = downcast_to_f32(cost.gas); + info!( - "We have detected latest batch {} but latest on Ethereum is {} This batch is estimated to cost {} Gas / {:.4} ETH to submit", - latest_cosmos_batch_nonce, - latest_ethereum_batch, - cost.gas_price.clone(), - downcast_to_u128(cost.get_total()).unwrap() as f32 - / downcast_to_u128(one_eth()).unwrap() as f32 - ); - let tx_options = vec![SendTxOption::GasPriceMultiplier(gas_multiplier)]; + "We have detected latest batch {} but latest on Ethereum is {} This batch is estimated to cost {} Gas / {:.4} ETH to submit", + latest_cosmos_batch_nonce, + latest_ethereum_batch, + cost.gas_price.clone(), + downcast_to_f32(cost.get_total()).unwrap() / one_eth_f32() + ); + cost.gas = (gas_as_f32 * gas_multiplier).into(); let res = send_eth_transaction_batch( current_valset.clone(), @@ -209,7 +215,7 @@ async fn submit_batches( timeout, gravity_contract_address, gravity_id.clone(), - tx_options, + cost, eth_client, ) .await; From d3a2c2517209295aace6aed45a2c41ace917e11b Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 16 Nov 2021 23:20:49 -0800 Subject: [PATCH 055/115] WIP: gas fixes --- .../ethereum_gravity/src/submit_batch.rs | 27 ++++--- orchestrator/ethereum_gravity/src/utils.rs | 80 +++++++++++-------- .../ethereum_gravity/src/valset_update.rs | 9 ++- orchestrator/gravity_utils/src/error.rs | 9 +++ orchestrator/relayer/src/valset_relaying.rs | 1 + 5 files changed, 77 insertions(+), 49 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/submit_batch.rs b/orchestrator/ethereum_gravity/src/submit_batch.rs index 25611470a..8cbdd2bea 100644 --- a/orchestrator/ethereum_gravity/src/submit_batch.rs +++ b/orchestrator/ethereum_gravity/src/submit_batch.rs @@ -1,4 +1,4 @@ -use crate::utils::{EthClient, EthSignerMiddleware, GasCost, get_max_gas_cost, get_tx_batch_nonce}; +use crate::utils::{EthClient, EthSignerMiddleware, GasCost, get_send_transaction_gas_price, get_tx_batch_nonce}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; @@ -55,6 +55,9 @@ pub async fn send_eth_transaction_batch( let contract_call = build_submit_batch_contract_call( current_valset, &batch, confirms, gravity_contract_address, gravity_id, eth_client.clone() )?; + + let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + // TODO(bolten): we need to implement the gas multiplier being passed as a TxOption let pending_tx = contract_call.send().await?; let tx_hash = *pending_tx; @@ -97,16 +100,13 @@ pub async fn estimate_tx_batch_cost( gravity_id: String, eth_client: EthClient, ) -> Result { - let max_gas_cost = get_max_gas_cost(eth_client.clone()).await?; - let contract_call = build_submit_batch_contract_call( - current_valset, &batch, confirms, gravity_contract_address, gravity_id, eth_client + current_valset, &batch, confirms, gravity_contract_address, gravity_id, eth_client.clone() )?; - let contract_call = contract_call.gas(max_gas_cost.gas).gas_price(max_gas_cost.gas_price); Ok(GasCost { gas: contract_call.estimate_gas().await?, - gas_price: max_gas_cost.gas_price, + gas_price: get_send_transaction_gas_price(eth_client.clone()).await?, }) } @@ -127,12 +127,13 @@ pub fn build_submit_batch_contract_call( let sig_arrays = to_arrays(sig_data); let (amounts, destinations, fees) = batch.get_checkpoint_values(); - let contract = Gravity::new(gravity_contract_address, eth_client); - Ok(contract.submit_batch( - current_addresses, current_powers, current_valset_nonce.into(), - sig_arrays.v, sig_arrays.r, sig_arrays.s, - amounts, destinations, fees, - new_batch_nonce.into(), batch.token_contract, batch.batch_timeout.into()) + let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) + .submit_batch(current_addresses, current_powers, current_valset_nonce.into(), + sig_arrays.v, sig_arrays.r, sig_arrays.s, + amounts, destinations, fees, + new_batch_nonce.into(), batch.token_contract, batch.batch_timeout.into()) .from(eth_client.address()) - .value(U256::zero())) + .value(U256::zero()); + + Ok(contract_call) } diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 0f924a0df..a71fbfece 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -1,7 +1,7 @@ -use ethers::abi::Detokenize; -use ethers::contract::builders::ContractCall; use ethers::core::abi::{self, Token}; +use ethers::middleware::gas_oracle::{Etherscan, GasCategory}; use ethers::prelude::*; +use ethers::prelude::gas_oracle::GasOracle; use ethers::types::Address as EthAddress; use ethers::utils::keccak256; use gravity_abi::gravity::*; @@ -44,8 +44,12 @@ pub async fn get_valset_nonce( eth_client: EthClient, ) -> Result { let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) - .state_last_valset_nonce(); - let contract_call = build_contract_eth_call(contract_call, eth_client.clone()).await?; + .state_last_valset_nonce() + .from(eth_client.address()) + .value(U256::zero()); + let gas_cost = get_call_gas_cost(eth_client.clone()).await?; + let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let valset_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? @@ -65,8 +69,12 @@ pub async fn get_tx_batch_nonce( eth_client: EthClient, ) -> Result { let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) - .last_batch_nonce(erc20_contract_address); - let contract_call = build_contract_eth_call(contract_call, eth_client.clone()).await?; + .last_batch_nonce(erc20_contract_address) + .from(eth_client.address()) + .value(U256::zero()); + let gas_cost = get_call_gas_cost(eth_client.clone()).await?; + let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let tx_batch_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? @@ -94,8 +102,12 @@ pub async fn get_logic_call_nonce( invalidation_id_slice.copy_from_slice(&invalidation_id[..]); let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) - .last_logic_call_nonce(invalidation_id_slice); - let contract_call = build_contract_eth_call(contract_call, eth_client.clone()).await?; + .last_logic_call_nonce(invalidation_id_slice) + .from(eth_client.address()) + .value(U256::zero()); + let gas_cost = get_call_gas_cost(eth_client.clone()).await?; + let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let logic_call_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? @@ -114,8 +126,12 @@ pub async fn get_event_nonce( eth_client: EthClient, ) -> Result { let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) - .state_last_event_nonce(); - let contract_call = build_contract_eth_call(contract_call, eth_client.clone()).await?; + .state_last_event_nonce() + .from(eth_client.address()) + .value(U256::zero()); + let gas_cost = get_call_gas_cost(eth_client.clone()).await?; + let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let event_nonce = contract_call.call().await?; // TODO (bolten): do we actually want to halt the bridge as the original comment implies? @@ -134,8 +150,12 @@ pub async fn get_gravity_id( eth_client: EthClient, ) -> Result { let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) - .state_gravity_id(); - let contract_call = build_contract_eth_call(contract_call, eth_client.clone()).await?; + .state_gravity_id() + .from(eth_client.address()) + .value(U256::zero()); + let gas_cost = get_call_gas_cost(eth_client.clone()).await?; + let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let gravity_id = contract_call.call().await?; let id_as_string = String::from_utf8(gravity_id.to_vec()); @@ -147,42 +167,38 @@ pub async fn get_gravity_id( } } -/// Since all the contract eth_calls here use the same gas and value settings, use a common -/// function to append them to the ContractCall builder. -/// /// Retrieve gas price and limit in a similar fashion to web30's simulate_transaction. /// These values are intended to be used in conjunction with eth_call rather than /// eth_sendtransaction. In ethers this is represented by `call()` on a ContractCall rather /// than `send()`. Using `call()` will not send a transaction from the caller account or /// spend gas. -pub async fn build_contract_eth_call( - contract_call: ContractCall, - eth_client: EthClient, -) -> Result, GravityError> { +pub async fn get_call_gas_cost(eth_client: EthClient) -> Result { const GAS_LIMIT: u128 = 12450000; // the most Hardhat will allow, will work on Geth let caller_balance = eth_client.get_balance(eth_client.address(), None).await?; let latest_block = eth_client.get_block(BlockNumber::Latest).await?.unwrap(); - let price = latest_block.base_fee_per_gas.unwrap_or(1u8.into()); // "or" clause shouldn't happen unless pre-London - if price == U256::zero() { + let gas_price = latest_block.base_fee_per_gas.unwrap_or(1u8.into()); // "or" clause shouldn't happen unless pre-London + if gas_price == U256::zero() { return Err(GravityError::EthereumBadDataError("Latest block returned base fee per gas of zero".to_string())); } - let limit = min(GAS_LIMIT.into(), caller_balance.div_mod(price).0); + let gas = min(GAS_LIMIT.into(), caller_balance.div_mod(gas_price).0); - Ok(contract_call.from(eth_client.address()) - .gas(limit) - .gas_price(price) - .value(U256::zero())) + Ok(GasCost { + gas, + gas_price + }) } -pub async fn get_max_gas_cost(eth_client: EthClient) -> Result { - let our_balance = eth_client.get_balance(eth_client.address(), None).await?; +/// If ETHERSCAN_API_KEY env var is set, we'll call out to Etherscan for a gas estimate. +/// Otherwise, just call eth_gasPrice. +pub async fn get_send_transaction_gas_price(eth_client: EthClient) -> Result { + if let Ok(api_key) = std::env::var("ETHERSCAN_API_KEY") { + let etherscan_oracle = Etherscan::new(Some(api_key.as_str())).category(GasCategory::Standard); + return Ok(etherscan_oracle.fetch().await?); + } - Ok(GasCost { - gas: min((u64::MAX - 1).into(), our_balance), - gas_price: eth_client.get_gas_price().await?, - }) + Ok(eth_client.get_gas_price().await?) } /// Just a helper struct to represent the cost of actions on Ethereum diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index b0cb5c439..78133eb76 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -1,4 +1,4 @@ -use crate::utils::{EthClient, EthSignerMiddleware, GasCost, get_max_gas_cost, get_valset_nonce}; +use crate::utils::{EthClient, EthSignerMiddleware, GasCost, get_send_transaction_gas_price, get_valset_nonce}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; @@ -16,6 +16,7 @@ pub async fn send_eth_valset_update( timeout: Duration, gravity_contract_address: EthAddress, gravity_id: String, + gas_cost: GasCost, eth_client: EthClient, ) -> Result<(), GravityError> { let old_nonce = old_valset.nonce; @@ -38,6 +39,8 @@ pub async fn send_eth_valset_update( let contract_call = build_valset_update_contract_call( &new_valset, &old_valset, confirms, gravity_contract_address, gravity_id, eth_client.clone() )?; + let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let pending_tx = contract_call.send().await?; let tx_hash = *pending_tx; info!("Sent valset update with txid {}", tx_hash); @@ -75,15 +78,13 @@ pub async fn estimate_valset_cost( gravity_id: String, eth_client: EthClient, ) -> Result { - let max_gas_cost = get_max_gas_cost(eth_client.clone()).await?; let contract_call = build_valset_update_contract_call( new_valset, old_valset, confirms, gravity_contract_address, gravity_id, eth_client.clone() )?; - let contract_call = contract_call.gas(max_gas_cost.gas).gas_price(max_gas_cost.gas_price); Ok(GasCost { gas: contract_call.estimate_gas().await?, - gas_price: max_gas_cost.gas_price, + gas_price: get_send_transaction_gas_price(eth_client.clone()).await?, }) } diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index 8d5445071..d9ab615c6 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -8,6 +8,7 @@ use ethers::abi::Error as EthersAbiError; use ethers::abi::ethereum_types::FromDecStrErr as EthersParseUintError; use ethers::prelude::*; use ethers::prelude::ContractError; +use ethers::prelude::gas_oracle::GasOracleError as EthersGasOracleError; use ethers::prelude::ProviderError as EthersProviderError; use ethers::prelude::signer::SignerMiddlewareError; use ethers::types::SignatureError as EthersSignatureError; @@ -27,6 +28,7 @@ pub enum GravityError { EthereumRestError(SignerMiddlewareError, LocalWallet>), EthersAbiError(EthersAbiError), EthersContractError(ContractError, LocalWallet>>), + EthersGasOracleError(EthersGasOracleError), EthersParseAddressError(EthersParseAddressError), EthersParseUintError(EthersParseUintError), EthersProviderError(EthersProviderError), @@ -58,6 +60,7 @@ impl fmt::Display for GravityError { GravityError::EthereumRestError(val) => write!(f, "Ethereum REST error: {}", val), GravityError::EthersAbiError(val) => write!(f, "Ethers ABI error: {}", val), GravityError::EthersContractError(val) => write!(f, "Ethers contract error: {}", val), + GravityError::EthersGasOracleError(val) => write!(f, "Ethers gas oracle error: {}", val), GravityError::EthersParseAddressError(val) => write!(f, "Ethers H160 address parse error: {}", val), GravityError::EthersParseUintError(val) => write!(f, "Ethers U256 parse error: {}", val), GravityError::EthersProviderError(val) => write!(f, "Ethers provider error: {}", val), @@ -123,6 +126,12 @@ impl From, LocalWallet>>> for Grav } } +impl From for GravityError { + fn from(error: EthersGasOracleError) -> Self { + GravityError::EthersGasOracleError(error) + } +} + impl From for GravityError { fn from(error: EthersParseAddressError) -> Self { GravityError::EthersParseAddressError(error) diff --git a/orchestrator/relayer/src/valset_relaying.rs b/orchestrator/relayer/src/valset_relaying.rs index 8ce65f82b..c467b18ab 100644 --- a/orchestrator/relayer/src/valset_relaying.rs +++ b/orchestrator/relayer/src/valset_relaying.rs @@ -158,6 +158,7 @@ pub async fn relay_valsets( timeout, gravity_contract_address, gravity_id, + cost, eth_client.clone(), ) .await; From ef94b8f05e6e717194f8e6f85b439f11b7db5662 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 16 Nov 2021 23:33:04 -0800 Subject: [PATCH 056/115] WIP: fix gas price multiplier and downcast to f32 --- orchestrator/orchestrator/src/main_loop.rs | 4 ++-- orchestrator/relayer/src/batch_relaying.rs | 10 ++++++---- orchestrator/relayer/src/main_loop.rs | 6 +++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/orchestrator/orchestrator/src/main_loop.rs b/orchestrator/orchestrator/src/main_loop.rs index d71b42c3f..441f0c2bb 100644 --- a/orchestrator/orchestrator/src/main_loop.rs +++ b/orchestrator/orchestrator/src/main_loop.rs @@ -56,7 +56,7 @@ pub async fn orchestrator_main_loop( gravity_contract_address: EthAddress, gas_price: (f64, String), metrics_listen: &net::SocketAddr, - eth_gas_multiplier: f32, + eth_gas_price_multiplier: f32, blocks_to_search: u128, gas_adjustment: f64, relayer_opt_out: bool, @@ -99,7 +99,7 @@ pub async fn orchestrator_main_loop( eth_client.clone(), grpc_client.clone(), gravity_contract_address, - eth_gas_multiplier, + eth_gas_price_multiplier, ); futures::future::join5(a, b, c, d, e).await; } else { diff --git a/orchestrator/relayer/src/batch_relaying.rs b/orchestrator/relayer/src/batch_relaying.rs index cfea11ee0..75ae6768b 100644 --- a/orchestrator/relayer/src/batch_relaying.rs +++ b/orchestrator/relayer/src/batch_relaying.rs @@ -34,7 +34,7 @@ pub async fn relay_batches( gravity_contract_address: EthAddress, gravity_id: String, timeout: Duration, - gas_multiplier: f32, + eth_gas_price_multiplier: f32, ) { let possible_batches = get_batches_and_signatures(current_valset.clone(), grpc_client, gravity_id.clone()).await; @@ -47,7 +47,7 @@ pub async fn relay_batches( gravity_contract_address, gravity_id, timeout, - gas_multiplier, + eth_gas_price_multiplier, possible_batches, ) .await; @@ -186,17 +186,18 @@ async fn submit_batches( eth_client.clone(), ) .await; + if cost.is_err() { error!("Batch cost estimate failed with {:?}", cost); continue; } + let mut cost = cost.unwrap(); let total_cost = downcast_to_f32(cost.get_total()); if total_cost.is_none() { error!("Total gas cost greater than f32 max, skipping batch submission: {}", oldest_signed_batch.nonce); continue; } - let gas_as_f32 = downcast_to_f32(cost.gas); info!( "We have detected latest batch {} but latest on Ethereum is {} This batch is estimated to cost {} Gas / {:.4} ETH to submit", @@ -206,7 +207,7 @@ async fn submit_batches( downcast_to_f32(cost.get_total()).unwrap() / one_eth_f32() ); - cost.gas = (gas_as_f32 * gas_multiplier).into(); + cost.gas_price = (downcast_to_f32(cost.gas_price) * eth_gas_price_multiplier).into(); let res = send_eth_transaction_batch( current_valset.clone(), @@ -219,6 +220,7 @@ async fn submit_batches( eth_client, ) .await; + if res.is_err() { info!("Batch submission failed with {:?}", res); } diff --git a/orchestrator/relayer/src/main_loop.rs b/orchestrator/relayer/src/main_loop.rs index 5ba7da697..b104c6f35 100644 --- a/orchestrator/relayer/src/main_loop.rs +++ b/orchestrator/relayer/src/main_loop.rs @@ -17,7 +17,7 @@ pub async fn relayer_main_loop( eth_client: EthClient, grpc_client: GravityQueryClient, gravity_contract_address: EthAddress, - gas_multiplier: f32, + eth_gas_price_multiplier: f32, ) { let mut grpc_client = grpc_client; loop { @@ -57,7 +57,7 @@ pub async fn relayer_main_loop( gravity_contract_address, gravity_id.clone(), LOOP_SPEED, - gas_multiplier, + eth_gas_price_multiplier, ) .await; @@ -68,7 +68,7 @@ pub async fn relayer_main_loop( gravity_contract_address, gravity_id.clone(), LOOP_SPEED, - gas_multiplier + eth_gas_price_multiplier ) .await; From d62e9cb748bb42f1631e89cb528da19af2331651 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 17 Nov 2021 09:59:41 -0800 Subject: [PATCH 057/115] Convert logic call relaying --- .../ethereum_gravity/src/logic_call.rs | 283 +++++------------- orchestrator/ethereum_gravity/src/utils.rs | 21 +- orchestrator/relayer/src/batch_relaying.rs | 3 +- .../relayer/src/logic_call_relaying.rs | 41 ++- 4 files changed, 111 insertions(+), 237 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/logic_call.rs b/orchestrator/ethereum_gravity/src/logic_call.rs index 2ec85097d..12fd12162 100644 --- a/orchestrator/ethereum_gravity/src/logic_call.rs +++ b/orchestrator/ethereum_gravity/src/logic_call.rs @@ -1,11 +1,15 @@ -use crate::utils::{get_logic_call_nonce, GasCost}; -use clarity::{abi::Token, utils::bytes_to_hex_str, PrivateKey as EthPrivateKey}; -use clarity::{Address as EthAddress, Uint256}; +use crate::utils::{EthClient, EthSignerMiddleware, GasCost, + convert_invalidation_id_to_fixed_array, + get_logic_call_nonce, + get_send_transaction_gas_price}; +use ethers::contract::builders::ContractCall; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; +use gravity_abi::gravity::*; +use gravity_utils::ethereum::bytes_to_hex_str; use gravity_utils::types::*; use gravity_utils::{error::GravityError, message_signatures::encode_logic_call_confirm_hashed}; -use web30::types::SendTxOption; -use std::{cmp::min, time::Duration}; -use web30::{client::Web3, types::TransactionRequest}; +use std::time::Duration; /// this function generates an appropriate Ethereum transaction /// to submit the provided logic call @@ -14,15 +18,14 @@ pub async fn send_eth_logic_call( current_valset: Valset, call: LogicCall, confirms: &[LogicCallConfirmResponse], - web3: &Web3, timeout: Duration, gravity_contract_address: EthAddress, gravity_id: String, - our_eth_key: EthPrivateKey, - options: Vec, + gas_cost: GasCost, + eth_client: EthClient, ) -> Result<(), GravityError> { let new_call_nonce = call.invalidation_nonce; - let eth_address = our_eth_key.to_public_key().unwrap(); + let eth_address = eth_client.address(); info!( "Ordering signatures and submitting LogicCall {}:{} to Ethereum", bytes_to_hex_str(&call.invalidation_id), @@ -34,10 +37,11 @@ pub async fn send_eth_logic_call( gravity_contract_address, call.invalidation_id.clone(), eth_address, - &web3, + eth_client.clone(), ) .await?; - let current_block_height = web3.eth_block_number().await?; + + let current_block_height = eth_client.get_block_number().await?; if before_nonce >= new_call_nonce { info!( "Someone else updated the LogicCall to {}, exiting early", @@ -52,29 +56,32 @@ pub async fn send_eth_logic_call( return Ok(()); } - let payload = encode_logic_call_payload(current_valset, &call, confirms, gravity_id)?; + let contract_call = build_send_logic_call_contract_call( + current_valset, &call, confirms, gravity_contract_address, gravity_id, eth_client.clone() + )?; + + let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); - let tx = web3 - .send_transaction( - gravity_contract_address, - payload, - 0u32.into(), - eth_address, - our_eth_key, - options, - ) - .await?; - info!("Sent batch update with txid {:#066x}", tx); + let pending_tx = contract_call.send().await?; + let tx_hash = *pending_tx; + info!("Sent logic call with txid {}", tx_hash); + // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? + // additionally we are mirroring only waiting for 1 confirmation by leaving that as default + let pending_tx = pending_tx.interval(Duration::from_secs(1)); - web3.wait_for_transaction(tx.clone(), timeout, None).await?; + match tokio::time::timeout(timeout, pending_tx).await?? { + Some(receipt) => (), + None => error!("Did not receive transaction receipt when submitting batch: {}", tx_hash), + } let last_nonce = get_logic_call_nonce( gravity_contract_address, call.invalidation_id, eth_address, - &web3, + eth_client.clone(), ) .await?; + if last_nonce != new_call_nonce { error!( "Current nonce is {} expected to update to nonce {}", @@ -94,208 +101,60 @@ pub async fn estimate_logic_call_cost( current_valset: Valset, call: LogicCall, confirms: &[LogicCallConfirmResponse], - web3: &Web3, gravity_contract_address: EthAddress, gravity_id: String, - our_eth_key: EthPrivateKey, + eth_client: EthClient, ) -> Result { - let our_eth_address = our_eth_key.to_public_key().unwrap(); - let our_balance = web3.eth_get_balance(our_eth_address).await?; - let our_nonce = web3.eth_get_transaction_count(our_eth_address).await?; - let gas_limit = min((u64::MAX - 1).into(), our_balance.clone()); - let gas_price = web3.eth_gas_price().await?; - let zero: Uint256 = 0u8.into(); - let val = web3 - .eth_estimate_gas(TransactionRequest { - from: Some(our_eth_address), - to: gravity_contract_address, - nonce: Some(our_nonce.clone().into()), - gas_price: Some(gas_price.clone().into()), - gas: Some(gas_limit.into()), - value: Some(zero.into()), - data: Some( - encode_logic_call_payload(current_valset, &call, confirms, gravity_id)?.into(), - ), - }) - .await?; + let contract_call = build_send_logic_call_contract_call( + current_valset, &call, confirms, gravity_contract_address, gravity_id, eth_client.clone() + )?; Ok(GasCost { - gas: val, - gas_price, + gas: contract_call.estimate_gas().await?, + gas_price: get_send_transaction_gas_price(eth_client.clone()).await?, }) } -/// Encodes the logic call payload for both cost estimation and submission to EThereum -fn encode_logic_call_payload( +pub fn build_send_logic_call_contract_call( current_valset: Valset, call: &LogicCall, confirms: &[LogicCallConfirmResponse], + gravity_contract_address: EthAddress, gravity_id: String, -) -> Result, GravityError> { + eth_client: EthClient, +) -> Result, GravityError> { let (current_addresses, current_powers) = current_valset.filter_empty_addresses(); + let current_powers: Vec = current_powers.iter().map(|power| (*power).into()).collect(); let current_valset_nonce = current_valset.nonce; let hash = encode_logic_call_confirm_hashed(gravity_id, call.clone()); let sig_data = current_valset.order_sigs(&hash, confirms)?; let sig_arrays = to_arrays(sig_data); - let mut transfer_amounts = Vec::new(); - let mut transfer_token_contracts = Vec::new(); - let mut fee_amounts = Vec::new(); - let mut fee_token_contracts = Vec::new(); - for item in call.transfers.iter() { - transfer_amounts.push(Token::Uint(item.amount.clone())); - transfer_token_contracts.push(item.token_contract_address); - } - for item in call.fees.iter() { - fee_amounts.push(Token::Uint(item.amount.clone())); - fee_token_contracts.push(item.token_contract_address); - } - - // Solidity function signature - // function submitBatch( - // // The validators that approve the batch and new valset - // address[] memory _currentValidators, - // uint256[] memory _currentPowers, - // uint256 _currentValsetNonce, - // // These are arrays of the parts of the validators signatures - // uint8[] memory _v, - // bytes32[] memory _r, - // bytes32[] memory _s, - // // The LogicCall arguments, encoded as a struct (see the Ethereum ABI encoding documentation for the handling of structs as arguments) - // uint256[] transferAmounts; - // address[] transferTokenContracts; - // // The fees (transferred to msg.sender) - // uint256[] feeAmounts; - // address[] feeTokenContracts; - // // The arbitrary logic call - // address logicContractAddress; - // bytes payload; - // // Invalidation metadata - // uint256 timeOut; - // bytes32 invalidationId; - // uint256 invalidationNonce; - let struct_tokens = &[ - Token::Dynamic(transfer_amounts), - transfer_token_contracts.into(), - Token::Dynamic(fee_amounts), - fee_token_contracts.into(), - call.logic_contract_address.into(), - Token::UnboundedBytes(call.payload.clone()), - call.timeout.into(), - Token::Bytes(call.invalidation_id.clone()), - call.invalidation_nonce.into(), - ]; - let tokens = &[ - current_addresses.into(), - current_powers.into(), - current_valset_nonce.into(), - sig_arrays.v, - sig_arrays.r, - sig_arrays.s, - Token::Struct(struct_tokens.to_vec()), - ]; - let payload = clarity::abi::encode_call( - "submitLogicCall(address[],uint256[],uint256,uint8[],bytes32[],bytes32[],(uint256[],address[],uint256[],address[],address,bytes,uint256,bytes32,uint256))", - tokens, - ) - .unwrap(); - trace!("Tokens {:?}", tokens); - - Ok(payload) -} - -#[cfg(test)] -mod tests { - use super::*; - use clarity::utils::hex_str_to_bytes; - use clarity::Signature; - - #[test] - /// This test encodes an abiV2 function call, specifically one - /// with a nontrivial struct in the header - fn encode_abiv2_function_header() { - // a golden master example encoding taken from Hardhat with all of it's parameters recreated - let encoded = "0x0c246c8200000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c783df8a850f42e7f7e57013759c285caa701eb6000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000001b916bf9a6a908cbf3adee07b90c257ad68cd7006616e56db9de1b8138b83c6b600000000000000000000000000000000000000000000000000000000000000013d124e8782f054c80d07de84b5423a5f9a1d1cb005337a634066854b56b11da50000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000017c1736ccf692f653c433d7aa2ab45148c016f68000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000455e2bfa248696e76616c69646174696f6e49640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c85759553aee2d4125afa8a9421aaf5397b96e6b000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c85759553aee2d4125afa8a9421aaf5397b96e6b000000000000000000000000000000000000000000000000000000000000002074657374696e675061796c6f6164000000000000000000000000000000000000"; - let encoded = hex_str_to_bytes(encoded).unwrap(); - - let token_contract_address = "0xc85759553AEE2D4125aFa8a9421AAf5397b96E6b" - .parse() - .unwrap(); - let logic_contract_address = "0x17c1736CcF692F653c433d7aa2aB45148C016F68" - .parse() - .unwrap(); - let invalidation_scope = - hex_str_to_bytes("0x696e76616c69646174696f6e4964000000000000000000000000000000000000") - .unwrap(); - let invalidation_nonce = 1u8.into(); - let ethereum_signer = "0xc783df8a850f42e7F7e57013759C285caa701eB6" - .parse() - .unwrap(); - let token = vec![Erc20Token { - amount: 1u8.into(), - token_contract_address, - }]; - - let logic_call = LogicCall { - transfers: token.clone(), - fees: token, - logic_contract_address, - payload: hex_str_to_bytes( - "0x74657374696e675061796c6f6164000000000000000000000000000000000000", - ) - .unwrap(), - timeout: 4766922941000, - invalidation_id: invalidation_scope.clone(), - invalidation_nonce, - }; - - // a validator set - let valset = Valset { - nonce: 0, - members: vec![ValsetMember { - eth_address: Some(ethereum_signer), - power: 4294967295, - }], - }; - let confirm = LogicCallConfirmResponse { - invalidation_id: invalidation_scope, - invalidation_nonce, - ethereum_signer, - eth_signature: Signature { - v: 28u8.into(), - r: Uint256::from_bytes_be( - &hex_str_to_bytes( - "0xb916bf9a6a908cbf3adee07b90c257ad68cd7006616e56db9de1b8138b83c6b6", - ) - .unwrap(), - ), - s: Uint256::from_bytes_be( - &hex_str_to_bytes( - "0x3d124e8782f054c80d07de84b5423a5f9a1d1cb005337a634066854b56b11da5", - ) - .unwrap(), - ), - }, - }; - - assert_eq!( - bytes_to_hex_str(&encoded), - bytes_to_hex_str( - &encode_logic_call_payload(valset, &logic_call, &[confirm], "foo".to_string()) - .unwrap() - ) - ); - } - - /// prints a byte vec line by line as unint256 words - fn _print_bytes_as_uint256_words(input: &[u8]) { - for i in 0..(input.len() / 32) { - let start = i * 32; - let mut end = start + 32; - if end > input.len() { - end = input.len() - } - println!("{}", bytes_to_hex_str(&input[start..end])) - } - } + let transfer_amounts = call.transfers.iter() + .map(|transfer| transfer.amount).collect(); + let transfer_token_contracts = call.transfers.iter() + .map(|transfer| transfer.token_contract_address).collect(); + let fee_amounts = call.fees.iter() + .map(|fee| fee.amount).collect(); + let fee_token_contracts = call.fees.iter() + .map(|fee| fee.token_contract_address).collect(); + let invalidation_id = convert_invalidation_id_to_fixed_array(call.invalidation_id)?; + + let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) + .submit_logic_call(current_addresses, current_powers, current_valset_nonce.into(), + sig_arrays.v, sig_arrays.r, sig_arrays.s, + LogicCallArgs { + transfer_amounts, + transfer_token_contracts, + fee_amounts, + fee_token_contracts, + logic_contract_address: call.logic_contract_address, + payload: call.payload, + time_out: call.timeout.into(), + invalidation_id, + invalidation_nonce: call.invalidation_nonce.into(), }) + .from(eth_client.address()) + .value(U256::zero()); + + Ok(contract_call) } diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index a71fbfece..7264e96dc 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -93,16 +93,10 @@ pub async fn get_logic_call_nonce( caller_address: EthAddress, eth_client: EthClient, ) -> Result { - if invalidation_id.len() != 32 { - return Err(GravityError::InvalidArgumentError(format!( - "Error getting logic call nonce, invalidation id is not 32 bytes: {:?}", invalidation_id))) - } - - let mut invalidation_id_slice: [u8; 32] = Default::default(); - invalidation_id_slice.copy_from_slice(&invalidation_id[..]); + let invalidation_id = convert_invalidation_id_to_fixed_array(invalidation_id)?; let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) - .last_logic_call_nonce(invalidation_id_slice) + .last_logic_call_nonce(invalidation_id) .from(eth_client.address()) .value(U256::zero()); let gas_cost = get_call_gas_cost(eth_client.clone()).await?; @@ -201,6 +195,17 @@ pub async fn get_send_transaction_gas_price(eth_client: EthClient) -> Result) -> Result<[u8; 32], GravityError> { + if invalidation_id.len() != 32 { + return Err(GravityError::InvalidArgumentError(format!( + "Error getting logic call nonce, invalidation id is not 32 bytes: {:?}", invalidation_id))) + } + + let mut invalidation_id_slice: [u8; 32] = Default::default(); + invalidation_id_slice.copy_from_slice(&invalidation_id[..]); + Ok(invalidation_id_slice) +} + /// Just a helper struct to represent the cost of actions on Ethereum #[derive(Debug, Default, Clone)] pub struct GasCost { diff --git a/orchestrator/relayer/src/batch_relaying.rs b/orchestrator/relayer/src/batch_relaying.rs index 75ae6768b..e1cdb1ee8 100644 --- a/orchestrator/relayer/src/batch_relaying.rs +++ b/orchestrator/relayer/src/batch_relaying.rs @@ -198,6 +198,7 @@ async fn submit_batches( error!("Total gas cost greater than f32 max, skipping batch submission: {}", oldest_signed_batch.nonce); continue; } + let gas_price_as_f32 = downcast_to_f32(cost.gas_price); info!( "We have detected latest batch {} but latest on Ethereum is {} This batch is estimated to cost {} Gas / {:.4} ETH to submit", @@ -207,7 +208,7 @@ async fn submit_batches( downcast_to_f32(cost.get_total()).unwrap() / one_eth_f32() ); - cost.gas_price = (downcast_to_f32(cost.gas_price) * eth_gas_price_multiplier).into(); + cost.gas_price = (gas_price_as_f32 * eth_gas_price_multiplier).into(); let res = send_eth_transaction_batch( current_valset.clone(), diff --git a/orchestrator/relayer/src/logic_call_relaying.rs b/orchestrator/relayer/src/logic_call_relaying.rs index 18c98b455..6f0fc237b 100644 --- a/orchestrator/relayer/src/logic_call_relaying.rs +++ b/orchestrator/relayer/src/logic_call_relaying.rs @@ -1,12 +1,13 @@ -use clarity::PrivateKey as EthPrivateKey; -use clarity::{address::Address as EthAddress, utils::bytes_to_hex_str}; use cosmos_gravity::query::{get_latest_logic_calls, get_logic_call_signatures}; use ethereum_gravity::one_eth; use ethereum_gravity::{ logic_call::send_eth_logic_call, - utils::{downcast_to_u128, get_logic_call_nonce}, + utils::{EthClient, get_logic_call_nonce}, }; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; +use gravity_utils::ethereum::downcast_to_f32; use gravity_utils::types::{LogicCallConfirmResponse, Valset}; use gravity_utils::{message_signatures::encode_logic_call_confirm_hashed, types::LogicCall}; use web30::types::SendTxOption; @@ -17,15 +18,15 @@ use web30::client::Web3; pub async fn relay_logic_calls( // the validator set currently in the contract on Ethereum current_valset: Valset, - ethereum_key: EthPrivateKey, - web3: &Web3, + eth_client: EthClient, grpc_client: &mut GravityQueryClient, gravity_contract_address: EthAddress, gravity_id: String, timeout: Duration, gas_multiplier: f32, ) { - let our_ethereum_address = ethereum_key.to_public_key().unwrap(); + // TODO(bolten): replace a lot of manual caller address passing + let our_ethereum_address = eth_client.address(); let latest_calls = get_latest_logic_calls(grpc_client).await; trace!("Latest Logic calls {:?}", latest_calls); @@ -76,7 +77,7 @@ pub async fn relay_logic_calls( gravity_contract_address, oldest_signed_call.invalidation_id.clone(), our_ethereum_address, - web3, + eth_client.clone(), ) .await; if latest_ethereum_call.is_err() { @@ -93,39 +94,47 @@ pub async fn relay_logic_calls( current_valset.clone(), oldest_signed_call.clone(), &oldest_signatures, - web3, gravity_contract_address, gravity_id.clone(), - ethereum_key, + eth_client.clone(), ) .await; + if cost.is_err() { error!("LogicCall cost estimate failed with {:?}", cost); return; } - let cost = cost.unwrap(); + + let mut cost = cost.unwrap(); + let total_cost = downcast_to_f32(cost.get_total()); + if total_cost.is_none() { + error!("Total gas cost greater than f32 max, skipping batch submission: {}", oldest_signed_batch.nonce); + continue; + } + let gas_price_as_f32 = downcast_to_f32(cost.gas_price); + info!( "We have detected latest LogicCall {} but latest on Ethereum is {} This LogicCall is estimated to cost {} Gas / {:.4} ETH to submit", latest_cosmos_call_nonce, latest_ethereum_call, cost.gas_price.clone(), - downcast_to_u128(cost.get_total()).unwrap() as f32 - / downcast_to_u128(one_eth()).unwrap() as f32 + downcast_to_f32(cost.get_total()).unwrap() / one_eth_f32(), ); - let tx_options = vec![SendTxOption::GasPriceMultiplier(gas_multiplier)]; + + cost.gas_price = (gas_price_as_f32 * eth_gas_price_multiplier).into(); let res = send_eth_logic_call( current_valset, oldest_signed_call, &oldest_signatures, - web3, timeout, gravity_contract_address, gravity_id.clone(), - ethereum_key, - tx_options, + cost, + eth_client.clone(), ) .await; + if res.is_err() { info!("LogicCall submission failed with {:?}", res); } From 5bada4e80c71c2f62787d730277dd19a3013bb6d Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 17 Nov 2021 10:19:51 -0800 Subject: [PATCH 058/115] WIP: convert deploy erc20 --- .../ethereum_gravity/src/deploy_erc20.rs | 59 ++++++++----------- .../ethereum_gravity/src/submit_batch.rs | 1 - 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/deploy_erc20.rs b/orchestrator/ethereum_gravity/src/deploy_erc20.rs index a32b5943a..18ed52a5c 100644 --- a/orchestrator/ethereum_gravity/src/deploy_erc20.rs +++ b/orchestrator/ethereum_gravity/src/deploy_erc20.rs @@ -2,14 +2,11 @@ //! the event for this deployment is then ferried over to Cosmos where the validators will accept the ERC20 contract address //! as the representation of this asset on Ethereum -use clarity::{ - abi::{encode_call, Token}, - Uint256, -}; -use clarity::{Address, PrivateKey}; +use crate::utils::{EthClient, get_send_transaction_gas_price}; +use ethers::prelude::*; +use gravity_abi::gravity::*; use gravity_utils::error::GravityError; use std::time::Duration; -use web30::{client::Web3, types::SendTxOption}; /// Calls the Gravity ethereum contract to deploy the ERC20 representation of the given Cosmos asset /// denom. If an existing contract is already deployed representing this asset this call will cost @@ -21,35 +18,31 @@ pub async fn deploy_erc20( erc20_symbol: String, decimals: u8, gravity_contract: Address, - web3: &Web3, wait_timeout: Option, - sender_secret: PrivateKey, - options: Vec, -) -> Result { - let sender_address = sender_secret.to_public_key().unwrap(); - let tx_hash = web3 - .send_transaction( - gravity_contract, - encode_call( - "deployERC20(string,string,string,uint8)", - &[ - Token::String(cosmos_denom), - Token::String(erc20_name), - Token::String(erc20_symbol), - decimals.into(), - ], - )?, - 0u32.into(), - sender_address, - sender_secret, - options, - ) - .await?; + eth_client: EthClient, +) -> Result { + let contract_call = Gravity::new(gravity_contract, eth_client.clone()) + .deploy_erc20(cosmos_denom, erc20_name, erc20_symbol, decimals); + let gas_price = get_send_transaction_gas_price(eth_client.clone()).await?; + let contract_call = contract_call.gas_price(gas_price); + + let pending_tx = contract_call.send().await?; + let tx_hash = *pending_tx; + info!("Sent logic call with txid {}", tx_hash); + // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? + // additionally we are mirroring only waiting for 1 confirmation by leaving that as default + let pending_tx = pending_tx.interval(Duration::from_secs(1)); + let potential_error = GravityError::GravityContractError(format!("Did not receive transaction receipt when deploying: {}", tx_hash)); if let Some(timeout) = wait_timeout { - web3.wait_for_transaction(tx_hash.clone(), timeout, None) - .await?; + match tokio::time::timeout(timeout, pending_tx).await?? { + Some(receipt) => Ok(receipt.transaction_hash), + None => Err(potential_error) + } + } else { + match pending_tx.await? { + Some(receipt) => Ok(receipt.transaction_hash), + None => Err(potential_error) + } } - - Ok(tx_hash) } diff --git a/orchestrator/ethereum_gravity/src/submit_batch.rs b/orchestrator/ethereum_gravity/src/submit_batch.rs index 8cbdd2bea..388aa6aa0 100644 --- a/orchestrator/ethereum_gravity/src/submit_batch.rs +++ b/orchestrator/ethereum_gravity/src/submit_batch.rs @@ -58,7 +58,6 @@ pub async fn send_eth_transaction_batch( let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); - // TODO(bolten): we need to implement the gas multiplier being passed as a TxOption let pending_tx = contract_call.send().await?; let tx_hash = *pending_tx; info!("Sent batch update with txid {}", tx_hash); From b39174bfc9fa3370014fb25df0529a5425689697 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 17 Nov 2021 21:39:34 -0800 Subject: [PATCH 059/115] Finish converting deploy ERC-20 and gorc command --- .../ethereum_gravity/src/deploy_erc20.rs | 6 +++--- orchestrator/gorc/src/commands/deploy/erc20.rs | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/deploy_erc20.rs b/orchestrator/ethereum_gravity/src/deploy_erc20.rs index 18ed52a5c..4d2c04b6a 100644 --- a/orchestrator/ethereum_gravity/src/deploy_erc20.rs +++ b/orchestrator/ethereum_gravity/src/deploy_erc20.rs @@ -20,7 +20,7 @@ pub async fn deploy_erc20( gravity_contract: Address, wait_timeout: Option, eth_client: EthClient, -) -> Result { +) -> Result { let contract_call = Gravity::new(gravity_contract, eth_client.clone()) .deploy_erc20(cosmos_denom, erc20_name, erc20_symbol, decimals); let gas_price = get_send_transaction_gas_price(eth_client.clone()).await?; @@ -28,11 +28,11 @@ pub async fn deploy_erc20( let pending_tx = contract_call.send().await?; let tx_hash = *pending_tx; - info!("Sent logic call with txid {}", tx_hash); + info!("Deploying ERC-20 with tx hash {}", tx_hash); // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? // additionally we are mirroring only waiting for 1 confirmation by leaving that as default let pending_tx = pending_tx.interval(Duration::from_secs(1)); - let potential_error = GravityError::GravityContractError(format!("Did not receive transaction receipt when deploying: {}", tx_hash)); + let potential_error = GravityError::GravityContractError(format!("Did not receive transaction receipt when deploying ERC-20: {}", tx_hash)); if let Some(timeout) = wait_timeout { match tokio::time::timeout(timeout, pending_tx).await?? { diff --git a/orchestrator/gorc/src/commands/deploy/erc20.rs b/orchestrator/gorc/src/commands/deploy/erc20.rs index bb9768604..129ff0d9c 100644 --- a/orchestrator/gorc/src/commands/deploy/erc20.rs +++ b/orchestrator/gorc/src/commands/deploy/erc20.rs @@ -35,6 +35,9 @@ impl Erc20 { let config = APP.config(); + let ethereum_wallet = config.load_ethers_wallet(self.ethereum_key.clone()); + let ethereum_address = ethereum_wallet.address(); + let contract_address = config .gravity .contract @@ -51,11 +54,10 @@ impl Erc20 { .await; let mut grpc = connections.grpc.clone().unwrap(); - let web3 = connections.web3.clone().unwrap(); + let eth_client = SignerMiddleware::new(connections.eth_provider.clone().unwrap(), ethereum_wallet.clone()); + let eth_client = Arc::new(eth_client); - let ethereum_key = config.load_clarity_key(self.ethereum_key.clone()); - let ethereum_public_key = ethereum_key.to_public_key().unwrap(); - check_for_eth(ethereum_public_key, &web3).await; + check_for_eth(ethereum_address, ð_client.provider()).await; let req = DenomToErc20ParamsRequest { denom: denom.clone(), @@ -75,15 +77,13 @@ impl Erc20 { res.erc20_symbol, u8::try_from(res.erc20_decimals).unwrap(), contract_address, - &web3, Some(timeout), - ethereum_key, - vec![], + eth_client.clone(), ) .await .expect("Could not deploy ERC20"); - println!("We have deployed ERC20 contract {:#066x}, waiting to see if the Cosmos chain choses to adopt it", res); + println!("We have deployed ERC20 contract {}, waiting to see if the Cosmos chain choses to adopt it", res); let start = Instant::now(); loop { From a45620d7fc0931d23a1c3d6613ebf0e106fac765 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 17 Nov 2021 21:53:58 -0800 Subject: [PATCH 060/115] Downcast replacements --- orchestrator/cosmos_gravity/src/build.rs | 29 ++++++++++++------------ 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/orchestrator/cosmos_gravity/src/build.rs b/orchestrator/cosmos_gravity/src/build.rs index ec1bb1e00..426bb2d0f 100644 --- a/orchestrator/cosmos_gravity/src/build.rs +++ b/orchestrator/cosmos_gravity/src/build.rs @@ -1,11 +1,10 @@ -use clarity::PrivateKey as EthPrivateKey; use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::utils::bytes_to_hex_str; use deep_space::Contact; use deep_space::Msg; -use ethereum_gravity::utils::downcast_uint256; use gravity_proto::gravity as proto; use gravity_proto::ToAny; +use gravity_utils::ethereum::downcast_to_u64; use gravity_utils::message_signatures::{ encode_logic_call_confirm, encode_tx_batch_confirm, encode_valset_confirm, }; @@ -124,8 +123,8 @@ pub fn ethereum_event_messages( let mut unordered_msgs = std::collections::HashMap::new(); for deposit in deposits { let event = proto::SendToCosmosEvent { - event_nonce: downcast_uint256(deposit.event_nonce.clone()).unwrap(), - ethereum_height: downcast_uint256(deposit.block_height).unwrap(), + event_nonce: downcast_to_u64(deposit.event_nonce.clone()).unwrap(), + ethereum_height: downcast_to_u64(deposit.block_height).unwrap(), token_contract: deposit.erc20.to_string(), amount: deposit.amount.to_string(), cosmos_receiver: deposit.destination.to_string(), @@ -140,9 +139,9 @@ pub fn ethereum_event_messages( } for batch in batches { let event = proto::BatchExecutedEvent { - event_nonce: downcast_uint256(batch.event_nonce.clone()).unwrap(), - batch_nonce: downcast_uint256(batch.batch_nonce.clone()).unwrap(), - ethereum_height: downcast_uint256(batch.block_height).unwrap(), + event_nonce: downcast_to_u64(batch.event_nonce.clone()).unwrap(), + batch_nonce: downcast_to_u64(batch.batch_nonce.clone()).unwrap(), + ethereum_height: downcast_to_u64(batch.block_height).unwrap(), token_contract: batch.erc20.to_string(), }; let msg = proto::MsgSubmitEthereumEvent { @@ -154,8 +153,8 @@ pub fn ethereum_event_messages( } for deploy in erc20_deploys { let event = proto::Erc20DeployedEvent { - event_nonce: downcast_uint256(deploy.event_nonce.clone()).unwrap(), - ethereum_height: downcast_uint256(deploy.block_height).unwrap(), + event_nonce: downcast_to_u64(deploy.event_nonce.clone()).unwrap(), + ethereum_height: downcast_to_u64(deploy.block_height).unwrap(), cosmos_denom: deploy.cosmos_denom, token_contract: deploy.erc20_address.to_string(), erc20_name: deploy.name, @@ -171,10 +170,10 @@ pub fn ethereum_event_messages( } for logic_call in logic_calls { let event = proto::ContractCallExecutedEvent { - event_nonce: downcast_uint256(logic_call.event_nonce.clone()).unwrap(), - ethereum_height: downcast_uint256(logic_call.block_height).unwrap(), + event_nonce: downcast_to_u64(logic_call.event_nonce.clone()).unwrap(), + ethereum_height: downcast_to_u64(logic_call.block_height).unwrap(), invalidation_id: logic_call.invalidation_id, - invalidation_nonce: downcast_uint256(logic_call.invalidation_nonce).unwrap(), + invalidation_nonce: downcast_to_u64(logic_call.invalidation_nonce).unwrap(), }; let msg = proto::MsgSubmitEthereumEvent { signer: cosmos_address.to_string(), @@ -185,9 +184,9 @@ pub fn ethereum_event_messages( } for valset in valsets { let event = proto::SignerSetTxExecutedEvent { - event_nonce: downcast_uint256(valset.event_nonce.clone()).unwrap(), - signer_set_tx_nonce: downcast_uint256(valset.valset_nonce.clone()).unwrap(), - ethereum_height: downcast_uint256(valset.block_height).unwrap(), + event_nonce: downcast_to_u64(valset.event_nonce.clone()).unwrap(), + signer_set_tx_nonce: downcast_to_u64(valset.valset_nonce.clone()).unwrap(), + ethereum_height: downcast_to_u64(valset.block_height).unwrap(), members: valset.members.iter().map(|v| v.into()).collect(), }; let msg = proto::MsgSubmitEthereumEvent { From 7080fbb829ec8865aa46876aca07ecbe4ff24edc Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 17 Nov 2021 22:02:14 -0800 Subject: [PATCH 061/115] Convert orchestrator main_loop --- orchestrator/orchestrator/src/main_loop.rs | 25 ++++++++++------------ 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/orchestrator/orchestrator/src/main_loop.rs b/orchestrator/orchestrator/src/main_loop.rs index 441f0c2bb..f996fa799 100644 --- a/orchestrator/orchestrator/src/main_loop.rs +++ b/orchestrator/orchestrator/src/main_loop.rs @@ -8,8 +8,6 @@ use crate::{ ethereum_event_watcher::check_for_events, metrics::metrics_main_loop, oracle_resync::get_last_checked_block, }; -use clarity::Uint256; -use clarity::{utils::bytes_to_hex_str, PrivateKey as EthPrivateKey}; use cosmos_gravity::send::send_main_loop; use cosmos_gravity::{ build, @@ -25,6 +23,7 @@ use deep_space::{Contact, Msg}; use ethereum_gravity::utils::{EthClient, get_gravity_id}; use ethers::{prelude::*, types::Address as EthAddress}; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; +use gravity_utils::ethereum::bytes_to_hex_str; use relayer::main_loop::relayer_main_loop; use std::convert::TryInto; use std::sync::Arc; @@ -35,7 +34,6 @@ use std::{ use tokio::join; use tokio::time::sleep as delay_for; use tonic::transport::Channel; -use web30::client::Web3; /// The execution speed governing all loops in this file /// which is to say all loops started by Orchestrator main @@ -121,12 +119,11 @@ pub async fn eth_oracle_main_loop( msg_sender: tokio::sync::mpsc::Sender>, ) { let our_cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); - let long_timeout_web30 = Web3::new(&web3.get_url(), Duration::from_secs(120)); - let mut last_checked_block: Uint256 = get_last_checked_block( + let mut last_checked_block: U256 = get_last_checked_block( grpc_client.clone(), our_cosmos_address, gravity_contract_address, - &long_timeout_web30, + eth_client.clone(), blocks_to_search, ) .await; @@ -136,7 +133,7 @@ pub async fn eth_oracle_main_loop( loop { let loop_start = Instant::now(); - let latest_eth_block = web3.eth_block_number().await; + let latest_eth_block = eth_client.get_block_number().await; let latest_cosmos_block = contact.get_chain_status().await; match (latest_eth_block, latest_cosmos_block) { (Ok(latest_eth_block), Ok(ChainStatus::Moving { block_height })) => { @@ -181,7 +178,7 @@ pub async fn eth_oracle_main_loop( // Relays events from Ethereum -> Cosmos match check_for_events( - &web3, + eth_client.clone(), &contact, &mut grpc_client, gravity_contract_address, @@ -225,10 +222,10 @@ pub async fn eth_signer_main_loop( msg_sender: tokio::sync::mpsc::Sender>, ) { let our_cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); - let our_ethereum_address = ethereum_key.to_public_key().unwrap(); + let our_ethereum_address = eth_client.address(); let mut grpc_client = grpc_client; - let gravity_id = get_gravity_id(contract_address, our_ethereum_address, &web3).await; + let gravity_id = get_gravity_id(contract_address, our_ethereum_address, eth_client.clone()).await; if gravity_id.is_err() { error!("Failed to get GravityID, check your Eth node"); return; @@ -238,7 +235,7 @@ pub async fn eth_signer_main_loop( loop { let loop_start = Instant::now(); - let latest_eth_block = web3.eth_block_number().await; + let latest_eth_block = eth_client.get_block_number().await; let latest_cosmos_block = contact.get_chain_status().await; match (latest_eth_block, latest_cosmos_block) { (Ok(latest_eth_block), Ok(ChainStatus::Moving { block_height })) => { @@ -294,7 +291,7 @@ pub async fn eth_signer_main_loop( ); let messages = build::signer_set_tx_confirmation_messages( &contact, - ethereum_key, + eth_client.clone(), valsets, cosmos_key, gravity_id.clone(), @@ -327,7 +324,7 @@ pub async fn eth_signer_main_loop( let transaction_batches = vec![last_unsigned_batch]; let messages = build::batch_tx_confirmation_messages( &contact, - ethereum_key, + eth_client.clone(), transaction_batches, cosmos_key, gravity_id.clone(), @@ -359,7 +356,7 @@ pub async fn eth_signer_main_loop( let logic_calls = vec![logic_call]; let messages = build::contract_call_tx_confirmation_messages( &contact, - ethereum_key, + eth_client.clone(), logic_calls, cosmos_key, gravity_id.clone(), From f2778e9f09535176a2d9f0f558208a3e083288ec Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 17 Nov 2021 23:26:06 -0800 Subject: [PATCH 062/115] Convert build.rs --- orchestrator/cosmos_gravity/src/build.rs | 37 +++++++++++++++--------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/orchestrator/cosmos_gravity/src/build.rs b/orchestrator/cosmos_gravity/src/build.rs index 426bb2d0f..c70c030f7 100644 --- a/orchestrator/cosmos_gravity/src/build.rs +++ b/orchestrator/cosmos_gravity/src/build.rs @@ -1,10 +1,13 @@ use deep_space::private_key::PrivateKey as CosmosPrivateKey; -use deep_space::utils::bytes_to_hex_str; use deep_space::Contact; use deep_space::Msg; +use ethereum_gravity::utils::EthClient; +use ethers::core::k256::ecdsa::signature::DigestSigner; +use ethers::prelude::Middleware; +use ethers::prelude::Signer; use gravity_proto::gravity as proto; use gravity_proto::ToAny; -use gravity_utils::ethereum::downcast_to_u64; +use gravity_utils::ethereum::{bytes_to_hex_str, downcast_to_u64}; use gravity_utils::message_signatures::{ encode_logic_call_confirm, encode_tx_batch_confirm, encode_valset_confirm, }; @@ -12,22 +15,24 @@ use gravity_utils::types::*; pub fn signer_set_tx_confirmation_messages( contact: &Contact, - ethereum_key: EthPrivateKey, + eth_client: EthClient, valsets: Vec, cosmos_key: CosmosPrivateKey, gravity_id: String, ) -> Vec { let cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); - let ethereum_address = ethereum_key.to_public_key().unwrap(); + let ethereum_address = eth_client.address(); let mut msgs = Vec::new(); for valset in valsets { let data = encode_valset_confirm(gravity_id.clone(), valset.clone()); - let signature = ethereum_key.sign_ethereum_msg(&data); + // Signer trait responds with a Result, but we use a LocalWallet and it + // will never throw an error + let signature = eth_client.signer().sign_message(data).await.unwrap(); let confirmation = proto::SignerSetTxConfirmation { ethereum_signer: ethereum_address.to_string(), signer_set_nonce: valset.nonce, - signature: signature.to_bytes().to_vec(), + signature: signature.into(), }; let msg = proto::MsgSubmitEthereumTxConfirmation { signer: cosmos_address.to_string(), @@ -41,23 +46,25 @@ pub fn signer_set_tx_confirmation_messages( pub fn batch_tx_confirmation_messages( contact: &Contact, - ethereum_key: EthPrivateKey, + eth_client: EthClient, batches: Vec, cosmos_key: CosmosPrivateKey, gravity_id: String, ) -> Vec { let cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); - let ethereum_address = ethereum_key.to_public_key().unwrap(); + let ethereum_address = eth_client.address(); let mut msgs = Vec::new(); for batch in batches { let data = encode_tx_batch_confirm(gravity_id.clone(), batch.clone()); - let signature = ethereum_key.sign_ethereum_msg(&data); + // Signer trait responds with a Result, but we use a LocalWallet and it + // will never throw an error + let signature = eth_client.signer().sign_message(data).await.unwrap(); let confirmation = proto::BatchTxConfirmation { token_contract: batch.token_contract.to_string(), batch_nonce: batch.nonce, ethereum_signer: ethereum_address.to_string(), - signature: signature.to_bytes().to_vec(), + signature: signature.into(), }; let msg = proto::MsgSubmitEthereumEvent { signer: cosmos_address.to_string(), @@ -71,21 +78,23 @@ pub fn batch_tx_confirmation_messages( pub fn contract_call_tx_confirmation_messages( contact: &Contact, - ethereum_key: EthPrivateKey, + eth_client: EthClient, logic_calls: Vec, cosmos_key: CosmosPrivateKey, gravity_id: String, ) -> Vec { let cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); - let ethereum_address = ethereum_key.to_public_key().unwrap(); + let ethereum_address = eth_client.address(); let mut msgs = Vec::new(); for logic_call in logic_calls { let data = encode_logic_call_confirm(gravity_id.clone(), logic_call.clone()); - let signature = ethereum_key.sign_ethereum_msg(&data); + // Signer trait responds with a Result, but we use a LocalWallet and it + // will never throw an error + let signature = eth_client.signer().sign_message(data).await.unwrap(); let confirmation = proto::ContractCallTxConfirmation { ethereum_signer: ethereum_address.to_string(), - signature: signature.to_bytes().to_vec(), + signature: signature.into(), invalidation_scope: bytes_to_hex_str(&logic_call.invalidation_id) .as_bytes() .to_vec(), From 56f06c441fd1d8243b237b36081ccad29c433294 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 17 Nov 2021 23:49:00 -0800 Subject: [PATCH 063/115] Convert metrics --- orchestrator/orchestrator/src/metrics.rs | 83 ++++++++++++------------ 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/orchestrator/orchestrator/src/metrics.rs b/orchestrator/orchestrator/src/metrics.rs index 4923a89ef..9396b2601 100644 --- a/orchestrator/orchestrator/src/metrics.rs +++ b/orchestrator/orchestrator/src/metrics.rs @@ -1,6 +1,7 @@ use std::{convert::TryInto, net}; use axum::prelude::*; +use ethers::prelude::*; use hyper::Server; use lazy_static::lazy_static; use prometheus::*; @@ -63,7 +64,7 @@ lazy_static! { .unwrap(); } -// Guages (guarded by setters) +// Gauges (guarded by setters) lazy_static! { static ref COSMOS_BLOCK_HEIGHT: IntGauge = register_int_gauge!(opts!( "cosmos_block_height", @@ -177,83 +178,83 @@ pub fn set_cosmos_last_event_nonce(v: u64) { set_u64(&COSMOS_LAST_EVENT_NONCE, v); } -pub fn set_ethereum_block_height(v: clarity::Uint256) { - set_uint256(ÐEREUM_BLOCK_HEIGHT, v); +pub fn set_ethereum_block_height(v: U256) { + set_U256(ÐEREUM_BLOCK_HEIGHT, v); } -pub fn set_ethereum_check_for_events_end_block(v: clarity::Uint256) { - set_uint256(ÐEREUM_CHECK_FOR_EVENTS_END_BLOCK, v); +pub fn set_ethereum_check_for_events_end_block(v: U256) { + set_U256(ÐEREUM_CHECK_FOR_EVENTS_END_BLOCK, v); } -pub fn set_ethereum_check_for_events_starting_block(v: clarity::Uint256) { - set_uint256(ÐEREUM_CHECK_FOR_EVENTS_STARTING_BLOCK, v); +pub fn set_ethereum_check_for_events_starting_block(v: U256) { + set_U256(ÐEREUM_CHECK_FOR_EVENTS_STARTING_BLOCK, v); } -pub fn set_ethereum_last_batch_event(v: clarity::Uint256) { - set_uint256(ÐEREUM_LAST_BATCH_EVENT, v.clone()); - set_uint256(ÐEREUM_LAST_EVENT_NONCE, v); +pub fn set_ethereum_last_batch_event(v: U256) { + set_U256(ÐEREUM_LAST_BATCH_EVENT, v); + set_U256(ÐEREUM_LAST_EVENT_NONCE, v); } -pub fn set_ethereum_last_batch_nonce(v: clarity::Uint256) { - set_uint256(ÐEREUM_LAST_BATCH_NONCE, v); +pub fn set_ethereum_last_batch_nonce(v: U256) { + set_U256(ÐEREUM_LAST_BATCH_NONCE, v); } -pub fn set_ethereum_last_deposit_block(v: clarity::Uint256) { - set_uint256(ÐEREUM_LAST_DEPOSIT_BLOCK, v); +pub fn set_ethereum_last_deposit_block(v: U256) { + set_U256(ÐEREUM_LAST_DEPOSIT_BLOCK, v); } -pub fn set_ethereum_last_deposit_event(v: clarity::Uint256) { - set_uint256(ÐEREUM_LAST_DEPOSIT_EVENT, v.clone()); - set_uint256(ÐEREUM_LAST_EVENT_NONCE, v); +pub fn set_ethereum_last_deposit_event(v: U256) { + set_U256(ÐEREUM_LAST_DEPOSIT_EVENT, v); + set_U256(ÐEREUM_LAST_EVENT_NONCE, v); } -pub fn set_ethereum_last_erc20_block(v: clarity::Uint256) { - set_uint256(ÐEREUM_LAST_ERC20_BLOCK, v); +pub fn set_ethereum_last_erc20_block(v: U256) { + set_U256(ÐEREUM_LAST_ERC20_BLOCK, v); } -pub fn set_ethereum_last_erc20_event(v: clarity::Uint256) { - set_uint256(ÐEREUM_LAST_ERC20_EVENT, v.clone()); - set_uint256(ÐEREUM_LAST_EVENT_NONCE, v); +pub fn set_ethereum_last_erc20_event(v: U256) { + set_U256(ÐEREUM_LAST_ERC20_EVENT, v); + set_U256(ÐEREUM_LAST_EVENT_NONCE, v); } -pub fn set_ethereum_last_logic_call_event(v: clarity::Uint256) { - set_uint256(ÐEREUM_LAST_LOGIC_CALL_EVENT, v.clone()); - set_uint256(ÐEREUM_LAST_EVENT_NONCE, v); +pub fn set_ethereum_last_logic_call_event(v: U256) { + set_U256(ÐEREUM_LAST_LOGIC_CALL_EVENT, v); + set_U256(ÐEREUM_LAST_EVENT_NONCE, v); } -pub fn set_ethereum_last_logic_call_nonce(v: clarity::Uint256) { - set_uint256(ÐEREUM_LAST_LOGIC_CALL_NONCE, v); +pub fn set_ethereum_last_logic_call_nonce(v: U256) { + set_U256(ÐEREUM_LAST_LOGIC_CALL_NONCE, v); } -pub fn set_ethereum_last_valset_event(v: clarity::Uint256) { - set_uint256(ÐEREUM_LAST_VALSET_EVENT, v.clone()); - set_uint256(ÐEREUM_LAST_EVENT_NONCE, v); +pub fn set_ethereum_last_valset_event(v: U256) { + set_U256(ÐEREUM_LAST_VALSET_EVENT, v); + set_U256(ÐEREUM_LAST_EVENT_NONCE, v); } -pub fn set_ethereum_last_valset_nonce(v: clarity::Uint256) { - set_uint256(ÐEREUM_LAST_VALSET_NONCE, v); +pub fn set_ethereum_last_valset_nonce(v: U256) { + set_U256(ÐEREUM_LAST_VALSET_NONCE, v); } -pub fn set_ethereum_bal(v: clarity::Uint256) { - set_uint256(ÐEREUM_BAL, v); +pub fn set_ethereum_bal(v: U256) { + set_U256(ÐEREUM_BAL, v); } -fn set_u64(guage: &IntGauge, value: u64) { +fn set_u64(gauge: &IntGauge, value: u64) { let v = match value.try_into() { Ok(v) => v, Err(_) => -1, }; - if v > guage.get() { - guage.set(v); + if v > gauge.get() { + gauge.set(v); } } -fn set_uint256(guage: &IntGauge, value: clarity::Uint256) { - let v = match value.to_str_radix(10).parse() { +fn set_U256(gauge: &IntGauge, value: U256) { + let v = match value.to_string().parse() { Ok(v) => v, Err(_) => -1, }; - if v > guage.get() { - guage.set(v); + if v > gauge.get() { + gauge.set(v); } } From 3d96849137d62a48b508856813b2c382b1cf2497 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 17 Nov 2021 23:56:48 -0800 Subject: [PATCH 064/115] WIP converting last parts of the orchestrator --- .../ethereum_gravity/src/send_to_cosmos.rs | 31 ++++++------------- .../src/ethereum_event_watcher.rs | 9 ++++-- .../orchestrator/src/oracle_resync.rs | 8 +++-- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs index 47bf4b18c..3233b0ce5 100644 --- a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs +++ b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs @@ -1,14 +1,11 @@ //! Helper functions for sending tokens to Cosmos -use std::time::Duration; - -use clarity::abi::{encode_call, Token}; -use clarity::PrivateKey as EthPrivateKey; -use clarity::{Address, Uint256}; +use crate::utils::EthClient; use deep_space::address::Address as CosmosAddress; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; use gravity_utils::error::GravityError; -use web30::client::Web3; -use web30::types::SendTxOption; +use std::time::Duration; const SEND_TO_COSMOS_GAS_LIMIT: u128 = 100_000; @@ -16,25 +13,15 @@ const SEND_TO_COSMOS_GAS_LIMIT: u128 = 100_000; pub async fn send_to_cosmos( erc20: Address, gravity_contract: Address, - amount: Uint256, + amount: U256, cosmos_destination: CosmosAddress, - sender_secret: EthPrivateKey, wait_timeout: Option, - web3: &Web3, - options: Vec, -) -> Result { - let sender_address = sender_secret.to_public_key()?; + eth_client: EthClient, +) -> Result { + let sender_address = eth_client.address(); let mut approve_nonce = None; - for option in options.iter() { - if let SendTxOption::Nonce(_) = option { - return Err(GravityError::InvalidOptionsError( - "This call sends more than one tx! Can't specify".to_string(), - )); - } - } - - let approved = web3 + let approved = .check_erc20_approved(erc20, sender_address, gravity_contract) .await?; if !approved { diff --git a/orchestrator/orchestrator/src/ethereum_event_watcher.rs b/orchestrator/orchestrator/src/ethereum_event_watcher.rs index 33dc591dc..2b8cfa6d6 100644 --- a/orchestrator/orchestrator/src/ethereum_event_watcher.rs +++ b/orchestrator/orchestrator/src/ethereum_event_watcher.rs @@ -4,14 +4,17 @@ use crate::get_with_retry::get_block_number_with_retry; use crate::get_with_retry::get_net_version_with_retry; use crate::metrics; -use clarity::{utils::bytes_to_hex_str, Address as EthAddress, Uint256}; use cosmos_gravity::build; use cosmos_gravity::query::get_last_event_nonce; use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::{Contact, Msg}; +use ethereum_gravity::utils::EthClient; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::{ error::GravityError, + ethereum::bytes_to_hex_str, types::{ ERC20_DEPLOYED_EVENT_STR, LOGIC_CALL_EVENT_STR, SEND_TO_COSMOS_EVENT_STR, TRANSACTION_BATCH_EXECUTED_EVENT_STR, VALSET_UPDATED_EVENT_STR, @@ -25,14 +28,14 @@ use web30::client::Web3; use web30::jsonrpc::error::Web3Error; pub async fn check_for_events( - web3: &Web3, + eth_client: EthClient, contact: &Contact, grpc_client: &mut GravityQueryClient, gravity_contract_address: EthAddress, cosmos_key: CosmosPrivateKey, starting_block: Uint256, msg_sender: tokio::sync::mpsc::Sender>, -) -> Result { +) -> Result { let prefix = contact.get_prefix(); let our_cosmos_address = cosmos_key.to_address(&prefix).unwrap(); let latest_block = get_block_number_with_retry(web3).await; diff --git a/orchestrator/orchestrator/src/oracle_resync.rs b/orchestrator/orchestrator/src/oracle_resync.rs index 8bb366d1a..d740afe4a 100644 --- a/orchestrator/orchestrator/src/oracle_resync.rs +++ b/orchestrator/orchestrator/src/oracle_resync.rs @@ -1,5 +1,7 @@ -use clarity::{Address, Uint256}; use deep_space::address::Address as CosmosAddress; +use ethereum_gravity::utils::EthClient; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::types::{ ERC20_DEPLOYED_EVENT_STR, LOGIC_CALL_EVENT_STR, SEND_TO_COSMOS_EVENT_STR, @@ -9,7 +11,6 @@ use gravity_utils::types::{ }; use tokio::time::sleep as delay_for; use tonic::transport::Channel; -use web30::client::Web3; use crate::get_with_retry::get_block_number_with_retry; use crate::get_with_retry::get_last_event_nonce_with_retry; @@ -21,9 +22,10 @@ pub async fn get_last_checked_block( grpc_client: GravityQueryClient, our_cosmos_address: CosmosAddress, gravity_contract_address: Address, - web3: &Web3, + eth_client: EthClient, blocks_to_search: u128, ) -> Uint256 { + // needs 120 second timeout let mut grpc_client = grpc_client; let latest_block = get_block_number_with_retry(web3).await; From a527abda82886fa09051a5b881445d23d7a97606 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 18 Nov 2021 00:02:52 -0800 Subject: [PATCH 065/115] Hash raw messages before signing them --- orchestrator/cosmos_gravity/src/build.rs | 7 ++++--- orchestrator/gravity_utils/src/message_signatures.rs | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/orchestrator/cosmos_gravity/src/build.rs b/orchestrator/cosmos_gravity/src/build.rs index c70c030f7..c47709a1e 100644 --- a/orchestrator/cosmos_gravity/src/build.rs +++ b/orchestrator/cosmos_gravity/src/build.rs @@ -5,6 +5,7 @@ use ethereum_gravity::utils::EthClient; use ethers::core::k256::ecdsa::signature::DigestSigner; use ethers::prelude::Middleware; use ethers::prelude::Signer; +use ethers::utils::keccak256; use gravity_proto::gravity as proto; use gravity_proto::ToAny; use gravity_utils::ethereum::{bytes_to_hex_str, downcast_to_u64}; @@ -25,7 +26,7 @@ pub fn signer_set_tx_confirmation_messages( let mut msgs = Vec::new(); for valset in valsets { - let data = encode_valset_confirm(gravity_id.clone(), valset.clone()); + let data = keccak256(encode_valset_confirm(gravity_id.clone(), valset.clone()).as_slice()); // Signer trait responds with a Result, but we use a LocalWallet and it // will never throw an error let signature = eth_client.signer().sign_message(data).await.unwrap(); @@ -56,7 +57,7 @@ pub fn batch_tx_confirmation_messages( let mut msgs = Vec::new(); for batch in batches { - let data = encode_tx_batch_confirm(gravity_id.clone(), batch.clone()); + let data = keccak256(encode_tx_batch_confirm(gravity_id.clone(), batch.clone()).as_slice()); // Signer trait responds with a Result, but we use a LocalWallet and it // will never throw an error let signature = eth_client.signer().sign_message(data).await.unwrap(); @@ -88,7 +89,7 @@ pub fn contract_call_tx_confirmation_messages( let mut msgs = Vec::new(); for logic_call in logic_calls { - let data = encode_logic_call_confirm(gravity_id.clone(), logic_call.clone()); + let data = keccak256(encode_logic_call_confirm(gravity_id.clone(), logic_call.clone()).as_slice()); // Signer trait responds with a Result, but we use a LocalWallet and it // will never throw an error let signature = eth_client.signer().sign_message(data).await.unwrap(); diff --git a/orchestrator/gravity_utils/src/message_signatures.rs b/orchestrator/gravity_utils/src/message_signatures.rs index 7f032d1c6..d9f3bdced 100644 --- a/orchestrator/gravity_utils/src/message_signatures.rs +++ b/orchestrator/gravity_utils/src/message_signatures.rs @@ -1,6 +1,7 @@ use crate::types::{LogicCall, TransactionBatch, Valset}; use ethers::core::abi::{self, Token}; use ethers::utils::hash_message; +use ethers::utils::keccak256; /// takes the required input data and produces the required signature to confirm a validator /// set update on the Gravity Ethereum contract. This value will then be signed before being @@ -22,7 +23,7 @@ pub fn encode_valset_confirm(gravity_id: String, valset: Valset) -> Vec { } pub fn encode_valset_confirm_hashed(gravity_id: String, valset: Valset) -> Vec { - let digest = encode_valset_confirm(gravity_id, valset); + let digest = keccak256(encode_valset_confirm(gravity_id, valset).as_slice()); hash_message(digest).as_bytes().to_vec() } @@ -126,7 +127,7 @@ pub fn encode_tx_batch_confirm(gravity_id: String, batch: TransactionBatch) -> V } pub fn encode_tx_batch_confirm_hashed(gravity_id: String, batch: TransactionBatch) -> Vec { - let digest = encode_tx_batch_confirm(gravity_id, batch); + let digest = keccak256(encode_tx_batch_confirm(gravity_id, batch).as_slice()); hash_message(digest).as_bytes().to_vec() } @@ -266,7 +267,7 @@ pub fn encode_logic_call_confirm(gravity_id: String, call: LogicCall) -> Vec } pub fn encode_logic_call_confirm_hashed(gravity_id: String, call: LogicCall) -> Vec { - let digest = encode_logic_call_confirm(gravity_id, call); + let digest = keccak256(encode_logic_call_confirm(gravity_id, call).as_slice()); hash_message(digest).as_bytes().to_vec() } From ee633172e4c26e2058cda60d2cae3f0a58094bab Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 18 Nov 2021 01:14:02 -0800 Subject: [PATCH 066/115] WIP on converting send_to_cosmos --- .../ethereum_gravity/src/deploy_erc20.rs | 6 +- .../ethereum_gravity/src/erc20_utils.rs | 64 +++++++++++++++++++ orchestrator/ethereum_gravity/src/lib.rs | 1 + .../ethereum_gravity/src/send_to_cosmos.rs | 23 ++----- 4 files changed, 73 insertions(+), 21 deletions(-) create mode 100644 orchestrator/ethereum_gravity/src/erc20_utils.rs diff --git a/orchestrator/ethereum_gravity/src/deploy_erc20.rs b/orchestrator/ethereum_gravity/src/deploy_erc20.rs index 4d2c04b6a..b8a22cd57 100644 --- a/orchestrator/ethereum_gravity/src/deploy_erc20.rs +++ b/orchestrator/ethereum_gravity/src/deploy_erc20.rs @@ -22,7 +22,7 @@ pub async fn deploy_erc20( eth_client: EthClient, ) -> Result { let contract_call = Gravity::new(gravity_contract, eth_client.clone()) - .deploy_erc20(cosmos_denom, erc20_name, erc20_symbol, decimals); + .deploy_erc20(cosmos_denom, erc20_name, erc20_symbol.clone(), decimals); let gas_price = get_send_transaction_gas_price(eth_client.clone()).await?; let contract_call = contract_call.gas_price(gas_price); @@ -32,7 +32,9 @@ pub async fn deploy_erc20( // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? // additionally we are mirroring only waiting for 1 confirmation by leaving that as default let pending_tx = pending_tx.interval(Duration::from_secs(1)); - let potential_error = GravityError::GravityContractError(format!("Did not receive transaction receipt when deploying ERC-20: {}", tx_hash)); + let potential_error = GravityError::GravityContractError( + format!("Did not receive transaction receipt when deploying ERC-20 {}: {}", erc20_symbol, tx_hash) + ); if let Some(timeout) = wait_timeout { match tokio::time::timeout(timeout, pending_tx).await?? { diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs new file mode 100644 index 000000000..b26074a83 --- /dev/null +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -0,0 +1,64 @@ +use crate::utils::EthClient; +use ethers::abi::parse_abi; +use ethers::prelude::*; +use gravity_utils::error::GravityError; +use std::time::Duration; + +/// Checks if any given contract is approved to spend money from any given erc20 contract +/// using any given address. What exactly this does can be hard to grok, essentially when +/// you want contract A to be able to spend your erc20 contract funds you need to call 'approve' +/// on the ERC20 contract with your own address and A's address so that in the future when you call +/// contract A it can manipulate your ERC20 balances. This function checks if that has already been done. +pub async fn check_erc20_approved( + erc20: Address, + gravity_contract: Address, + eth_client: EthClient, +) -> Result { + let abi = BaseContract::from(parse_abi(&[ + "function allowance(address owner, address spender) external view returns (uint256)" + ]).unwrap()); + let erc20_contract = abi.into_contract(erc20, eth_client.clone()); + let allowance = erc20_contract.allowance(eth_client.address(), gravity_contract).call().await?; + + // TODO(bolten): verify if this check is sufficient/correct + // Check if the allowance remaining is greater than half of a U256- it's as good + // a test as any. + Ok(allowance > (U256::MAX / 2u32.into())) +} + +/// Approves a given contract to spend erc20 funds from the given address from the erc20 contract provided. +/// What exactly this does can be hard to grok, essentially when you want contract A to be able to spend +/// your erc20 contract funds you need to call 'approve' on the ERC20 contract with your own address and A's +/// address so that in the future when you call contract A it can manipulate your ERC20 balances. +/// This function performs that action and waits for it to complete for up to Timeout duration +pub async fn approve_erc20_transfers( + erc20: Address, + target_contract: Address, + timeout_option: Option, + eth_client: EthClient, +) -> Result { + let abi = BaseContract::from(parse_abi(&[ + "function approve(address spender, uint256 amount) external returns (bool)" + ]).unwrap()); + let erc20_contract = abi.into_contract(erc20, eth_client.clone()); + + let pending_tx = erc20_contract.method::<_, bool>("approve", target_contract, U256::MAX).send().await?; + let tx_hash = *pending_tx; + info!("Approving ERC-20 {} with txid {}", erc20, tx_hash); + // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? + // additionally we are mirroring only waiting for 1 confirmation by leaving that as default + let pending_tx = pending_tx.interval(Duration::from_secs(1)); + let potential_error = GravityError::GravityContractError(format!("Did not receive transaction receipt when approving ERC-20 {}: {}", erc20, tx_hash)); + + if let Some(timeout) = timeout_option { + match tokio::time::timeout(timeout, pending_tx).await?? { + Some(receipt) => Ok(receipt.transaction_hash), + None => Err(potential_error) + } + } else { + match pending_tx.await? { + Some(receipt) => Ok(receipt.transaction_hash), + None => Err(potential_error) + } + } +} \ No newline at end of file diff --git a/orchestrator/ethereum_gravity/src/lib.rs b/orchestrator/ethereum_gravity/src/lib.rs index 105e8bd3e..4d19694a4 100644 --- a/orchestrator/ethereum_gravity/src/lib.rs +++ b/orchestrator/ethereum_gravity/src/lib.rs @@ -5,6 +5,7 @@ use ethers::types::U256; #[macro_use] extern crate log; +pub mod erc20_utils; pub mod deploy_erc20; pub mod logic_call; pub mod send_to_cosmos; diff --git a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs index 3233b0ce5..76e5778cf 100644 --- a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs +++ b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs @@ -1,6 +1,6 @@ //! Helper functions for sending tokens to Cosmos -use crate::utils::EthClient; +use crate::{erc20_utils::{approve_erc20_transfers, check_erc20_approved}, utils::EthClient}; use deep_space::address::Address as CosmosAddress; use ethers::prelude::*; use ethers::types::Address as EthAddress; @@ -21,25 +21,10 @@ pub async fn send_to_cosmos( let sender_address = eth_client.address(); let mut approve_nonce = None; - let approved = - .check_erc20_approved(erc20, sender_address, gravity_contract) - .await?; + let approved = check_erc20_approved(erc20, gravity_contract, eth_client.clone()).await?; if !approved { - let mut options = options.clone(); - let nonce = web3.eth_get_transaction_count(sender_address).await?; - options.push(SendTxOption::Nonce(nonce.clone())); - approve_nonce = Some(nonce); - let txid = web3 - .approve_erc20_transfers(erc20, sender_secret, gravity_contract, None, options) - .await?; - trace!( - "We are not approved for ERC20 transfers, approving txid: {:#066x}", - txid - ); - if let Some(timeout) = wait_timeout { - web3.wait_for_transaction(txid, timeout, None).await?; - trace!("Approval finished!") - } + let txid = approve_erc20_transfers(erc20, gravity_contract, wait_timeout, eth_client.clone()).await?; + trace!("ERC-20 approval for {} finished with txid {}", erc20, txid); } // if the user sets a gas limit we should honor it, if they don't we From 55f1fa50c810aa9de51b080a5e2a3362494a72ca Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 18 Nov 2021 01:43:57 -0800 Subject: [PATCH 067/115] Finish converting send_to_cosmos --- .../ethereum_gravity/src/erc20_utils.rs | 10 ++- .../ethereum_gravity/src/send_to_cosmos.rs | 75 +++++++------------ orchestrator/gravity_utils/src/error.rs | 9 +++ 3 files changed, 44 insertions(+), 50 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs index b26074a83..871285b5a 100644 --- a/orchestrator/ethereum_gravity/src/erc20_utils.rs +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -18,12 +18,13 @@ pub async fn check_erc20_approved( "function allowance(address owner, address spender) external view returns (uint256)" ]).unwrap()); let erc20_contract = abi.into_contract(erc20, eth_client.clone()); - let allowance = erc20_contract.allowance(eth_client.address(), gravity_contract).call().await?; + let contract_call = erc20_contract.method::<_, U256>("allowance", (eth_client.address(), gravity_contract))?; + let allowance = contract_call.call().await?; // TODO(bolten): verify if this check is sufficient/correct - // Check if the allowance remaining is greater than half of a U256- it's as good + // Check if the allowance remaining is greater than half of a U256 - it's as good // a test as any. - Ok(allowance > (U256::MAX / 2u32.into())) + Ok(allowance > (U256::MAX.div_mod(2u32.into()).0)) } /// Approves a given contract to spend erc20 funds from the given address from the erc20 contract provided. @@ -41,8 +42,9 @@ pub async fn approve_erc20_transfers( "function approve(address spender, uint256 amount) external returns (bool)" ]).unwrap()); let erc20_contract = abi.into_contract(erc20, eth_client.clone()); + let contract_call = erc20_contract.method::<_, bool>("approve", (target_contract, U256::MAX))?; - let pending_tx = erc20_contract.method::<_, bool>("approve", target_contract, U256::MAX).send().await?; + let pending_tx = contract_call.send().await?; let tx_hash = *pending_tx; info!("Approving ERC-20 {} with txid {}", erc20, tx_hash); // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? diff --git a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs index 76e5778cf..ed4ed5a14 100644 --- a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs +++ b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs @@ -3,10 +3,13 @@ use crate::{erc20_utils::{approve_erc20_transfers, check_erc20_approved}, utils::EthClient}; use deep_space::address::Address as CosmosAddress; use ethers::prelude::*; -use ethers::types::Address as EthAddress; +use gravity_abi::gravity::*; use gravity_utils::error::GravityError; use std::time::Duration; +// TODO(bolten): no callers of this function ever sent any SendTxOptions +// for gas or anything else, but will apply this default hard limit as it was +// done originally -- should we change this? const SEND_TO_COSMOS_GAS_LIMIT: u128 = 100_000; #[allow(clippy::too_many_arguments)] @@ -17,35 +20,13 @@ pub async fn send_to_cosmos( cosmos_destination: CosmosAddress, wait_timeout: Option, eth_client: EthClient, -) -> Result { - let sender_address = eth_client.address(); - let mut approve_nonce = None; - +) -> Result { let approved = check_erc20_approved(erc20, gravity_contract, eth_client.clone()).await?; if !approved { let txid = approve_erc20_transfers(erc20, gravity_contract, wait_timeout, eth_client.clone()).await?; trace!("ERC-20 approval for {} finished with txid {}", erc20, txid); } - // if the user sets a gas limit we should honor it, if they don't we - // should add the default - let mut has_gas_limit = false; - let mut options = options; - for option in options.iter() { - if let SendTxOption::GasLimit(_) = option { - has_gas_limit = true; - break; - } - } - if !has_gas_limit { - options.push(SendTxOption::GasLimit(SEND_TO_COSMOS_GAS_LIMIT.into())); - } - // if we have run an approval we should increment our nonce by one so that - // we can be sure our actual tx can go in immediately behind - if let Some(nonce) = approve_nonce { - options.push(SendTxOption::Nonce(nonce + 1u8.into())); - } - // This code deals with some specifics of Ethereum byte encoding, Ethereum is BigEndian // so small values like addresses that don't take up the full length of the byte vector // are pushed up to the top. This duplicates the way Ethereum encodes it's own addresses @@ -54,30 +35,32 @@ pub async fn send_to_cosmos( while cosmos_dest_address_bytes.len() < 32 { cosmos_dest_address_bytes.insert(0, 0u8); } - let encoded_destination_address = Token::Bytes(cosmos_dest_address_bytes); + // TODO(bolten): have to convert back from what was done above for the contract call, + // there's probably a cleaner way to do this + let mut cosmos_dest_address_bytes_slice: [u8; 32] = Default::default(); + cosmos_dest_address_bytes_slice.copy_from_slice(&cosmos_dest_address_bytes[..]); + + let contract_call = Gravity::new(gravity_contract, eth_client.clone()) + .send_to_cosmos(erc20, cosmos_dest_address_bytes_slice, amount) + .gas(SEND_TO_COSMOS_GAS_LIMIT); - let tx_hash = web3 - .send_transaction( - gravity_contract, - encode_call( - "sendToCosmos(address,bytes32,uint256)", - &[ - erc20.into(), - encoded_destination_address, - amount.clone().into(), - ], - )?, - 0u32.into(), - sender_address, - sender_secret, - options, - ) - .await?; + let pending_tx = contract_call.send().await?; + let tx_hash = *pending_tx; + info!("Sending to Cosmos with txid {}", tx_hash); + // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? + // additionally we are mirroring only waiting for 1 confirmation by leaving that as default + let pending_tx = pending_tx.interval(Duration::from_secs(1)); + let potential_error = GravityError::GravityContractError(format!("Did not receive transaction receipt when sending to Cosmos: {}", tx_hash)); if let Some(timeout) = wait_timeout { - web3.wait_for_transaction(tx_hash.clone(), timeout, None) - .await?; + match tokio::time::timeout(timeout, pending_tx).await?? { + Some(receipt) => Ok(receipt.transaction_hash), + None => Err(potential_error) + } + } else { + match pending_tx.await? { + Some(receipt) => Ok(receipt.transaction_hash), + None => Err(potential_error) + } } - - Ok(tx_hash) } diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index d9ab615c6..cc5aef379 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -6,6 +6,7 @@ use deep_space::error::AddressError as CosmosAddressError; use deep_space::error::CosmosGrpcError; use ethers::abi::Error as EthersAbiError; use ethers::abi::ethereum_types::FromDecStrErr as EthersParseUintError; +use ethers::contract::AbiError as EthersContractAbiError; use ethers::prelude::*; use ethers::prelude::ContractError; use ethers::prelude::gas_oracle::GasOracleError as EthersGasOracleError; @@ -27,6 +28,7 @@ pub enum GravityError { EthereumBadDataError(String), EthereumRestError(SignerMiddlewareError, LocalWallet>), EthersAbiError(EthersAbiError), + EthersContractAbiError(EthersContractAbiError), EthersContractError(ContractError, LocalWallet>>), EthersGasOracleError(EthersGasOracleError), EthersParseAddressError(EthersParseAddressError), @@ -59,6 +61,7 @@ impl fmt::Display for GravityError { GravityError::EthereumBadDataError(val) => write!(f, "Received unexpected data from Ethereum: {}", val), GravityError::EthereumRestError(val) => write!(f, "Ethereum REST error: {}", val), GravityError::EthersAbiError(val) => write!(f, "Ethers ABI error: {}", val), + GravityError::EthersContractAbiError(val) => write!(f, "Ethers contract ABI error: {}", val), GravityError::EthersContractError(val) => write!(f, "Ethers contract error: {}", val), GravityError::EthersGasOracleError(val) => write!(f, "Ethers gas oracle error: {}", val), GravityError::EthersParseAddressError(val) => write!(f, "Ethers H160 address parse error: {}", val), @@ -120,6 +123,12 @@ impl From for GravityError { } } +impl From for GravityError { + fn from(error: EthersContractAbiError) -> Self { + GravityError::EthersContractAbiError(error) + } +} + impl From, LocalWallet>>> for GravityError { fn from(error: ContractError, LocalWallet>>) -> Self { GravityError::EthersContractError(error) From db58e43d732e028582f72d2bce88f89e51af8b4e Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 18 Nov 2021 01:44:22 -0800 Subject: [PATCH 068/115] WIP: various fixes --- orchestrator/cosmos_gravity/src/build.rs | 8 +++----- orchestrator/ethereum_gravity/src/logic_call.rs | 6 +++--- orchestrator/ethereum_gravity/src/submit_batch.rs | 2 +- orchestrator/ethereum_gravity/src/valset_update.rs | 4 ++-- orchestrator/orchestrator/src/main_loop.rs | 6 +++--- orchestrator/relayer/src/batch_relaying.rs | 6 +++--- 6 files changed, 15 insertions(+), 17 deletions(-) diff --git a/orchestrator/cosmos_gravity/src/build.rs b/orchestrator/cosmos_gravity/src/build.rs index c47709a1e..d5bc680f0 100644 --- a/orchestrator/cosmos_gravity/src/build.rs +++ b/orchestrator/cosmos_gravity/src/build.rs @@ -2,8 +2,6 @@ use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::Contact; use deep_space::Msg; use ethereum_gravity::utils::EthClient; -use ethers::core::k256::ecdsa::signature::DigestSigner; -use ethers::prelude::Middleware; use ethers::prelude::Signer; use ethers::utils::keccak256; use gravity_proto::gravity as proto; @@ -14,7 +12,7 @@ use gravity_utils::message_signatures::{ }; use gravity_utils::types::*; -pub fn signer_set_tx_confirmation_messages( +pub async fn signer_set_tx_confirmation_messages( contact: &Contact, eth_client: EthClient, valsets: Vec, @@ -45,7 +43,7 @@ pub fn signer_set_tx_confirmation_messages( msgs } -pub fn batch_tx_confirmation_messages( +pub async fn batch_tx_confirmation_messages( contact: &Contact, eth_client: EthClient, batches: Vec, @@ -77,7 +75,7 @@ pub fn batch_tx_confirmation_messages( msgs } -pub fn contract_call_tx_confirmation_messages( +pub async fn contract_call_tx_confirmation_messages( contact: &Contact, eth_client: EthClient, logic_calls: Vec, diff --git a/orchestrator/ethereum_gravity/src/logic_call.rs b/orchestrator/ethereum_gravity/src/logic_call.rs index 12fd12162..195b6d891 100644 --- a/orchestrator/ethereum_gravity/src/logic_call.rs +++ b/orchestrator/ethereum_gravity/src/logic_call.rs @@ -70,7 +70,7 @@ pub async fn send_eth_logic_call( let pending_tx = pending_tx.interval(Duration::from_secs(1)); match tokio::time::timeout(timeout, pending_tx).await?? { - Some(receipt) => (), + Some(_) => (), None => error!("Did not receive transaction receipt when submitting batch: {}", tx_hash), } @@ -138,7 +138,7 @@ pub fn build_send_logic_call_contract_call( .map(|fee| fee.amount).collect(); let fee_token_contracts = call.fees.iter() .map(|fee| fee.token_contract_address).collect(); - let invalidation_id = convert_invalidation_id_to_fixed_array(call.invalidation_id)?; + let invalidation_id = convert_invalidation_id_to_fixed_array(call.invalidation_id.clone())?; let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) .submit_logic_call(current_addresses, current_powers, current_valset_nonce.into(), @@ -149,7 +149,7 @@ pub fn build_send_logic_call_contract_call( fee_amounts, fee_token_contracts, logic_contract_address: call.logic_contract_address, - payload: call.payload, + payload: call.payload.clone(), time_out: call.timeout.into(), invalidation_id, invalidation_nonce: call.invalidation_nonce.into(), }) diff --git a/orchestrator/ethereum_gravity/src/submit_batch.rs b/orchestrator/ethereum_gravity/src/submit_batch.rs index 388aa6aa0..eb80dcc31 100644 --- a/orchestrator/ethereum_gravity/src/submit_batch.rs +++ b/orchestrator/ethereum_gravity/src/submit_batch.rs @@ -66,7 +66,7 @@ pub async fn send_eth_transaction_batch( let pending_tx = pending_tx.interval(Duration::from_secs(1)); match tokio::time::timeout(timeout, pending_tx).await?? { - Some(receipt) => (), + Some(_) => (), None => error!("Did not receive transaction receipt when submitting batch: {}", tx_hash), } diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index 78133eb76..59058f695 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -49,7 +49,7 @@ pub async fn send_eth_valset_update( let pending_tx = pending_tx.interval(Duration::from_secs(1)); match tokio::time::timeout(timeout, pending_tx).await?? { - Some(receipt) => (), + Some(_) => (), None => error!("Did not receive transaction receipt when sending valset update: {}", tx_hash), } @@ -109,7 +109,7 @@ pub fn build_valset_update_contract_call( let sig_data = old_valset.order_sigs(&hash, confirms)?; let sig_arrays = to_arrays(sig_data); - let contract = Gravity::new(gravity_contract_address, eth_client); + let contract = Gravity::new(gravity_contract_address, eth_client.clone()); Ok(contract.update_valset( new_addresses, new_powers, new_valset.nonce.into(), old_addresses, old_powers, old_valset.nonce.into(), diff --git a/orchestrator/orchestrator/src/main_loop.rs b/orchestrator/orchestrator/src/main_loop.rs index f996fa799..90f05a667 100644 --- a/orchestrator/orchestrator/src/main_loop.rs +++ b/orchestrator/orchestrator/src/main_loop.rs @@ -295,7 +295,7 @@ pub async fn eth_signer_main_loop( valsets, cosmos_key, gravity_id.clone(), - ); + ).await.unwrap(); msg_sender .send(messages) .await @@ -328,7 +328,7 @@ pub async fn eth_signer_main_loop( transaction_batches, cosmos_key, gravity_id.clone(), - ); + ).await.unwrap(); msg_sender .send(messages) .await @@ -360,7 +360,7 @@ pub async fn eth_signer_main_loop( logic_calls, cosmos_key, gravity_id.clone(), - ); + ).await.unwrap(); msg_sender .send(messages) .await diff --git a/orchestrator/relayer/src/batch_relaying.rs b/orchestrator/relayer/src/batch_relaying.rs index e1cdb1ee8..48b701d54 100644 --- a/orchestrator/relayer/src/batch_relaying.rs +++ b/orchestrator/relayer/src/batch_relaying.rs @@ -130,7 +130,7 @@ async fn submit_batches( gravity_contract_address: EthAddress, gravity_id: String, timeout: Duration, - gas_multiplier: f32, + eth_gas_price_multiplier: f32, possible_batches: HashMap>, ) { let our_ethereum_address = eth_client.address(); @@ -198,7 +198,7 @@ async fn submit_batches( error!("Total gas cost greater than f32 max, skipping batch submission: {}", oldest_signed_batch.nonce); continue; } - let gas_price_as_f32 = downcast_to_f32(cost.gas_price); + let gas_price_as_f32 = downcast_to_f32(cost.gas_price).unwrap(); // if the total cost isn't greater, this isn't info!( "We have detected latest batch {} but latest on Ethereum is {} This batch is estimated to cost {} Gas / {:.4} ETH to submit", @@ -208,7 +208,7 @@ async fn submit_batches( downcast_to_f32(cost.get_total()).unwrap() / one_eth_f32() ); - cost.gas_price = (gas_price_as_f32 * eth_gas_price_multiplier).into(); + cost.gas_price = (gas_price_as_f32 * eth_gas_price_multiplier).round(); let res = send_eth_transaction_batch( current_valset.clone(), From bf87d24b8e3738833741d4fdd159cb9e2bb9629e Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 18 Nov 2021 09:27:58 -0800 Subject: [PATCH 069/115] WIP: even more fixes --- orchestrator/relayer/src/batch_relaying.rs | 10 ++++----- .../relayer/src/find_latest_valset.rs | 21 ++++++++++--------- .../relayer/src/logic_call_relaying.rs | 20 ++++++++---------- orchestrator/relayer/src/main_loop.rs | 4 ++-- orchestrator/relayer/src/valset_relaying.rs | 14 +++++++++---- 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/orchestrator/relayer/src/batch_relaying.rs b/orchestrator/relayer/src/batch_relaying.rs index 48b701d54..d1dbd1647 100644 --- a/orchestrator/relayer/src/batch_relaying.rs +++ b/orchestrator/relayer/src/batch_relaying.rs @@ -8,7 +8,6 @@ use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::ethereum::downcast_to_f32; use gravity_utils::message_signatures::encode_tx_batch_confirm_hashed; use gravity_utils::types::{BatchConfirmResponse, TransactionBatch, Valset}; -use web30::types::SendTxOption; use std::collections::HashMap; use std::time::Duration; use tonic::transport::Channel; @@ -151,7 +150,7 @@ async fn submit_batches( gravity_contract_address, erc20_contract, our_ethereum_address, - eth_client, + eth_client.clone(), ) .await; if latest_ethereum_batch.is_err() { @@ -198,6 +197,7 @@ async fn submit_batches( error!("Total gas cost greater than f32 max, skipping batch submission: {}", oldest_signed_batch.nonce); continue; } + let total_cost = total_cost.unwrap(); let gas_price_as_f32 = downcast_to_f32(cost.gas_price).unwrap(); // if the total cost isn't greater, this isn't info!( @@ -205,10 +205,10 @@ async fn submit_batches( latest_cosmos_batch_nonce, latest_ethereum_batch, cost.gas_price.clone(), - downcast_to_f32(cost.get_total()).unwrap() / one_eth_f32() + total_cost / one_eth_f32() ); - cost.gas_price = (gas_price_as_f32 * eth_gas_price_multiplier).round(); + cost.gas_price = ((gas_price_as_f32 * eth_gas_price_multiplier) as u128).into(); let res = send_eth_transaction_batch( current_valset.clone(), @@ -218,7 +218,7 @@ async fn submit_batches( gravity_contract_address, gravity_id.clone(), cost, - eth_client, + eth_client.clone(), ) .await; diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index f5274262d..14f896fdf 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -1,8 +1,8 @@ -use crate::main_loop::EthClient; -use clarity::{Address, Uint256}; +use ethereum_gravity::utils::EthClient; use ethers::prelude::*; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use gravity_utils::types::{VALSET_UPDATED_EVENT_STR, ValsetUpdatedEvent}; +use gravity_utils::types::{FromLog, VALSET_UPDATED_EVENT_STR, ValsetUpdatedEvent}; use gravity_utils::{error::GravityError, ethereum::downcast_to_u64, types::Valset}; use std::panic; use tonic::transport::Channel; @@ -14,21 +14,22 @@ use tonic::transport::Channel; /// this will take longer. pub async fn find_latest_valset( grpc_client: &mut GravityQueryClient, - gravity_contract_address: Address, + gravity_contract_address: EthAddress, eth_client: EthClient, ) -> Result { + // calculate some constant U64 values only once const BLOCKS_TO_SEARCH: u64 = 5_000u64; let mut filter = Filter::new() - .address(gravity_contract_address) + .address(ValueOrArray::Value(gravity_contract_address)) .event(&VALSET_UPDATED_EVENT_STR); let mut end_filter_block = eth_client.get_block_number().await?; - while end_filter_block > 0u64 { + while end_filter_block > 0u64.into() { trace!("About to submit a Valset or Batch, looking back into the history to find the last Valset Update, on block {}", end_filter_block); - let start_filter_block = end_filter_block.saturating_sub(BLOCKS_TO_SEARCH); - filter.select(start_filter_block..end_filter_block); + let start_filter_block = end_filter_block.saturating_sub(BLOCKS_TO_SEARCH.into()); + filter = filter.select(start_filter_block..end_filter_block); let mut filtered_logged_events = eth_client.get_logs(&filter).await?; filtered_logged_events.reverse(); // we'll process these in reverse order to start from the most recent and work backwards @@ -49,7 +50,7 @@ pub async fn find_latest_valset( let latest_eth_valset = Valset { nonce: downcast_nonce.unwrap(), - members: event.members, + members: valset_updated_event.members, }; let cosmos_chain_valset = cosmos_gravity::query::get_valset(grpc_client, latest_eth_valset.nonce) @@ -62,7 +63,7 @@ pub async fn find_latest_valset( } } - end_filter_block = start_filter_block.saturating_sub(1); // filter ranges are inclusive, avoid searching same block + end_filter_block = start_filter_block.saturating_sub(1u64.into()); // filter ranges are inclusive, avoid searching same block } panic!("Could not find the last validator set for contract {}, probably not a valid Gravity contract!", gravity_contract_address) diff --git a/orchestrator/relayer/src/logic_call_relaying.rs b/orchestrator/relayer/src/logic_call_relaying.rs index 6f0fc237b..a59816467 100644 --- a/orchestrator/relayer/src/logic_call_relaying.rs +++ b/orchestrator/relayer/src/logic_call_relaying.rs @@ -1,19 +1,16 @@ use cosmos_gravity::query::{get_latest_logic_calls, get_logic_call_signatures}; -use ethereum_gravity::one_eth; +use ethereum_gravity::one_eth_f32; use ethereum_gravity::{ logic_call::send_eth_logic_call, utils::{EthClient, get_logic_call_nonce}, }; -use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use gravity_utils::ethereum::downcast_to_f32; +use gravity_utils::ethereum::{bytes_to_hex_str, downcast_to_f32}; use gravity_utils::types::{LogicCallConfirmResponse, Valset}; use gravity_utils::{message_signatures::encode_logic_call_confirm_hashed, types::LogicCall}; -use web30::types::SendTxOption; use std::time::Duration; use tonic::transport::Channel; -use web30::client::Web3; pub async fn relay_logic_calls( // the validator set currently in the contract on Ethereum @@ -23,7 +20,7 @@ pub async fn relay_logic_calls( gravity_contract_address: EthAddress, gravity_id: String, timeout: Duration, - gas_multiplier: f32, + eth_gas_price_multiplier: f32, ) { // TODO(bolten): replace a lot of manual caller address passing let our_ethereum_address = eth_client.address(); @@ -108,20 +105,21 @@ pub async fn relay_logic_calls( let mut cost = cost.unwrap(); let total_cost = downcast_to_f32(cost.get_total()); if total_cost.is_none() { - error!("Total gas cost greater than f32 max, skipping batch submission: {}", oldest_signed_batch.nonce); - continue; + error!("Total gas cost greater than f32 max, skipping logic call submission: {}", oldest_signed_call.invalidation_nonce); + return; } - let gas_price_as_f32 = downcast_to_f32(cost.gas_price); + let total_cost = total_cost.unwrap(); + let gas_price_as_f32 = downcast_to_f32(cost.gas_price).unwrap(); // if the total cost isn't greater, this isn't info!( "We have detected latest LogicCall {} but latest on Ethereum is {} This LogicCall is estimated to cost {} Gas / {:.4} ETH to submit", latest_cosmos_call_nonce, latest_ethereum_call, cost.gas_price.clone(), - downcast_to_f32(cost.get_total()).unwrap() / one_eth_f32(), + total_cost / one_eth_f32(), ); - cost.gas_price = (gas_price_as_f32 * eth_gas_price_multiplier).into(); + cost.gas_price = ((gas_price_as_f32 * eth_gas_price_multiplier) as u128).into(); let res = send_eth_logic_call( current_valset, diff --git a/orchestrator/relayer/src/main_loop.rs b/orchestrator/relayer/src/main_loop.rs index b104c6f35..9fa710d4d 100644 --- a/orchestrator/relayer/src/main_loop.rs +++ b/orchestrator/relayer/src/main_loop.rs @@ -3,9 +3,9 @@ use crate::{ logic_call_relaying::relay_logic_calls, valset_relaying::relay_valsets, }; use ethereum_gravity::utils::{EthClient, get_gravity_id}; -use ethers::{prelude::*, types::Address as EthAddress}; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use std::{sync::Arc, time::{Duration, Instant}}; +use std::time::{Duration, Instant}; use tokio::time::sleep as delay_for; use tonic::transport::Channel; diff --git a/orchestrator/relayer/src/valset_relaying.rs b/orchestrator/relayer/src/valset_relaying.rs index c467b18ab..041be0d0b 100644 --- a/orchestrator/relayer/src/valset_relaying.rs +++ b/orchestrator/relayer/src/valset_relaying.rs @@ -5,10 +5,10 @@ use std::time::Duration; use cosmos_gravity::query::get_latest_valset; use cosmos_gravity::query::{get_all_valset_confirms, get_valset}; -use ethereum_gravity::{one_eth, valset_update::send_eth_valset_update}; +use ethereum_gravity::{one_eth_f32, utils::EthClient, valset_update::send_eth_valset_update}; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use gravity_utils::{ethereum::downcast_to_u128, ethereum::bytes_to_hex_str, +use gravity_utils::{ethereum::downcast_to_f32, ethereum::bytes_to_hex_str, message_signatures::encode_valset_confirm_hashed, types::Valset}; use tonic::transport::Channel; @@ -134,6 +134,7 @@ pub async fn relay_valsets( eth_client.clone(), ) .await; + if cost.is_err() { error!( "Valset cost estimate for Nonce {} failed with {:?}", @@ -142,13 +143,18 @@ pub async fn relay_valsets( return; } let cost = cost.unwrap(); + let total_cost = downcast_to_f32(cost.get_total()); + if total_cost.is_none() { + error!("Total gas cost greater than f32 max, skipping valset submission: {}", latest_cosmos_valset.nonce); + return; + } + let total_cost = total_cost.unwrap(); info!( "We have detected latest valset {} but latest on Ethereum is {} This valset is estimated to cost {} Gas / {:.4} ETH to submit", latest_cosmos_valset.nonce, current_eth_valset.nonce, cost.gas_price.clone(), - downcast_to_u128(cost.get_total()).unwrap() as f32 - / downcast_to_u128(one_eth()).unwrap() as f32 + total_cost / one_eth_f32() ); let relay_response = send_eth_valset_update( From 7d2dd73f7e90b42820b626ae59262bd217e850d6 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 18 Nov 2021 09:35:09 -0800 Subject: [PATCH 070/115] WIP: further fixes Annoyingly, the Signer trait requires that the sign operation be async, but using a LocalWallet as we are means that it can't throw any errors, so returning a Result is kinda useless. However, because we must use await, the message builder functions must also be async, so we have to call async functions even though they don't return a Result. --- orchestrator/ethereum_gravity/src/utils.rs | 2 +- orchestrator/orchestrator/src/main_loop.rs | 12 +++++------- orchestrator/orchestrator/src/metrics.rs | 4 ++-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 7264e96dc..ca2412d25 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -156,7 +156,7 @@ pub async fn get_gravity_id( match id_as_string { Ok(id) => Ok(id), Err(err) => Err(GravityError::GravityContractError(format!( - "Received invalid utf8 when getting gravity id: {:?}", &gravity_id + "Received invalid utf8 when getting gravity id {:?}: {}", &gravity_id, err ))) } } diff --git a/orchestrator/orchestrator/src/main_loop.rs b/orchestrator/orchestrator/src/main_loop.rs index 90f05a667..83a243cdc 100644 --- a/orchestrator/orchestrator/src/main_loop.rs +++ b/orchestrator/orchestrator/src/main_loop.rs @@ -26,12 +26,10 @@ use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::ethereum::bytes_to_hex_str; use relayer::main_loop::relayer_main_loop; use std::convert::TryInto; -use std::sync::Arc; use std::{ net, time::{Duration, Instant}, }; -use tokio::join; use tokio::time::sleep as delay_for; use tonic::transport::Channel; @@ -138,7 +136,7 @@ pub async fn eth_oracle_main_loop( match (latest_eth_block, latest_cosmos_block) { (Ok(latest_eth_block), Ok(ChainStatus::Moving { block_height })) => { metrics::set_cosmos_block_height(block_height.clone()); - metrics::set_ethereum_block_height(latest_eth_block.clone()); + metrics::set_ethereum_block_height(latest_eth_block.as_u64()); trace!( "Latest Eth block {} Latest Cosmos block {}", latest_eth_block, @@ -240,7 +238,7 @@ pub async fn eth_signer_main_loop( match (latest_eth_block, latest_cosmos_block) { (Ok(latest_eth_block), Ok(ChainStatus::Moving { block_height })) => { metrics::set_cosmos_block_height(block_height.clone()); - metrics::set_ethereum_block_height(latest_eth_block.clone()); + metrics::set_ethereum_block_height(latest_eth_block.as_u64()); trace!( "Latest Eth block {} Latest Cosmos block {}", latest_eth_block, @@ -295,7 +293,7 @@ pub async fn eth_signer_main_loop( valsets, cosmos_key, gravity_id.clone(), - ).await.unwrap(); + ).await; msg_sender .send(messages) .await @@ -328,7 +326,7 @@ pub async fn eth_signer_main_loop( transaction_batches, cosmos_key, gravity_id.clone(), - ).await.unwrap(); + ).await; msg_sender .send(messages) .await @@ -360,7 +358,7 @@ pub async fn eth_signer_main_loop( logic_calls, cosmos_key, gravity_id.clone(), - ).await.unwrap(); + ).await; msg_sender .send(messages) .await diff --git a/orchestrator/orchestrator/src/metrics.rs b/orchestrator/orchestrator/src/metrics.rs index 9396b2601..98573544e 100644 --- a/orchestrator/orchestrator/src/metrics.rs +++ b/orchestrator/orchestrator/src/metrics.rs @@ -178,8 +178,8 @@ pub fn set_cosmos_last_event_nonce(v: u64) { set_u64(&COSMOS_LAST_EVENT_NONCE, v); } -pub fn set_ethereum_block_height(v: U256) { - set_U256(ÐEREUM_BLOCK_HEIGHT, v); +pub fn set_ethereum_block_height(v: u64) { + set_u64(ÐEREUM_BLOCK_HEIGHT, v); } pub fn set_ethereum_check_for_events_end_block(v: U256) { From 728cb4febe0351edcd2165765cd8a844df5b6b0e Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 18 Nov 2021 16:35:59 -0800 Subject: [PATCH 071/115] Convert oracle_resync and ethereum_event_watcher --- .../gorc/src/commands/orchestrator/start.rs | 2 +- .../src/types/ethereum_events.rs | 12 +- .../src/ethereum_event_watcher.rs | 360 +++++++++--------- .../orchestrator/src/get_with_retry.rs | 16 +- orchestrator/orchestrator/src/main_loop.rs | 6 +- orchestrator/orchestrator/src/metrics.rs | 8 +- .../orchestrator/src/oracle_resync.rs | 193 +++++----- 7 files changed, 292 insertions(+), 305 deletions(-) diff --git a/orchestrator/gorc/src/commands/orchestrator/start.rs b/orchestrator/gorc/src/commands/orchestrator/start.rs index 4363f7310..bea0a7ff4 100644 --- a/orchestrator/gorc/src/commands/orchestrator/start.rs +++ b/orchestrator/gorc/src/commands/orchestrator/start.rs @@ -97,7 +97,7 @@ impl Runnable for StartCommand { gas_price, &config.metrics.listen_addr, config.ethereum.gas_price_multiplier, - config.ethereum.blocks_to_search as u128, + config.ethereum.blocks_to_search, config.cosmos.gas_adjustment, self.orchestrator_only, config.cosmos.msg_batch_size, diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 6d6e51818..34bdd87fd 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -180,8 +180,8 @@ pub struct TransactionBatchExecutedEvent { pub event_nonce: U256, } -impl TransactionBatchExecutedEvent { - pub fn from_log(input: &Log) -> Result { +impl FromLog for TransactionBatchExecutedEvent { + fn from_log(input: &Log) -> Result { let event: TransactionBatchExecutedEventFilter = log_to_ethers_event(input)?; Ok(TransactionBatchExecutedEvent { @@ -263,8 +263,8 @@ pub struct Erc20DeployedEvent { pub block_height: U256, } -impl Erc20DeployedEvent { - pub fn from_log(input: &Log) -> Result { +impl FromLog for Erc20DeployedEvent { + fn from_log(input: &Log) -> Result { let event: Erc20DeployedEventFilter = log_to_ethers_event(input)?; Ok(Erc20DeployedEvent { @@ -298,8 +298,8 @@ pub struct LogicCallExecutedEvent { pub block_height: U256, } -impl LogicCallExecutedEvent { - pub fn from_log(input: &Log) -> Result { +impl FromLog for LogicCallExecutedEvent { + fn from_log(input: &Log) -> Result { let event: LogicCallEventFilter = log_to_ethers_event(input)?; Ok(LogicCallExecutedEvent { diff --git a/orchestrator/orchestrator/src/ethereum_event_watcher.rs b/orchestrator/orchestrator/src/ethereum_event_watcher.rs index 2b8cfa6d6..e0c5b5f69 100644 --- a/orchestrator/orchestrator/src/ethereum_event_watcher.rs +++ b/orchestrator/orchestrator/src/ethereum_event_watcher.rs @@ -2,7 +2,7 @@ //! or a transaction batch update. It then responds to these events by performing actions on the Cosmos chain if required use crate::get_with_retry::get_block_number_with_retry; -use crate::get_with_retry::get_net_version_with_retry; +use crate::get_with_retry::get_chain_id_with_retry; use crate::metrics; use cosmos_gravity::build; use cosmos_gravity::query::get_last_event_nonce; @@ -12,6 +12,9 @@ use ethereum_gravity::utils::EthClient; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; +use gravity_utils::ethereum::downcast_to_u64; +use gravity_utils::types::EventNonceFilter; +use gravity_utils::types::{FromLogs, FromLogsWithPrefix}; use gravity_utils::{ error::GravityError, ethereum::bytes_to_hex_str, @@ -24,8 +27,6 @@ use gravity_utils::{ }; use std::time; use tonic::transport::Channel; -use web30::client::Web3; -use web30::jsonrpc::error::Web3Error; pub async fn check_for_events( eth_client: EthClient, @@ -33,203 +34,190 @@ pub async fn check_for_events( grpc_client: &mut GravityQueryClient, gravity_contract_address: EthAddress, cosmos_key: CosmosPrivateKey, - starting_block: Uint256, + starting_block: U64, msg_sender: tokio::sync::mpsc::Sender>, -) -> Result { +) -> Result { let prefix = contact.get_prefix(); let our_cosmos_address = cosmos_key.to_address(&prefix).unwrap(); - let latest_block = get_block_number_with_retry(web3).await; - let latest_block = latest_block - get_block_delay(web3).await; - - metrics::set_ethereum_check_for_events_starting_block(starting_block.clone()); - metrics::set_ethereum_check_for_events_end_block(latest_block.clone()); - - let deposits = web3 - .check_for_events( - starting_block.clone(), - Some(latest_block.clone()), - vec![gravity_contract_address], - vec![SEND_TO_COSMOS_EVENT_STR], + let latest_block = get_block_number_with_retry(eth_client.clone()).await; + let latest_block = latest_block - get_block_delay(eth_client.clone()).await?; + + metrics::set_ethereum_check_for_events_starting_block(starting_block.as_u64()); + metrics::set_ethereum_check_for_events_end_block(latest_block.as_u64()); + + let filter_gravity_contract_address = ValueOrArray::Value(gravity_contract_address); + + let mut erc20_deployed_filter = Filter::new().address(filter_gravity_contract_address.clone()) + .event(&ERC20_DEPLOYED_EVENT_STR); + let mut logic_call_filter = Filter::new().address(filter_gravity_contract_address.clone()) + .event(&LOGIC_CALL_EVENT_STR); + let mut send_to_cosmos_filter = Filter::new().address(filter_gravity_contract_address.clone()) + .event(&SEND_TO_COSMOS_EVENT_STR); + let mut transaction_batch_filter = Filter::new().address(filter_gravity_contract_address.clone()) + .event(&TRANSACTION_BATCH_EXECUTED_EVENT_STR); + let mut valset_updated_filter = Filter::new().address(filter_gravity_contract_address.clone()) + .event(&VALSET_UPDATED_EVENT_STR); + + let search_range = starting_block..latest_block; + + // select uses an inclusive version of the range + erc20_deployed_filter = erc20_deployed_filter.select(search_range.clone()); + logic_call_filter = logic_call_filter.select(search_range.clone()); + send_to_cosmos_filter = send_to_cosmos_filter.select(search_range.clone()); + transaction_batch_filter = transaction_batch_filter.select(search_range.clone()); + valset_updated_filter = valset_updated_filter.select(search_range.clone()); + + let erc20_deployed_events = eth_client.get_logs(&erc20_deployed_filter).await?; + let logic_call_events = eth_client.get_logs(&logic_call_filter).await?; + let send_to_cosmos_events = eth_client.get_logs(&send_to_cosmos_filter).await?; + let transaction_batch_events = eth_client.get_logs(&transaction_batch_filter).await?; + let valset_updated_events = eth_client.get_logs(&valset_updated_filter).await?; + + debug!("ERC20 events detected {:?}", erc20_deployed_events); + debug!("Logic call events detected {:?}", logic_call_events); + debug!("Send to Cosmos events detected {:?}", send_to_cosmos_events); + debug!("Batch events detected {:?}", transaction_batch_events); + debug!("Valset events detected {:?}", valset_updated_events); + + let erc20_deployed_events = Erc20DeployedEvent::from_logs(&erc20_deployed_events)?; + let logic_call_events = LogicCallExecutedEvent::from_logs(&logic_call_events)?; + let send_to_cosmos_events = SendToCosmosEvent::from_logs(&send_to_cosmos_events, &prefix)?; + let transaction_batch_events = TransactionBatchExecutedEvent::from_logs(&transaction_batch_events)?; + let valset_updated_events = ValsetUpdatedEvent::from_logs(&valset_updated_events)?; + + debug!("parsed erc20 deploys {:?}", erc20_deployed_events); + debug!("parsed logic call executions {:?}", logic_call_events); + debug!("parsed send to cosmos events {:?}", send_to_cosmos_events); + debug!("parsed batches {:?}", transaction_batch_events); + debug!("parsed valsets {:?}", valset_updated_events); + + // note that starting block overlaps with our last checked block, because we have to deal with + // the possibility that the relayer was killed after relaying only one of multiple events in a single + // block, so we also need this routine so make sure we don't send in the first event in this hypothetical + // multi event block again. In theory we only send all events for every block and that will pass of fail + // atomicly but lets not take that risk. + let last_event_nonce = get_last_event_nonce(grpc_client, our_cosmos_address).await?; + metrics::set_cosmos_last_event_nonce(last_event_nonce); + + let erc20_deployed_events: Vec = + Erc20DeployedEvent::filter_by_event_nonce(last_event_nonce, &erc20_deployed_events); + let logic_call_events: Vec = + LogicCallExecutedEvent::filter_by_event_nonce(last_event_nonce, &logic_call_events); + let send_to_cosmos_events: Vec = + SendToCosmosEvent::filter_by_event_nonce(last_event_nonce, &send_to_cosmos_events); + let transaction_batch_events: Vec = + TransactionBatchExecutedEvent::filter_by_event_nonce(last_event_nonce, &transaction_batch_events); + let valset_updated_events: Vec = + ValsetUpdatedEvent::filter_by_event_nonce(last_event_nonce, &valset_updated_events); + + for erc20_deployed_event in erc20_deployed_events.iter() { + info!( + "Oracle observed ERC20 deploy with denom {} erc20 name {} and symbol {} and event_nonce {}", + erc20_deployed_event.cosmos_denom, + erc20_deployed_event.name, + erc20_deployed_event.symbol, + erc20_deployed_event.event_nonce, ) - .await; - debug!("Deposit events detected {:?}", deposits); + } - let batches = web3 - .check_for_events( - starting_block.clone(), - Some(latest_block.clone()), - vec![gravity_contract_address], - vec![TRANSACTION_BATCH_EXECUTED_EVENT_STR], - ) - .await; - debug!("Batche events detected {:?}", batches); + for logic_call_event in logic_call_events.iter() { + info!( + "Oracle observed logic call execution with invalidation_id {} invalidation_nonce {} and event_nonce {}", + bytes_to_hex_str(&logic_call_event.invalidation_id), + logic_call_event.invalidation_nonce, + logic_call_event.event_nonce + ); + } - let valsets = web3 - .check_for_events( - starting_block.clone(), - Some(latest_block.clone()), - vec![gravity_contract_address], - vec![VALSET_UPDATED_EVENT_STR], - ) - .await; - debug!("Valset events detected {:?}", valsets); + for send_to_cosmos_event in send_to_cosmos_events.iter() { + info!( + "Oracle observed deposit with ethereum sender {}, cosmos_reciever {}, amount {}, and event nonce {}", + send_to_cosmos_event.sender, + send_to_cosmos_event.destination, + send_to_cosmos_event.amount, + send_to_cosmos_event.event_nonce + ); + } - let erc20_deployed = web3 - .check_for_events( - starting_block.clone(), - Some(latest_block.clone()), - vec![gravity_contract_address], - vec![ERC20_DEPLOYED_EVENT_STR], - ) - .await; - debug!("ERC20 events detected {:?}", erc20_deployed); + for transaction_batch_event in transaction_batch_events.iter() { + info!( + "Oracle observed batch with batch_nonce {}, erc20 {}, and event_nonce {}", + transaction_batch_event.batch_nonce, + transaction_batch_event.erc20, + transaction_batch_event.event_nonce + ); + } - let logic_calls = web3 - .check_for_events( - starting_block.clone(), - Some(latest_block.clone()), - vec![gravity_contract_address], - vec![LOGIC_CALL_EVENT_STR], + for valset_updated_event in valset_updated_events.iter() { + info!( + "Oracle observed valset with valset_nonce {}, event_nonce {}, block_height {} and members {:?}", + valset_updated_event.valset_nonce, + valset_updated_event.event_nonce, + valset_updated_event.block_height, + valset_updated_event.members ) - .await; - debug!("Logic call events detected {:?}", logic_calls); + } - if let (Ok(valsets), Ok(batches), Ok(deposits), Ok(deploys), Ok(logic_calls)) = - (valsets, batches, deposits, erc20_deployed, logic_calls) + if !erc20_deployed_events.is_empty() + || !logic_call_events.is_empty() + || !send_to_cosmos_events.is_empty() + || !transaction_batch_events.is_empty() + || !valset_updated_events.is_empty() { - let deposits = SendToCosmosEvent::from_logs(&deposits, &prefix)?; - debug!("parsed deposits {:?}", deposits); - - let batches = TransactionBatchExecutedEvent::from_logs(&batches)?; - debug!("parsed batches {:?}", batches); - - let valsets = ValsetUpdatedEvent::from_logs(&valsets)?; - debug!("parsed valsets {:?}", valsets); - - let erc20_deploys = Erc20DeployedEvent::from_logs(&deploys)?; - debug!("parsed erc20 deploys {:?}", erc20_deploys); - - let logic_calls = LogicCallExecutedEvent::from_logs(&logic_calls)?; - debug!("logic call executions {:?}", logic_calls); - - // note that starting block overlaps with our last checked block, because we have to deal with - // the possibility that the relayer was killed after relaying only one of multiple events in a single - // block, so we also need this routine so make sure we don't send in the first event in this hypothetical - // multi event block again. In theory we only send all events for every block and that will pass of fail - // atomicly but lets not take that risk. - let last_event_nonce = get_last_event_nonce(grpc_client, our_cosmos_address).await?; - metrics::set_cosmos_last_event_nonce(last_event_nonce); - - let deposits = SendToCosmosEvent::filter_by_event_nonce(last_event_nonce, &deposits); - let batches = - TransactionBatchExecutedEvent::filter_by_event_nonce(last_event_nonce, &batches); - let valsets = ValsetUpdatedEvent::filter_by_event_nonce(last_event_nonce, &valsets); - let erc20_deploys = - Erc20DeployedEvent::filter_by_event_nonce(last_event_nonce, &erc20_deploys); - let logic_calls = - LogicCallExecutedEvent::filter_by_event_nonce(last_event_nonce, &logic_calls); - - for deposit in deposits.iter() { - info!( - "Oracle observed deposit with ethereum sender {}, cosmos_reciever {}, amount {}, and event nonce {}", - deposit.sender, deposit.destination, deposit.amount, deposit.event_nonce - ); + let messages = build::ethereum_event_messages( + contact, + cosmos_key, + send_to_cosmos_events.to_owned(), + transaction_batch_events.to_owned(), + erc20_deployed_events.to_owned(), + logic_call_events.to_owned(), + valset_updated_events.to_owned(), + ); + + info!("Sending {} messages to cosmos", messages.len()); + + if let Some(erc20_deployed_event) = erc20_deployed_events.last() { + metrics::set_ethereum_last_erc20_event(erc20_deployed_event.event_nonce); + metrics::set_ethereum_last_erc20_block(erc20_deployed_event.block_height); } - for batch in batches.iter() { - info!( - "Oracle observed batch with batch_nonce {}, erc20 {}, and event_nonce {}", - batch.batch_nonce, batch.erc20, batch.event_nonce - ); + if let Some(send_to_cosmos_event) = send_to_cosmos_events.last() { + metrics::set_ethereum_last_deposit_event(send_to_cosmos_event.event_nonce); + metrics::set_ethereum_last_deposit_block(send_to_cosmos_event.block_height); } - for valset in valsets.iter() { - info!( - "Oracle observed valset with valset_nonce {}, event_nonce {}, block_height {} and members {:?}", - valset.valset_nonce, valset.event_nonce, valset.block_height, valset.members, - ) + if let Some(transaction_batch_event) = transaction_batch_events.last() { + metrics::set_ethereum_last_batch_event(transaction_batch_event.event_nonce); + metrics::set_ethereum_last_batch_nonce(transaction_batch_event.batch_nonce); } - for erc20_deploy in erc20_deploys.iter() { - info!( - "Oracle observed ERC20 deploy with denom {} erc20 name {} and symbol {} and event_nonce {}", - erc20_deploy.cosmos_denom, erc20_deploy.name, erc20_deploy.symbol, erc20_deploy.event_nonce, - ) + if let Some(valset_updated_event) = valset_updated_events.last() { + metrics::set_ethereum_last_valset_event(valset_updated_event.event_nonce); + metrics::set_ethereum_last_valset_nonce(valset_updated_event.valset_nonce); } - for logic_call in logic_calls.iter() { - info!( - "Oracle observed logic call execution with invalidation_id {} invalidation_nonce {} and event_nonce {}", - bytes_to_hex_str(&logic_call.invalidation_id), - logic_call.invalidation_nonce, - logic_call.event_nonce - ); + if let Some(logic_call_event) = logic_call_events.last() { + metrics::set_ethereum_last_logic_call_event(logic_call_event.event_nonce); + metrics::set_ethereum_last_logic_call_nonce(logic_call_event.invalidation_nonce); } - if !deposits.is_empty() - || !batches.is_empty() - || !valsets.is_empty() - || !erc20_deploys.is_empty() - || !logic_calls.is_empty() - { - let messages = build::ethereum_event_messages( - contact, - cosmos_key, - deposits.to_owned(), - batches.to_owned(), - erc20_deploys.to_owned(), - logic_calls.to_owned(), - valsets.to_owned(), - ); - - info!("Sending {} messages to cosmos", messages.len()); - - if let Some(deposit) = deposits.last() { - metrics::set_ethereum_last_deposit_event(deposit.event_nonce.clone()); - metrics::set_ethereum_last_deposit_block(deposit.block_height.clone()); - } - - if let Some(batch) = batches.last() { - metrics::set_ethereum_last_batch_event(batch.event_nonce.clone()); - metrics::set_ethereum_last_batch_nonce(batch.batch_nonce.clone()); - } + msg_sender + .send(messages) + .await + .expect("Could not send messages"); - if let Some(valset) = valsets.last() { - metrics::set_ethereum_last_valset_event(valset.event_nonce.clone()); - metrics::set_ethereum_last_valset_nonce(valset.valset_nonce.clone()); - } + let timeout = time::Duration::from_secs(30); + contact.wait_for_next_block(timeout).await?; - if let Some(erc20_deploy) = erc20_deploys.last() { - metrics::set_ethereum_last_erc20_event(erc20_deploy.event_nonce.clone()); - metrics::set_ethereum_last_erc20_block(erc20_deploy.block_height.clone()); - } - - if let Some(logic_call) = logic_calls.last() { - metrics::set_ethereum_last_logic_call_event(logic_call.event_nonce.clone()); - metrics::set_ethereum_last_logic_call_nonce(logic_call.invalidation_nonce.clone()); - } - - msg_sender - .send(messages) - .await - .expect("Could not send messages"); - - let timeout = time::Duration::from_secs(30); - contact.wait_for_next_block(timeout).await?; - - let new_event_nonce = get_last_event_nonce(grpc_client, our_cosmos_address).await?; - if new_event_nonce == last_event_nonce { - return Err(GravityError::InvalidBridgeStateError( - format!("Claims did not process, trying to update but still on {}, trying again in a moment", last_event_nonce), - )); - } + let new_event_nonce = get_last_event_nonce(grpc_client, our_cosmos_address).await?; + if new_event_nonce == last_event_nonce { + return Err(GravityError::InvalidBridgeStateError( + format!("Claims did not process, trying to update but still on {}, trying again in a moment", last_event_nonce), + )); } - Ok(latest_block) - } else { - Err(GravityError::EthereumRestError(Web3Error::BadResponse( - "Failed to get logs!".to_string(), - ))) } + + Ok(latest_block) } /// The number of blocks behind the 'latest block' on Ethereum our event checking should be. @@ -252,17 +240,27 @@ pub async fn check_for_events( /// Given an uncle every 2.8 minutes, a 6 deep reorg would be 2.8 minutes * (100^4) or one /// 6 deep reorg every 53,272 years. /// -pub async fn get_block_delay(web3: &Web3) -> Uint256 { - let net_version = get_net_version_with_retry(web3).await; +pub async fn get_block_delay(eth_client: EthClient) -> Result { + // TODO(bolten): technically we want the network id from net_version, but chain id + // should be the same for our use cases...when this PR is in a released version of + // ethers we can move back to net_version: + // https://github.com/gakonst/ethers-rs/pull/595 + let chain_id_result = get_chain_id_with_retry(eth_client.clone()).await; + let chain_id = downcast_to_u64(chain_id_result); + if chain_id.is_none() { + return Err(GravityError::EthereumBadDataError( + format!("Chain ID is larger than u64 max: {}", chain_id_result)) + ); + } - match net_version { + match chain_id.unwrap() { // Mainline Ethereum, Ethereum classic, or the Ropsten, Mordor testnets // all POW Chains - 1 | 3 | 7 => 6u8.into(), + 1 | 3 | 7 => Ok(6u8.into()), // Rinkeby, Goerli, Dev, our own Gravity Ethereum testnet, and Kotti respectively // all non-pow chains - 4 | 5 | 2018 | 15 | 6 => 0u8.into(), + 4 | 5 | 2018 | 15 | 6 => Ok(0u8.into()), // assume the safe option (POW) where we don't know - _ => 6u8.into(), + _ => Ok(6u8.into()), } } diff --git a/orchestrator/orchestrator/src/get_with_retry.rs b/orchestrator/orchestrator/src/get_with_retry.rs index 62d2105b9..ba2fcada2 100644 --- a/orchestrator/orchestrator/src/get_with_retry.rs +++ b/orchestrator/orchestrator/src/get_with_retry.rs @@ -1,22 +1,22 @@ //! Basic utility functions to stubbornly get data -use clarity::Uint256; use cosmos_gravity::query::get_last_event_nonce; use deep_space::address::Address as CosmosAddress; +use ethereum_gravity::utils::EthClient; +use ethers::prelude::*; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use std::time::Duration; use tokio::time::sleep as delay_for; use tonic::transport::Channel; -use web30::client::Web3; pub const RETRY_TIME: Duration = Duration::from_secs(5); /// gets the current block number, no matter how long it takes -pub async fn get_block_number_with_retry(web3: &Web3) -> Uint256 { - let mut res = web3.eth_block_number().await; +pub async fn get_block_number_with_retry(eth_client: EthClient) -> U64 { + let mut res = eth_client.get_block_number().await; while res.is_err() { error!("Failed to get latest block! Is your Eth node working?"); delay_for(RETRY_TIME).await; - res = web3.eth_block_number().await; + res = eth_client.get_block_number().await; } res.unwrap() } @@ -39,12 +39,12 @@ pub async fn get_last_event_nonce_with_retry( } /// gets the net version, no matter how long it takes -pub async fn get_net_version_with_retry(web3: &Web3) -> u64 { - let mut res = web3.net_version().await; +pub async fn get_chain_id_with_retry(eth_client: EthClient) -> U256 { + let mut res = eth_client.get_chainid().await; while res.is_err() { error!("Failed to get net version! Is your Eth node working?"); delay_for(RETRY_TIME).await; - res = web3.net_version().await; + res = eth_client.get_chainid().await; } res.unwrap() } diff --git a/orchestrator/orchestrator/src/main_loop.rs b/orchestrator/orchestrator/src/main_loop.rs index 83a243cdc..628eb5116 100644 --- a/orchestrator/orchestrator/src/main_loop.rs +++ b/orchestrator/orchestrator/src/main_loop.rs @@ -53,7 +53,7 @@ pub async fn orchestrator_main_loop( gas_price: (f64, String), metrics_listen: &net::SocketAddr, eth_gas_price_multiplier: f32, - blocks_to_search: u128, + blocks_to_search: u64, gas_adjustment: f64, relayer_opt_out: bool, cosmos_msg_batch_size: u32, @@ -113,11 +113,11 @@ pub async fn eth_oracle_main_loop( eth_client: EthClient, grpc_client: GravityQueryClient, gravity_contract_address: EthAddress, - blocks_to_search: u128, + blocks_to_search: u64, msg_sender: tokio::sync::mpsc::Sender>, ) { let our_cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); - let mut last_checked_block: U256 = get_last_checked_block( + let mut last_checked_block = get_last_checked_block( grpc_client.clone(), our_cosmos_address, gravity_contract_address, diff --git a/orchestrator/orchestrator/src/metrics.rs b/orchestrator/orchestrator/src/metrics.rs index 98573544e..960130e4c 100644 --- a/orchestrator/orchestrator/src/metrics.rs +++ b/orchestrator/orchestrator/src/metrics.rs @@ -182,12 +182,12 @@ pub fn set_ethereum_block_height(v: u64) { set_u64(ÐEREUM_BLOCK_HEIGHT, v); } -pub fn set_ethereum_check_for_events_end_block(v: U256) { - set_U256(ÐEREUM_CHECK_FOR_EVENTS_END_BLOCK, v); +pub fn set_ethereum_check_for_events_end_block(v: u64) { + set_u64(ÐEREUM_CHECK_FOR_EVENTS_END_BLOCK, v); } -pub fn set_ethereum_check_for_events_starting_block(v: U256) { - set_U256(ÐEREUM_CHECK_FOR_EVENTS_STARTING_BLOCK, v); +pub fn set_ethereum_check_for_events_starting_block(v: u64) { + set_u64(ÐEREUM_CHECK_FOR_EVENTS_STARTING_BLOCK, v); } pub fn set_ethereum_last_batch_event(v: U256) { diff --git a/orchestrator/orchestrator/src/oracle_resync.rs b/orchestrator/orchestrator/src/oracle_resync.rs index d740afe4a..a36f17c86 100644 --- a/orchestrator/orchestrator/src/oracle_resync.rs +++ b/orchestrator/orchestrator/src/oracle_resync.rs @@ -3,6 +3,7 @@ use ethereum_gravity::utils::EthClient; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; +use gravity_utils::types::{FromLog, FromLogWithPrefix}; use gravity_utils::types::{ ERC20_DEPLOYED_EVENT_STR, LOGIC_CALL_EVENT_STR, SEND_TO_COSMOS_EVENT_STR, TRANSACTION_BATCH_EXECUTED_EVENT_STR, VALSET_UPDATED_EVENT_STR, @@ -21,15 +22,13 @@ use crate::get_with_retry::RETRY_TIME; pub async fn get_last_checked_block( grpc_client: GravityQueryClient, our_cosmos_address: CosmosAddress, - gravity_contract_address: Address, + gravity_contract_address: EthAddress, eth_client: EthClient, - blocks_to_search: u128, -) -> Uint256 { - // needs 120 second timeout + blocks_to_search: u64, +) -> U64 { + // TODO(bolten): needs 120 second timeout from old web30 with long timeout let mut grpc_client = grpc_client; - - let latest_block = get_block_number_with_retry(web3).await; - let mut last_event_nonce: Uint256 = + let mut last_event_nonce: U256 = get_last_event_nonce_with_retry(&mut grpc_client, our_cosmos_address) .await .into(); @@ -41,143 +40,132 @@ pub async fn get_last_checked_block( last_event_nonce = 1u8.into(); } - let mut current_block: Uint256 = latest_block.clone(); + let filter_gravity_contract_address = ValueOrArray::Value(gravity_contract_address); + + let mut erc20_deployed_filter = Filter::new().address(filter_gravity_contract_address.clone()) + .event(&ERC20_DEPLOYED_EVENT_STR); + let mut logic_call_filter = Filter::new().address(filter_gravity_contract_address.clone()) + .event(&LOGIC_CALL_EVENT_STR); + let mut send_to_cosmos_filter = Filter::new().address(filter_gravity_contract_address.clone()) + .event(&SEND_TO_COSMOS_EVENT_STR); + let mut transaction_batch_filter = Filter::new().address(filter_gravity_contract_address.clone()) + .event(&TRANSACTION_BATCH_EXECUTED_EVENT_STR); + let mut valset_updated_filter = Filter::new().address(filter_gravity_contract_address.clone()) + .event(&VALSET_UPDATED_EVENT_STR); + + let mut end_search_block = get_block_number_with_retry(eth_client.clone()).await; + let blocks_to_search: U64 = blocks_to_search.into(); - while current_block.clone() > 0u8.into() { + while end_search_block > 0u8.into() { info!( "Oracle is resyncing, looking back into the history to find our last event nonce {}, on block {}", - last_event_nonce, current_block + last_event_nonce, end_search_block ); - let end_search = if current_block.clone() < blocks_to_search.into() { - 0u8.into() - } else { - current_block.clone() - blocks_to_search.into() - }; - let batch_events = web3 - .check_for_events( - end_search.clone(), - Some(current_block.clone()), - vec![gravity_contract_address], - vec![TRANSACTION_BATCH_EXECUTED_EVENT_STR], - ) - .await; - let send_to_cosmos_events = web3 - .check_for_events( - end_search.clone(), - Some(current_block.clone()), - vec![gravity_contract_address], - vec![SEND_TO_COSMOS_EVENT_STR], - ) - .await; - let erc20_deployed_events = web3 - .check_for_events( - end_search.clone(), - Some(current_block.clone()), - vec![gravity_contract_address], - vec![ERC20_DEPLOYED_EVENT_STR], - ) - .await; - let logic_call_executed_events = web3 - .check_for_events( - end_search.clone(), - Some(current_block.clone()), - vec![gravity_contract_address], - vec![LOGIC_CALL_EVENT_STR], - ) - .await; - - // valset update events have one special property - // that is useful to us in this handler a valset update event for nonce 0 is emitted - // in the contract constructor meaning once you find that event you can exit the search - // with confidence that you have not missed any events without searching the entire blockchain - // history - let valset_events = web3 - .check_for_events( - end_search.clone(), - Some(current_block.clone()), - vec![gravity_contract_address], - vec![VALSET_UPDATED_EVENT_STR], - ) - .await; - if batch_events.is_err() + + let start_search_block = end_search_block.saturating_sub(blocks_to_search); + let search_range = start_search_block..end_search_block; + + // select uses an inclusive version of the range + erc20_deployed_filter = erc20_deployed_filter.select(search_range.clone()); + logic_call_filter = logic_call_filter.select(search_range.clone()); + send_to_cosmos_filter = send_to_cosmos_filter.select(search_range.clone()); + transaction_batch_filter = transaction_batch_filter.select(search_range.clone()); + valset_updated_filter = valset_updated_filter.select(search_range.clone()); + + let erc20_deployed_events = eth_client.get_logs(&erc20_deployed_filter).await; + let logic_call_events = eth_client.get_logs(&logic_call_filter).await; + let send_to_cosmos_events = eth_client.get_logs(&send_to_cosmos_filter).await; + let transaction_batch_events = eth_client.get_logs(&transaction_batch_filter).await; + let valset_updated_events = eth_client.get_logs(&valset_updated_filter).await; + + // valset update events have one special property that is useful to us in this handler: + // a valset update event for nonce 0 is emitted in the contract constructor meaning once you + // find that event you can exit the search with confidence that you have not missed any events + // without searching the entire blockchain history + + if erc20_deployed_events.is_err() + || logic_call_events.is_err() || send_to_cosmos_events.is_err() - || valset_events.is_err() - || erc20_deployed_events.is_err() - || logic_call_executed_events.is_err() + || transaction_batch_events.is_err() + || valset_updated_events.is_err() { - error!("Failed to get blockchain events while resyncing, is your Eth node working? If you see only one of these it's fine",); + error!("Failed to get blockchain events while resyncing, is your Eth node working? If you see only one of these it's fine"); delay_for(RETRY_TIME).await; continue; } - let batch_events = batch_events.unwrap(); - let send_to_cosmos_events = send_to_cosmos_events.unwrap(); - let mut valset_events = valset_events.unwrap(); + let erc20_deployed_events = erc20_deployed_events.unwrap(); - let logic_call_executed_events = logic_call_executed_events.unwrap(); + let logic_call_events = logic_call_events.unwrap(); + let send_to_cosmos_events = send_to_cosmos_events.unwrap(); + let transaction_batch_events = transaction_batch_events.unwrap(); + let mut valset_updated_events = valset_updated_events.unwrap(); // look for and return the block number of the event last seen on the Cosmos chain // then we will play events from that block (including that block, just in case // there is more than one event there) onwards. We use valset nonce 0 as an indicator // of what block the contract was deployed on. - for event in batch_events { - match TransactionBatchExecutedEvent::from_log(&event) { - Ok(batch) => { + for event in erc20_deployed_events { + match Erc20DeployedEvent::from_log(&event) { + Ok(deploy) => { trace!( - "{} batch event nonce {} last event nonce", - batch.event_nonce, + "{} deploy event nonce {} last event nonce", + deploy.event_nonce, last_event_nonce ); - if batch.event_nonce == last_event_nonce && event.block_number.is_some() { + if deploy.event_nonce == last_event_nonce && event.block_number.is_some() { return event.block_number.unwrap(); } } - Err(e) => error!("Got batch event that we can't parse {}", e), + Err(e) => error!("Got ERC20Deployed event that we can't parse {}", e), } } - for event in send_to_cosmos_events { - let prefix = our_cosmos_address.get_prefix(); - match SendToCosmosEvent::from_log(&event, &prefix) { - Ok(send) => { + + for event in logic_call_events { + match LogicCallExecutedEvent::from_log(&event) { + Ok(call) => { trace!( - "{} send event nonce {} last event nonce", - send.event_nonce, + "{} LogicCall event nonce {} last event nonce", + call.event_nonce, last_event_nonce ); - if send.event_nonce == last_event_nonce && event.block_number.is_some() { + if call.event_nonce == last_event_nonce && event.block_number.is_some() { return event.block_number.unwrap(); } } - Err(e) => error!("Got SendToCosmos event that we can't parse {}", e), + Err(e) => error!("Got ERC20Deployed event that we can't parse {}", e), } } - for event in erc20_deployed_events { - match Erc20DeployedEvent::from_log(&event) { - Ok(deploy) => { + + for event in send_to_cosmos_events { + let prefix = our_cosmos_address.get_prefix(); + match SendToCosmosEvent::from_log(&event, &prefix.as_str()) { + Ok(send) => { trace!( - "{} deploy event nonce {} last event nonce", - deploy.event_nonce, + "{} send event nonce {} last event nonce", + send.event_nonce, last_event_nonce ); - if deploy.event_nonce == last_event_nonce && event.block_number.is_some() { + if send.event_nonce == last_event_nonce && event.block_number.is_some() { return event.block_number.unwrap(); } } - Err(e) => error!("Got ERC20Deployed event that we can't parse {}", e), + Err(e) => error!("Got SendToCosmos event that we can't parse {}", e), } } - for event in logic_call_executed_events { - match LogicCallExecutedEvent::from_log(&event) { - Ok(call) => { + + for event in transaction_batch_events { + match TransactionBatchExecutedEvent::from_log(&event) { + Ok(batch) => { trace!( - "{} LogicCall event nonce {} last event nonce", - call.event_nonce, + "{} batch event nonce {} last event nonce", + batch.event_nonce, last_event_nonce ); - if call.event_nonce == last_event_nonce && event.block_number.is_some() { + if batch.event_nonce == last_event_nonce && event.block_number.is_some() { return event.block_number.unwrap(); } } - Err(e) => error!("Got ERC20Deployed event that we can't parse {}", e), + Err(e) => error!("Got batch event that we can't parse {}", e), } } @@ -186,8 +174,8 @@ pub async fn get_last_checked_block( // we will encounter the first validator sets first and exit early and incorrectly. // note that reversing everything won't actually get you that much of a performance gain // because this only involves events within the searching block range. - valset_events.reverse(); - for event in valset_events { + valset_updated_events.reverse(); + for event in valset_updated_events { match ValsetUpdatedEvent::from_log(&event) { Ok(valset) => { // if we've found this event it is the first possible event from the contract @@ -215,7 +203,8 @@ pub async fn get_last_checked_block( Err(e) => error!("Got valset event that we can't parse {}", e), } } - current_block = end_search; + + end_search_block = start_search_block.saturating_sub(1u8.into()); // filter ranges are inclusive, avoid searching same block } // we should exit above when we find the zero valset, if we have the wrong contract address through we could be at it a while as we go over From c714c96016e96d3501fa8410b1b140b6b48a4402 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 18 Nov 2021 16:41:10 -0800 Subject: [PATCH 072/115] Add some TODOs --- orchestrator/ethereum_gravity/src/erc20_utils.rs | 2 ++ orchestrator/orchestrator/src/oracle_resync.rs | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs index 871285b5a..86ab71575 100644 --- a/orchestrator/ethereum_gravity/src/erc20_utils.rs +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -4,6 +4,8 @@ use ethers::prelude::*; use gravity_utils::error::GravityError; use std::time::Duration; +// TODO(bolten): verify our usage of contract.method:: is passing arguments correctly + /// Checks if any given contract is approved to spend money from any given erc20 contract /// using any given address. What exactly this does can be hard to grok, essentially when /// you want contract A to be able to spend your erc20 contract funds you need to call 'approve' diff --git a/orchestrator/orchestrator/src/oracle_resync.rs b/orchestrator/orchestrator/src/oracle_resync.rs index a36f17c86..84b26d974 100644 --- a/orchestrator/orchestrator/src/oracle_resync.rs +++ b/orchestrator/orchestrator/src/oracle_resync.rs @@ -26,7 +26,8 @@ pub async fn get_last_checked_block( eth_client: EthClient, blocks_to_search: u64, ) -> U64 { - // TODO(bolten): needs 120 second timeout from old web30 with long timeout + // TODO(bolten): original version of this used a 120 second timeout when querying + // the eth chain, should we replicate that in eth_client? let mut grpc_client = grpc_client; let mut last_event_nonce: U256 = get_last_event_nonce_with_retry(&mut grpc_client, our_cosmos_address) From cdc87f2af5e4354a12994f79d1fb455adb99ab6d Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 18 Nov 2021 16:45:59 -0800 Subject: [PATCH 073/115] Remove unnecessary capturing of our eth address --- orchestrator/ethereum_gravity/src/logic_call.rs | 3 --- orchestrator/ethereum_gravity/src/submit_batch.rs | 3 --- orchestrator/ethereum_gravity/src/utils.rs | 5 ----- orchestrator/ethereum_gravity/src/valset_update.rs | 6 +++--- orchestrator/orchestrator/src/main_loop.rs | 3 +-- orchestrator/relayer/src/batch_relaying.rs | 2 -- orchestrator/relayer/src/logic_call_relaying.rs | 4 ---- orchestrator/relayer/src/main_loop.rs | 3 +-- 8 files changed, 5 insertions(+), 24 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/logic_call.rs b/orchestrator/ethereum_gravity/src/logic_call.rs index 195b6d891..cb9b804c7 100644 --- a/orchestrator/ethereum_gravity/src/logic_call.rs +++ b/orchestrator/ethereum_gravity/src/logic_call.rs @@ -25,7 +25,6 @@ pub async fn send_eth_logic_call( eth_client: EthClient, ) -> Result<(), GravityError> { let new_call_nonce = call.invalidation_nonce; - let eth_address = eth_client.address(); info!( "Ordering signatures and submitting LogicCall {}:{} to Ethereum", bytes_to_hex_str(&call.invalidation_id), @@ -36,7 +35,6 @@ pub async fn send_eth_logic_call( let before_nonce = get_logic_call_nonce( gravity_contract_address, call.invalidation_id.clone(), - eth_address, eth_client.clone(), ) .await?; @@ -77,7 +75,6 @@ pub async fn send_eth_logic_call( let last_nonce = get_logic_call_nonce( gravity_contract_address, call.invalidation_id, - eth_address, eth_client.clone(), ) .await?; diff --git a/orchestrator/ethereum_gravity/src/submit_batch.rs b/orchestrator/ethereum_gravity/src/submit_batch.rs index eb80dcc31..43ed51a7f 100644 --- a/orchestrator/ethereum_gravity/src/submit_batch.rs +++ b/orchestrator/ethereum_gravity/src/submit_batch.rs @@ -22,7 +22,6 @@ pub async fn send_eth_transaction_batch( eth_client: EthClient, ) -> Result<(), GravityError> { let new_batch_nonce = batch.nonce; - let eth_address = eth_client.address(); info!( "Ordering signatures and submitting TransactionBatch {}:{} to Ethereum", batch.token_contract, new_batch_nonce @@ -32,7 +31,6 @@ pub async fn send_eth_transaction_batch( let before_nonce = get_tx_batch_nonce( gravity_contract_address, batch.token_contract, - eth_address, eth_client.clone(), ) .await?; @@ -73,7 +71,6 @@ pub async fn send_eth_transaction_batch( let last_nonce = get_tx_batch_nonce( gravity_contract_address, batch.token_contract, - eth_address, eth_client.clone(), ) .await?; diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index ca2412d25..b43dcb2df 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -40,7 +40,6 @@ pub fn get_checkpoint_hash(valset: &Valset, gravity_id: &str) -> Result, /// Gets the latest validator set nonce pub async fn get_valset_nonce( gravity_contract_address: EthAddress, - caller_address: EthAddress, eth_client: EthClient, ) -> Result { let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) @@ -65,7 +64,6 @@ pub async fn get_valset_nonce( pub async fn get_tx_batch_nonce( gravity_contract_address: EthAddress, erc20_contract_address: EthAddress, - caller_address: EthAddress, eth_client: EthClient, ) -> Result { let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) @@ -90,7 +88,6 @@ pub async fn get_tx_batch_nonce( pub async fn get_logic_call_nonce( gravity_contract_address: EthAddress, invalidation_id: Vec, - caller_address: EthAddress, eth_client: EthClient, ) -> Result { let invalidation_id = convert_invalidation_id_to_fixed_array(invalidation_id)?; @@ -116,7 +113,6 @@ pub async fn get_logic_call_nonce( /// Gets the latest transaction batch nonce pub async fn get_event_nonce( gravity_contract_address: EthAddress, - caller_address: EthAddress, eth_client: EthClient, ) -> Result { let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) @@ -140,7 +136,6 @@ pub async fn get_event_nonce( /// Gets the gravityID pub async fn get_gravity_id( gravity_contract_address: EthAddress, - caller_address: EthAddress, eth_client: EthClient, ) -> Result { let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index 59058f695..8a2eb7fcd 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -22,12 +22,12 @@ pub async fn send_eth_valset_update( let old_nonce = old_valset.nonce; let new_nonce = new_valset.nonce; assert!(new_nonce > old_nonce); - let eth_address = eth_client.address(); + info!( "Ordering signatures and submitting validator set {} -> {} update to Ethereum", old_nonce, new_nonce ); - let before_nonce = get_valset_nonce(gravity_contract_address, eth_address, eth_client.clone()).await?; + let before_nonce = get_valset_nonce(gravity_contract_address, eth_client.clone()).await?; if before_nonce != old_nonce { info!( "Someone else updated the valset to {}, exiting early", @@ -53,7 +53,7 @@ pub async fn send_eth_valset_update( None => error!("Did not receive transaction receipt when sending valset update: {}", tx_hash), } - let last_nonce = get_valset_nonce(gravity_contract_address, eth_address, eth_client.clone()).await?; + let last_nonce = get_valset_nonce(gravity_contract_address, eth_client.clone()).await?; if last_nonce != new_nonce { error!( "Current nonce is {} expected to update to nonce {}", diff --git a/orchestrator/orchestrator/src/main_loop.rs b/orchestrator/orchestrator/src/main_loop.rs index 628eb5116..89112318b 100644 --- a/orchestrator/orchestrator/src/main_loop.rs +++ b/orchestrator/orchestrator/src/main_loop.rs @@ -220,10 +220,9 @@ pub async fn eth_signer_main_loop( msg_sender: tokio::sync::mpsc::Sender>, ) { let our_cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); - let our_ethereum_address = eth_client.address(); let mut grpc_client = grpc_client; - let gravity_id = get_gravity_id(contract_address, our_ethereum_address, eth_client.clone()).await; + let gravity_id = get_gravity_id(contract_address, eth_client.clone()).await; if gravity_id.is_err() { error!("Failed to get GravityID, check your Eth node"); return; diff --git a/orchestrator/relayer/src/batch_relaying.rs b/orchestrator/relayer/src/batch_relaying.rs index d1dbd1647..f2d5ddee7 100644 --- a/orchestrator/relayer/src/batch_relaying.rs +++ b/orchestrator/relayer/src/batch_relaying.rs @@ -132,7 +132,6 @@ async fn submit_batches( eth_gas_price_multiplier: f32, possible_batches: HashMap>, ) { - let our_ethereum_address = eth_client.address(); let ethereum_block_height = if let Ok(bn) = eth_client.get_block_number().await { bn } else { @@ -149,7 +148,6 @@ async fn submit_batches( let latest_ethereum_batch = get_tx_batch_nonce( gravity_contract_address, erc20_contract, - our_ethereum_address, eth_client.clone(), ) .await; diff --git a/orchestrator/relayer/src/logic_call_relaying.rs b/orchestrator/relayer/src/logic_call_relaying.rs index a59816467..a5afecd20 100644 --- a/orchestrator/relayer/src/logic_call_relaying.rs +++ b/orchestrator/relayer/src/logic_call_relaying.rs @@ -22,9 +22,6 @@ pub async fn relay_logic_calls( timeout: Duration, eth_gas_price_multiplier: f32, ) { - // TODO(bolten): replace a lot of manual caller address passing - let our_ethereum_address = eth_client.address(); - let latest_calls = get_latest_logic_calls(grpc_client).await; trace!("Latest Logic calls {:?}", latest_calls); if latest_calls.is_err() { @@ -73,7 +70,6 @@ pub async fn relay_logic_calls( let latest_ethereum_call = get_logic_call_nonce( gravity_contract_address, oldest_signed_call.invalidation_id.clone(), - our_ethereum_address, eth_client.clone(), ) .await; diff --git a/orchestrator/relayer/src/main_loop.rs b/orchestrator/relayer/src/main_loop.rs index 9fa710d4d..1abf7af80 100644 --- a/orchestrator/relayer/src/main_loop.rs +++ b/orchestrator/relayer/src/main_loop.rs @@ -23,7 +23,6 @@ pub async fn relayer_main_loop( loop { let loop_start = Instant::now(); - let our_ethereum_address = eth_client.address(); let current_eth_valset = find_latest_valset(&mut grpc_client, gravity_contract_address, eth_client.clone()).await; if current_eth_valset.is_err() { @@ -33,7 +32,7 @@ pub async fn relayer_main_loop( let current_eth_valset = current_eth_valset.unwrap(); let gravity_id = - get_gravity_id(gravity_contract_address, our_ethereum_address, eth_client.clone()).await; + get_gravity_id(gravity_contract_address, eth_client.clone()).await; if gravity_id.is_err() { error!("Failed to get GravityID, check your Eth node"); return; From 7faebb386afa5e982fcb5ad961807450ba23411f Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 18 Nov 2021 16:50:35 -0800 Subject: [PATCH 074/115] Warning fixes --- orchestrator/gorc/src/commands.rs | 2 +- .../gorc/src/commands/print_config.rs | 2 +- orchestrator/orchestrator/src/metrics.rs | 34 +++++++++---------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/orchestrator/gorc/src/commands.rs b/orchestrator/gorc/src/commands.rs index d988f20ab..805d9ebeb 100644 --- a/orchestrator/gorc/src/commands.rs +++ b/orchestrator/gorc/src/commands.rs @@ -13,7 +13,7 @@ mod tests; mod tx; use crate::config::GorcConfig; -use abscissa_core::{Application, Clap, Command, Configurable, FrameworkError, Runnable}; +use abscissa_core::{Clap, Command, Configurable, FrameworkError, Runnable}; use std::path::PathBuf; /// Gorc Configuration Filename diff --git a/orchestrator/gorc/src/commands/print_config.rs b/orchestrator/gorc/src/commands/print_config.rs index b8bb391c7..4254fe267 100644 --- a/orchestrator/gorc/src/commands/print_config.rs +++ b/orchestrator/gorc/src/commands/print_config.rs @@ -1,5 +1,5 @@ use crate::config::GorcConfig; -use crate::{application::APP, prelude::*}; +use crate::application::APP; use abscissa_core::{Application, Command, Clap, Runnable}; /// Command for printing configurations diff --git a/orchestrator/orchestrator/src/metrics.rs b/orchestrator/orchestrator/src/metrics.rs index 960130e4c..b8840903f 100644 --- a/orchestrator/orchestrator/src/metrics.rs +++ b/orchestrator/orchestrator/src/metrics.rs @@ -191,52 +191,52 @@ pub fn set_ethereum_check_for_events_starting_block(v: u64) { } pub fn set_ethereum_last_batch_event(v: U256) { - set_U256(ÐEREUM_LAST_BATCH_EVENT, v); - set_U256(ÐEREUM_LAST_EVENT_NONCE, v); + set_u256(ÐEREUM_LAST_BATCH_EVENT, v); + set_u256(ÐEREUM_LAST_EVENT_NONCE, v); } pub fn set_ethereum_last_batch_nonce(v: U256) { - set_U256(ÐEREUM_LAST_BATCH_NONCE, v); + set_u256(ÐEREUM_LAST_BATCH_NONCE, v); } pub fn set_ethereum_last_deposit_block(v: U256) { - set_U256(ÐEREUM_LAST_DEPOSIT_BLOCK, v); + set_u256(ÐEREUM_LAST_DEPOSIT_BLOCK, v); } pub fn set_ethereum_last_deposit_event(v: U256) { - set_U256(ÐEREUM_LAST_DEPOSIT_EVENT, v); - set_U256(ÐEREUM_LAST_EVENT_NONCE, v); + set_u256(ÐEREUM_LAST_DEPOSIT_EVENT, v); + set_u256(ÐEREUM_LAST_EVENT_NONCE, v); } pub fn set_ethereum_last_erc20_block(v: U256) { - set_U256(ÐEREUM_LAST_ERC20_BLOCK, v); + set_u256(ÐEREUM_LAST_ERC20_BLOCK, v); } pub fn set_ethereum_last_erc20_event(v: U256) { - set_U256(ÐEREUM_LAST_ERC20_EVENT, v); - set_U256(ÐEREUM_LAST_EVENT_NONCE, v); + set_u256(ÐEREUM_LAST_ERC20_EVENT, v); + set_u256(ÐEREUM_LAST_EVENT_NONCE, v); } pub fn set_ethereum_last_logic_call_event(v: U256) { - set_U256(ÐEREUM_LAST_LOGIC_CALL_EVENT, v); - set_U256(ÐEREUM_LAST_EVENT_NONCE, v); + set_u256(ÐEREUM_LAST_LOGIC_CALL_EVENT, v); + set_u256(ÐEREUM_LAST_EVENT_NONCE, v); } pub fn set_ethereum_last_logic_call_nonce(v: U256) { - set_U256(ÐEREUM_LAST_LOGIC_CALL_NONCE, v); + set_u256(ÐEREUM_LAST_LOGIC_CALL_NONCE, v); } pub fn set_ethereum_last_valset_event(v: U256) { - set_U256(ÐEREUM_LAST_VALSET_EVENT, v); - set_U256(ÐEREUM_LAST_EVENT_NONCE, v); + set_u256(ÐEREUM_LAST_VALSET_EVENT, v); + set_u256(ÐEREUM_LAST_EVENT_NONCE, v); } pub fn set_ethereum_last_valset_nonce(v: U256) { - set_U256(ÐEREUM_LAST_VALSET_NONCE, v); + set_u256(ÐEREUM_LAST_VALSET_NONCE, v); } pub fn set_ethereum_bal(v: U256) { - set_U256(ÐEREUM_BAL, v); + set_u256(ÐEREUM_BAL, v); } fn set_u64(gauge: &IntGauge, value: u64) { @@ -249,7 +249,7 @@ fn set_u64(gauge: &IntGauge, value: u64) { } } -fn set_U256(gauge: &IntGauge, value: U256) { +fn set_u256(gauge: &IntGauge, value: U256) { let v = match value.to_string().parse() { Ok(v) => v, Err(_) => -1, From ec8b828796f56e001b259dc34cbd1099cab58a17 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 18 Nov 2021 18:17:23 -0800 Subject: [PATCH 075/115] WIP: gorc conversion --- .../ethereum_gravity/src/erc20_utils.rs | 13 ++++++ .../gorc/src/commands/deploy/erc20.rs | 7 ++- .../gorc/src/commands/eth_to_cosmos.rs | 43 ++++++++++--------- .../gorc/src/commands/keys/eth/show.rs | 2 + .../gorc/src/commands/orchestrator/start.rs | 2 +- .../gorc/src/commands/sign_delegate_keys.rs | 6 ++- orchestrator/gorc/src/commands/tx/eth.rs | 4 +- .../gravity_utils/src/connection_prep.rs | 6 ++- orchestrator/relayer/src/main.rs | 2 +- 9 files changed, 52 insertions(+), 33 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs index 86ab71575..7accef76d 100644 --- a/orchestrator/ethereum_gravity/src/erc20_utils.rs +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -65,4 +65,17 @@ pub async fn approve_erc20_transfers( None => Err(potential_error) } } +} + +pub async fn get_erc20_balance( + erc20: Address, + eth_client: EthClient, +) -> Result { + let abi = BaseContract::from(parse_abi(&[ + "function balanceOf(address account) external view returns (uint256)" + ]).unwrap()); + let erc20_contract = abi.into_contract(erc20, eth_client.clone()); + let contract_call = erc20_contract.method::<_, U256>("allowance", eth_client.address())?; + + Ok(contract_call.call().await?) } \ No newline at end of file diff --git a/orchestrator/gorc/src/commands/deploy/erc20.rs b/orchestrator/gorc/src/commands/deploy/erc20.rs index 129ff0d9c..a62ebdb97 100644 --- a/orchestrator/gorc/src/commands/deploy/erc20.rs +++ b/orchestrator/gorc/src/commands/deploy/erc20.rs @@ -1,11 +1,12 @@ use crate::{application::APP, prelude::*}; use abscissa_core::{Command, Clap, Runnable}; use ethereum_gravity::deploy_erc20::deploy_erc20; +use ethers::prelude::*; use gravity_proto::gravity::{DenomToErc20ParamsRequest, DenomToErc20Request}; use gravity_utils::connection_prep::{check_for_eth, create_rpc_connections}; use std::convert::TryFrom; use std::process::exit; -use std::time::{Duration, Instant}; +use std::{sync::Arc, time::{Duration, Instant}}; use tokio::time::sleep as delay_for; /// Deploy Erc20 @@ -36,8 +37,6 @@ impl Erc20 { let config = APP.config(); let ethereum_wallet = config.load_ethers_wallet(self.ethereum_key.clone()); - let ethereum_address = ethereum_wallet.address(); - let contract_address = config .gravity .contract @@ -57,7 +56,7 @@ impl Erc20 { let eth_client = SignerMiddleware::new(connections.eth_provider.clone().unwrap(), ethereum_wallet.clone()); let eth_client = Arc::new(eth_client); - check_for_eth(ethereum_address, ð_client.provider()).await; + check_for_eth(eth_client.address(), eth_client.clone()).await; let req = DenomToErc20ParamsRequest { denom: denom.clone(), diff --git a/orchestrator/gorc/src/commands/eth_to_cosmos.rs b/orchestrator/gorc/src/commands/eth_to_cosmos.rs index 42dcc6990..120943cb8 100644 --- a/orchestrator/gorc/src/commands/eth_to_cosmos.rs +++ b/orchestrator/gorc/src/commands/eth_to_cosmos.rs @@ -1,11 +1,12 @@ use crate::application::APP; use abscissa_core::{status_err, Application, Command, Clap, Runnable}; -use clarity::Address as EthAddress; -use clarity::Uint256; +use ethereum_gravity::erc20_utils::get_erc20_balance; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; use deep_space::address::Address as CosmosAddress; use ethereum_gravity::send_to_cosmos::send_to_cosmos; use gravity_utils::connection_prep::{check_for_eth, create_rpc_connections}; -use std::time::Duration; +use std::{sync::Arc, time::Duration}; const TIMEOUT: Duration = Duration::from_secs(60); @@ -24,7 +25,7 @@ impl Runnable for EthToCosmosCmd { .expect("Invalid ERC20 contract address!"); let ethereum_key = self.args.get(1).expect("key is required"); - let ethereum_key = config.load_clarity_key(ethereum_key.clone()); + let ethereum_wallet = config.load_ethers_wallet(ethereum_key.clone()); let contract_address = self.args.get(2).expect("contract address is required"); let contract_address: EthAddress = @@ -32,6 +33,7 @@ impl Runnable for EthToCosmosCmd { let cosmos_prefix = config.cosmos.prefix.trim(); let eth_rpc = config.ethereum.rpc.trim(); + abscissa_tokio::run_with_actix(&APP, async { let connections = create_rpc_connections( cosmos_prefix.to_string(), @@ -40,58 +42,57 @@ impl Runnable for EthToCosmosCmd { TIMEOUT, ) .await; - let web3 = connections.web3.unwrap(); + + let eth_client = SignerMiddleware::new(connections.eth_provider.clone().unwrap(), ethereum_wallet.clone()); + let eth_client = Arc::new(eth_client); let cosmos_dest = self.args.get(3).expect("cosmos destination is required"); let cosmos_dest: CosmosAddress = cosmos_dest.parse().unwrap(); - let ethereum_public_key = ethereum_key.to_public_key().unwrap(); - check_for_eth(ethereum_public_key, &web3).await; + let ethereum_address = eth_client.address(); + check_for_eth(ethereum_address, eth_client.clone()).await; let init_amount = self.args.get(4).expect("amount is required"); - let amount: Uint256 = init_amount.parse().unwrap(); + let amount: U256 = init_amount.parse().unwrap(); - let erc20_balance = web3 - .get_erc20_balance(erc20_address, ethereum_public_key) - .await + let erc20_balance = get_erc20_balance(erc20_address, eth_client.clone()).await .expect("Failed to get balance, check ERC20 contract address"); let times = self.args.get(5).expect("times is required"); - let times = times.parse::().expect("cannot parse times"); + let times_usize = times.parse::().expect("cannot parse times"); + let times_u256 = times.parse::().expect("cannot parse times"); if erc20_balance == 0u8.into() { panic!( "You have zero {} tokens, please double check your sender and erc20 addresses!", contract_address ); - } else if amount.clone() * times.into() > erc20_balance { + } else if amount * times_u256 > erc20_balance { panic!( "Insufficient balance {} > {}", - amount * times.into(), + amount * times_u256, erc20_balance ); } - for _ in 0..times { + for _ in 0..times_usize { println!( "Sending {} / {} to Cosmos from {} to {}", init_amount.parse::().unwrap(), erc20_address, - ethereum_public_key, + ethereum_address, cosmos_dest ); // we send some erc20 tokens to the gravity contract to register a deposit let res = send_to_cosmos( erc20_address, contract_address, - amount.clone(), + amount, cosmos_dest, - ethereum_key, Some(TIMEOUT), - &web3, - vec![], + eth_client.clone(), ) .await; match res { - Ok(tx_id) => println!("Send to Cosmos txid: {:#066x}", tx_id), + Ok(tx_id) => println!("Send to Cosmos txid: {}", tx_id), Err(e) => println!("Failed to send tokens! {:?}", e), } } diff --git a/orchestrator/gorc/src/commands/keys/eth/show.rs b/orchestrator/gorc/src/commands/keys/eth/show.rs index b6bb728ce..4b23198a3 100644 --- a/orchestrator/gorc/src/commands/keys/eth/show.rs +++ b/orchestrator/gorc/src/commands/keys/eth/show.rs @@ -18,6 +18,8 @@ impl Runnable for ShowEthKeyCmd { fn run(&self) { let config = APP.config(); let name = self.args.get(0).expect("name is required"); + // TODO(bolten): is ethers wallet even capable of printing the public and + // private keys? let key = config.load_clarity_key(name.clone()); let pub_key = key.to_public_key().expect("Could not build public key"); diff --git a/orchestrator/gorc/src/commands/orchestrator/start.rs b/orchestrator/gorc/src/commands/orchestrator/start.rs index bea0a7ff4..332802aa4 100644 --- a/orchestrator/gorc/src/commands/orchestrator/start.rs +++ b/orchestrator/gorc/src/commands/orchestrator/start.rs @@ -84,7 +84,7 @@ impl Runnable for StartCommand { // check if we actually have the promised balance of tokens to pay fees check_for_fee_denom(&fees_denom, cosmos_address, &contact).await; - check_for_eth(ethereum_address, ð_client.provider()).await; + check_for_eth(ethereum_address, eth_client.clone()).await; let gas_price = config.cosmos.gas_price.as_tuple(); diff --git a/orchestrator/gorc/src/commands/sign_delegate_keys.rs b/orchestrator/gorc/src/commands/sign_delegate_keys.rs index 1e3f0fc5c..e0b80bdb0 100644 --- a/orchestrator/gorc/src/commands/sign_delegate_keys.rs +++ b/orchestrator/gorc/src/commands/sign_delegate_keys.rs @@ -1,5 +1,6 @@ use crate::{application::APP, prelude::*}; use abscissa_core::{Application, Command, Clap, Runnable}; +use ethers::{prelude::Signer, utils::keccak256}; use gravity_proto::gravity as proto; use std::time::Duration; @@ -15,7 +16,7 @@ impl Runnable for SignDelegateKeysCmd { let config = APP.config(); abscissa_tokio::run_with_actix(&APP, async { let name = self.args.get(0).expect("ethereum-key-name is required"); - let key = config.load_clarity_key(name.clone()); + let ethereum_wallet = config.load_ethers_wallet(name.clone()); let val = self.args.get(1).expect("validator-address is required"); let address = val.parse().expect("Could not parse address"); @@ -46,7 +47,8 @@ impl Runnable for SignDelegateKeysCmd { let mut buf = bytes::BytesMut::with_capacity(size); prost::Message::encode(&msg, &mut buf).expect("Failed to encode DelegateKeysSignMsg!"); - let signature = key.sign_ethereum_msg(&buf); + let data = keccak256(buf); // TODO(bolten): the rest of the orchestrator expects a hash as a message...here too? + let signature = ethereum_wallet.sign_message(data).await.expect("Could not sign DelegateKeysSignMsg"); println!("{}", signature); }) diff --git a/orchestrator/gorc/src/commands/tx/eth.rs b/orchestrator/gorc/src/commands/tx/eth.rs index abe094f1b..e7b53ae1a 100644 --- a/orchestrator/gorc/src/commands/tx/eth.rs +++ b/orchestrator/gorc/src/commands/tx/eth.rs @@ -2,8 +2,8 @@ use crate::{application::APP, prelude::*, utils::*}; use abscissa_core::{Command, Clap, Runnable}; -use clarity::Address as EthAddress; -use clarity::{PrivateKey as EthPrivateKey, Uint256}; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; use deep_space::address::Address as CosmosAddress; use ethereum_gravity::send_to_cosmos::send_to_cosmos; use gravity_utils::connection_prep::{check_for_eth, create_rpc_connections}; diff --git a/orchestrator/gravity_utils/src/connection_prep.rs b/orchestrator/gravity_utils/src/connection_prep.rs index 83cd64f55..b6285efd5 100644 --- a/orchestrator/gravity_utils/src/connection_prep.rs +++ b/orchestrator/gravity_utils/src/connection_prep.rs @@ -13,6 +13,7 @@ use gravity_proto::gravity::DelegateKeysByEthereumSignerRequest; use gravity_proto::gravity::DelegateKeysByOrchestratorRequest; use std::convert::TryFrom; use std::process::exit; +use std::sync::Arc; use std::time::Duration; use tokio::time::sleep as delay_for; use tonic::transport::Channel; @@ -352,9 +353,10 @@ pub async fn check_for_fee_denom(fee_denom: &str, address: CosmosAddress, contac } } +// TODO(bolten): is using LocalWallet too specific? /// Checks the user has some Ethereum in their address to pay for things -pub async fn check_for_eth(address: EthAddress, eth_provider: &EthProvider) { - let balance = eth_provider.get_balance(address, None).await.unwrap(); +pub async fn check_for_eth(address: EthAddress, eth_client: Arc, LocalWallet>>) { + let balance = eth_client.get_balance(address, None).await.unwrap(); if balance == 0u8.into() { warn!("You don't have any Ethereum! You will need to send some to {} for this program to work. Dust will do for basic operations, more info about average relaying costs will be presented as the program runs", address); } diff --git a/orchestrator/relayer/src/main.rs b/orchestrator/relayer/src/main.rs index a641a9ad2..5ffe12e65 100644 --- a/orchestrator/relayer/src/main.rs +++ b/orchestrator/relayer/src/main.rs @@ -95,7 +95,7 @@ async fn main() { // we can't move any steps above this because they may fail on an incorrect // historic chain state while syncing occurs wait_for_cosmos_node_ready(&contact).await; - check_for_eth(public_eth_key, ð_client.provider()).await; + check_for_eth(public_eth_key, eth_client.clone()).await; relayer_main_loop( eth_client, From c816ba18f3bfa3af52452c8e23f38b6e02e5276c Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Thu, 18 Nov 2021 23:08:46 -0800 Subject: [PATCH 076/115] Finish gorc conversion --- orchestrator/cosmos_gravity/src/send.rs | 39 ++++++++++++------- .../gorc/src/commands/cosmos_to_eth.rs | 8 +++- .../gorc/src/commands/eth_to_cosmos.rs | 4 +- .../gorc/src/commands/keys/eth/show.rs | 3 +- orchestrator/gorc/src/commands/tx/cosmos.rs | 7 +++- orchestrator/gorc/src/commands/tx/eth.rs | 27 ++++++------- orchestrator/gravity_utils/src/error.rs | 31 ++++++++++++--- 7 files changed, 78 insertions(+), 41 deletions(-) diff --git a/orchestrator/cosmos_gravity/src/send.rs b/orchestrator/cosmos_gravity/src/send.rs index 8d6b06fd4..327772106 100644 --- a/orchestrator/cosmos_gravity/src/send.rs +++ b/orchestrator/cosmos_gravity/src/send.rs @@ -1,6 +1,4 @@ use bytes::BytesMut; -use clarity::Address as EthAddress; -use clarity::PrivateKey as EthPrivateKey; use deep_space::address::Address; use deep_space::coin::Coin; use deep_space::error::CosmosGrpcError; @@ -8,15 +6,19 @@ use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::Contact; use deep_space::Fee; use deep_space::Msg; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; +use ethers::utils::keccak256; use gravity_proto::cosmos_sdk_proto::cosmos::base::abci::v1beta1::TxResponse; use gravity_proto::cosmos_sdk_proto::cosmos::tx::v1beta1::BroadcastMode; use gravity_proto::gravity as proto; +use gravity_utils::error::GravityError; use prost::Message; use std::cmp; use std::collections::HashSet; use std::time::Duration; -pub const MEMO: &str = "Sent using Althea Orchestrator"; +pub const MEMO: &str = "Sent using Gravity Bridge Orchestrator"; pub const TIMEOUT: Duration = Duration::from_secs(60); /// Send a transaction updating the eth address for the sending @@ -26,10 +28,10 @@ pub async fn update_gravity_delegate_addresses( delegate_eth_address: EthAddress, delegate_cosmos_address: Address, cosmos_key: CosmosPrivateKey, - etheruem_key: EthPrivateKey, + ethereum_wallet: LocalWallet, gas_price: (f64, String), gas_adjustment: f64, -) -> Result { +) -> Result { let our_valoper_address = cosmos_key .to_address(&contact.get_prefix()) .unwrap() @@ -53,12 +55,13 @@ pub async fn update_gravity_delegate_addresses( let mut data = BytesMut::with_capacity(eth_sign_msg.encoded_len()); Message::encode(ð_sign_msg, &mut data).expect("encoding failed"); - let eth_signature = etheruem_key.sign_ethereum_msg(&data).to_bytes().to_vec(); + let data_hash = keccak256(data); + let eth_signature = ethereum_wallet.sign_message(data_hash).await?; let msg = proto::MsgDelegateKeys { validator_address: our_valoper_address.to_string(), orchestrator_address: delegate_cosmos_address.to_string(), ethereum_address: delegate_eth_address.to_string(), - eth_signature, + eth_signature: eth_signature.to_vec(), }; let msg = Msg::new("/gravity.v1.MsgDelegateKeys", msg); @@ -75,12 +78,12 @@ pub async fn send_to_eth( gas_price: (f64, String), contact: &Contact, gas_adjustment: f64, -) -> Result { +) -> Result { if amount.denom != bridge_fee.denom { - return Err(CosmosGrpcError::BadInput(format!( + return Err(GravityError::CosmosGrpcError(CosmosGrpcError::BadInput(format!( "The amount ({}) and bridge_fee ({}) denominations do not match.", amount.denom, bridge_fee.denom, - ))) + )))) } let cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); @@ -101,7 +104,7 @@ pub async fn send_request_batch_tx( gas_price: (f64, String), contact: &Contact, gas_adjustment: f64, -) -> Result { +) -> Result { let cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); let msg_request_batch = proto::MsgRequestBatchTx { signer: cosmos_address.to_string(), @@ -118,7 +121,7 @@ async fn __send_messages( gas_price: (f64, String), messages: Vec, gas_adjustment: f64, -) -> Result { +) -> Result { let cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); let fee_amount = Coin { @@ -157,7 +160,10 @@ async fn __send_messages( .send_transaction(msg_bytes, BroadcastMode::Sync) .await?; - contact.wait_for_tx(response, TIMEOUT).await + match contact.wait_for_tx(response, TIMEOUT).await { + Ok(res) => Ok(res), + Err(e) => Err(GravityError::CosmosGrpcError(e)) + } } pub async fn send_messages( @@ -166,7 +172,7 @@ pub async fn send_messages( gas_price: (f64, String), messages: Vec, gas_adjustment: f64, -) -> Result { +) -> Result { let cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); let fee_amount = Coin { @@ -204,7 +210,10 @@ pub async fn send_messages( .send_transaction(msg_bytes, BroadcastMode::Sync) .await?; - contact.wait_for_tx(response, TIMEOUT).await + match contact.wait_for_tx(response, TIMEOUT).await { + Ok(res) => Ok(res), + Err(e) => Err(GravityError::CosmosGrpcError(e)) + } } pub async fn send_main_loop( diff --git a/orchestrator/gorc/src/commands/cosmos_to_eth.rs b/orchestrator/gorc/src/commands/cosmos_to_eth.rs index 8b02d10a5..ade8814fb 100644 --- a/orchestrator/gorc/src/commands/cosmos_to_eth.rs +++ b/orchestrator/gorc/src/commands/cosmos_to_eth.rs @@ -1,9 +1,9 @@ use crate::application::APP; use abscissa_core::{status_err, Application, Clap, Command, Runnable}; -use clarity::Address as EthAddress; use clarity::Uint256; use cosmos_gravity::send::{send_request_batch_tx, send_to_eth}; use deep_space::coin::Coin; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::DenomToErc20Request; use gravity_utils::connection_prep::{check_for_fee_denom, create_rpc_connections}; use std::{process::exit, time::Duration}; @@ -27,6 +27,9 @@ pub fn one_atom() -> f64 { 1000000f64 } +// TODO(bolten): deep_space's Coin type relies internally on clarity's Uint256, +// and it would make this code super akward to try to get around that...replacing +// that here might be part of a broader deep_space replacement pub fn print_atom(input: Uint256) -> String { let float: f64 = input.to_string().parse().unwrap(); let res = float / one_atom(); @@ -85,13 +88,14 @@ impl Runnable for CosmosToEthCmd { exit(1); } } + let amount = Coin { amount: amount.clone(), denom: gravity_denom.clone(), }; let bridge_fee = Coin { - denom: gravity_denom.clone(), amount: 1u64.into(), + denom: gravity_denom.clone(), }; let eth_dest = self.args.get(3).expect("ethereum destination is required"); diff --git a/orchestrator/gorc/src/commands/eth_to_cosmos.rs b/orchestrator/gorc/src/commands/eth_to_cosmos.rs index 120943cb8..bd65a3173 100644 --- a/orchestrator/gorc/src/commands/eth_to_cosmos.rs +++ b/orchestrator/gorc/src/commands/eth_to_cosmos.rs @@ -1,10 +1,10 @@ use crate::application::APP; use abscissa_core::{status_err, Application, Command, Clap, Runnable}; +use deep_space::address::Address as CosmosAddress; use ethereum_gravity::erc20_utils::get_erc20_balance; +use ethereum_gravity::send_to_cosmos::send_to_cosmos; use ethers::prelude::*; use ethers::types::Address as EthAddress; -use deep_space::address::Address as CosmosAddress; -use ethereum_gravity::send_to_cosmos::send_to_cosmos; use gravity_utils::connection_prep::{check_for_eth, create_rpc_connections}; use std::{sync::Arc, time::Duration}; diff --git a/orchestrator/gorc/src/commands/keys/eth/show.rs b/orchestrator/gorc/src/commands/keys/eth/show.rs index 4b23198a3..6c4287f30 100644 --- a/orchestrator/gorc/src/commands/keys/eth/show.rs +++ b/orchestrator/gorc/src/commands/keys/eth/show.rs @@ -19,7 +19,8 @@ impl Runnable for ShowEthKeyCmd { let config = APP.config(); let name = self.args.get(0).expect("name is required"); // TODO(bolten): is ethers wallet even capable of printing the public and - // private keys? + // private keys? for now, leaving load_clarity_key in config.rs and + // maintaining the functionality here let key = config.load_clarity_key(name.clone()); let pub_key = key.to_public_key().expect("Could not build public key"); diff --git a/orchestrator/gorc/src/commands/tx/cosmos.rs b/orchestrator/gorc/src/commands/tx/cosmos.rs index b1eb5aa88..dda332e58 100644 --- a/orchestrator/gorc/src/commands/tx/cosmos.rs +++ b/orchestrator/gorc/src/commands/tx/cosmos.rs @@ -2,9 +2,10 @@ use crate::{application::APP, prelude::*, utils::*}; use abscissa_core::{Clap, Command, Runnable}; -use clarity::{Address as EthAddress, Uint256}; +use clarity::Uint256; use cosmos_gravity::send::send_to_eth; use deep_space::{coin::Coin, private_key::PrivateKey as CosmosPrivateKey}; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::DenomToErc20Request; use gravity_utils::connection_prep::{check_for_fee_denom, create_rpc_connections}; use regex::Regex; @@ -62,6 +63,8 @@ impl Runnable for SendToEth { let cosmos_key = get_cosmos_key(&from_cosmos_key); + // TODO(bolten): I guess this command doesn't work yet? I hope no one is trying to + // call it let cosmos_address = cosmos_key.to_address("//TODO add to config file").unwrap(); println!("Sending from Cosmos address {}", cosmos_address); @@ -94,7 +97,7 @@ impl Runnable for SendToEth { exit(1); } } let amount = Coin { - amount, + amount: amount.clone(), denom: denom.clone(), }; let bridge_fee = Coin { diff --git a/orchestrator/gorc/src/commands/tx/eth.rs b/orchestrator/gorc/src/commands/tx/eth.rs index e7b53ae1a..9d7b16607 100644 --- a/orchestrator/gorc/src/commands/tx/eth.rs +++ b/orchestrator/gorc/src/commands/tx/eth.rs @@ -2,11 +2,13 @@ use crate::{application::APP, prelude::*, utils::*}; use abscissa_core::{Command, Clap, Runnable}; +use ethereum_gravity::erc20_utils::get_erc20_balance; use ethers::prelude::*; use ethers::types::Address as EthAddress; use deep_space::address::Address as CosmosAddress; use ethereum_gravity::send_to_cosmos::send_to_cosmos; use gravity_utils::connection_prep::{check_for_eth, create_rpc_connections}; +use std::sync::Arc; /// Create transactions in Eth chain #[derive(Command, Debug, Clap)] @@ -28,7 +30,9 @@ pub struct SendToCosmos { help: bool, } -fn lookup_eth_key(_key: String) -> EthPrivateKey { +// TODO(bolten): I guess this command is also non-functional? +// are the commands under tx dead code? +fn lookup_eth_key(_key: String) -> LocalWallet { todo!() } @@ -45,11 +49,11 @@ impl Runnable for SendToCosmos { .parse() .expect("Expected a valid Eth Address"); let erc20_amount = self.free[3].clone(); - let eth_key = lookup_eth_key(from_eth_key); + let ethereum_wallet = lookup_eth_key(from_eth_key); println!( "Sending from Eth address {}", - eth_key.to_public_key().unwrap() + ethereum_wallet.address() ); let config = APP.config(); let cosmos_prefix = config.cosmos.prefix.clone(); @@ -66,16 +70,15 @@ impl Runnable for SendToCosmos { let connections = create_rpc_connections(cosmos_prefix, Some(cosmso_grpc), Some(eth_rpc), TIMEOUT) .await; - let web3 = connections.web3.unwrap(); - let ethereum_public_key = eth_key.to_public_key().unwrap(); - check_for_eth(ethereum_public_key, &web3).await; + let eth_client = SignerMiddleware::new(connections.eth_provider.clone().unwrap(), ethereum_wallet.clone()); + let eth_client = Arc::new(eth_client); + check_for_eth(eth_client.address(), eth_client.clone()).await; - let amount: Uint256 = erc20_amount + let amount: U256 = erc20_amount .parse() .expect("Expected amount in xx.yy format"); - let erc20_balance = web3 - .get_erc20_balance(erc20_contract, ethereum_public_key) + let erc20_balance = get_erc20_balance(erc20_contract, eth_client.clone()) .await .expect("Failed to get balance, check ERC20 contract address"); @@ -87,7 +90,7 @@ impl Runnable for SendToCosmos { } println!( "Sending {} / {} to Cosmos from {} to {}", - amount, erc20_contract, ethereum_public_key, to_cosmos_addr + amount, erc20_contract, eth_client.address(), to_cosmos_addr ); // we send some erc20 tokens to the gravity contract to register a deposit let res = send_to_cosmos( @@ -95,10 +98,8 @@ impl Runnable for SendToCosmos { contract_address, amount.clone(), to_cosmos_addr, - eth_key, Some(TIMEOUT), - &web3, - vec![], + eth_client.clone(), ) .await; match res { diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index cc5aef379..4f3a7b3ad 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -4,6 +4,7 @@ use clarity::Error as ClarityError; use deep_space::error::AddressError as CosmosAddressError; use deep_space::error::CosmosGrpcError; +use deep_space::error::PrivateKeyError as CosmosPrivateKeyError; use ethers::abi::Error as EthersAbiError; use ethers::abi::ethereum_types::FromDecStrErr as EthersParseUintError; use ethers::contract::AbiError as EthersContractAbiError; @@ -12,6 +13,7 @@ use ethers::prelude::ContractError; use ethers::prelude::gas_oracle::GasOracleError as EthersGasOracleError; use ethers::prelude::ProviderError as EthersProviderError; use ethers::prelude::signer::SignerMiddlewareError; +use ethers::signers::WalletError as EthersWalletError; use ethers::types::SignatureError as EthersSignatureError; use rustc_hex::FromHexError as EthersParseAddressError; use num_bigint::ParseBigIntError; @@ -25,6 +27,7 @@ pub enum GravityError { InvalidBigInt(ParseBigIntError), CosmosGrpcError(CosmosGrpcError), CosmosAddressError(CosmosAddressError), + CosmosPrivateKeyError(CosmosPrivateKeyError), EthereumBadDataError(String), EthereumRestError(SignerMiddlewareError, LocalWallet>), EthersAbiError(EthersAbiError), @@ -35,6 +38,7 @@ pub enum GravityError { EthersParseUintError(EthersParseUintError), EthersProviderError(EthersProviderError), EthersSignatureError(EthersSignatureError), + EthersWalletError(EthersWalletError), GravityContractError(String), InvalidArgumentError(String), InvalidBridgeStateError(String), @@ -58,6 +62,7 @@ impl fmt::Display for GravityError { write!(f, "Got invalid BigInt from cosmos! {}", val) } GravityError::CosmosAddressError(val) => write!(f, "Cosmos Address error {}", val), + GravityError::CosmosPrivateKeyError(val) => write!(f, "Cosmos private key error: {}", val), GravityError::EthereumBadDataError(val) => write!(f, "Received unexpected data from Ethereum: {}", val), GravityError::EthereumRestError(val) => write!(f, "Ethereum REST error: {}", val), GravityError::EthersAbiError(val) => write!(f, "Ethers ABI error: {}", val), @@ -68,6 +73,7 @@ impl fmt::Display for GravityError { GravityError::EthersParseUintError(val) => write!(f, "Ethers U256 parse error: {}", val), GravityError::EthersProviderError(val) => write!(f, "Ethers provider error: {}", val), GravityError::EthersSignatureError(val) => write!(f, "Ethers signature error: {}", val), + GravityError::EthersWalletError(val) => write!(f, "Ethers wallet error: {}", val), GravityError::GravityContractError(val) => write!(f, "Gravity contract error: {}", val), GravityError::InvalidArgumentError(val) => write!(f, "Invalid argument error: {}", val), GravityError::InvalidOptionsError(val) => { @@ -93,12 +99,25 @@ impl fmt::Display for GravityError { impl std::error::Error for GravityError {} + impl From for GravityError { fn from(error: CosmosGrpcError) -> Self { GravityError::CosmosGrpcError(error) } } +impl From for GravityError { + fn from(error: CosmosAddressError) -> Self { + GravityError::CosmosAddressError(error) + } +} + +impl From for GravityError { + fn from(error: CosmosPrivateKeyError) -> Self { + GravityError::CosmosPrivateKeyError(error) + } +} + impl From for GravityError { fn from(_error: Elapsed) -> Self { GravityError::TimeoutError @@ -165,15 +184,15 @@ impl From for GravityError { } } -impl From for GravityError { - fn from(error: Status) -> Self { - GravityError::GravityGrpcError(error) +impl From for GravityError { + fn from(error: EthersWalletError) -> Self { + GravityError::EthersWalletError(error) } } -impl From for GravityError { - fn from(error: CosmosAddressError) -> Self { - GravityError::CosmosAddressError(error) +impl From for GravityError { + fn from(error: Status) -> Self { + GravityError::GravityGrpcError(error) } } From abbe3450c5507ba95f8c5faec2165c099f69f05b Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 19 Nov 2021 09:42:25 -0800 Subject: [PATCH 077/115] Convert register_delegate_keys, small erc20 note --- orchestrator/ethereum_gravity/src/erc20_utils.rs | 1 + orchestrator/register_delegate_keys/src/main.rs | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs index 7accef76d..f51c2d79b 100644 --- a/orchestrator/ethereum_gravity/src/erc20_utils.rs +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -5,6 +5,7 @@ use gravity_utils::error::GravityError; use std::time::Duration; // TODO(bolten): verify our usage of contract.method:: is passing arguments correctly +// maybe we can get full generic erc20 ABI from somewhere and add it to the abigen call /// Checks if any given contract is approved to spend money from any given erc20 contract /// using any given address. What exactly this does can be hard to grok, essentially when diff --git a/orchestrator/register_delegate_keys/src/main.rs b/orchestrator/register_delegate_keys/src/main.rs index 0ed770bbe..b2a64e536 100644 --- a/orchestrator/register_delegate_keys/src/main.rs +++ b/orchestrator/register_delegate_keys/src/main.rs @@ -5,14 +5,15 @@ extern crate serde_derive; #[macro_use] extern crate lazy_static; -use log::error; - use clarity::PrivateKey as EthPrivateKey; use cosmos_gravity::send::update_gravity_delegate_addresses; use deep_space::{coin::Coin, mnemonic::Mnemonic, private_key::PrivateKey as CosmosPrivateKey}; use docopt::Docopt; +use ethers::core::k256::ecdsa::SigningKey; +use ethers::prelude::*; use gravity_utils::connection_prep::check_for_fee_denom; use gravity_utils::connection_prep::{create_rpc_connections, wait_for_cosmos_node_ready}; +use log::error; use rand::{thread_rng, Rng}; use std::time::Duration; @@ -110,14 +111,20 @@ async fn main() { key }; - let ethereum_address = ethereum_key.to_public_key().unwrap(); + // TODO(bolten): left clarity in place for the above bit because it seems like + // SigningKey/VerifyingKey don't implement the Display trait + let signing_key = SigningKey::from_bytes(ðereum_key.to_bytes()).unwrap(); + let ethereum_wallet = LocalWallet::from(signing_key); + + let ethereum_address = ethereum_wallet.address(); let cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); + let res = update_gravity_delegate_addresses( &contact, ethereum_address, cosmos_address, validator_key, - ethereum_key, + ethereum_wallet, (0f64,"".to_string()), 1.0f64, ) From dbae63906f7588596b81ffef9d2428def99184f8 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 19 Nov 2021 10:02:02 -0800 Subject: [PATCH 078/115] Import OpenZeppelin ERC20 contract --- orchestrator/abi_build/src/main.rs | 29 ++ .../ethereum_gravity/src/erc20_utils.rs | 26 +- orchestrator/gravity_abi/ERC20.json | 288 ++++++++++++++++++ orchestrator/gravity_abi/src/erc20.rs | 239 +++++++++++++++ orchestrator/gravity_abi/src/lib.rs | 1 + 5 files changed, 564 insertions(+), 19 deletions(-) create mode 100644 orchestrator/gravity_abi/ERC20.json create mode 100644 orchestrator/gravity_abi/src/erc20.rs diff --git a/orchestrator/abi_build/src/main.rs b/orchestrator/abi_build/src/main.rs index 0a4dedf9c..a0c4edd25 100644 --- a/orchestrator/abi_build/src/main.rs +++ b/orchestrator/abi_build/src/main.rs @@ -2,6 +2,8 @@ use ethers::contract::Abigen; use std::process; fn main() { + // Gravity contract + let abigen = match Abigen::new("Gravity", "../gravity_abi/Gravity.json") { Ok(abigen) => abigen, Err(e) => { @@ -26,4 +28,31 @@ fn main() { Ok(_) => (), Err(e) => println!("Error writing gravity.rs: {}", e), } + + // OpenZeppelin ERC20 contract + + let abigen = match Abigen::new("ERC20", "../gravity_abi/ERC20.json") { + Ok(abigen) => abigen, + Err(e) => { + println!("Could not open ERC20.json: {}", e); + process::exit(1); + } + }; + + let abi = match abigen + .add_event_derive("serde::Deserialize") + .add_event_derive("serde::Serialize") + .generate() + { + Ok(abi) => abi, + Err(e) => { + println!("Could not generate abi from ERC20.json: {}", e); + process::exit(1); + } + }; + + match abi.write_to_file("../gravity_abi/src/erc20.rs") { + Ok(_) => (), + Err(e) => println!("Error writing erc20.rs: {}", e), + } } diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs index f51c2d79b..a8c682ae1 100644 --- a/orchestrator/ethereum_gravity/src/erc20_utils.rs +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -1,12 +1,9 @@ use crate::utils::EthClient; -use ethers::abi::parse_abi; use ethers::prelude::*; +use gravity_abi::erc20::ERC20; use gravity_utils::error::GravityError; use std::time::Duration; -// TODO(bolten): verify our usage of contract.method:: is passing arguments correctly -// maybe we can get full generic erc20 ABI from somewhere and add it to the abigen call - /// Checks if any given contract is approved to spend money from any given erc20 contract /// using any given address. What exactly this does can be hard to grok, essentially when /// you want contract A to be able to spend your erc20 contract funds you need to call 'approve' @@ -17,11 +14,8 @@ pub async fn check_erc20_approved( gravity_contract: Address, eth_client: EthClient, ) -> Result { - let abi = BaseContract::from(parse_abi(&[ - "function allowance(address owner, address spender) external view returns (uint256)" - ]).unwrap()); - let erc20_contract = abi.into_contract(erc20, eth_client.clone()); - let contract_call = erc20_contract.method::<_, U256>("allowance", (eth_client.address(), gravity_contract))?; + let erc20_contract = ERC20::new(erc20, eth_client.clone()); + let contract_call = erc20_contract.allowance(eth_client.address(), gravity_contract); let allowance = contract_call.call().await?; // TODO(bolten): verify if this check is sufficient/correct @@ -41,11 +35,8 @@ pub async fn approve_erc20_transfers( timeout_option: Option, eth_client: EthClient, ) -> Result { - let abi = BaseContract::from(parse_abi(&[ - "function approve(address spender, uint256 amount) external returns (bool)" - ]).unwrap()); - let erc20_contract = abi.into_contract(erc20, eth_client.clone()); - let contract_call = erc20_contract.method::<_, bool>("approve", (target_contract, U256::MAX))?; + let erc20_contract = ERC20::new(erc20, eth_client.clone()); + let contract_call = erc20_contract.approve(target_contract, U256::MAX); let pending_tx = contract_call.send().await?; let tx_hash = *pending_tx; @@ -72,11 +63,8 @@ pub async fn get_erc20_balance( erc20: Address, eth_client: EthClient, ) -> Result { - let abi = BaseContract::from(parse_abi(&[ - "function balanceOf(address account) external view returns (uint256)" - ]).unwrap()); - let erc20_contract = abi.into_contract(erc20, eth_client.clone()); - let contract_call = erc20_contract.method::<_, U256>("allowance", eth_client.address())?; + let erc20_contract = ERC20::new(erc20, eth_client.clone()); + let contract_call = erc20_contract.balance_of(eth_client.address()); Ok(contract_call.call().await?) } \ No newline at end of file diff --git a/orchestrator/gravity_abi/ERC20.json b/orchestrator/gravity_abi/ERC20.json new file mode 100644 index 000000000..5b22926bc --- /dev/null +++ b/orchestrator/gravity_abi/ERC20.json @@ -0,0 +1,288 @@ +[ + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/orchestrator/gravity_abi/src/erc20.rs b/orchestrator/gravity_abi/src/erc20.rs new file mode 100644 index 000000000..f59ce5511 --- /dev/null +++ b/orchestrator/gravity_abi/src/erc20.rs @@ -0,0 +1,239 @@ +pub use erc20_mod::*; +#[allow(clippy::too_many_arguments)] +mod erc20_mod { + #![allow(clippy::enum_variant_names)] + #![allow(dead_code)] + #![allow(clippy::type_complexity)] + #![allow(unused_imports)] + use ethers::contract::{ + builders::{ContractCall, Event}, + Contract, Lazy, + }; + use ethers::core::{ + abi::{Abi, Detokenize, InvalidOutputType, Token, Tokenizable}, + types::*, + }; + use ethers::providers::Middleware; + #[doc = "ERC20 was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs"] + use std::sync::Arc; + pub static ERC20_ABI: ethers::contract::Lazy = + ethers::contract::Lazy::new(|| { + serde_json :: from_str ("[\n {\n \"inputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"name\",\n \"type\": \"string\"\n },\n {\n \"internalType\": \"string\",\n \"name\": \"symbol\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"constructor\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"allowance\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"account\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"decimals\",\n \"outputs\": [\n {\n \"internalType\": \"uint8\",\n \"name\": \"\",\n \"type\": \"uint8\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"subtractedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"decreaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"addedValue\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"increaseAllowance\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"internalType\": \"string\",\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [],\n \"name\": \"totalSupply\",\n \"outputs\": [\n {\n \"internalType\": \"uint256\",\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"recipient\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transfer\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address\",\n \"name\": \"sender\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"recipient\",\n \"type\": \"address\"\n },\n {\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [\n {\n \"internalType\": \"bool\",\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n]\n") . expect ("invalid abi") + }); + #[derive(Clone)] + pub struct ERC20(ethers::contract::Contract); + impl std::ops::Deref for ERC20 { + type Target = ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl std::fmt::Debug for ERC20 { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_tuple(stringify!(ERC20)) + .field(&self.address()) + .finish() + } + } + impl<'a, M: ethers::providers::Middleware> ERC20 { + #[doc = r" Creates a new contract instance with the specified `ethers`"] + #[doc = r" client at the given `Address`. The contract derefs to a `ethers::Contract`"] + #[doc = r" object"] + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + let contract = + ethers::contract::Contract::new(address.into(), ERC20_ABI.clone(), client); + Self(contract) + } + #[doc = "Calls the contract's `allowance` (0xdd62ed3e) function"] + pub fn allowance( + &self, + owner: ethers::core::types::Address, + spender: ethers::core::types::Address, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([221, 98, 237, 62], (owner, spender)) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `approve` (0x095ea7b3) function"] + pub fn approve( + &self, + spender: ethers::core::types::Address, + amount: ethers::core::types::U256, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([9, 94, 167, 179], (spender, amount)) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `balanceOf` (0x70a08231) function"] + pub fn balance_of( + &self, + account: ethers::core::types::Address, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([112, 160, 130, 49], account) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `decimals` (0x313ce567) function"] + pub fn decimals(&self) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([49, 60, 229, 103], ()) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `decreaseAllowance` (0xa457c2d7) function"] + pub fn decrease_allowance( + &self, + spender: ethers::core::types::Address, + subtracted_value: ethers::core::types::U256, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([164, 87, 194, 215], (spender, subtracted_value)) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `increaseAllowance` (0x39509351) function"] + pub fn increase_allowance( + &self, + spender: ethers::core::types::Address, + added_value: ethers::core::types::U256, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([57, 80, 147, 81], (spender, added_value)) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `name` (0x06fdde03) function"] + pub fn name(&self) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([6, 253, 222, 3], ()) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `symbol` (0x95d89b41) function"] + pub fn symbol(&self) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([149, 216, 155, 65], ()) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `totalSupply` (0x18160ddd) function"] + pub fn total_supply( + &self, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([24, 22, 13, 221], ()) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `transfer` (0xa9059cbb) function"] + pub fn transfer( + &self, + recipient: ethers::core::types::Address, + amount: ethers::core::types::U256, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([169, 5, 156, 187], (recipient, amount)) + .expect("method not found (this should never happen)") + } + #[doc = "Calls the contract's `transferFrom` (0x23b872dd) function"] + pub fn transfer_from( + &self, + sender: ethers::core::types::Address, + recipient: ethers::core::types::Address, + amount: ethers::core::types::U256, + ) -> ethers::contract::builders::ContractCall { + self.0 + .method_hash([35, 184, 114, 221], (sender, recipient, amount)) + .expect("method not found (this should never happen)") + } + #[doc = "Gets the contract's `Approval` event"] + pub fn approval_filter(&self) -> ethers::contract::builders::Event { + self.0.event() + } + #[doc = "Gets the contract's `Transfer` event"] + pub fn transfer_filter(&self) -> ethers::contract::builders::Event { + self.0.event() + } + #[doc = r" Returns an [`Event`](#ethers_contract::builders::Event) builder for all events of this contract"] + pub fn events(&self) -> ethers::contract::builders::Event { + self.0.event_with_filter(Default::default()) + } + } + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthEvent, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethevent(name = "Approval", abi = "Approval(address,address,uint256)")] + pub struct ApprovalFilter { + #[ethevent(indexed)] + pub owner: ethers::core::types::Address, + #[ethevent(indexed)] + pub spender: ethers::core::types::Address, + pub value: ethers::core::types::U256, + } + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthEvent, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethevent(name = "Transfer", abi = "Transfer(address,address,uint256)")] + pub struct TransferFilter { + #[ethevent(indexed)] + pub from: ethers::core::types::Address, + #[ethevent(indexed)] + pub to: ethers::core::types::Address, + pub value: ethers::core::types::U256, + } + #[derive(Debug, Clone, PartialEq, Eq)] + pub enum ERC20Events { + ApprovalFilter(ApprovalFilter), + TransferFilter(TransferFilter), + } + impl ethers::core::abi::Tokenizable for ERC20Events { + fn from_token( + token: ethers::core::abi::Token, + ) -> Result + where + Self: Sized, + { + if let Ok(decoded) = ApprovalFilter::from_token(token.clone()) { + return Ok(ERC20Events::ApprovalFilter(decoded)); + } + if let Ok(decoded) = TransferFilter::from_token(token.clone()) { + return Ok(ERC20Events::TransferFilter(decoded)); + } + Err(ethers::core::abi::InvalidOutputType( + "Failed to decode all event variants".to_string(), + )) + } + fn into_token(self) -> ethers::core::abi::Token { + match self { + ERC20Events::ApprovalFilter(element) => element.into_token(), + ERC20Events::TransferFilter(element) => element.into_token(), + } + } + } + impl ethers::core::abi::TokenizableItem for ERC20Events {} + impl ethers::contract::EthLogDecode for ERC20Events { + fn decode_log(log: ðers::core::abi::RawLog) -> Result + where + Self: Sized, + { + if let Ok(decoded) = ApprovalFilter::decode_log(log) { + return Ok(ERC20Events::ApprovalFilter(decoded)); + } + if let Ok(decoded) = TransferFilter::decode_log(log) { + return Ok(ERC20Events::TransferFilter(decoded)); + } + Err(ethers::core::abi::Error::InvalidData) + } + } +} diff --git a/orchestrator/gravity_abi/src/lib.rs b/orchestrator/gravity_abi/src/lib.rs index 28701a439..dce4f7034 100644 --- a/orchestrator/gravity_abi/src/lib.rs +++ b/orchestrator/gravity_abi/src/lib.rs @@ -1 +1,2 @@ +pub mod erc20; pub mod gravity; From 9f7d87b446d1ee917318b5603b6de59750bcab24 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 19 Nov 2021 10:08:51 -0800 Subject: [PATCH 079/115] Remove warning in register_delegate_keys --- orchestrator/register_delegate_keys/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchestrator/register_delegate_keys/src/main.rs b/orchestrator/register_delegate_keys/src/main.rs index b2a64e536..8cb057b28 100644 --- a/orchestrator/register_delegate_keys/src/main.rs +++ b/orchestrator/register_delegate_keys/src/main.rs @@ -65,7 +65,7 @@ async fn main() { .unwrap_or_else(|e| e.exit()); let fee_denom = args.flag_fees; - let fee = Coin { + let _fee = Coin { denom: fee_denom.clone(), amount: 1u64.into(), }; From 59807ab447f587e49daf28b93140064b6ee62cf4 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 19 Nov 2021 12:46:31 -0800 Subject: [PATCH 080/115] Update message_signatures.rs unit tests --- orchestrator/gravity_utils/src/error.rs | 18 +++++ orchestrator/gravity_utils/src/ethereum.rs | 20 ++++++ .../gravity_utils/src/message_signatures.rs | 68 +++++++++---------- 3 files changed, 71 insertions(+), 35 deletions(-) diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index 4f3a7b3ad..b841b5eb1 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -18,6 +18,8 @@ use ethers::types::SignatureError as EthersSignatureError; use rustc_hex::FromHexError as EthersParseAddressError; use num_bigint::ParseBigIntError; use std::fmt::{self, Debug}; +use std::num::ParseIntError; +use std::string::FromUtf8Error; use tokio::time::error::Elapsed; use tonic::Status; @@ -51,6 +53,8 @@ pub enum GravityError { GravityGrpcError(Status), InsufficientVotingPowerToPass(String), ParseBigIntError(ParseBigIntError), + ParseIntError(ParseIntError), + FromUtf8Error(FromUtf8Error), } impl fmt::Display for GravityError { @@ -93,6 +97,8 @@ impl fmt::Display for GravityError { write!(f, "{}", val) } GravityError::ParseBigIntError(val) => write!(f, "Failed to parse big integer {}", val), + GravityError::ParseIntError(val) => write!(f, "Failed to parse integer: {}", val), + GravityError::FromUtf8Error(val) => write!(f, "Failed to parse bytes to UTF-8: {}", val), } } } @@ -201,3 +207,15 @@ impl From for GravityError { GravityError::InvalidBigInt(error) } } + +impl From for GravityError { + fn from(error: ParseIntError) -> Self { + GravityError::ParseIntError(error) + } +} + +impl From for GravityError { + fn from(error: FromUtf8Error) -> Self { + GravityError::FromUtf8Error(error) + } +} diff --git a/orchestrator/gravity_utils/src/ethereum.rs b/orchestrator/gravity_utils/src/ethereum.rs index c89ff8f01..98b8b2363 100644 --- a/orchestrator/gravity_utils/src/ethereum.rs +++ b/orchestrator/gravity_utils/src/ethereum.rs @@ -1,3 +1,4 @@ +use crate::error::GravityError; use ethers::prelude::*; use std::panic; @@ -33,6 +34,25 @@ pub fn bytes_to_hex_str(bytes: &[u8]) -> String { .fold(String::new(), |acc, x| acc + &x) } +pub fn hex_str_to_bytes(s: &str) -> Result, GravityError> { + let s = match s.strip_prefix("0x") { + Some(s) => s, + None => &s, + }; + let bytes = s + .as_bytes() + .chunks(2) + .map::, _>(|ch| { + let str = String::from_utf8(ch.to_vec())?; + let byte = u8::from_str_radix(&str, 16)?; + + Ok(byte) + }) + .collect::, _>>()?; + + Ok(bytes) +} + #[test] fn test_downcast_to_u64() { let mut i = 0u64; diff --git a/orchestrator/gravity_utils/src/message_signatures.rs b/orchestrator/gravity_utils/src/message_signatures.rs index d9f3bdced..30ac7826b 100644 --- a/orchestrator/gravity_utils/src/message_signatures.rs +++ b/orchestrator/gravity_utils/src/message_signatures.rs @@ -29,9 +29,8 @@ pub fn encode_valset_confirm_hashed(gravity_id: String, valset: Valset) -> Vec = hex_str_to_bytes("0x88165860d955aee7dc3e83d9d1156a5864b708841965585d206dbef6e9e1a499") @@ -68,8 +67,8 @@ fn test_valset_signature() { ], }; let checkpoint = encode_valset_confirm("foo".to_string(), valset); - let checkpoint_hash = Keccak256::digest(&checkpoint); - assert_eq!(correct_hash, checkpoint_hash.as_slice()); + let checkpoint_hash = keccak256(&checkpoint); + assert_eq!(correct_hash, checkpoint_hash); // the same valset, except with an intentionally incorrect hash let valset = Valset { @@ -102,8 +101,8 @@ fn test_valset_signature() { ], }; let checkpoint = encode_valset_confirm("foo".to_string(), valset); - let checkpoint_hash = Keccak256::digest(&checkpoint); - assert_ne!(correct_hash, checkpoint_hash.as_slice()) + let checkpoint_hash = keccak256(&checkpoint); + assert_ne!(correct_hash, checkpoint_hash) } /// takes the required input data and produces the required signature to confirm a transaction @@ -131,14 +130,13 @@ pub fn encode_tx_batch_confirm_hashed(gravity_id: String, batch: TransactionBatc hash_message(digest).as_bytes().to_vec() } -#[test] -fn test_batch_signature() { - use crate::types::BatchTransaction; - use crate::types::Erc20Token; - use clarity::utils::hex_str_to_bytes; - use clarity::PrivateKey as EthPrivateKey; +#[tokio::test] +async fn test_batch_signature() { + use crate::{ethereum::hex_str_to_bytes, types::{BatchTransaction, Erc20Token}}; + use ethers::core::k256::ecdsa::SigningKey; + use ethers::prelude::*; + use ethers::utils::keccak256; use rand::Rng; - use sha3::{Digest, Keccak256}; let correct_hash: Vec = hex_str_to_bytes("0xa3a7ee0a363b8ad2514e7ee8f110d7449c0d88f3b0913c28c1751e6e0079a9b2") @@ -172,27 +170,28 @@ fn test_batch_signature() { }; let checkpoint = encode_tx_batch_confirm("foo".to_string(), batch.clone()); - let checkpoint_hash = Keccak256::digest(&checkpoint); + let checkpoint_hash = keccak256(&checkpoint); assert_eq!(correct_hash.len(), checkpoint_hash.len()); - assert_eq!(correct_hash, checkpoint_hash.as_slice()); + assert_eq!(correct_hash, checkpoint_hash); // checkpoint is correct lets make sure our signature code works let mut rng = rand::thread_rng(); let secret: [u8; 32] = rng.gen(); - let eth_key = EthPrivateKey::from_slice(&secret).unwrap(); - let eth_address = eth_key.to_public_key().unwrap(); + let eth_key = SigningKey::from_bytes(&secret).unwrap(); + let eth_wallet = LocalWallet::from(eth_key); + let eth_address = eth_wallet.address(); let checkpoint = encode_tx_batch_confirm_hashed("foo".to_string(), batch); - let eth_signature = eth_key.sign_hash(&checkpoint); + let eth_signature = eth_wallet.sign_message(checkpoint.clone()).await.unwrap(); - assert_eq!(eth_address, eth_signature.recover(&checkpoint).unwrap()); + assert_eq!(eth_address, eth_signature.recover(checkpoint.clone()).unwrap()); } -#[test] -fn test_specific_batch_signature() { - use crate::types::BatchTransaction; - use crate::types::Erc20Token; - use clarity::PrivateKey as EthPrivateKey; +#[tokio::test] +async fn test_specific_batch_signature() { + use crate::types::{BatchTransaction, Erc20Token}; + use ethers::core::k256::ecdsa::SigningKey; + use ethers::prelude::*; use rand::Rng; let erc20_addr = "0x0635FF793Edf48cf5dB294916720A78e6e490E40" @@ -226,14 +225,15 @@ fn test_specific_batch_signature() { let mut rng = rand::thread_rng(); let secret: [u8; 32] = rng.gen(); // the starting location of the funds - let eth_key = EthPrivateKey::from_slice(&secret).unwrap(); - let eth_address = eth_key.to_public_key().unwrap(); + let eth_key = SigningKey::from_bytes(&secret).unwrap(); + let eth_wallet = LocalWallet::from(eth_key); + let eth_address = eth_wallet.address(); let checkpoint = encode_tx_batch_confirm_hashed("foo".to_string(), batch); - let eth_signature = eth_key.sign_hash(&checkpoint); + let eth_signature = eth_wallet.sign_message(checkpoint.clone()).await.unwrap(); - assert_eq!(eth_address, eth_signature.recover(&checkpoint).unwrap()); + assert_eq!(eth_address, eth_signature.recover(checkpoint.clone()).unwrap()); } /// takes the required input data and produces the required signature to confirm a logic @@ -273,10 +273,8 @@ pub fn encode_logic_call_confirm_hashed(gravity_id: String, call: LogicCall) -> #[test] fn test_logic_call_signature() { - use crate::types::Erc20Token; - use crate::types::LogicCall; - use clarity::utils::hex_str_to_bytes; - use sha3::{Digest, Keccak256}; + use crate::{ethereum::hex_str_to_bytes, types::{Erc20Token, LogicCall}}; + use ethers::utils::keccak256; let correct_hash: Vec = hex_str_to_bytes("0x1de95c9ace999f8ec70c6dc8d045942da2612950567c4861aca959c0650194da") @@ -310,8 +308,8 @@ fn test_logic_call_signature() { let checkpoint = encode_logic_call_confirm("foo".to_string(), logic_call); println!("{}", checkpoint.len() / 32); - let checkpoint_hash = Keccak256::digest(&checkpoint); + let checkpoint_hash = keccak256(&checkpoint); assert_eq!(correct_hash.len(), checkpoint_hash.len()); - assert_eq!(correct_hash, checkpoint_hash.as_slice()) + assert_eq!(correct_hash, checkpoint_hash) } From d19ceb054daae5fae51b01bf64af5c358e0e4484 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 19 Nov 2021 15:35:18 -0800 Subject: [PATCH 081/115] Remove downcast tests, port hex_str_to_bytes tests Since we're not using a custom uint 256 implementation any more, it's not super useful to re-test the properties of the object here. --- orchestrator/gravity_utils/src/ethereum.rs | 82 ++++++++++++++-------- 1 file changed, 51 insertions(+), 31 deletions(-) diff --git a/orchestrator/gravity_utils/src/ethereum.rs b/orchestrator/gravity_utils/src/ethereum.rs index 98b8b2363..cb7f9e369 100644 --- a/orchestrator/gravity_utils/src/ethereum.rs +++ b/orchestrator/gravity_utils/src/ethereum.rs @@ -54,43 +54,63 @@ pub fn hex_str_to_bytes(s: &str) -> Result, GravityError> { } #[test] -fn test_downcast_to_u64() { - let mut i = 0u64; - while i < 100_000 { - assert_eq!(i, downcast_to_u64(i.into()).unwrap()); - i += 1 - } - let mut i: u64 = std::u32::MAX.into(); - i -= 100; - let end = i + 100_000; - while i < end { - assert_eq!(i, downcast_to_u64(i.into()).unwrap()); - i += 1 - } +fn encode_bytes() { + assert_eq!(bytes_to_hex_str(&[0xf]), "0f".to_owned()); + assert_eq!(bytes_to_hex_str(&[0xff]), "ff".to_owned()); + assert_eq!( + bytes_to_hex_str(&[0xde, 0xad, 0xbe, 0xef]), + "deadbeef".to_owned() + ); } #[test] -fn test_downcast_to_u128() { - let mut i = 0u128; - while i < 100_000 { - assert_eq!(i, downcast_to_u128(i.into()).unwrap()); - i += 1 - } - let mut i: u128 = std::u64::MAX.into(); - i -= 100; - let end = i + 100_000; - while i < end { - assert_eq!(i, downcast_to_u128(i.into()).unwrap()); - i += 1 +fn decode_bytes() { + assert_eq!( + hex_str_to_bytes(&"deadbeef".to_owned()).expect("Unable to decode"), + [222, 173, 190, 239] + ); +} + +#[test] +fn decode_odd_amount_of_bytes() { + assert_eq!(hex_str_to_bytes(&"f".to_owned()).unwrap(), vec![15]); +} + +#[test] +fn bytes_raises_decode_error() { + use crate::error::GravityError; + + let e = hex_str_to_bytes(&"\u{012345}deadbeef".to_owned()).unwrap_err(); + + match e { + GravityError::FromUtf8Error(_) => {} + _ => panic!(), + }; +} + +#[test] +fn bytes_raises_parse_error() { + use crate::error::GravityError; + + let e = hex_str_to_bytes(&"Lorem ipsum".to_owned()).unwrap_err(); + match e { + GravityError::ParseIntError(_) => {} + _ => panic!(), } } #[test] -fn encode_bytes() { - assert_eq!(bytes_to_hex_str(&[0xf]), "0f".to_owned()); - assert_eq!(bytes_to_hex_str(&[0xff]), "ff".to_owned()); +fn parse_prefixed_empty() { assert_eq!( - bytes_to_hex_str(&[0xde, 0xad, 0xbe, 0xef]), - "deadbeef".to_owned() + hex_str_to_bytes(&"0x".to_owned()).unwrap(), + Vec::::new() ); -} \ No newline at end of file +} + +#[test] +fn parse_prefixed_non_empty() { + assert_eq!( + hex_str_to_bytes(&"0xdeadbeef".to_owned()).unwrap(), + vec![0xde, 0xad, 0xbe, 0xef] + ); +} From 7b54baa8e555fad69d49b27c3c92dedd0322e10e Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 19 Nov 2021 15:55:18 -0800 Subject: [PATCH 082/115] Move Eth types out of utils --- orchestrator/cosmos_gravity/src/build.rs | 4 ++-- orchestrator/ethereum_gravity/src/deploy_erc20.rs | 2 +- orchestrator/ethereum_gravity/src/erc20_utils.rs | 2 +- orchestrator/ethereum_gravity/src/lib.rs | 1 + orchestrator/ethereum_gravity/src/logic_call.rs | 5 +++-- orchestrator/ethereum_gravity/src/send_to_cosmos.rs | 2 +- orchestrator/ethereum_gravity/src/submit_batch.rs | 3 ++- orchestrator/ethereum_gravity/src/types.rs | 5 +++++ orchestrator/ethereum_gravity/src/utils.rs | 5 +---- orchestrator/ethereum_gravity/src/valset_update.rs | 3 ++- orchestrator/orchestrator/src/ethereum_event_watcher.rs | 2 +- orchestrator/orchestrator/src/get_with_retry.rs | 2 +- orchestrator/orchestrator/src/main_loop.rs | 3 ++- orchestrator/orchestrator/src/oracle_resync.rs | 2 +- orchestrator/relayer/src/batch_relaying.rs | 2 +- orchestrator/relayer/src/find_latest_valset.rs | 2 +- orchestrator/relayer/src/logic_call_relaying.rs | 3 ++- orchestrator/relayer/src/main_loop.rs | 2 +- orchestrator/relayer/src/valset_relaying.rs | 2 +- 19 files changed, 30 insertions(+), 22 deletions(-) create mode 100644 orchestrator/ethereum_gravity/src/types.rs diff --git a/orchestrator/cosmos_gravity/src/build.rs b/orchestrator/cosmos_gravity/src/build.rs index d5bc680f0..c0a38fa06 100644 --- a/orchestrator/cosmos_gravity/src/build.rs +++ b/orchestrator/cosmos_gravity/src/build.rs @@ -1,8 +1,8 @@ use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::Contact; use deep_space::Msg; -use ethereum_gravity::utils::EthClient; -use ethers::prelude::Signer; +use ethereum_gravity::types::EthClient; +use ethers::prelude::*; use ethers::utils::keccak256; use gravity_proto::gravity as proto; use gravity_proto::ToAny; diff --git a/orchestrator/ethereum_gravity/src/deploy_erc20.rs b/orchestrator/ethereum_gravity/src/deploy_erc20.rs index b8a22cd57..9c3a628c2 100644 --- a/orchestrator/ethereum_gravity/src/deploy_erc20.rs +++ b/orchestrator/ethereum_gravity/src/deploy_erc20.rs @@ -2,7 +2,7 @@ //! the event for this deployment is then ferried over to Cosmos where the validators will accept the ERC20 contract address //! as the representation of this asset on Ethereum -use crate::utils::{EthClient, get_send_transaction_gas_price}; +use crate::{types::EthClient, utils::get_send_transaction_gas_price}; use ethers::prelude::*; use gravity_abi::gravity::*; use gravity_utils::error::GravityError; diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs index a8c682ae1..352694a16 100644 --- a/orchestrator/ethereum_gravity/src/erc20_utils.rs +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -1,4 +1,4 @@ -use crate::utils::EthClient; +use crate::types::EthClient; use ethers::prelude::*; use gravity_abi::erc20::ERC20; use gravity_utils::error::GravityError; diff --git a/orchestrator/ethereum_gravity/src/lib.rs b/orchestrator/ethereum_gravity/src/lib.rs index 4d19694a4..cf054ffb7 100644 --- a/orchestrator/ethereum_gravity/src/lib.rs +++ b/orchestrator/ethereum_gravity/src/lib.rs @@ -10,6 +10,7 @@ pub mod deploy_erc20; pub mod logic_call; pub mod send_to_cosmos; pub mod submit_batch; +pub mod types; pub mod utils; pub mod valset_update; diff --git a/orchestrator/ethereum_gravity/src/logic_call.rs b/orchestrator/ethereum_gravity/src/logic_call.rs index cb9b804c7..2f360506b 100644 --- a/orchestrator/ethereum_gravity/src/logic_call.rs +++ b/orchestrator/ethereum_gravity/src/logic_call.rs @@ -1,7 +1,8 @@ -use crate::utils::{EthClient, EthSignerMiddleware, GasCost, +use crate::{types::{EthClient, EthSignerMiddleware}, + utils::{GasCost, convert_invalidation_id_to_fixed_array, get_logic_call_nonce, - get_send_transaction_gas_price}; + get_send_transaction_gas_price}}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; diff --git a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs index ed4ed5a14..eac76b4a3 100644 --- a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs +++ b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs @@ -1,6 +1,6 @@ //! Helper functions for sending tokens to Cosmos -use crate::{erc20_utils::{approve_erc20_transfers, check_erc20_approved}, utils::EthClient}; +use crate::{erc20_utils::{approve_erc20_transfers, check_erc20_approved}, types::EthClient}; use deep_space::address::Address as CosmosAddress; use ethers::prelude::*; use gravity_abi::gravity::*; diff --git a/orchestrator/ethereum_gravity/src/submit_batch.rs b/orchestrator/ethereum_gravity/src/submit_batch.rs index 43ed51a7f..691baf16b 100644 --- a/orchestrator/ethereum_gravity/src/submit_batch.rs +++ b/orchestrator/ethereum_gravity/src/submit_batch.rs @@ -1,4 +1,5 @@ -use crate::utils::{EthClient, EthSignerMiddleware, GasCost, get_send_transaction_gas_price, get_tx_batch_nonce}; +use crate::{types::{EthClient, EthSignerMiddleware}, + utils::{GasCost, get_send_transaction_gas_price, get_tx_batch_nonce}}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; diff --git a/orchestrator/ethereum_gravity/src/types.rs b/orchestrator/ethereum_gravity/src/types.rs new file mode 100644 index 000000000..82ad639d9 --- /dev/null +++ b/orchestrator/ethereum_gravity/src/types.rs @@ -0,0 +1,5 @@ +use ethers::prelude::*; +use std::sync::Arc; + +pub type EthSignerMiddleware = SignerMiddleware, LocalWallet>; +pub type EthClient = Arc; \ No newline at end of file diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index b43dcb2df..f65a0f247 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -1,3 +1,4 @@ +use crate::types::EthClient; use ethers::core::abi::{self, Token}; use ethers::middleware::gas_oracle::{Etherscan, GasCategory}; use ethers::prelude::*; @@ -9,10 +10,6 @@ use gravity_utils::error::GravityError; use gravity_utils::ethereum::downcast_to_u64; use gravity_utils::types::*; use std::cmp::min; -use std::sync::Arc; - -pub type EthSignerMiddleware = SignerMiddleware, LocalWallet>; -pub type EthClient = Arc; pub fn get_checkpoint_abi_encode( valset: &Valset, diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index 8a2eb7fcd..fe1972bd8 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -1,4 +1,5 @@ -use crate::utils::{EthClient, EthSignerMiddleware, GasCost, get_send_transaction_gas_price, get_valset_nonce}; +use crate::{types::{EthClient, EthSignerMiddleware}, + utils::{GasCost, get_send_transaction_gas_price, get_valset_nonce}}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; diff --git a/orchestrator/orchestrator/src/ethereum_event_watcher.rs b/orchestrator/orchestrator/src/ethereum_event_watcher.rs index e0c5b5f69..8b080bfec 100644 --- a/orchestrator/orchestrator/src/ethereum_event_watcher.rs +++ b/orchestrator/orchestrator/src/ethereum_event_watcher.rs @@ -8,7 +8,7 @@ use cosmos_gravity::build; use cosmos_gravity::query::get_last_event_nonce; use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::{Contact, Msg}; -use ethereum_gravity::utils::EthClient; +use ethereum_gravity::types::EthClient; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; diff --git a/orchestrator/orchestrator/src/get_with_retry.rs b/orchestrator/orchestrator/src/get_with_retry.rs index ba2fcada2..3c9fe975a 100644 --- a/orchestrator/orchestrator/src/get_with_retry.rs +++ b/orchestrator/orchestrator/src/get_with_retry.rs @@ -1,7 +1,7 @@ //! Basic utility functions to stubbornly get data use cosmos_gravity::query::get_last_event_nonce; use deep_space::address::Address as CosmosAddress; -use ethereum_gravity::utils::EthClient; +use ethereum_gravity::types::EthClient; use ethers::prelude::*; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use std::time::Duration; diff --git a/orchestrator/orchestrator/src/main_loop.rs b/orchestrator/orchestrator/src/main_loop.rs index 89112318b..27664ff11 100644 --- a/orchestrator/orchestrator/src/main_loop.rs +++ b/orchestrator/orchestrator/src/main_loop.rs @@ -20,7 +20,8 @@ use deep_space::client::ChainStatus; use deep_space::error::CosmosGrpcError; use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::{Contact, Msg}; -use ethereum_gravity::utils::{EthClient, get_gravity_id}; +use ethereum_gravity::types::EthClient; +use ethereum_gravity::utils::get_gravity_id; use ethers::{prelude::*, types::Address as EthAddress}; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::ethereum::bytes_to_hex_str; diff --git a/orchestrator/orchestrator/src/oracle_resync.rs b/orchestrator/orchestrator/src/oracle_resync.rs index 84b26d974..656270091 100644 --- a/orchestrator/orchestrator/src/oracle_resync.rs +++ b/orchestrator/orchestrator/src/oracle_resync.rs @@ -1,5 +1,5 @@ use deep_space::address::Address as CosmosAddress; -use ethereum_gravity::utils::EthClient; +use ethereum_gravity::types::EthClient; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; diff --git a/orchestrator/relayer/src/batch_relaying.rs b/orchestrator/relayer/src/batch_relaying.rs index f2d5ddee7..3e15ada7d 100644 --- a/orchestrator/relayer/src/batch_relaying.rs +++ b/orchestrator/relayer/src/batch_relaying.rs @@ -1,6 +1,6 @@ use cosmos_gravity::query::get_latest_transaction_batches; use cosmos_gravity::query::get_transaction_batch_signatures; -use ethereum_gravity::{one_eth_f32, submit_batch::send_eth_transaction_batch, utils::EthClient, +use ethereum_gravity::{one_eth_f32, submit_batch::send_eth_transaction_batch, types::EthClient, utils::get_tx_batch_nonce}; use ethers::prelude::*; use ethers::types::Address as EthAddress; diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index 14f896fdf..295a6f446 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -1,4 +1,4 @@ -use ethereum_gravity::utils::EthClient; +use ethereum_gravity::types::EthClient; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; diff --git a/orchestrator/relayer/src/logic_call_relaying.rs b/orchestrator/relayer/src/logic_call_relaying.rs index a5afecd20..fc02b30db 100644 --- a/orchestrator/relayer/src/logic_call_relaying.rs +++ b/orchestrator/relayer/src/logic_call_relaying.rs @@ -2,7 +2,8 @@ use cosmos_gravity::query::{get_latest_logic_calls, get_logic_call_signatures}; use ethereum_gravity::one_eth_f32; use ethereum_gravity::{ logic_call::send_eth_logic_call, - utils::{EthClient, get_logic_call_nonce}, + types::EthClient, + utils::get_logic_call_nonce, }; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; diff --git a/orchestrator/relayer/src/main_loop.rs b/orchestrator/relayer/src/main_loop.rs index 1abf7af80..39699b34b 100644 --- a/orchestrator/relayer/src/main_loop.rs +++ b/orchestrator/relayer/src/main_loop.rs @@ -2,7 +2,7 @@ use crate::{ batch_relaying::relay_batches, find_latest_valset::find_latest_valset, logic_call_relaying::relay_logic_calls, valset_relaying::relay_valsets, }; -use ethereum_gravity::utils::{EthClient, get_gravity_id}; +use ethereum_gravity::{types::EthClient, utils::get_gravity_id}; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use std::time::{Duration, Instant}; diff --git a/orchestrator/relayer/src/valset_relaying.rs b/orchestrator/relayer/src/valset_relaying.rs index 041be0d0b..f8c459070 100644 --- a/orchestrator/relayer/src/valset_relaying.rs +++ b/orchestrator/relayer/src/valset_relaying.rs @@ -5,7 +5,7 @@ use std::time::Duration; use cosmos_gravity::query::get_latest_valset; use cosmos_gravity::query::{get_all_valset_confirms, get_valset}; -use ethereum_gravity::{one_eth_f32, utils::EthClient, valset_update::send_eth_valset_update}; +use ethereum_gravity::{one_eth_f32, types::EthClient, valset_update::send_eth_valset_update}; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::{ethereum::downcast_to_f32, ethereum::bytes_to_hex_str, From f0bcc3af58b5d770cc8b14273cf650d85e49dfa0 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 19 Nov 2021 18:25:48 -0800 Subject: [PATCH 083/115] Don't assume ERC20 addresses come from the client --- orchestrator/ethereum_gravity/src/erc20_utils.rs | 6 ++++-- orchestrator/ethereum_gravity/src/send_to_cosmos.rs | 2 +- orchestrator/gorc/src/commands/eth_to_cosmos.rs | 2 +- orchestrator/gorc/src/commands/tx/eth.rs | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs index 352694a16..fd2523b6c 100644 --- a/orchestrator/ethereum_gravity/src/erc20_utils.rs +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -12,10 +12,11 @@ use std::time::Duration; pub async fn check_erc20_approved( erc20: Address, gravity_contract: Address, + address: Address, eth_client: EthClient, ) -> Result { let erc20_contract = ERC20::new(erc20, eth_client.clone()); - let contract_call = erc20_contract.allowance(eth_client.address(), gravity_contract); + let contract_call = erc20_contract.allowance(address, gravity_contract); let allowance = contract_call.call().await?; // TODO(bolten): verify if this check is sufficient/correct @@ -61,10 +62,11 @@ pub async fn approve_erc20_transfers( pub async fn get_erc20_balance( erc20: Address, + address: Address, eth_client: EthClient, ) -> Result { let erc20_contract = ERC20::new(erc20, eth_client.clone()); - let contract_call = erc20_contract.balance_of(eth_client.address()); + let contract_call = erc20_contract.balance_of(address); Ok(contract_call.call().await?) } \ No newline at end of file diff --git a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs index eac76b4a3..23bed749f 100644 --- a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs +++ b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs @@ -21,7 +21,7 @@ pub async fn send_to_cosmos( wait_timeout: Option, eth_client: EthClient, ) -> Result { - let approved = check_erc20_approved(erc20, gravity_contract, eth_client.clone()).await?; + let approved = check_erc20_approved(erc20, gravity_contract, eth_client.address(), eth_client.clone()).await?; if !approved { let txid = approve_erc20_transfers(erc20, gravity_contract, wait_timeout, eth_client.clone()).await?; trace!("ERC-20 approval for {} finished with txid {}", erc20, txid); diff --git a/orchestrator/gorc/src/commands/eth_to_cosmos.rs b/orchestrator/gorc/src/commands/eth_to_cosmos.rs index bd65a3173..32e5d0245 100644 --- a/orchestrator/gorc/src/commands/eth_to_cosmos.rs +++ b/orchestrator/gorc/src/commands/eth_to_cosmos.rs @@ -53,7 +53,7 @@ impl Runnable for EthToCosmosCmd { let init_amount = self.args.get(4).expect("amount is required"); let amount: U256 = init_amount.parse().unwrap(); - let erc20_balance = get_erc20_balance(erc20_address, eth_client.clone()).await + let erc20_balance = get_erc20_balance(erc20_address, ethereum_address, eth_client.clone()).await .expect("Failed to get balance, check ERC20 contract address"); let times = self.args.get(5).expect("times is required"); diff --git a/orchestrator/gorc/src/commands/tx/eth.rs b/orchestrator/gorc/src/commands/tx/eth.rs index 9d7b16607..0780fec29 100644 --- a/orchestrator/gorc/src/commands/tx/eth.rs +++ b/orchestrator/gorc/src/commands/tx/eth.rs @@ -78,7 +78,7 @@ impl Runnable for SendToCosmos { .parse() .expect("Expected amount in xx.yy format"); - let erc20_balance = get_erc20_balance(erc20_contract, eth_client.clone()) + let erc20_balance = get_erc20_balance(erc20_contract, eth_client.address(), eth_client.clone()) .await .expect("Failed to get balance, check ERC20 contract address"); From 4484196972823dc7c2dd7111da762d6b71dbff77 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 19 Nov 2021 18:26:24 -0800 Subject: [PATCH 084/115] Add a TODO around downcast tests --- orchestrator/gravity_utils/src/ethereum.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/orchestrator/gravity_utils/src/ethereum.rs b/orchestrator/gravity_utils/src/ethereum.rs index cb7f9e369..fa70943b6 100644 --- a/orchestrator/gravity_utils/src/ethereum.rs +++ b/orchestrator/gravity_utils/src/ethereum.rs @@ -53,6 +53,8 @@ pub fn hex_str_to_bytes(s: &str) -> Result, GravityError> { Ok(bytes) } +// TODO(bolten): add tests to make sure the downcast panics catch + #[test] fn encode_bytes() { assert_eq!(bytes_to_hex_str(&[0xf]), "0f".to_owned()); From 0be8e7da5e0c8bd25b9e3ae441b61187288af9f5 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 19 Nov 2021 18:40:05 -0800 Subject: [PATCH 085/115] No reason to use "as EthProvider" in connections --- orchestrator/gravity_utils/src/connection_prep.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/orchestrator/gravity_utils/src/connection_prep.rs b/orchestrator/gravity_utils/src/connection_prep.rs index b6285efd5..c762d209a 100644 --- a/orchestrator/gravity_utils/src/connection_prep.rs +++ b/orchestrator/gravity_utils/src/connection_prep.rs @@ -6,7 +6,7 @@ use deep_space::client::ChainStatus; use deep_space::Address as CosmosAddress; use deep_space::Contact; use ethers::prelude::*; -use ethers::providers::Provider as EthProvider; +use ethers::providers::Provider; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_proto::gravity::DelegateKeysByEthereumSignerRequest; @@ -20,7 +20,7 @@ use tonic::transport::Channel; use url::Url; pub struct Connections { - pub eth_provider: Option>, + pub eth_provider: Option>, pub grpc: Option>, pub contact: Option, } @@ -119,7 +119,7 @@ pub async fn create_rpc_connections( let eth_url = eth_rpc_url.trim_end_matches('/'); // TODO(bolten): should probably set a non-default interval, but what is the appropriate // value? - let base_eth_provider = EthProvider::::try_from(eth_url).unwrap_or_else(|_| { + let base_eth_provider = Provider::::try_from(eth_url).unwrap_or_else(|_| { panic!("Could not instantiate Ethereum HTTP provider: {}", eth_url) }); let try_base = base_eth_provider.get_block_number().await; @@ -138,14 +138,14 @@ pub async fn create_rpc_connections( let prefix = url.scheme(); let ipv6_url = format!("{}://::1:{}", prefix, port); let ipv4_url = format!("{}://127.0.0.1:{}", prefix, port); - let ipv6_eth_provider = EthProvider::::try_from(ipv6_url.as_str()) + let ipv6_eth_provider = Provider::::try_from(ipv6_url.as_str()) .unwrap_or_else(|_| { panic!( "Could not instantiate Ethereum HTTP provider: {}", &ipv6_url ) }); - let ipv4_eth_provider = EthProvider::::try_from(ipv4_url.as_str()) + let ipv4_eth_provider = Provider::::try_from(ipv4_url.as_str()) .unwrap_or_else(|_| { panic!( "Could not instantiate Ethereum HTTP provider: {}", @@ -174,7 +174,7 @@ pub async fn create_rpc_connections( // transparently upgrade to https if available, we can't transparently downgrade for obvious security reasons let https_on_80_url = format!("https://{}:80", body); let https_on_443_url = format!("https://{}:443", body); - let https_on_80_eth_provider = EthProvider::::try_from( + let https_on_80_eth_provider = Provider::::try_from( https_on_80_url.as_str(), ) .unwrap_or_else(|_| { @@ -183,7 +183,7 @@ pub async fn create_rpc_connections( &https_on_80_url ) }); - let https_on_443_eth_provider = EthProvider::::try_from( + let https_on_443_eth_provider = Provider::::try_from( https_on_443_url.as_str(), ) .unwrap_or_else(|_| { From 6939cc609384248af545365e27aebd2813b245e0 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 19 Nov 2021 19:12:06 -0800 Subject: [PATCH 086/115] Re-order events to account for partial failure --- .../src/ethereum_event_watcher.rs | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/orchestrator/orchestrator/src/ethereum_event_watcher.rs b/orchestrator/orchestrator/src/ethereum_event_watcher.rs index 8b080bfec..77cf4c418 100644 --- a/orchestrator/orchestrator/src/ethereum_event_watcher.rs +++ b/orchestrator/orchestrator/src/ethereum_event_watcher.rs @@ -68,27 +68,28 @@ pub async fn check_for_events( valset_updated_filter = valset_updated_filter.select(search_range.clone()); let erc20_deployed_events = eth_client.get_logs(&erc20_deployed_filter).await?; - let logic_call_events = eth_client.get_logs(&logic_call_filter).await?; - let send_to_cosmos_events = eth_client.get_logs(&send_to_cosmos_filter).await?; - let transaction_batch_events = eth_client.get_logs(&transaction_batch_filter).await?; - let valset_updated_events = eth_client.get_logs(&valset_updated_filter).await?; - debug!("ERC20 events detected {:?}", erc20_deployed_events); - debug!("Logic call events detected {:?}", logic_call_events); - debug!("Send to Cosmos events detected {:?}", send_to_cosmos_events); - debug!("Batch events detected {:?}", transaction_batch_events); - debug!("Valset events detected {:?}", valset_updated_events); - let erc20_deployed_events = Erc20DeployedEvent::from_logs(&erc20_deployed_events)?; - let logic_call_events = LogicCallExecutedEvent::from_logs(&logic_call_events)?; - let send_to_cosmos_events = SendToCosmosEvent::from_logs(&send_to_cosmos_events, &prefix)?; - let transaction_batch_events = TransactionBatchExecutedEvent::from_logs(&transaction_batch_events)?; - let valset_updated_events = ValsetUpdatedEvent::from_logs(&valset_updated_events)?; - debug!("parsed erc20 deploys {:?}", erc20_deployed_events); + + let logic_call_events = eth_client.get_logs(&logic_call_filter).await?; + debug!("Logic call events detected {:?}", logic_call_events); + let logic_call_events = LogicCallExecutedEvent::from_logs(&logic_call_events)?; debug!("parsed logic call executions {:?}", logic_call_events); + + let send_to_cosmos_events = eth_client.get_logs(&send_to_cosmos_filter).await?; + debug!("Send to Cosmos events detected {:?}", send_to_cosmos_events); + let send_to_cosmos_events = SendToCosmosEvent::from_logs(&send_to_cosmos_events, &prefix)?; debug!("parsed send to cosmos events {:?}", send_to_cosmos_events); + + let transaction_batch_events = eth_client.get_logs(&transaction_batch_filter).await?; + debug!("Batch events detected {:?}", transaction_batch_events); + let transaction_batch_events = TransactionBatchExecutedEvent::from_logs(&transaction_batch_events)?; debug!("parsed batches {:?}", transaction_batch_events); + + let valset_updated_events = eth_client.get_logs(&valset_updated_filter).await?; + debug!("Valset events detected {:?}", valset_updated_events); + let valset_updated_events = ValsetUpdatedEvent::from_logs(&valset_updated_events)?; debug!("parsed valsets {:?}", valset_updated_events); // note that starting block overlaps with our last checked block, because we have to deal with From c72e1232631c0f1b135903a3bbbeee0e10418d4c Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 19 Nov 2021 23:29:09 -0800 Subject: [PATCH 087/115] fully compilable refactor --- orchestrator/Cargo.lock | 3 + .../ethereum_gravity/src/erc20_utils.rs | 28 ++++ orchestrator/test_runner/Cargo.toml | 3 + .../test_runner/src/arbitrary_logic.rs | 4 +- orchestrator/test_runner/src/bootstrapping.rs | 9 +- orchestrator/test_runner/src/happy_path.rs | 96 +++++------ orchestrator/test_runner/src/happy_path_v2.rs | 34 ++-- orchestrator/test_runner/src/main.rs | 48 ++++-- .../test_runner/src/orch_keys_update.rs | 16 +- .../src/transaction_stress_test.rs | 51 +++--- orchestrator/test_runner/src/utils.rs | 157 +++++++++--------- orchestrator/test_runner/src/valset_stress.rs | 6 +- 12 files changed, 246 insertions(+), 209 deletions(-) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index ecabda67c..a9906b6d7 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -4496,9 +4496,12 @@ dependencies = [ "docopt", "env_logger", "ethereum_gravity", + "ethers", "futures", + "gravity_abi", "gravity_proto", "gravity_utils", + "hex", "lazy_static", "log", "orchestrator", diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs index fd2523b6c..5045ab6ca 100644 --- a/orchestrator/ethereum_gravity/src/erc20_utils.rs +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -69,4 +69,32 @@ pub async fn get_erc20_balance( let contract_call = erc20_contract.balance_of(address); Ok(contract_call.call().await?) +} + +// TODO(bolten): is this dead code? +pub async fn erc20_transfer( + erc20: Address, + destination: Address, + amount: U256, + eth_client: EthClient, +) -> Result { + let erc20_contract = ERC20::new(erc20, eth_client.clone()); + let contract_call = erc20_contract.transfer(destination, amount); + + let pending_tx = contract_call.send().await?; + let tx_hash = *pending_tx; + info!("Transferring {} ERC-20 {} from {} to {} with txid {}", + amount, erc20, eth_client.address(), destination, tx_hash + ); + // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? + // additionally we are mirroring only waiting for 1 confirmation by leaving that as default + let pending_tx = pending_tx.interval(Duration::from_secs(1)); + let potential_error = GravityError::GravityContractError(format!( + "Did not receive transaction receipt when transferring ERC-20 {}: {}", erc20, tx_hash) + ); + + match pending_tx.await? { + Some(receipt) => Ok(receipt.transaction_hash), + None => Err(potential_error) + } } \ No newline at end of file diff --git a/orchestrator/test_runner/Cargo.toml b/orchestrator/test_runner/Cargo.toml index dd41f1125..b6e4af85e 100644 --- a/orchestrator/test_runner/Cargo.toml +++ b/orchestrator/test_runner/Cargo.toml @@ -12,6 +12,7 @@ edition = "2018" [dependencies] ethereum_gravity = {path = "../ethereum_gravity"} cosmos_gravity = {path = "../cosmos_gravity"} +gravity_abi = { path = "../gravity_abi" } gravity_utils = {path = "../gravity_utils"} gravity_proto = {path = "../gravity_proto/"} orchestrator = {path = "../orchestrator/"} @@ -20,6 +21,7 @@ deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} serde_derive = "1.0" clarity = "0.4.11" docopt = "1" +ethers = "0.5.4" serde = "1.0" actix = "0.11" actix-web = {version = "3", features=["openssl"]} @@ -33,3 +35,4 @@ tokio = "1.4.0" rand = "0.8" tonic = "0.4" futures = "0.3" +hex = "0.4.3" diff --git a/orchestrator/test_runner/src/arbitrary_logic.rs b/orchestrator/test_runner/src/arbitrary_logic.rs index 21d69bf05..6c071d24c 100644 --- a/orchestrator/test_runner/src/arbitrary_logic.rs +++ b/orchestrator/test_runner/src/arbitrary_logic.rs @@ -3,13 +3,13 @@ use crate::TOTAL_TIMEOUT; use deep_space::Contact; +use ethers::prelude::*; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use tokio::time::sleep as delay_for; use tonic::transport::Channel; -use web30::client::Web3; pub async fn arbitrary_logic_test( - _web30: &Web3, + _eth_provider: &Provider, _grpc_client: GravityQueryClient, _contact: &Contact, ) { diff --git a/orchestrator/test_runner/src/bootstrapping.rs b/orchestrator/test_runner/src/bootstrapping.rs index 15bac577e..cbf32999c 100644 --- a/orchestrator/test_runner/src/bootstrapping.rs +++ b/orchestrator/test_runner/src/bootstrapping.rs @@ -1,11 +1,11 @@ use crate::utils::ValidatorKeys; -use clarity::Address as EthAddress; -use clarity::PrivateKey as EthPrivateKey; +use ethers::core::k256::ecdsa::SigningKey; +use ethers::types::Address as EthAddress; use deep_space::private_key::PrivateKey as CosmosPrivateKey; use std::fs::File; use std::io::{BufRead, BufReader, Read}; -pub fn parse_ethereum_keys() -> Vec { +pub fn parse_ethereum_keys() -> Vec { let filename = "/testdata/validator-eth-keys"; let file = File::open(filename).expect("Failed to find eth keys"); let reader = BufReader::new(file); @@ -13,7 +13,8 @@ pub fn parse_ethereum_keys() -> Vec { for line in reader.lines() { let line = line.expect("Error reading eth-keys file!"); - let key: EthPrivateKey = line.parse().unwrap(); + let key_hex = hex::decode(line.strip_prefix("0x").unwrap()).unwrap(); + let key: SigningKey = SigningKey::from_bytes(&key_hex).unwrap(); ret.push(key); } ret diff --git a/orchestrator/test_runner/src/happy_path.rs b/orchestrator/test_runner/src/happy_path.rs index 826a3b700..af0a15abc 100644 --- a/orchestrator/test_runner/src/happy_path.rs +++ b/orchestrator/test_runner/src/happy_path.rs @@ -3,30 +3,32 @@ use crate::get_fee; use crate::get_gas_price; use crate::utils::*; use crate::MINER_ADDRESS; -use crate::MINER_PRIVATE_KEY; +use crate::MINER_CLIENT; use crate::OPERATION_TIMEOUT; use crate::TOTAL_TIMEOUT; -use clarity::PrivateKey as EthPrivateKey; -use clarity::{Address as EthAddress, Uint256}; +use clarity::Uint256; use cosmos_gravity::send::{send_request_batch_tx, send_to_eth}; use cosmos_gravity::{build, query::get_oldest_unsigned_transaction_batch, send}; use deep_space::address::Address as CosmosAddress; use deep_space::coin::Coin; use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::Contact; +use ethereum_gravity::erc20_utils::get_erc20_balance; use ethereum_gravity::utils::get_valset_nonce; use ethereum_gravity::{send_to_cosmos::send_to_cosmos, utils::get_tx_batch_nonce}; +use ethers::core::k256::ecdsa::SigningKey; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::types::SendToCosmosEvent; use rand::Rng; +use std::str::FromStr; use std::time::Duration; use std::time::Instant; use tokio::time::sleep as delay_for; use tonic::transport::Channel; -use web30::client::Web3; pub async fn happy_path_test( - web30: &Web3, grpc_client: GravityQueryClient, contact: &Contact, keys: Vec, @@ -49,10 +51,10 @@ pub async fn happy_path_test( if !validator_out { for _ in 0u32..2 { - test_valset_update(&web30, contact, &keys, gravity_address).await; + test_valset_update(contact, &keys, gravity_address).await; } } else { - wait_for_nonzero_valset(&web30, gravity_address).await; + wait_for_nonzero_valset(gravity_address).await; } // generate an address for coin sending tests, this ensures test imdepotency @@ -62,15 +64,15 @@ pub async fn happy_path_test( let dest_cosmos_address = dest_cosmos_private_key .to_address(CosmosAddress::DEFAULT_PREFIX) .unwrap(); - let dest_eth_private_key = EthPrivateKey::from_slice(&secret).unwrap(); - let dest_eth_address = dest_eth_private_key.to_public_key().unwrap(); + let dest_eth_private_key = SigningKey::from_bytes(&secret).unwrap(); + let dest_eth_wallet = LocalWallet::from(dest_eth_private_key.clone()); + let dest_eth_address = dest_eth_wallet.address(); // the denom and amount of the token bridged from Ethereum -> Cosmos // so the denom is the gravity token name // Send a token 3 times for _ in 0u32..3 { test_erc20_deposit( - &web30, &contact, dest_cosmos_address, gravity_address, @@ -98,7 +100,6 @@ pub async fn happy_path_test( test_batch( &contact, &mut grpc_client, - &web30, dest_eth_address, gravity_address, keys[0].validator_key, @@ -108,15 +109,15 @@ pub async fn happy_path_test( .await; } -pub async fn wait_for_nonzero_valset(web30: &Web3, gravity_address: EthAddress) { +pub async fn wait_for_nonzero_valset(gravity_address: EthAddress) { let start = Instant::now(); - let mut current_eth_valset_nonce = get_valset_nonce(gravity_address, *MINER_ADDRESS, &web30) + let mut current_eth_valset_nonce = get_valset_nonce(gravity_address, (*MINER_CLIENT).clone()) .await .expect("Failed to get current eth valset"); while 0 == current_eth_valset_nonce { info!("Validator set is not yet updated to >0, waiting"); - current_eth_valset_nonce = get_valset_nonce(gravity_address, *MINER_ADDRESS, &web30) + current_eth_valset_nonce = get_valset_nonce(gravity_address, (*MINER_CLIENT).clone()) .await .expect("Failed to get current eth valset"); delay_for(Duration::from_secs(4)).await; @@ -127,14 +128,13 @@ pub async fn wait_for_nonzero_valset(web30: &Web3, gravity_address: EthAddress) } pub async fn test_valset_update( - web30: &Web3, contact: &Contact, keys: &[ValidatorKeys], gravity_address: EthAddress, ) { // if we don't do this the orchestrators may run ahead of us and we'll be stuck here after // getting credit for two loops when we did one - let starting_eth_valset_nonce = get_valset_nonce(gravity_address, *MINER_ADDRESS, &web30) + let starting_eth_valset_nonce = get_valset_nonce(gravity_address, (*MINER_CLIENT).clone()) .await .expect("Failed to get starting eth valset"); let start = Instant::now(); @@ -197,7 +197,7 @@ pub async fn test_valset_update( break; } - let mut current_eth_valset_nonce = get_valset_nonce(gravity_address, *MINER_ADDRESS, &web30) + let mut current_eth_valset_nonce = get_valset_nonce(gravity_address, (*MINER_CLIENT).clone()) .await .expect("Failed to get current eth valset"); @@ -206,7 +206,7 @@ pub async fn test_valset_update( "Validator set is not yet updated to >{}, waiting", starting_eth_valset_nonce ); - current_eth_valset_nonce = get_valset_nonce(gravity_address, *MINER_ADDRESS, &web30) + current_eth_valset_nonce = get_valset_nonce(gravity_address, (*MINER_CLIENT).clone()) .await .expect("Failed to get current eth valset"); delay_for(Duration::from_secs(4)).await; @@ -221,13 +221,13 @@ pub async fn test_valset_update( /// this function tests Ethereum -> Cosmos async fn test_erc20_deposit( - web30: &Web3, contact: &Contact, dest: CosmosAddress, gravity_address: EthAddress, erc20_address: EthAddress, - amount: Uint256, + amount: U256, ) { + let amount_uint256 = Uint256::from_str(amount.to_string().as_str()).unwrap(); let start_coin = check_cosmos_balance("gravity", dest, &contact).await; info!( "Sending to Cosmos from {} to {} with amount {}", @@ -239,10 +239,8 @@ async fn test_erc20_deposit( gravity_address, amount.clone(), dest, - *MINER_PRIVATE_KEY, Some(TOTAL_TIMEOUT), - &web30, - vec![], + (*MINER_CLIENT).clone(), ) .await .expect("Failed to send tokens to Cosmos"); @@ -255,7 +253,7 @@ async fn test_erc20_deposit( check_cosmos_balance("gravity", dest, &contact).await, ) { (Some(start_coin), Some(end_coin)) => { - if start_coin.amount + amount.clone() == end_coin.amount + if start_coin.amount + amount_uint256.clone() == end_coin.amount && start_coin.denom == end_coin.denom { info!( @@ -266,7 +264,7 @@ async fn test_erc20_deposit( } } (None, Some(end_coin)) => { - if amount == end_coin.amount { + if amount_uint256 == end_coin.amount { info!( "Successfully bridged ERC20 {}{} to Cosmos! Balance is now {}{}", amount, end_coin.denom, end_coin.amount, end_coin.denom @@ -288,7 +286,6 @@ async fn test_erc20_deposit( async fn test_batch( contact: &Contact, grpc_client: &mut GravityQueryClient, - web30: &Web3, dest_eth_address: EthAddress, gravity_address: EthAddress, requester_cosmos_private_key: CosmosPrivateKey, @@ -349,7 +346,7 @@ async fn test_batch( .expect("Failed to get batch to sign"); let mut current_eth_batch_nonce = - get_tx_batch_nonce(gravity_address, erc20_contract, *MINER_ADDRESS, &web30) + get_tx_batch_nonce(gravity_address, erc20_contract, (*MINER_CLIENT).clone()) .await .expect("Failed to get current eth valset"); let starting_batch_nonce = current_eth_batch_nonce; @@ -361,7 +358,7 @@ async fn test_batch( starting_batch_nonce ); current_eth_batch_nonce = - get_tx_batch_nonce(gravity_address, erc20_contract, *MINER_ADDRESS, &web30) + get_tx_batch_nonce(gravity_address, erc20_contract, (*MINER_CLIENT).clone()) .await .expect("Failed to get current eth tx batch nonce"); delay_for(Duration::from_secs(4)).await; @@ -370,30 +367,27 @@ async fn test_batch( } } - let txid = web30 - .send_transaction( - dest_eth_address, - Vec::new(), - 1_000_000_000_000_000_000u128.into(), - *MINER_ADDRESS, - *MINER_PRIVATE_KEY, - vec![], - ) - .await - .expect("Failed to send Eth to validator {}"); - web30 - .wait_for_transaction(txid, TOTAL_TIMEOUT, None) - .await - .unwrap(); + let eth_client = (*MINER_CLIENT).clone(); + let tx = TransactionRequest { + from: Some(eth_client.address()), + to: Some(NameOrAddress::Address(dest_eth_address)), + gas: None, + gas_price: None, + value: Some(1_000_000_000_000_000_000u128.into()), + data: Some(Vec::new().into()), + nonce: None, + }; + + let pending_tx = eth_client.send_transaction(tx, None).await.unwrap(); + pending_tx.await.unwrap(); + + let amount_u256 = U256::from_str(amount.to_string().as_str()).unwrap(); // we have to send this address one eth so that it can perform contract calls - send_one_eth(dest_eth_address, web30).await; + send_one_eth(dest_eth_address, eth_client.clone()).await; assert_eq!( - web30 - .get_erc20_balance(erc20_contract, dest_eth_address) - .await - .unwrap(), - amount + get_erc20_balance(erc20_contract, dest_eth_address, eth_client.clone()).await.unwrap(), + amount_u256 ); info!( "Successfully updated txbatch nonce to {} and sent {}{} tokens to Ethereum!", @@ -405,10 +399,10 @@ async fn test_batch( // already been submitted to test the nonce functionality. #[allow(clippy::too_many_arguments)] async fn submit_duplicate_erc20_send( - nonce: Uint256, + nonce: U256, contact: &Contact, erc20_address: EthAddress, - amount: Uint256, + amount: U256, receiver: CosmosAddress, keys: &[ValidatorKeys], ) { diff --git a/orchestrator/test_runner/src/happy_path_v2.rs b/orchestrator/test_runner/src/happy_path_v2.rs index 693008b80..c4cb9ffc1 100644 --- a/orchestrator/test_runner/src/happy_path_v2.rs +++ b/orchestrator/test_runner/src/happy_path_v2.rs @@ -1,36 +1,40 @@ //! This is the happy path test for Cosmos to Ethereum asset transfers, meaning assets originated on Cosmos -use std::time::{Duration, Instant}; - +use crate::MINER_CLIENT; use crate::utils::get_user_key; use crate::utils::send_one_eth; use crate::TOTAL_TIMEOUT; use crate::{get_fee, utils::ValidatorKeys}; -use clarity::Address as EthAddress; use clarity::Uint256; use cosmos_gravity::send::{send_request_batch_tx, send_to_eth}; use deep_space::coin::Coin; use deep_space::Contact; +use ethereum_gravity::erc20_utils::get_erc20_balance; use ethereum_gravity::{deploy_erc20::deploy_erc20, utils::get_event_nonce}; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::{ query_client::QueryClient as GravityQueryClient, DenomToErc20Request, }; +use std::str::FromStr; +use std::sync::Arc; +use std::time::{Duration, Instant}; use tokio::time::sleep as delay_for; use tonic::transport::Channel; -use web30::client::Web3; pub async fn happy_path_test_v2( - web30: &Web3, + eth_provider: &Provider, grpc_client: GravityQueryClient, contact: &Contact, keys: Vec, gravity_address: EthAddress, ) { let mut grpc_client = grpc_client; + let eth_wallet = LocalWallet::from(keys[0].eth_key.clone()); + let eth_client = Arc::new(SignerMiddleware::new(eth_provider.clone(), eth_wallet)); let starting_event_nonce = get_event_nonce( gravity_address, - keys[0].eth_key.to_public_key().unwrap(), - web30, + eth_client.clone() ) .await .unwrap(); @@ -44,17 +48,14 @@ pub async fn happy_path_test_v2( token_to_send_to_eth_display_name.clone(), 6, gravity_address, - web30, Some(TOTAL_TIMEOUT), - keys[0].eth_key, - vec![], + eth_client.clone() ) .await .unwrap(); let ending_event_nonce = get_event_nonce( gravity_address, - keys[0].eth_key.to_public_key().unwrap(), - web30, + eth_client.clone() ) .await .unwrap(); @@ -137,7 +138,7 @@ pub async fn happy_path_test_v2( ); // send the user some eth, they only need this to check their // erc20 balance, so a pretty minor usecase - send_one_eth(user.eth_address, web30).await; + send_one_eth(user.eth_address, (*MINER_CLIENT).clone()).await; info!("Sent 1 eth to user address {}", user.eth_address); let res = send_to_eth( @@ -172,13 +173,14 @@ pub async fn happy_path_test_v2( info!("Waiting for batch to be signed and relayed to Ethereum"); let start = Instant::now(); while Instant::now() - start < TOTAL_TIMEOUT { - let balance = web30 - .get_erc20_balance(erc20_contract, user.eth_address) - .await; + let balance = get_erc20_balance( + erc20_contract, user.eth_address, (*MINER_CLIENT).clone() + ).await; if balance.is_err() { continue; } let balance = balance.unwrap(); + let balance = Uint256::from_str(balance.to_string().as_str()).unwrap(); if balance == amount_to_bridge { info!( "Successfully bridged {} Cosmos asset {} to Ethereum!", diff --git a/orchestrator/test_runner/src/main.rs b/orchestrator/test_runner/src/main.rs index ae99bb8d0..668260c45 100644 --- a/orchestrator/test_runner/src/main.rs +++ b/orchestrator/test_runner/src/main.rs @@ -11,17 +11,23 @@ extern crate lazy_static; use crate::bootstrapping::*; use crate::utils::*; use arbitrary_logic::arbitrary_logic_test; -use clarity::PrivateKey as EthPrivateKey; -use clarity::{Address as EthAddress, Uint256}; +use clarity::Uint256; use cosmos_gravity::utils::wait_for_cosmos_online; use deep_space::coin::Coin; use deep_space::Address as CosmosAddress; use deep_space::Contact; +use ethereum_gravity::types::EthClient; +use ethers::core::k256::ecdsa::SigningKey; +use ethers::prelude::*; +use ethers::providers::Provider; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; +use gravity_utils::ethereum::hex_str_to_bytes; use happy_path::happy_path_test; use happy_path_v2::happy_path_test_v2; use orch_keys_update::orch_keys_update; -use std::{env, time::Duration}; +use std::convert::TryFrom; +use std::{env, sync::Arc, time::Duration}; use transaction_stress_test::transaction_stress_test; use valset_stress::validator_set_stress_test; @@ -59,11 +65,17 @@ lazy_static! { // this key is the private key for the public key defined in tests/assets/ETHGenesis.json // where the full node / miner sends its rewards. Therefore it's always going // to have a lot of ETH to pay for things like contract deployments - static ref MINER_PRIVATE_KEY: EthPrivateKey = - "0xb1bab011e03a9862664706fc3bbaa1b16651528e5f0e7fbfcbfdd8be302a13e7" - .parse() - .unwrap(); - static ref MINER_ADDRESS: EthAddress = MINER_PRIVATE_KEY.to_public_key().unwrap(); + static ref MINER_PRIVATE_KEY: SigningKey = + SigningKey::from_bytes(hex_str_to_bytes( + "0xb1bab011e03a9862664706fc3bbaa1b16651528e5f0e7fbfcbfdd8be302a13e7").unwrap().as_slice() + ).unwrap(); + static ref MINER_WALLET: LocalWallet = LocalWallet::from((*MINER_PRIVATE_KEY).clone()); + static ref MINER_ADDRESS: EthAddress = (*MINER_WALLET).address(); + static ref MINER_PROVIDER: Provider = Provider::::try_from((*ETH_NODE).clone()).unwrap(); + static ref MINER_SIGNER: SignerMiddleware, LocalWallet> = + SignerMiddleware::new((*MINER_PROVIDER).clone(), (*MINER_WALLET).clone()); + static ref MINER_CLIENT: EthClient = Arc::new((*MINER_SIGNER).clone()); + } /// Gets the standard non-token fee for the testnet. We deploy the test chain with STAKE @@ -89,11 +101,15 @@ pub fn get_chain_id() -> String { "gravity-test".to_string() } -pub fn one_eth() -> Uint256 { +pub fn one_eth() -> U256 { 1000000000000000000u128.into() } -pub fn one_hundred_eth() -> Uint256 { +pub fn one_hundred_eth() -> U256 { + (1000000000000000000u128 * 100).into() +} + +pub fn one_hundred_eth_uint256() -> Uint256 { (1000000000000000000u128 * 100).into() } @@ -123,7 +139,7 @@ pub async fn main() { let grpc_client = GravityQueryClient::connect(COSMOS_NODE_GRPC.as_str()) .await .unwrap(); - let web30 = web30::client::Web3::new(ETH_NODE.as_str(), OPERATION_TIMEOUT); + let eth_provider = Provider::::try_from((*ETH_NODE).clone()).unwrap(); let keys = get_keys(); // // if we detect this env var we are only deploying contracts, do that then exit. @@ -164,7 +180,6 @@ pub async fn main() { if test_type == "VALIDATOR_OUT" { info!("Starting Validator out test"); happy_path_test( - &web30, grpc_client, &contact, keys, @@ -182,19 +197,19 @@ pub async fn main() { CosmosAddress::DEFAULT_PREFIX, ) .unwrap(); - transaction_stress_test(&web30, &contact, keys, gravity_address, erc20_addresses).await; + transaction_stress_test(ð_provider, &contact, keys, gravity_address, erc20_addresses).await; return; } else if test_type == "VALSET_STRESS" { info!("Starting valset stress test"); - validator_set_stress_test(&web30, &contact, keys, gravity_address).await; + validator_set_stress_test(&contact, keys, gravity_address).await; return; } else if test_type == "V2_HAPPY_PATH" { info!("Starting happy path for Gravity v2"); - happy_path_test_v2(&web30, grpc_client, &contact, keys, gravity_address).await; + happy_path_test_v2(ð_provider, grpc_client, &contact, keys, gravity_address).await; return; } else if test_type == "ARBITRARY_LOGIC" { info!("Starting arbitrary logic tests!"); - arbitrary_logic_test(&web30, grpc_client, &contact).await; + arbitrary_logic_test(ð_provider, grpc_client, &contact).await; return; } else if test_type == "ORCHESTRATOR_KEYS" { info!("Starting orchestrator key update tests!"); @@ -204,7 +219,6 @@ pub async fn main() { } info!("Starting Happy path test"); happy_path_test( - &web30, grpc_client, &contact, keys, diff --git a/orchestrator/test_runner/src/orch_keys_update.rs b/orchestrator/test_runner/src/orch_keys_update.rs index 34ff5804d..054fd3a76 100644 --- a/orchestrator/test_runner/src/orch_keys_update.rs +++ b/orchestrator/test_runner/src/orch_keys_update.rs @@ -1,13 +1,12 @@ //! This test verifies that live updating of orchestrator keys works correctly -use crate::get_fee; use crate::utils::ValidatorKeys; -use clarity::Address as EthAddress; -use clarity::PrivateKey as EthPrivateKey; use cosmos_gravity::send::update_gravity_delegate_addresses; use deep_space::address::Address as CosmosAddress; use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::Contact; +use ethers::{core::k256::ecdsa::SigningKey, prelude::*}; +use ethers::types::Address as EthAddress; use gravity_proto::gravity::{ query_client::QueryClient as GravityQueryClient, DelegateKeysByEthereumSignerRequest, DelegateKeysByOrchestratorRequest, @@ -28,7 +27,7 @@ pub async fn orch_keys_update( // just to test that we have the right keys from the gentx info!("About to check already set delegate addresses"); for k in keys.iter() { - let eth_address = k.eth_key.to_public_key().unwrap(); + let eth_address = LocalWallet::from(k.eth_key.clone()).address(); let orch_address = k.orch_key.to_address(&contact.get_prefix()).unwrap(); let eth_response = grpc_client .delegate_keys_by_ethereum_signer(DelegateKeysByEthereumSignerRequest { @@ -62,7 +61,8 @@ pub async fn orch_keys_update( let mut rng = rand::thread_rng(); let secret: [u8; 32] = rng.gen(); // generate some new keys to replace the old ones - let ethereum_key = EthPrivateKey::from_slice(&secret).unwrap(); + let ethereum_key = SigningKey::from_bytes(&secret).unwrap(); + let ethereum_wallet = LocalWallet::from(ethereum_key.clone()); let cosmos_key = CosmosPrivateKey::from_secret(&secret); // update the keys in the key list k.eth_key = ethereum_key; @@ -71,16 +71,16 @@ pub async fn orch_keys_update( info!( "Signing and submitting Delegate addresses {} for validator {}", - ethereum_key.to_public_key().unwrap(), + ethereum_wallet.address(), cosmos_address, ); // send in the new delegate keys signed by the validator address update_gravity_delegate_addresses( &contact, - ethereum_key.to_public_key().unwrap(), + ethereum_wallet.address(), cosmos_address, k.validator_key, - k.eth_key, + ethereum_wallet, (0f64,"".to_string()), 2.0, ) diff --git a/orchestrator/test_runner/src/transaction_stress_test.rs b/orchestrator/test_runner/src/transaction_stress_test.rs index 92cabcdfd..195189705 100644 --- a/orchestrator/test_runner/src/transaction_stress_test.rs +++ b/orchestrator/test_runner/src/transaction_stress_test.rs @@ -1,16 +1,14 @@ -use crate::{get_fee, one_eth, one_hundred_eth, utils::*, TOTAL_TIMEOUT}; -use clarity::Address as EthAddress; +use crate::{MINER_CLIENT, one_eth, one_hundred_eth, one_hundred_eth_uint256, utils::*, TOTAL_TIMEOUT}; +use clarity::Uint256; use cosmos_gravity::send::{send_request_batch_tx, send_to_eth}; use deep_space::coin::Coin; use deep_space::Contact; -use ethereum_gravity::{send_to_cosmos::send_to_cosmos, utils::get_tx_batch_nonce}; +use ethereum_gravity::{erc20_utils::get_erc20_balance, send_to_cosmos::send_to_cosmos, utils::get_tx_batch_nonce}; +use ethers::prelude::*; +use ethers::types::Address as EthAddress; use futures::future::join_all; -use std::{ - collections::HashSet, - time::{Duration, Instant}, -}; +use std::{collections::HashSet, str::FromStr, sync::Arc, time::{Duration, Instant}}; use tokio::time::sleep as delay_for; -use web30::client::Web3; const TIMEOUT: Duration = Duration::from_secs(120); @@ -29,7 +27,7 @@ const NUM_USERS: usize = 100; /// transactions and producing large batches #[allow(clippy::too_many_arguments)] pub async fn transaction_stress_test( - web30: &Web3, + eth_provider: &Provider, contact: &Contact, keys: Vec, gravity_address: EthAddress, @@ -48,39 +46,32 @@ pub async fn transaction_stress_test( let mut eth_destinations = Vec::new(); eth_destinations.extend(sending_eth_addresses.clone()); eth_destinations.extend(dest_eth_addresses); - send_eth_bulk(one_eth(), ð_destinations, web30).await; + send_eth_bulk(one_eth(), ð_destinations, (*MINER_CLIENT).clone()).await; info!("Sent {} addresses 1 ETH", NUM_USERS); // now we need to send all the sending eth addresses erc20's to send for token in erc20_addresses.iter() { - send_erc20_bulk(one_hundred_eth(), *token, &sending_eth_addresses, web30).await; + send_erc20_bulk(one_hundred_eth(), *token, &sending_eth_addresses, (*MINER_CLIENT).clone()).await; info!("Sent {} addresses 100 {}", NUM_USERS, token); } for token in erc20_addresses.iter() { let mut sends = Vec::new(); for keys in user_keys.iter() { + let eth_wallet = LocalWallet::from(keys.eth_key.clone()); + let eth_client = Arc::new(SignerMiddleware::new(eth_provider.clone(), eth_wallet)); let fut = send_to_cosmos( *token, gravity_address, one_hundred_eth(), keys.cosmos_address, - keys.eth_key, Some(TIMEOUT), - web30, - Vec::new(), + eth_client.clone(), ); sends.push(fut); } - let txids = join_all(sends).await; - let mut wait_for_txid = Vec::new(); - for txid in txids { - let wait = web30.wait_for_transaction(txid.unwrap(), TIMEOUT, None); - wait_for_txid.push(wait); - } - let results = join_all(wait_for_txid).await; + let results = join_all(sends).await; for result in results { - let result = result.unwrap(); - result.block_number.unwrap(); + result.unwrap(); } info!( "Locked 100 {} from {} into the Gravity Ethereum Contract", @@ -99,7 +90,7 @@ pub async fn transaction_stress_test( let mut found = false; for balance in balances.iter() { if balance.denom.contains(&token.to_string()) - && balance.amount == one_hundred_eth() + && balance.amount == one_hundred_eth_uint256() { found = true; } @@ -125,7 +116,7 @@ pub async fn transaction_stress_test( ); } - let send_amount = one_hundred_eth() - 500u16.into(); + let send_amount = one_hundred_eth_uint256() - 500u16.into(); let mut denoms = HashSet::new(); for token in erc20_addresses.iter() { @@ -150,7 +141,7 @@ pub async fn transaction_stress_test( denom: send_coin.denom.clone(), amount: 1u8.into(), }; - let res = send_to_eth(c_key, e_dest_addr, send_coin, send_fee, (0f64,"".to_string()),&contact, 1.0); + let res = send_to_eth(c_key, e_dest_addr, send_coin, send_fee, (0f64,"".to_string()), &contact, 1.0); futs.push(res); } let results = join_all(futs).await; @@ -179,7 +170,8 @@ pub async fn transaction_stress_test( for keys in user_keys.iter() { let e_dest_addr = keys.eth_dest_address; for token in erc20_addresses.iter() { - let bal = web30.get_erc20_balance(*token, e_dest_addr).await.unwrap(); + let bal = get_erc20_balance(*token, e_dest_addr, (*MINER_CLIENT).clone()).await.unwrap(); + let bal = Uint256::from_str(bal.to_string().as_str()).unwrap(); if bal != send_amount.clone() { good = false; } @@ -203,13 +195,14 @@ pub async fn transaction_stress_test( // we should find a batch nonce greater than zero since all the batches // executed + let eth_wallet = LocalWallet::from(keys[0].eth_key.clone()); + let eth_client = Arc::new(SignerMiddleware::new(eth_provider.clone(), eth_wallet)); for token in erc20_addresses { assert!( get_tx_batch_nonce( gravity_address, token, - keys[0].eth_key.to_public_key().unwrap(), - web30 + eth_client.clone() ) .await .unwrap() diff --git a/orchestrator/test_runner/src/utils.rs b/orchestrator/test_runner/src/utils.rs index 04c782465..4185e5fe0 100644 --- a/orchestrator/test_runner/src/utils.rs +++ b/orchestrator/test_runner/src/utils.rs @@ -1,32 +1,29 @@ -use crate::TOTAL_TIMEOUT; -use crate::{MINER_PRIVATE_KEY}; -use crate::{MINER_ADDRESS, OPERATION_TIMEOUT}; -use clarity::{Address as EthAddress, Uint256}; -use clarity::{PrivateKey as EthPrivateKey, Transaction}; +use crate::one_eth; use deep_space::address::Address as CosmosAddress; use deep_space::coin::Coin; use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::Contact; +use ethereum_gravity::{erc20_utils::get_erc20_balance, types::EthClient}; +use ethers::prelude::*; +use ethers::core::k256::ecdsa::SigningKey; +use ethers::types::Address as EthAddress; use futures::future::join_all; +use gravity_abi::erc20::ERC20; use rand::Rng; -use web30::{client::Web3, types::SendTxOption}; - -pub async fn send_one_eth(dest: EthAddress, web30: &Web3) { - let txid = web30 - .send_transaction( - dest, - Vec::new(), - 1_000_000_000_000_000_000u128.into(), - *MINER_ADDRESS, - *MINER_PRIVATE_KEY, - vec![], - ) - .await - .expect("Failed to send Eth to validator {}"); - web30 - .wait_for_transaction(txid, TOTAL_TIMEOUT, None) - .await - .unwrap(); + +pub async fn send_one_eth(dest: EthAddress, eth_client: EthClient) { + let tx = TransactionRequest { + from: Some(eth_client.address()), + to: Some(NameOrAddress::Address(dest)), + gas: None, + gas_price: None, + value: Some(one_eth()), + data: Some(Vec::new().into()), + nonce: None, + }; + + let pending_tx = eth_client.send_transaction(tx, None).await.unwrap(); + pending_tx.await.unwrap(); } pub async fn check_cosmos_balance( @@ -50,36 +47,45 @@ pub async fn check_cosmos_balance( /// single address without your sequence getting out of whack. By manually setting the nonce /// here we can send thousands of transactions in only a few blocks pub async fn send_erc20_bulk( - amount: Uint256, + amount: U256, erc20: EthAddress, destinations: &[EthAddress], - web3: &Web3, + eth_client: EthClient, ) { - let miner_balance = web3.get_erc20_balance(erc20, *MINER_ADDRESS).await.unwrap(); - assert!(miner_balance > amount.clone() * destinations.len().into()); - let mut nonce = web3 - .eth_get_transaction_count(*MINER_ADDRESS) - .await - .unwrap(); + let miner_balance = get_erc20_balance(erc20, eth_client.address(), eth_client.clone()).await.unwrap(); + assert!(miner_balance > amount.clone().checked_mul(destinations.len().into()).unwrap()); + + let mut nonce = eth_client.get_transaction_count(eth_client.address(), None).await.unwrap(); let mut transactions = Vec::new(); + for address in destinations { - let send = web3.erc20_send( - amount.clone(), - *address, - erc20, - *MINER_PRIVATE_KEY, - Some(OPERATION_TIMEOUT), - vec![ - SendTxOption::Nonce(nonce.clone()), - SendTxOption::GasLimit(100_000u32.into()), - ], - ); - transactions.push(send); + let data = ERC20::new(erc20, eth_client.clone()).transfer(*address, amount).calldata().unwrap(); + + let tx = TransactionRequest { + from: Some(eth_client.address()), + to: Some(NameOrAddress::Address(erc20)), + gas: Some(100_000u32.into()), + gas_price: None, + value: Some(0u32.into()), + data: Some(data), + nonce: Some(nonce.clone()), + }; + + let tx = eth_client.send_transaction(tx, None); + transactions.push(tx); nonce += 1u64.into(); } - let _txids = join_all(transactions).await; + + let pending_tx_results = join_all(transactions).await; + let mut pending_txs = Vec::new(); + for pending_tx_result in pending_tx_results { + let pending_tx = pending_tx_result.unwrap(); + pending_txs.push(pending_tx); + } + join_all(pending_txs).await; + for address in destinations { - let new_balance = web3.get_erc20_balance(erc20, *address).await.unwrap(); + let new_balance = get_erc20_balance(erc20, *address, eth_client.clone()).await.unwrap(); assert!(new_balance >= amount.clone()); } } @@ -88,46 +94,41 @@ pub async fn send_erc20_bulk( /// the real problem here is that you can't do more than one send operation at a time from a /// single address without your sequence getting out of whack. By manually setting the nonce /// here we can quickly send thousands of transactions in only a few blocks -pub async fn send_eth_bulk(amount: Uint256, destinations: &[EthAddress], web3: &Web3) { - let net_version = web3.net_version().await.unwrap(); - let mut nonce = web3 - .eth_get_transaction_count(*MINER_ADDRESS) - .await - .unwrap(); +pub async fn send_eth_bulk(amount: U256, destinations: &[EthAddress], eth_client: EthClient) { + let mut nonce = eth_client.get_transaction_count(eth_client.address(), None).await.unwrap(); let mut transactions = Vec::new(); + for address in destinations { - let t = Transaction { - to: *address, - nonce: nonce.clone(), - gas_price: 1_000_000_000u64.into(), - gas_limit: 24000u64.into(), - value: amount.clone(), - data: Vec::new(), - signature: None, + let tx = TransactionRequest { + from: Some(eth_client.address()), + to: Some(NameOrAddress::Address(*address)), + gas: Some(24_000u64.into()), + gas_price: Some(1_000_000_000u64.into()), + value: Some(amount.clone()), + data: Some(Vec::new().into()), + nonce: Some(nonce.clone()), }; - let t = t.sign(&*MINER_PRIVATE_KEY, Some(net_version)); - transactions.push(t); + + let tx = eth_client.send_transaction(tx, None); + transactions.push(tx); nonce += 1u64.into(); } - let mut sends = Vec::new(); - for tx in transactions { - sends.push(web3.eth_send_raw_transaction(tx.to_bytes().unwrap())); - } - let txids = join_all(sends).await; - let mut wait_for_txid = Vec::new(); - for txid in txids { - let wait = web3.wait_for_transaction(txid.unwrap(), TOTAL_TIMEOUT, None); - wait_for_txid.push(wait); + + let pending_tx_results = join_all(transactions).await; + let mut pending_txs = Vec::new(); + for pending_tx_result in pending_tx_results { + let pending_tx = pending_tx_result.unwrap(); + pending_txs.push(pending_tx); } - join_all(wait_for_txid).await; + join_all(pending_txs).await; } pub fn get_user_key() -> BridgeUserKey { let mut rng = rand::thread_rng(); let secret: [u8; 32] = rng.gen(); // the starting location of the funds - let eth_key = EthPrivateKey::from_slice(&secret).unwrap(); - let eth_address = eth_key.to_public_key().unwrap(); + let eth_key = SigningKey::from_bytes(&secret).unwrap(); + let eth_address = LocalWallet::from(eth_key.clone()).address(); // the destination on cosmos that sends along to the final ethereum destination let cosmos_key = CosmosPrivateKey::from_secret(&secret); let cosmos_address = cosmos_key @@ -136,8 +137,8 @@ pub fn get_user_key() -> BridgeUserKey { let mut rng = rand::thread_rng(); let secret: [u8; 32] = rng.gen(); // the final destination of the tokens back on Ethereum - let eth_dest_key = EthPrivateKey::from_slice(&secret).unwrap(); - let eth_dest_address = eth_key.to_public_key().unwrap(); + let eth_dest_key = SigningKey::from_bytes(&secret).unwrap(); + let eth_dest_address = LocalWallet::from(eth_dest_key.clone()).address(); BridgeUserKey { eth_address, eth_key, @@ -151,19 +152,19 @@ pub fn get_user_key() -> BridgeUserKey { pub struct BridgeUserKey { // the starting addresses that get Eth balances to send across the bridge pub eth_address: EthAddress, - pub eth_key: EthPrivateKey, + pub eth_key: SigningKey, // the cosmos addresses that get the funds and send them on to the dest eth addresses pub cosmos_address: CosmosAddress, pub cosmos_key: CosmosPrivateKey, // the location tokens are sent back to on Ethereum pub eth_dest_address: EthAddress, - pub eth_dest_key: EthPrivateKey, + pub eth_dest_key: SigningKey, } #[derive(Debug, Clone)] pub struct ValidatorKeys { /// The Ethereum key used by this validator to sign Gravity bridge messages - pub eth_key: EthPrivateKey, + pub eth_key: SigningKey, /// The Orchestrator key used by this validator to submit oracle messages and signatures /// to the cosmos chain pub orch_key: CosmosPrivateKey, diff --git a/orchestrator/test_runner/src/valset_stress.rs b/orchestrator/test_runner/src/valset_stress.rs index df37b2b29..215b5e28e 100644 --- a/orchestrator/test_runner/src/valset_stress.rs +++ b/orchestrator/test_runner/src/valset_stress.rs @@ -1,16 +1,14 @@ use crate::happy_path::test_valset_update; use crate::utils::ValidatorKeys; -use clarity::Address as EthAddress; use deep_space::Contact; -use web30::client::Web3; +use ethers::types::Address as EthAddress; pub async fn validator_set_stress_test( - web30: &Web3, contact: &Contact, keys: Vec, gravity_address: EthAddress, ) { for _ in 0u32..10 { - test_valset_update(&web30, contact, &keys, gravity_address).await; + test_valset_update(contact, &keys, gravity_address).await; } } From 6afba3ae86cd85749e6d193e1beca07c9821dfe6 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Fri, 19 Nov 2021 23:33:16 -0800 Subject: [PATCH 088/115] cargo fmt --- orchestrator/cosmos_gravity/src/build.rs | 3 +- orchestrator/cosmos_gravity/src/send.rs | 14 ++-- .../ethereum_gravity/src/deploy_erc20.rs | 19 +++-- .../ethereum_gravity/src/erc20_utils.rs | 27 ++++--- orchestrator/ethereum_gravity/src/lib.rs | 2 +- .../ethereum_gravity/src/logic_call.rs | 72 ++++++++++++----- .../ethereum_gravity/src/send_to_cosmos.rs | 26 +++++-- .../ethereum_gravity/src/submit_batch.rs | 47 ++++++++--- orchestrator/ethereum_gravity/src/types.rs | 2 +- orchestrator/ethereum_gravity/src/utils.rs | 57 +++++++++----- .../ethereum_gravity/src/valset_update.rs | 49 +++++++++--- orchestrator/gorc/src/bin/gorc/main.rs | 1 - orchestrator/gorc/src/commands.rs | 11 +-- orchestrator/gorc/src/commands/deploy.rs | 2 +- .../gorc/src/commands/deploy/erc20.rs | 12 ++- .../gorc/src/commands/eth_to_cosmos.rs | 13 +++- orchestrator/gorc/src/commands/keys.rs | 2 +- orchestrator/gorc/src/commands/keys/cosmos.rs | 2 +- .../gorc/src/commands/keys/cosmos/add.rs | 2 +- .../gorc/src/commands/keys/cosmos/delete.rs | 2 +- .../gorc/src/commands/keys/cosmos/list.rs | 2 +- .../gorc/src/commands/keys/cosmos/recover.rs | 11 +-- .../gorc/src/commands/keys/cosmos/rename.rs | 2 +- .../gorc/src/commands/keys/cosmos/show.rs | 4 +- orchestrator/gorc/src/commands/keys/eth.rs | 2 +- .../gorc/src/commands/keys/eth/add.rs | 2 +- .../gorc/src/commands/keys/eth/delete.rs | 2 +- .../gorc/src/commands/keys/eth/import.rs | 2 +- .../gorc/src/commands/keys/eth/list.rs | 2 +- .../gorc/src/commands/keys/eth/recover.rs | 11 +-- .../gorc/src/commands/keys/eth/rename.rs | 2 +- .../gorc/src/commands/keys/eth/show.rs | 2 +- .../gorc/src/commands/orchestrator.rs | 4 +- .../gorc/src/commands/orchestrator/start.rs | 5 +- .../gorc/src/commands/print_config.rs | 4 +- orchestrator/gorc/src/commands/query.rs | 2 +- .../gorc/src/commands/query/cosmos.rs | 2 +- orchestrator/gorc/src/commands/query/eth.rs | 2 +- .../gorc/src/commands/sign_delegate_keys.rs | 7 +- orchestrator/gorc/src/commands/tests.rs | 2 +- orchestrator/gorc/src/commands/tx.rs | 2 +- orchestrator/gorc/src/commands/tx/eth.rs | 28 ++++--- orchestrator/gorc/src/utils.rs | 4 +- orchestrator/gravity_proto/src/lib.rs | 2 +- .../gravity_utils/src/connection_prep.rs | 21 ++--- orchestrator/gravity_utils/src/error.rs | 39 ++++++---- .../gravity_utils/src/message_signatures.rs | 78 +++++++++++++------ .../gravity_utils/src/types/batches.rs | 35 +++++---- .../gravity_utils/src/types/signatures.rs | 5 +- .../gravity_utils/src/types/valsets.rs | 5 +- .../src/ethereum_event_watcher.rs | 36 +++++---- orchestrator/orchestrator/src/main_loop.rs | 14 +++- .../orchestrator/src/oracle_resync.rs | 22 +++--- .../register_delegate_keys/src/main.rs | 2 +- orchestrator/relayer/src/batch_relaying.rs | 23 +++--- .../relayer/src/find_latest_valset.rs | 7 +- .../relayer/src/logic_call_relaying.rs | 9 ++- orchestrator/relayer/src/main.rs | 5 +- orchestrator/relayer/src/main_loop.rs | 13 ++-- orchestrator/relayer/src/valset_relaying.rs | 11 ++- orchestrator/src/lib.rs | 14 ++-- orchestrator/test_runner/src/bootstrapping.rs | 2 +- orchestrator/test_runner/src/happy_path.rs | 8 +- orchestrator/test_runner/src/happy_path_v2.rs | 31 +++----- orchestrator/test_runner/src/main.rs | 9 ++- .../test_runner/src/orch_keys_update.rs | 4 +- .../src/transaction_stress_test.rs | 59 ++++++++++---- orchestrator/test_runner/src/utils.rs | 35 +++++++-- 68 files changed, 621 insertions(+), 339 deletions(-) diff --git a/orchestrator/cosmos_gravity/src/build.rs b/orchestrator/cosmos_gravity/src/build.rs index c0a38fa06..419ca73b2 100644 --- a/orchestrator/cosmos_gravity/src/build.rs +++ b/orchestrator/cosmos_gravity/src/build.rs @@ -87,7 +87,8 @@ pub async fn contract_call_tx_confirmation_messages( let mut msgs = Vec::new(); for logic_call in logic_calls { - let data = keccak256(encode_logic_call_confirm(gravity_id.clone(), logic_call.clone()).as_slice()); + let data = + keccak256(encode_logic_call_confirm(gravity_id.clone(), logic_call.clone()).as_slice()); // Signer trait responds with a Result, but we use a LocalWallet and it // will never throw an error let signature = eth_client.signer().sign_message(data).await.unwrap(); diff --git a/orchestrator/cosmos_gravity/src/send.rs b/orchestrator/cosmos_gravity/src/send.rs index 327772106..13cbed93e 100644 --- a/orchestrator/cosmos_gravity/src/send.rs +++ b/orchestrator/cosmos_gravity/src/send.rs @@ -80,10 +80,12 @@ pub async fn send_to_eth( gas_adjustment: f64, ) -> Result { if amount.denom != bridge_fee.denom { - return Err(GravityError::CosmosGrpcError(CosmosGrpcError::BadInput(format!( - "The amount ({}) and bridge_fee ({}) denominations do not match.", - amount.denom, bridge_fee.denom, - )))) + return Err(GravityError::CosmosGrpcError(CosmosGrpcError::BadInput( + format!( + "The amount ({}) and bridge_fee ({}) denominations do not match.", + amount.denom, bridge_fee.denom, + ), + ))); } let cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); @@ -162,7 +164,7 @@ async fn __send_messages( match contact.wait_for_tx(response, TIMEOUT).await { Ok(res) => Ok(res), - Err(e) => Err(GravityError::CosmosGrpcError(e)) + Err(e) => Err(GravityError::CosmosGrpcError(e)), } } @@ -212,7 +214,7 @@ pub async fn send_messages( match contact.wait_for_tx(response, TIMEOUT).await { Ok(res) => Ok(res), - Err(e) => Err(GravityError::CosmosGrpcError(e)) + Err(e) => Err(GravityError::CosmosGrpcError(e)), } } diff --git a/orchestrator/ethereum_gravity/src/deploy_erc20.rs b/orchestrator/ethereum_gravity/src/deploy_erc20.rs index 9c3a628c2..1b7486f90 100644 --- a/orchestrator/ethereum_gravity/src/deploy_erc20.rs +++ b/orchestrator/ethereum_gravity/src/deploy_erc20.rs @@ -21,8 +21,12 @@ pub async fn deploy_erc20( wait_timeout: Option, eth_client: EthClient, ) -> Result { - let contract_call = Gravity::new(gravity_contract, eth_client.clone()) - .deploy_erc20(cosmos_denom, erc20_name, erc20_symbol.clone(), decimals); + let contract_call = Gravity::new(gravity_contract, eth_client.clone()).deploy_erc20( + cosmos_denom, + erc20_name, + erc20_symbol.clone(), + decimals, + ); let gas_price = get_send_transaction_gas_price(eth_client.clone()).await?; let contract_call = contract_call.gas_price(gas_price); @@ -32,19 +36,20 @@ pub async fn deploy_erc20( // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? // additionally we are mirroring only waiting for 1 confirmation by leaving that as default let pending_tx = pending_tx.interval(Duration::from_secs(1)); - let potential_error = GravityError::GravityContractError( - format!("Did not receive transaction receipt when deploying ERC-20 {}: {}", erc20_symbol, tx_hash) - ); + let potential_error = GravityError::GravityContractError(format!( + "Did not receive transaction receipt when deploying ERC-20 {}: {}", + erc20_symbol, tx_hash + )); if let Some(timeout) = wait_timeout { match tokio::time::timeout(timeout, pending_tx).await?? { Some(receipt) => Ok(receipt.transaction_hash), - None => Err(potential_error) + None => Err(potential_error), } } else { match pending_tx.await? { Some(receipt) => Ok(receipt.transaction_hash), - None => Err(potential_error) + None => Err(potential_error), } } } diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs index 5045ab6ca..feb987231 100644 --- a/orchestrator/ethereum_gravity/src/erc20_utils.rs +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -45,17 +45,20 @@ pub async fn approve_erc20_transfers( // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? // additionally we are mirroring only waiting for 1 confirmation by leaving that as default let pending_tx = pending_tx.interval(Duration::from_secs(1)); - let potential_error = GravityError::GravityContractError(format!("Did not receive transaction receipt when approving ERC-20 {}: {}", erc20, tx_hash)); + let potential_error = GravityError::GravityContractError(format!( + "Did not receive transaction receipt when approving ERC-20 {}: {}", + erc20, tx_hash + )); if let Some(timeout) = timeout_option { match tokio::time::timeout(timeout, pending_tx).await?? { Some(receipt) => Ok(receipt.transaction_hash), - None => Err(potential_error) + None => Err(potential_error), } } else { match pending_tx.await? { Some(receipt) => Ok(receipt.transaction_hash), - None => Err(potential_error) + None => Err(potential_error), } } } @@ -83,18 +86,24 @@ pub async fn erc20_transfer( let pending_tx = contract_call.send().await?; let tx_hash = *pending_tx; - info!("Transferring {} ERC-20 {} from {} to {} with txid {}", - amount, erc20, eth_client.address(), destination, tx_hash + info!( + "Transferring {} ERC-20 {} from {} to {} with txid {}", + amount, + erc20, + eth_client.address(), + destination, + tx_hash ); // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? // additionally we are mirroring only waiting for 1 confirmation by leaving that as default let pending_tx = pending_tx.interval(Duration::from_secs(1)); let potential_error = GravityError::GravityContractError(format!( - "Did not receive transaction receipt when transferring ERC-20 {}: {}", erc20, tx_hash) - ); + "Did not receive transaction receipt when transferring ERC-20 {}: {}", + erc20, tx_hash + )); match pending_tx.await? { Some(receipt) => Ok(receipt.transaction_hash), - None => Err(potential_error) + None => Err(potential_error), } -} \ No newline at end of file +} diff --git a/orchestrator/ethereum_gravity/src/lib.rs b/orchestrator/ethereum_gravity/src/lib.rs index cf054ffb7..da2d7c075 100644 --- a/orchestrator/ethereum_gravity/src/lib.rs +++ b/orchestrator/ethereum_gravity/src/lib.rs @@ -5,8 +5,8 @@ use ethers::types::U256; #[macro_use] extern crate log; -pub mod erc20_utils; pub mod deploy_erc20; +pub mod erc20_utils; pub mod logic_call; pub mod send_to_cosmos; pub mod submit_batch; diff --git a/orchestrator/ethereum_gravity/src/logic_call.rs b/orchestrator/ethereum_gravity/src/logic_call.rs index 2f360506b..11561dd36 100644 --- a/orchestrator/ethereum_gravity/src/logic_call.rs +++ b/orchestrator/ethereum_gravity/src/logic_call.rs @@ -1,8 +1,10 @@ -use crate::{types::{EthClient, EthSignerMiddleware}, - utils::{GasCost, - convert_invalidation_id_to_fixed_array, - get_logic_call_nonce, - get_send_transaction_gas_price}}; +use crate::{ + types::{EthClient, EthSignerMiddleware}, + utils::{ + convert_invalidation_id_to_fixed_array, get_logic_call_nonce, + get_send_transaction_gas_price, GasCost, + }, +}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; @@ -56,10 +58,17 @@ pub async fn send_eth_logic_call( } let contract_call = build_send_logic_call_contract_call( - current_valset, &call, confirms, gravity_contract_address, gravity_id, eth_client.clone() + current_valset, + &call, + confirms, + gravity_contract_address, + gravity_id, + eth_client.clone(), )?; - let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let contract_call = contract_call + .gas(gas_cost.gas) + .gas_price(gas_cost.gas_price); let pending_tx = contract_call.send().await?; let tx_hash = *pending_tx; @@ -70,7 +79,10 @@ pub async fn send_eth_logic_call( match tokio::time::timeout(timeout, pending_tx).await?? { Some(_) => (), - None => error!("Did not receive transaction receipt when submitting batch: {}", tx_hash), + None => error!( + "Did not receive transaction receipt when submitting batch: {}", + tx_hash + ), } let last_nonce = get_logic_call_nonce( @@ -104,7 +116,12 @@ pub async fn estimate_logic_call_cost( eth_client: EthClient, ) -> Result { let contract_call = build_send_logic_call_contract_call( - current_valset, &call, confirms, gravity_contract_address, gravity_id, eth_client.clone() + current_valset, + &call, + confirms, + gravity_contract_address, + gravity_id, + eth_client.clone(), )?; Ok(GasCost { @@ -128,19 +145,32 @@ pub fn build_send_logic_call_contract_call( let sig_data = current_valset.order_sigs(&hash, confirms)?; let sig_arrays = to_arrays(sig_data); - let transfer_amounts = call.transfers.iter() - .map(|transfer| transfer.amount).collect(); - let transfer_token_contracts = call.transfers.iter() - .map(|transfer| transfer.token_contract_address).collect(); - let fee_amounts = call.fees.iter() - .map(|fee| fee.amount).collect(); - let fee_token_contracts = call.fees.iter() - .map(|fee| fee.token_contract_address).collect(); + let transfer_amounts = call + .transfers + .iter() + .map(|transfer| transfer.amount) + .collect(); + let transfer_token_contracts = call + .transfers + .iter() + .map(|transfer| transfer.token_contract_address) + .collect(); + let fee_amounts = call.fees.iter().map(|fee| fee.amount).collect(); + let fee_token_contracts = call + .fees + .iter() + .map(|fee| fee.token_contract_address) + .collect(); let invalidation_id = convert_invalidation_id_to_fixed_array(call.invalidation_id.clone())?; let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) - .submit_logic_call(current_addresses, current_powers, current_valset_nonce.into(), - sig_arrays.v, sig_arrays.r, sig_arrays.s, + .submit_logic_call( + current_addresses, + current_powers, + current_valset_nonce.into(), + sig_arrays.v, + sig_arrays.r, + sig_arrays.s, LogicCallArgs { transfer_amounts, transfer_token_contracts, @@ -150,7 +180,9 @@ pub fn build_send_logic_call_contract_call( payload: call.payload.clone(), time_out: call.timeout.into(), invalidation_id, - invalidation_nonce: call.invalidation_nonce.into(), }) + invalidation_nonce: call.invalidation_nonce.into(), + }, + ) .from(eth_client.address()) .value(U256::zero()); diff --git a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs index 23bed749f..0b35e2e01 100644 --- a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs +++ b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs @@ -1,6 +1,9 @@ //! Helper functions for sending tokens to Cosmos -use crate::{erc20_utils::{approve_erc20_transfers, check_erc20_approved}, types::EthClient}; +use crate::{ + erc20_utils::{approve_erc20_transfers, check_erc20_approved}, + types::EthClient, +}; use deep_space::address::Address as CosmosAddress; use ethers::prelude::*; use gravity_abi::gravity::*; @@ -21,9 +24,17 @@ pub async fn send_to_cosmos( wait_timeout: Option, eth_client: EthClient, ) -> Result { - let approved = check_erc20_approved(erc20, gravity_contract, eth_client.address(), eth_client.clone()).await?; + let approved = check_erc20_approved( + erc20, + gravity_contract, + eth_client.address(), + eth_client.clone(), + ) + .await?; if !approved { - let txid = approve_erc20_transfers(erc20, gravity_contract, wait_timeout, eth_client.clone()).await?; + let txid = + approve_erc20_transfers(erc20, gravity_contract, wait_timeout, eth_client.clone()) + .await?; trace!("ERC-20 approval for {} finished with txid {}", erc20, txid); } @@ -50,17 +61,20 @@ pub async fn send_to_cosmos( // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? // additionally we are mirroring only waiting for 1 confirmation by leaving that as default let pending_tx = pending_tx.interval(Duration::from_secs(1)); - let potential_error = GravityError::GravityContractError(format!("Did not receive transaction receipt when sending to Cosmos: {}", tx_hash)); + let potential_error = GravityError::GravityContractError(format!( + "Did not receive transaction receipt when sending to Cosmos: {}", + tx_hash + )); if let Some(timeout) = wait_timeout { match tokio::time::timeout(timeout, pending_tx).await?? { Some(receipt) => Ok(receipt.transaction_hash), - None => Err(potential_error) + None => Err(potential_error), } } else { match pending_tx.await? { Some(receipt) => Ok(receipt.transaction_hash), - None => Err(potential_error) + None => Err(potential_error), } } } diff --git a/orchestrator/ethereum_gravity/src/submit_batch.rs b/orchestrator/ethereum_gravity/src/submit_batch.rs index 691baf16b..447e80a8f 100644 --- a/orchestrator/ethereum_gravity/src/submit_batch.rs +++ b/orchestrator/ethereum_gravity/src/submit_batch.rs @@ -1,5 +1,7 @@ -use crate::{types::{EthClient, EthSignerMiddleware}, - utils::{GasCost, get_send_transaction_gas_price, get_tx_batch_nonce}}; +use crate::{ + types::{EthClient, EthSignerMiddleware}, + utils::{get_send_transaction_gas_price, get_tx_batch_nonce, GasCost}, +}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; @@ -52,10 +54,17 @@ pub async fn send_eth_transaction_batch( } let contract_call = build_submit_batch_contract_call( - current_valset, &batch, confirms, gravity_contract_address, gravity_id, eth_client.clone() + current_valset, + &batch, + confirms, + gravity_contract_address, + gravity_id, + eth_client.clone(), )?; - let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let contract_call = contract_call + .gas(gas_cost.gas) + .gas_price(gas_cost.gas_price); let pending_tx = contract_call.send().await?; let tx_hash = *pending_tx; @@ -66,7 +75,10 @@ pub async fn send_eth_transaction_batch( match tokio::time::timeout(timeout, pending_tx).await?? { Some(_) => (), - None => error!("Did not receive transaction receipt when submitting batch: {}", tx_hash), + None => error!( + "Did not receive transaction receipt when submitting batch: {}", + tx_hash + ), } let last_nonce = get_tx_batch_nonce( @@ -98,7 +110,12 @@ pub async fn estimate_tx_batch_cost( eth_client: EthClient, ) -> Result { let contract_call = build_submit_batch_contract_call( - current_valset, &batch, confirms, gravity_contract_address, gravity_id, eth_client.clone() + current_valset, + &batch, + confirms, + gravity_contract_address, + gravity_id, + eth_client.clone(), )?; Ok(GasCost { @@ -125,10 +142,20 @@ pub fn build_submit_batch_contract_call( let (amounts, destinations, fees) = batch.get_checkpoint_values(); let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) - .submit_batch(current_addresses, current_powers, current_valset_nonce.into(), - sig_arrays.v, sig_arrays.r, sig_arrays.s, - amounts, destinations, fees, - new_batch_nonce.into(), batch.token_contract, batch.batch_timeout.into()) + .submit_batch( + current_addresses, + current_powers, + current_valset_nonce.into(), + sig_arrays.v, + sig_arrays.r, + sig_arrays.s, + amounts, + destinations, + fees, + new_batch_nonce.into(), + batch.token_contract, + batch.batch_timeout.into(), + ) .from(eth_client.address()) .value(U256::zero()); diff --git a/orchestrator/ethereum_gravity/src/types.rs b/orchestrator/ethereum_gravity/src/types.rs index 82ad639d9..91cd74033 100644 --- a/orchestrator/ethereum_gravity/src/types.rs +++ b/orchestrator/ethereum_gravity/src/types.rs @@ -2,4 +2,4 @@ use ethers::prelude::*; use std::sync::Arc; pub type EthSignerMiddleware = SignerMiddleware, LocalWallet>; -pub type EthClient = Arc; \ No newline at end of file +pub type EthClient = Arc; diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index f65a0f247..c8bf13e39 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -1,8 +1,8 @@ use crate::types::EthClient; use ethers::core::abi::{self, Token}; use ethers::middleware::gas_oracle::{Etherscan, GasCategory}; -use ethers::prelude::*; use ethers::prelude::gas_oracle::GasOracle; +use ethers::prelude::*; use ethers::types::Address as EthAddress; use ethers::utils::keccak256; use gravity_abi::gravity::*; @@ -16,8 +16,14 @@ pub fn get_checkpoint_abi_encode( gravity_id: &str, ) -> Result, GravityError> { let (eth_addresses, powers) = valset.filter_empty_addresses(); - let eth_addresses = eth_addresses.iter().map (|address| Token::Address(*address)).collect(); - let powers = powers.iter().map(|power| Token::Uint((*power).into())).collect(); + let eth_addresses = eth_addresses + .iter() + .map(|address| Token::Address(*address)) + .collect(); + let powers = powers + .iter() + .map(|power| Token::Uint((*power).into())) + .collect(); Ok(abi::encode(&[ Token::FixedBytes(gravity_id.as_bytes().to_vec()), @@ -44,7 +50,9 @@ pub async fn get_valset_nonce( .from(eth_client.address()) .value(U256::zero()); let gas_cost = get_call_gas_cost(eth_client.clone()).await?; - let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let contract_call = contract_call + .gas(gas_cost.gas) + .gas_price(gas_cost.gas_price); let valset_nonce = contract_call.call().await?; @@ -68,7 +76,9 @@ pub async fn get_tx_batch_nonce( .from(eth_client.address()) .value(U256::zero()); let gas_cost = get_call_gas_cost(eth_client.clone()).await?; - let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let contract_call = contract_call + .gas(gas_cost.gas) + .gas_price(gas_cost.gas_price); let tx_batch_nonce = contract_call.call().await?; @@ -94,7 +104,9 @@ pub async fn get_logic_call_nonce( .from(eth_client.address()) .value(U256::zero()); let gas_cost = get_call_gas_cost(eth_client.clone()).await?; - let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let contract_call = contract_call + .gas(gas_cost.gas) + .gas_price(gas_cost.gas_price); let logic_call_nonce = contract_call.call().await?; @@ -117,7 +129,9 @@ pub async fn get_event_nonce( .from(eth_client.address()) .value(U256::zero()); let gas_cost = get_call_gas_cost(eth_client.clone()).await?; - let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let contract_call = contract_call + .gas(gas_cost.gas) + .gas_price(gas_cost.gas_price); let event_nonce = contract_call.call().await?; @@ -140,7 +154,9 @@ pub async fn get_gravity_id( .from(eth_client.address()) .value(U256::zero()); let gas_cost = get_call_gas_cost(eth_client.clone()).await?; - let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let contract_call = contract_call + .gas(gas_cost.gas) + .gas_price(gas_cost.gas_price); let gravity_id = contract_call.call().await?; let id_as_string = String::from_utf8(gravity_id.to_vec()); @@ -148,8 +164,9 @@ pub async fn get_gravity_id( match id_as_string { Ok(id) => Ok(id), Err(err) => Err(GravityError::GravityContractError(format!( - "Received invalid utf8 when getting gravity id {:?}: {}", &gravity_id, err - ))) + "Received invalid utf8 when getting gravity id {:?}: {}", + &gravity_id, err + ))), } } @@ -165,32 +182,36 @@ pub async fn get_call_gas_cost(eth_client: EthClient) -> Result Result { if let Ok(api_key) = std::env::var("ETHERSCAN_API_KEY") { - let etherscan_oracle = Etherscan::new(Some(api_key.as_str())).category(GasCategory::Standard); + let etherscan_oracle = + Etherscan::new(Some(api_key.as_str())).category(GasCategory::Standard); return Ok(etherscan_oracle.fetch().await?); } Ok(eth_client.get_gas_price().await?) } -pub fn convert_invalidation_id_to_fixed_array(invalidation_id: Vec) -> Result<[u8; 32], GravityError> { +pub fn convert_invalidation_id_to_fixed_array( + invalidation_id: Vec, +) -> Result<[u8; 32], GravityError> { if invalidation_id.len() != 32 { return Err(GravityError::InvalidArgumentError(format!( - "Error getting logic call nonce, invalidation id is not 32 bytes: {:?}", invalidation_id))) + "Error getting logic call nonce, invalidation id is not 32 bytes: {:?}", + invalidation_id + ))); } let mut invalidation_id_slice: [u8; 32] = Default::default(); diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index fe1972bd8..a15922ad8 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -1,10 +1,14 @@ -use crate::{types::{EthClient, EthSignerMiddleware}, - utils::{GasCost, get_send_transaction_gas_price, get_valset_nonce}}; +use crate::{ + types::{EthClient, EthSignerMiddleware}, + utils::{get_send_transaction_gas_price, get_valset_nonce, GasCost}, +}; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_abi::gravity::*; -use gravity_utils::{error::GravityError, message_signatures::encode_valset_confirm_hashed, types::*}; +use gravity_utils::{ + error::GravityError, message_signatures::encode_valset_confirm_hashed, types::*, +}; use std::time::Duration; /// this function generates an appropriate Ethereum transaction @@ -38,9 +42,16 @@ pub async fn send_eth_valset_update( } let contract_call = build_valset_update_contract_call( - &new_valset, &old_valset, confirms, gravity_contract_address, gravity_id, eth_client.clone() + &new_valset, + &old_valset, + confirms, + gravity_contract_address, + gravity_id, + eth_client.clone(), )?; - let contract_call = contract_call.gas(gas_cost.gas).gas_price(gas_cost.gas_price); + let contract_call = contract_call + .gas(gas_cost.gas) + .gas_price(gas_cost.gas_price); let pending_tx = contract_call.send().await?; let tx_hash = *pending_tx; @@ -51,7 +62,10 @@ pub async fn send_eth_valset_update( match tokio::time::timeout(timeout, pending_tx).await?? { Some(_) => (), - None => error!("Did not receive transaction receipt when sending valset update: {}", tx_hash), + None => error!( + "Did not receive transaction receipt when sending valset update: {}", + tx_hash + ), } let last_nonce = get_valset_nonce(gravity_contract_address, eth_client.clone()).await?; @@ -80,7 +94,12 @@ pub async fn estimate_valset_cost( eth_client: EthClient, ) -> Result { let contract_call = build_valset_update_contract_call( - new_valset, old_valset, confirms, gravity_contract_address, gravity_id, eth_client.clone() + new_valset, + old_valset, + confirms, + gravity_contract_address, + gravity_id, + eth_client.clone(), )?; Ok(GasCost { @@ -111,10 +130,18 @@ pub fn build_valset_update_contract_call( let sig_arrays = to_arrays(sig_data); let contract = Gravity::new(gravity_contract_address, eth_client.clone()); - Ok(contract.update_valset( - new_addresses, new_powers, new_valset.nonce.into(), - old_addresses, old_powers, old_valset.nonce.into(), - sig_arrays.v, sig_arrays.r, sig_arrays.s) + Ok(contract + .update_valset( + new_addresses, + new_powers, + new_valset.nonce.into(), + old_addresses, + old_powers, + old_valset.nonce.into(), + sig_arrays.v, + sig_arrays.r, + sig_arrays.s, + ) .from(eth_client.address()) .value(U256::zero())) } diff --git a/orchestrator/gorc/src/bin/gorc/main.rs b/orchestrator/gorc/src/bin/gorc/main.rs index b5d335305..7ee994681 100644 --- a/orchestrator/gorc/src/bin/gorc/main.rs +++ b/orchestrator/gorc/src/bin/gorc/main.rs @@ -6,7 +6,6 @@ use gorc::application::APP; extern crate openssl_probe; - /// Boot Gorc fn main() { openssl_probe::init_ssl_cert_env_vars(); diff --git a/orchestrator/gorc/src/commands.rs b/orchestrator/gorc/src/commands.rs index 805d9ebeb..bb95068ab 100644 --- a/orchestrator/gorc/src/commands.rs +++ b/orchestrator/gorc/src/commands.rs @@ -71,8 +71,6 @@ impl Runnable for EntryPoint { } } - - /// This trait allows you to define how application configuration is loaded. impl Configurable for EntryPoint { /// Location of the configuration file @@ -98,12 +96,9 @@ impl Configurable for EntryPoint { /// /// This can be safely deleted if you don't want to override config /// settings from command-line options. - fn process_config( - &self, - config: GorcConfig, - ) -> Result { + fn process_config(&self, config: GorcConfig) -> Result { match &self.cmd { - _ => Ok(config), + _ => Ok(config), } } -} \ No newline at end of file +} diff --git a/orchestrator/gorc/src/commands/deploy.rs b/orchestrator/gorc/src/commands/deploy.rs index 1de12afa7..4b6f3fadd 100644 --- a/orchestrator/gorc/src/commands/deploy.rs +++ b/orchestrator/gorc/src/commands/deploy.rs @@ -1,7 +1,7 @@ mod erc20; use erc20::Erc20; -use abscissa_core::{Command, Clap, Runnable}; +use abscissa_core::{Clap, Command, Runnable}; /// Provides tools for contract deployment #[derive(Command, Debug, Clap, Runnable)] diff --git a/orchestrator/gorc/src/commands/deploy/erc20.rs b/orchestrator/gorc/src/commands/deploy/erc20.rs index a62ebdb97..6acb85154 100644 --- a/orchestrator/gorc/src/commands/deploy/erc20.rs +++ b/orchestrator/gorc/src/commands/deploy/erc20.rs @@ -1,12 +1,15 @@ use crate::{application::APP, prelude::*}; -use abscissa_core::{Command, Clap, Runnable}; +use abscissa_core::{Clap, Command, Runnable}; use ethereum_gravity::deploy_erc20::deploy_erc20; use ethers::prelude::*; use gravity_proto::gravity::{DenomToErc20ParamsRequest, DenomToErc20Request}; use gravity_utils::connection_prep::{check_for_eth, create_rpc_connections}; use std::convert::TryFrom; use std::process::exit; -use std::{sync::Arc, time::{Duration, Instant}}; +use std::{ + sync::Arc, + time::{Duration, Instant}, +}; use tokio::time::sleep as delay_for; /// Deploy Erc20 @@ -53,7 +56,10 @@ impl Erc20 { .await; let mut grpc = connections.grpc.clone().unwrap(); - let eth_client = SignerMiddleware::new(connections.eth_provider.clone().unwrap(), ethereum_wallet.clone()); + let eth_client = SignerMiddleware::new( + connections.eth_provider.clone().unwrap(), + ethereum_wallet.clone(), + ); let eth_client = Arc::new(eth_client); check_for_eth(eth_client.address(), eth_client.clone()).await; diff --git a/orchestrator/gorc/src/commands/eth_to_cosmos.rs b/orchestrator/gorc/src/commands/eth_to_cosmos.rs index 32e5d0245..8566d32f9 100644 --- a/orchestrator/gorc/src/commands/eth_to_cosmos.rs +++ b/orchestrator/gorc/src/commands/eth_to_cosmos.rs @@ -1,5 +1,5 @@ use crate::application::APP; -use abscissa_core::{status_err, Application, Command, Clap, Runnable}; +use abscissa_core::{status_err, Application, Clap, Command, Runnable}; use deep_space::address::Address as CosmosAddress; use ethereum_gravity::erc20_utils::get_erc20_balance; use ethereum_gravity::send_to_cosmos::send_to_cosmos; @@ -43,7 +43,10 @@ impl Runnable for EthToCosmosCmd { ) .await; - let eth_client = SignerMiddleware::new(connections.eth_provider.clone().unwrap(), ethereum_wallet.clone()); + let eth_client = SignerMiddleware::new( + connections.eth_provider.clone().unwrap(), + ethereum_wallet.clone(), + ); let eth_client = Arc::new(eth_client); let cosmos_dest = self.args.get(3).expect("cosmos destination is required"); let cosmos_dest: CosmosAddress = cosmos_dest.parse().unwrap(); @@ -53,8 +56,10 @@ impl Runnable for EthToCosmosCmd { let init_amount = self.args.get(4).expect("amount is required"); let amount: U256 = init_amount.parse().unwrap(); - let erc20_balance = get_erc20_balance(erc20_address, ethereum_address, eth_client.clone()).await - .expect("Failed to get balance, check ERC20 contract address"); + let erc20_balance = + get_erc20_balance(erc20_address, ethereum_address, eth_client.clone()) + .await + .expect("Failed to get balance, check ERC20 contract address"); let times = self.args.get(5).expect("times is required"); let times_usize = times.parse::().expect("cannot parse times"); diff --git a/orchestrator/gorc/src/commands/keys.rs b/orchestrator/gorc/src/commands/keys.rs index 8f149a9e1..b84040027 100644 --- a/orchestrator/gorc/src/commands/keys.rs +++ b/orchestrator/gorc/src/commands/keys.rs @@ -1,7 +1,7 @@ mod cosmos; mod eth; -use abscissa_core::{Command, Clap, Runnable}; +use abscissa_core::{Clap, Command, Runnable}; use crate::commands::keys::cosmos::CosmosKeysCmd; use crate::commands::keys::eth::EthKeysCmd; diff --git a/orchestrator/gorc/src/commands/keys/cosmos.rs b/orchestrator/gorc/src/commands/keys/cosmos.rs index 19f294126..f53c9bf67 100644 --- a/orchestrator/gorc/src/commands/keys/cosmos.rs +++ b/orchestrator/gorc/src/commands/keys/cosmos.rs @@ -5,7 +5,7 @@ mod recover; mod rename; mod show; -use abscissa_core::{Command, Clap, Runnable}; +use abscissa_core::{Clap, Command, Runnable}; #[derive(Command, Debug, Clap, Runnable)] pub enum CosmosKeysCmd { diff --git a/orchestrator/gorc/src/commands/keys/cosmos/add.rs b/orchestrator/gorc/src/commands/keys/cosmos/add.rs index 97e11999f..ea10cab58 100644 --- a/orchestrator/gorc/src/commands/keys/cosmos/add.rs +++ b/orchestrator/gorc/src/commands/keys/cosmos/add.rs @@ -1,6 +1,6 @@ use super::show::ShowCosmosKeyCmd; use crate::application::APP; -use abscissa_core::{Application, Command, Clap, Runnable}; +use abscissa_core::{Application, Clap, Command, Runnable}; use k256::pkcs8::ToPrivateKey; use rand_core::OsRng; use signatory::FsKeyStore; diff --git a/orchestrator/gorc/src/commands/keys/cosmos/delete.rs b/orchestrator/gorc/src/commands/keys/cosmos/delete.rs index 46cadd4c3..5a12511e6 100644 --- a/orchestrator/gorc/src/commands/keys/cosmos/delete.rs +++ b/orchestrator/gorc/src/commands/keys/cosmos/delete.rs @@ -1,5 +1,5 @@ use crate::application::APP; -use abscissa_core::{Application, Command, Clap, Runnable}; +use abscissa_core::{Application, Clap, Command, Runnable}; use signatory::FsKeyStore; use std::path::Path; diff --git a/orchestrator/gorc/src/commands/keys/cosmos/list.rs b/orchestrator/gorc/src/commands/keys/cosmos/list.rs index 5da0747b7..739639aab 100644 --- a/orchestrator/gorc/src/commands/keys/cosmos/list.rs +++ b/orchestrator/gorc/src/commands/keys/cosmos/list.rs @@ -1,6 +1,6 @@ use super::show::ShowCosmosKeyCmd; use crate::application::APP; -use abscissa_core::{Application, Command, Clap, Runnable}; +use abscissa_core::{Application, Clap, Command, Runnable}; use std::path::Path; /// List all Cosmos Keys diff --git a/orchestrator/gorc/src/commands/keys/cosmos/recover.rs b/orchestrator/gorc/src/commands/keys/cosmos/recover.rs index 5a02859dd..fd7fb0deb 100644 --- a/orchestrator/gorc/src/commands/keys/cosmos/recover.rs +++ b/orchestrator/gorc/src/commands/keys/cosmos/recover.rs @@ -1,6 +1,6 @@ use super::show::ShowCosmosKeyCmd; use crate::application::APP; -use abscissa_core::{Application, Command, Clap, Runnable}; +use abscissa_core::{Application, Clap, Command, Runnable}; use k256::pkcs8::ToPrivateKey; use signatory::FsKeyStore; use std::path; @@ -21,8 +21,7 @@ impl Runnable for RecoverCosmosKeyCmd { fn run(&self) { let config = APP.config(); let keystore = path::Path::new(&config.keystore); - let keystore = - FsKeyStore::create_or_open(keystore).expect("Could not open keystore"); + let keystore = FsKeyStore::create_or_open(keystore).expect("Could not open keystore"); let name = self.args.get(0).expect("name is required"); let name = name.parse().expect("Could not parse name"); @@ -35,10 +34,8 @@ impl Runnable for RecoverCosmosKeyCmd { let mnemonic = match self.args.get(1) { Some(mnemonic) => mnemonic.clone(), - None => rpassword::read_password_from_tty(Some( - "> Enter your bip39-mnemonic:\n", - )) - .expect("Could not read mnemonic"), + None => rpassword::read_password_from_tty(Some("> Enter your bip39-mnemonic:\n")) + .expect("Could not read mnemonic"), }; let mnemonic = bip32::Mnemonic::new(mnemonic.trim(), Default::default()) diff --git a/orchestrator/gorc/src/commands/keys/cosmos/rename.rs b/orchestrator/gorc/src/commands/keys/cosmos/rename.rs index 41f4f9c31..295c55396 100644 --- a/orchestrator/gorc/src/commands/keys/cosmos/rename.rs +++ b/orchestrator/gorc/src/commands/keys/cosmos/rename.rs @@ -1,5 +1,5 @@ -use abscissa_core::{Application, Command, Clap, Runnable}; use crate::application::APP; +use abscissa_core::{Application, Clap, Command, Runnable}; use std::path; /// Rename a Cosmos Key diff --git a/orchestrator/gorc/src/commands/keys/cosmos/show.rs b/orchestrator/gorc/src/commands/keys/cosmos/show.rs index 47ca320f7..7c931b853 100644 --- a/orchestrator/gorc/src/commands/keys/cosmos/show.rs +++ b/orchestrator/gorc/src/commands/keys/cosmos/show.rs @@ -1,5 +1,5 @@ use crate::application::APP; -use abscissa_core::{Application, Command, Clap, Runnable}; +use abscissa_core::{Application, Clap, Command, Runnable}; /// Show a Cosmos Key #[derive(Command, Debug, Default, Clap)] @@ -20,4 +20,4 @@ impl Runnable for ShowCosmosKeyCmd { println!("{}\t{}", name, address) } -} \ No newline at end of file +} diff --git a/orchestrator/gorc/src/commands/keys/eth.rs b/orchestrator/gorc/src/commands/keys/eth.rs index bb987e272..ef689a0cc 100644 --- a/orchestrator/gorc/src/commands/keys/eth.rs +++ b/orchestrator/gorc/src/commands/keys/eth.rs @@ -6,7 +6,7 @@ mod recover; mod rename; mod show; -use abscissa_core::{Command, Clap, Runnable}; +use abscissa_core::{Clap, Command, Runnable}; #[derive(Command, Debug, Clap, Runnable)] pub enum EthKeysCmd { diff --git a/orchestrator/gorc/src/commands/keys/eth/add.rs b/orchestrator/gorc/src/commands/keys/eth/add.rs index edd69c2f2..1c8c89822 100644 --- a/orchestrator/gorc/src/commands/keys/eth/add.rs +++ b/orchestrator/gorc/src/commands/keys/eth/add.rs @@ -1,6 +1,6 @@ use super::show::ShowEthKeyCmd; use crate::application::APP; -use abscissa_core::{Application, Command, Clap, Runnable}; +use abscissa_core::{Application, Clap, Command, Runnable}; use k256::pkcs8::ToPrivateKey; use rand_core::OsRng; use signatory::FsKeyStore; diff --git a/orchestrator/gorc/src/commands/keys/eth/delete.rs b/orchestrator/gorc/src/commands/keys/eth/delete.rs index 67c457898..18aca8a4b 100644 --- a/orchestrator/gorc/src/commands/keys/eth/delete.rs +++ b/orchestrator/gorc/src/commands/keys/eth/delete.rs @@ -1,5 +1,5 @@ use crate::application::APP; -use abscissa_core::{Application, Command, Clap, Runnable}; +use abscissa_core::{Application, Clap, Command, Runnable}; use signatory::FsKeyStore; use std::path; diff --git a/orchestrator/gorc/src/commands/keys/eth/import.rs b/orchestrator/gorc/src/commands/keys/eth/import.rs index ae29815a1..b8e6727f3 100644 --- a/orchestrator/gorc/src/commands/keys/eth/import.rs +++ b/orchestrator/gorc/src/commands/keys/eth/import.rs @@ -1,6 +1,6 @@ use super::show::ShowEthKeyCmd; use crate::application::APP; -use abscissa_core::{Application, Command, Clap, Runnable}; +use abscissa_core::{Application, Clap, Command, Runnable}; use k256::{pkcs8::ToPrivateKey, SecretKey}; use signatory::FsKeyStore; diff --git a/orchestrator/gorc/src/commands/keys/eth/list.rs b/orchestrator/gorc/src/commands/keys/eth/list.rs index 12f144076..19b72e2ce 100644 --- a/orchestrator/gorc/src/commands/keys/eth/list.rs +++ b/orchestrator/gorc/src/commands/keys/eth/list.rs @@ -1,6 +1,6 @@ use super::show::ShowEthKeyCmd; use crate::application::APP; -use abscissa_core::{Application, Command, Clap, Runnable}; +use abscissa_core::{Application, Clap, Command, Runnable}; use std::path; /// List all Eth Keys diff --git a/orchestrator/gorc/src/commands/keys/eth/recover.rs b/orchestrator/gorc/src/commands/keys/eth/recover.rs index c18e33c30..f0d325bde 100644 --- a/orchestrator/gorc/src/commands/keys/eth/recover.rs +++ b/orchestrator/gorc/src/commands/keys/eth/recover.rs @@ -1,6 +1,6 @@ use super::show::ShowEthKeyCmd; use crate::application::APP; -use abscissa_core::{Application, Command, Clap, Runnable}; +use abscissa_core::{Application, Clap, Command, Runnable}; use k256::pkcs8::ToPrivateKey; use signatory::FsKeyStore; use std::path; @@ -24,8 +24,7 @@ impl Runnable for RecoverEthKeyCmd { fn run(&self) { let config = APP.config(); let keystore = path::Path::new(&config.keystore); - let keystore = - FsKeyStore::create_or_open(keystore).expect("Could not open keystore"); + let keystore = FsKeyStore::create_or_open(keystore).expect("Could not open keystore"); let name = self.args.get(0).expect("name is required"); let name = name.parse().expect("Could not parse name"); @@ -38,10 +37,8 @@ impl Runnable for RecoverEthKeyCmd { let mnemonic = match self.args.get(1) { Some(mnemonic) => mnemonic.clone(), - None => rpassword::read_password_from_tty(Some( - "> Enter your bip39-mnemonic:\n", - )) - .expect("Could not read mnemonic"), + None => rpassword::read_password_from_tty(Some("> Enter your bip39-mnemonic:\n")) + .expect("Could not read mnemonic"), }; let mnemonic = bip32::Mnemonic::new(mnemonic.trim(), Default::default()) diff --git a/orchestrator/gorc/src/commands/keys/eth/rename.rs b/orchestrator/gorc/src/commands/keys/eth/rename.rs index 0dc4f533f..93706c8ed 100644 --- a/orchestrator/gorc/src/commands/keys/eth/rename.rs +++ b/orchestrator/gorc/src/commands/keys/eth/rename.rs @@ -1,5 +1,5 @@ use crate::application::APP; -use abscissa_core::{Application, Command, Clap, Runnable}; +use abscissa_core::{Application, Clap, Command, Runnable}; use signatory::FsKeyStore; use std::path; diff --git a/orchestrator/gorc/src/commands/keys/eth/show.rs b/orchestrator/gorc/src/commands/keys/eth/show.rs index 6c4287f30..0eadd9dd1 100644 --- a/orchestrator/gorc/src/commands/keys/eth/show.rs +++ b/orchestrator/gorc/src/commands/keys/eth/show.rs @@ -1,5 +1,5 @@ use crate::application::APP; -use abscissa_core::{Application, Command, Clap, Runnable}; +use abscissa_core::{Application, Clap, Command, Runnable}; /// Show an Eth Key #[derive(Command, Debug, Default, Clap)] diff --git a/orchestrator/gorc/src/commands/orchestrator.rs b/orchestrator/gorc/src/commands/orchestrator.rs index 49cd46fd6..f3dc8978a 100644 --- a/orchestrator/gorc/src/commands/orchestrator.rs +++ b/orchestrator/gorc/src/commands/orchestrator.rs @@ -1,9 +1,9 @@ mod start; -use abscissa_core::{Command, Clap, Runnable}; +use abscissa_core::{Clap, Command, Runnable}; /// Management commannds for the orchestrator #[derive(Command, Debug, Clap, Runnable)] pub enum OrchestratorCmd { - Start(start::StartCommand), + Start(start::StartCommand), } diff --git a/orchestrator/gorc/src/commands/orchestrator/start.rs b/orchestrator/gorc/src/commands/orchestrator/start.rs index 332802aa4..39cb4602a 100644 --- a/orchestrator/gorc/src/commands/orchestrator/start.rs +++ b/orchestrator/gorc/src/commands/orchestrator/start.rs @@ -61,7 +61,10 @@ impl Runnable for StartCommand { let mut grpc = connections.grpc.clone().unwrap(); let contact = connections.contact.clone().unwrap(); - let eth_client = SignerMiddleware::new(connections.eth_provider.clone().unwrap(), ethereum_wallet.clone()); + let eth_client = SignerMiddleware::new( + connections.eth_provider.clone().unwrap(), + ethereum_wallet.clone(), + ); let eth_client = Arc::new(eth_client); info!("Starting Relayer + Oracle + Ethereum Signer"); diff --git a/orchestrator/gorc/src/commands/print_config.rs b/orchestrator/gorc/src/commands/print_config.rs index 4254fe267..85b6d35a5 100644 --- a/orchestrator/gorc/src/commands/print_config.rs +++ b/orchestrator/gorc/src/commands/print_config.rs @@ -1,6 +1,6 @@ -use crate::config::GorcConfig; use crate::application::APP; -use abscissa_core::{Application, Command, Clap, Runnable}; +use crate::config::GorcConfig; +use abscissa_core::{Application, Clap, Command, Runnable}; /// Command for printing configurations #[derive(Command, Debug, Default, Clap)] diff --git a/orchestrator/gorc/src/commands/query.rs b/orchestrator/gorc/src/commands/query.rs index 4a0897028..c4fb29698 100644 --- a/orchestrator/gorc/src/commands/query.rs +++ b/orchestrator/gorc/src/commands/query.rs @@ -4,7 +4,7 @@ mod cosmos; mod eth; -use abscissa_core::{Command, Clap, Runnable}; +use abscissa_core::{Clap, Command, Runnable}; /// Query state on either ethereum or cosmos chains #[derive(Command, Debug, Clap)] diff --git a/orchestrator/gorc/src/commands/query/cosmos.rs b/orchestrator/gorc/src/commands/query/cosmos.rs index feab5015c..76e92723c 100644 --- a/orchestrator/gorc/src/commands/query/cosmos.rs +++ b/orchestrator/gorc/src/commands/query/cosmos.rs @@ -1,7 +1,7 @@ //! `cosmos subcommands` subcommand use crate::{application::APP, prelude::*}; -use abscissa_core::{Command, Clap, Runnable}; +use abscissa_core::{Clap, Command, Runnable}; /// Query cosmos chain #[derive(Command, Debug, Clap)] diff --git a/orchestrator/gorc/src/commands/query/eth.rs b/orchestrator/gorc/src/commands/query/eth.rs index 28b4fb6cd..4ec109d2c 100644 --- a/orchestrator/gorc/src/commands/query/eth.rs +++ b/orchestrator/gorc/src/commands/query/eth.rs @@ -1,7 +1,7 @@ //! `eth subcommands` subcommand use crate::{application::APP, prelude::*}; -use abscissa_core::{Command, Clap, Runnable}; +use abscissa_core::{Clap, Command, Runnable}; /// Query Eth chain #[derive(Command, Debug, Clap)] diff --git a/orchestrator/gorc/src/commands/sign_delegate_keys.rs b/orchestrator/gorc/src/commands/sign_delegate_keys.rs index e0b80bdb0..bf069509a 100644 --- a/orchestrator/gorc/src/commands/sign_delegate_keys.rs +++ b/orchestrator/gorc/src/commands/sign_delegate_keys.rs @@ -1,5 +1,5 @@ use crate::{application::APP, prelude::*}; -use abscissa_core::{Application, Command, Clap, Runnable}; +use abscissa_core::{Application, Clap, Command, Runnable}; use ethers::{prelude::Signer, utils::keccak256}; use gravity_proto::gravity as proto; use std::time::Duration; @@ -48,7 +48,10 @@ impl Runnable for SignDelegateKeysCmd { prost::Message::encode(&msg, &mut buf).expect("Failed to encode DelegateKeysSignMsg!"); let data = keccak256(buf); // TODO(bolten): the rest of the orchestrator expects a hash as a message...here too? - let signature = ethereum_wallet.sign_message(data).await.expect("Could not sign DelegateKeysSignMsg"); + let signature = ethereum_wallet + .sign_message(data) + .await + .expect("Could not sign DelegateKeysSignMsg"); println!("{}", signature); }) diff --git a/orchestrator/gorc/src/commands/tests.rs b/orchestrator/gorc/src/commands/tests.rs index 35c0d68d3..b3375f4f6 100644 --- a/orchestrator/gorc/src/commands/tests.rs +++ b/orchestrator/gorc/src/commands/tests.rs @@ -1,4 +1,4 @@ -use abscissa_core::{Command, Clap, Runnable}; +use abscissa_core::{Clap, Command, Runnable}; /// Run tests against configured chains #[derive(Command, Debug, Clap)] diff --git a/orchestrator/gorc/src/commands/tx.rs b/orchestrator/gorc/src/commands/tx.rs index 3bd0c50d9..906d891a2 100644 --- a/orchestrator/gorc/src/commands/tx.rs +++ b/orchestrator/gorc/src/commands/tx.rs @@ -4,7 +4,7 @@ mod cosmos; mod eth; -use abscissa_core::{Command, Clap, Runnable}; +use abscissa_core::{Clap, Command, Runnable}; /// Create transactions on either ethereum or cosmos chains #[derive(Command, Debug, Clap)] diff --git a/orchestrator/gorc/src/commands/tx/eth.rs b/orchestrator/gorc/src/commands/tx/eth.rs index 0780fec29..863781e98 100644 --- a/orchestrator/gorc/src/commands/tx/eth.rs +++ b/orchestrator/gorc/src/commands/tx/eth.rs @@ -1,12 +1,12 @@ //! `eth subcommands` subcommand use crate::{application::APP, prelude::*, utils::*}; -use abscissa_core::{Command, Clap, Runnable}; +use abscissa_core::{Clap, Command, Runnable}; +use deep_space::address::Address as CosmosAddress; use ethereum_gravity::erc20_utils::get_erc20_balance; +use ethereum_gravity::send_to_cosmos::send_to_cosmos; use ethers::prelude::*; use ethers::types::Address as EthAddress; -use deep_space::address::Address as CosmosAddress; -use ethereum_gravity::send_to_cosmos::send_to_cosmos; use gravity_utils::connection_prep::{check_for_eth, create_rpc_connections}; use std::sync::Arc; @@ -51,10 +51,7 @@ impl Runnable for SendToCosmos { let erc20_amount = self.free[3].clone(); let ethereum_wallet = lookup_eth_key(from_eth_key); - println!( - "Sending from Eth address {}", - ethereum_wallet.address() - ); + println!("Sending from Eth address {}", ethereum_wallet.address()); let config = APP.config(); let cosmos_prefix = config.cosmos.prefix.clone(); let cosmso_grpc = config.cosmos.grpc.clone(); @@ -70,7 +67,10 @@ impl Runnable for SendToCosmos { let connections = create_rpc_connections(cosmos_prefix, Some(cosmso_grpc), Some(eth_rpc), TIMEOUT) .await; - let eth_client = SignerMiddleware::new(connections.eth_provider.clone().unwrap(), ethereum_wallet.clone()); + let eth_client = SignerMiddleware::new( + connections.eth_provider.clone().unwrap(), + ethereum_wallet.clone(), + ); let eth_client = Arc::new(eth_client); check_for_eth(eth_client.address(), eth_client.clone()).await; @@ -78,9 +78,10 @@ impl Runnable for SendToCosmos { .parse() .expect("Expected amount in xx.yy format"); - let erc20_balance = get_erc20_balance(erc20_contract, eth_client.address(), eth_client.clone()) - .await - .expect("Failed to get balance, check ERC20 contract address"); + let erc20_balance = + get_erc20_balance(erc20_contract, eth_client.address(), eth_client.clone()) + .await + .expect("Failed to get balance, check ERC20 contract address"); if erc20_balance == 0u8.into() { panic!( @@ -90,7 +91,10 @@ impl Runnable for SendToCosmos { } println!( "Sending {} / {} to Cosmos from {} to {}", - amount, erc20_contract, eth_client.address(), to_cosmos_addr + amount, + erc20_contract, + eth_client.address(), + to_cosmos_addr ); // we send some erc20 tokens to the gravity contract to register a deposit let res = send_to_cosmos( diff --git a/orchestrator/gorc/src/utils.rs b/orchestrator/gorc/src/utils.rs index b968002f3..53f324a6c 100644 --- a/orchestrator/gorc/src/utils.rs +++ b/orchestrator/gorc/src/utils.rs @@ -1,3 +1,3 @@ -use std::{time::Duration}; +use std::time::Duration; -pub const TIMEOUT: Duration = Duration::from_secs(60); \ No newline at end of file +pub const TIMEOUT: Duration = Duration::from_secs(60); diff --git a/orchestrator/gravity_proto/src/lib.rs b/orchestrator/gravity_proto/src/lib.rs index 932268b99..c72f0cbbd 100644 --- a/orchestrator/gravity_proto/src/lib.rs +++ b/orchestrator/gravity_proto/src/lib.rs @@ -105,4 +105,4 @@ impl ToAny for gravity::SignerSetTxConfirmation { value: buf.to_vec(), }) } -} \ No newline at end of file +} diff --git a/orchestrator/gravity_utils/src/connection_prep.rs b/orchestrator/gravity_utils/src/connection_prep.rs index c762d209a..931608dd2 100644 --- a/orchestrator/gravity_utils/src/connection_prep.rs +++ b/orchestrator/gravity_utils/src/connection_prep.rs @@ -174,15 +174,13 @@ pub async fn create_rpc_connections( // transparently upgrade to https if available, we can't transparently downgrade for obvious security reasons let https_on_80_url = format!("https://{}:80", body); let https_on_443_url = format!("https://{}:443", body); - let https_on_80_eth_provider = Provider::::try_from( - https_on_80_url.as_str(), - ) - .unwrap_or_else(|_| { - panic!( - "Could not instantiate Ethereum HTTP provider: {}", - &https_on_80_url - ) - }); + let https_on_80_eth_provider = + Provider::::try_from(https_on_80_url.as_str()).unwrap_or_else(|_| { + panic!( + "Could not instantiate Ethereum HTTP provider: {}", + &https_on_80_url + ) + }); let https_on_443_eth_provider = Provider::::try_from( https_on_443_url.as_str(), ) @@ -355,7 +353,10 @@ pub async fn check_for_fee_denom(fee_denom: &str, address: CosmosAddress, contac // TODO(bolten): is using LocalWallet too specific? /// Checks the user has some Ethereum in their address to pay for things -pub async fn check_for_eth(address: EthAddress, eth_client: Arc, LocalWallet>>) { +pub async fn check_for_eth( + address: EthAddress, + eth_client: Arc, LocalWallet>>, +) { let balance = eth_client.get_balance(address, None).await.unwrap(); if balance == 0u8.into() { warn!("You don't have any Ethereum! You will need to send some to {} for this program to work. Dust will do for basic operations, more info about average relaying costs will be presented as the program runs", address); diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index b841b5eb1..684143c46 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -5,18 +5,18 @@ use clarity::Error as ClarityError; use deep_space::error::AddressError as CosmosAddressError; use deep_space::error::CosmosGrpcError; use deep_space::error::PrivateKeyError as CosmosPrivateKeyError; -use ethers::abi::Error as EthersAbiError; use ethers::abi::ethereum_types::FromDecStrErr as EthersParseUintError; +use ethers::abi::Error as EthersAbiError; use ethers::contract::AbiError as EthersContractAbiError; -use ethers::prelude::*; -use ethers::prelude::ContractError; use ethers::prelude::gas_oracle::GasOracleError as EthersGasOracleError; -use ethers::prelude::ProviderError as EthersProviderError; use ethers::prelude::signer::SignerMiddlewareError; +use ethers::prelude::ContractError; +use ethers::prelude::ProviderError as EthersProviderError; +use ethers::prelude::*; use ethers::signers::WalletError as EthersWalletError; use ethers::types::SignatureError as EthersSignatureError; -use rustc_hex::FromHexError as EthersParseAddressError; use num_bigint::ParseBigIntError; +use rustc_hex::FromHexError as EthersParseAddressError; use std::fmt::{self, Debug}; use std::num::ParseIntError; use std::string::FromUtf8Error; @@ -66,15 +66,27 @@ impl fmt::Display for GravityError { write!(f, "Got invalid BigInt from cosmos! {}", val) } GravityError::CosmosAddressError(val) => write!(f, "Cosmos Address error {}", val), - GravityError::CosmosPrivateKeyError(val) => write!(f, "Cosmos private key error: {}", val), - GravityError::EthereumBadDataError(val) => write!(f, "Received unexpected data from Ethereum: {}", val), + GravityError::CosmosPrivateKeyError(val) => { + write!(f, "Cosmos private key error: {}", val) + } + GravityError::EthereumBadDataError(val) => { + write!(f, "Received unexpected data from Ethereum: {}", val) + } GravityError::EthereumRestError(val) => write!(f, "Ethereum REST error: {}", val), GravityError::EthersAbiError(val) => write!(f, "Ethers ABI error: {}", val), - GravityError::EthersContractAbiError(val) => write!(f, "Ethers contract ABI error: {}", val), + GravityError::EthersContractAbiError(val) => { + write!(f, "Ethers contract ABI error: {}", val) + } GravityError::EthersContractError(val) => write!(f, "Ethers contract error: {}", val), - GravityError::EthersGasOracleError(val) => write!(f, "Ethers gas oracle error: {}", val), - GravityError::EthersParseAddressError(val) => write!(f, "Ethers H160 address parse error: {}", val), - GravityError::EthersParseUintError(val) => write!(f, "Ethers U256 parse error: {}", val), + GravityError::EthersGasOracleError(val) => { + write!(f, "Ethers gas oracle error: {}", val) + } + GravityError::EthersParseAddressError(val) => { + write!(f, "Ethers H160 address parse error: {}", val) + } + GravityError::EthersParseUintError(val) => { + write!(f, "Ethers U256 parse error: {}", val) + } GravityError::EthersProviderError(val) => write!(f, "Ethers provider error: {}", val), GravityError::EthersSignatureError(val) => write!(f, "Ethers signature error: {}", val), GravityError::EthersWalletError(val) => write!(f, "Ethers wallet error: {}", val), @@ -98,14 +110,15 @@ impl fmt::Display for GravityError { } GravityError::ParseBigIntError(val) => write!(f, "Failed to parse big integer {}", val), GravityError::ParseIntError(val) => write!(f, "Failed to parse integer: {}", val), - GravityError::FromUtf8Error(val) => write!(f, "Failed to parse bytes to UTF-8: {}", val), + GravityError::FromUtf8Error(val) => { + write!(f, "Failed to parse bytes to UTF-8: {}", val) + } } } } impl std::error::Error for GravityError {} - impl From for GravityError { fn from(error: CosmosGrpcError) -> Self { GravityError::CosmosGrpcError(error) diff --git a/orchestrator/gravity_utils/src/message_signatures.rs b/orchestrator/gravity_utils/src/message_signatures.rs index 30ac7826b..2bafd1b00 100644 --- a/orchestrator/gravity_utils/src/message_signatures.rs +++ b/orchestrator/gravity_utils/src/message_signatures.rs @@ -10,8 +10,14 @@ use ethers::utils::keccak256; /// digest that is normally signed or may be used as a 'hash of the message' pub fn encode_valset_confirm(gravity_id: String, valset: Valset) -> Vec { let (eth_addresses, powers) = valset.filter_empty_addresses(); - let eth_addresses = eth_addresses.iter().map (|address| Token::Address(*address)).collect(); - let powers = powers.iter().map(|power| Token::Uint((*power).into())).collect(); + let eth_addresses = eth_addresses + .iter() + .map(|address| Token::Address(*address)) + .collect(); + let powers = powers + .iter() + .map(|power| Token::Uint((*power).into())) + .collect(); abi::encode(&[ Token::FixedBytes(gravity_id.into_bytes()), @@ -132,7 +138,10 @@ pub fn encode_tx_batch_confirm_hashed(gravity_id: String, batch: TransactionBatc #[tokio::test] async fn test_batch_signature() { - use crate::{ethereum::hex_str_to_bytes, types::{BatchTransaction, Erc20Token}}; + use crate::{ + ethereum::hex_str_to_bytes, + types::{BatchTransaction, Erc20Token}, + }; use ethers::core::k256::ecdsa::SigningKey; use ethers::prelude::*; use ethers::utils::keccak256; @@ -184,7 +193,10 @@ async fn test_batch_signature() { let eth_signature = eth_wallet.sign_message(checkpoint.clone()).await.unwrap(); - assert_eq!(eth_address, eth_signature.recover(checkpoint.clone()).unwrap()); + assert_eq!( + eth_address, + eth_signature.recover(checkpoint.clone()).unwrap() + ); } #[tokio::test] @@ -233,7 +245,10 @@ async fn test_specific_batch_signature() { let eth_signature = eth_wallet.sign_message(checkpoint.clone()).await.unwrap(); - assert_eq!(eth_address, eth_signature.recover(checkpoint.clone()).unwrap()); + assert_eq!( + eth_address, + eth_signature.recover(checkpoint.clone()).unwrap() + ); } /// takes the required input data and produces the required signature to confirm a logic @@ -242,27 +257,39 @@ async fn test_specific_batch_signature() { /// Note: This is the message, you need to run Keccak256::digest() in order to get the 32byte /// digest that is normally signed or may be used as a 'hash of the message' pub fn encode_logic_call_confirm(gravity_id: String, call: LogicCall) -> Vec { - let transfer_amounts = call.transfers.iter() - .map(|transfer| Token::Uint(transfer.amount)).collect(); - let transfer_token_contracts = call.transfers.iter() - .map(|transfer| Token::Address(transfer.token_contract_address)).collect(); - let fee_amounts = call.fees.iter() - .map(|fee| Token::Uint(fee.amount)).collect(); - let fee_token_contracts = call.fees.iter() - .map(|fee| Token::Address(fee.token_contract_address)).collect(); + let transfer_amounts = call + .transfers + .iter() + .map(|transfer| Token::Uint(transfer.amount)) + .collect(); + let transfer_token_contracts = call + .transfers + .iter() + .map(|transfer| Token::Address(transfer.token_contract_address)) + .collect(); + let fee_amounts = call + .fees + .iter() + .map(|fee| Token::Uint(fee.amount)) + .collect(); + let fee_token_contracts = call + .fees + .iter() + .map(|fee| Token::Address(fee.token_contract_address)) + .collect(); abi::encode(&[ - Token::FixedBytes(gravity_id.into_bytes()), // Gravity Instance ID + Token::FixedBytes(gravity_id.into_bytes()), // Gravity Instance ID Token::FixedBytes("logicCall".to_string().into_bytes()), // Function Name - Token::Array(transfer_amounts), // Array of Transfer amounts - Token::Array(transfer_token_contracts), // ERC-20 contract for transfers - Token::Array(fee_amounts), // Array of Fees - Token::Array(fee_token_contracts), // ERC-20 contract for fee payments - Token::Address(call.logic_contract_address), // Address of a logic contract - Token::Bytes(call.payload), // Encoded arguments to logic contract - Token::Uint(call.timeout.into()), // Timeout on batch - Token::FixedBytes(call.invalidation_id), // Scope of logic batch - Token::Uint(call.invalidation_nonce.into()), // Nonce of logic batch. See 2-d nonce scheme. + Token::Array(transfer_amounts), // Array of Transfer amounts + Token::Array(transfer_token_contracts), // ERC-20 contract for transfers + Token::Array(fee_amounts), // Array of Fees + Token::Array(fee_token_contracts), // ERC-20 contract for fee payments + Token::Address(call.logic_contract_address), // Address of a logic contract + Token::Bytes(call.payload), // Encoded arguments to logic contract + Token::Uint(call.timeout.into()), // Timeout on batch + Token::FixedBytes(call.invalidation_id), // Scope of logic batch + Token::Uint(call.invalidation_nonce.into()), // Nonce of logic batch. See 2-d nonce scheme. ]) } @@ -273,7 +300,10 @@ pub fn encode_logic_call_confirm_hashed(gravity_id: String, call: LogicCall) -> #[test] fn test_logic_call_signature() { - use crate::{ethereum::hex_str_to_bytes, types::{Erc20Token, LogicCall}}; + use crate::{ + ethereum::hex_str_to_bytes, + types::{Erc20Token, LogicCall}, + }; use ethers::utils::keccak256; let correct_hash: Vec = diff --git a/orchestrator/gravity_utils/src/types/batches.rs b/orchestrator/gravity_utils/src/types/batches.rs index 4bde1944c..05c9e42d5 100644 --- a/orchestrator/gravity_utils/src/types/batches.rs +++ b/orchestrator/gravity_utils/src/types/batches.rs @@ -1,8 +1,8 @@ use super::*; use crate::error::GravityError; +use deep_space::Address as CosmosAddress; use ethers::core::abi::Token; use ethers::types::{Address as EthAddress, Signature as EthSignature}; -use deep_space::Address as CosmosAddress; use std::convert::TryFrom; /// This represents an individual transaction being bridged over to Ethereum @@ -48,12 +48,21 @@ impl TransactionBatch { /// extracts the amounts, destinations and fees as submitted to the Ethereum contract /// and used for signatures pub fn get_checkpoint_values(&self) -> (Vec, Vec, Vec) { - let amounts: Vec = - self.transactions.iter().map(|tx| tx.erc20_token.amount).collect(); - let destinations: Vec = - self.transactions.iter().map(|tx| tx.ethereum_recipient).collect(); - let fees: Vec = - self.transactions.iter().map(|tx| tx.erc20_fee.amount).collect(); + let amounts: Vec = self + .transactions + .iter() + .map(|tx| tx.erc20_token.amount) + .collect(); + let destinations: Vec = self + .transactions + .iter() + .map(|tx| tx.ethereum_recipient) + .collect(); + let fees: Vec = self + .transactions + .iter() + .map(|tx| tx.erc20_fee.amount) + .collect(); assert_eq!(amounts.len(), destinations.len()); assert_eq!(fees.len(), destinations.len()); @@ -63,12 +72,12 @@ impl TransactionBatch { pub fn get_checkpoint_values_tokens(&self) -> (Token, Token, Token) { let (amounts, destinations, fees) = self.get_checkpoint_values(); - let amounts_tokens = - amounts.iter().map(|amount| Token::Uint(*amount)).collect(); - let destinations_tokens = - destinations.iter().map(|destination| Token::Address(*destination)).collect(); - let fees_tokens = - fees.iter().map(|fee| Token::Uint(*fee)).collect(); + let amounts_tokens = amounts.iter().map(|amount| Token::Uint(*amount)).collect(); + let destinations_tokens = destinations + .iter() + .map(|destination| Token::Address(*destination)) + .collect(); + let fees_tokens = fees.iter().map(|fee| Token::Uint(*fee)).collect(); ( Token::Array(amounts_tokens), diff --git a/orchestrator/gravity_utils/src/types/signatures.rs b/orchestrator/gravity_utils/src/types/signatures.rs index 8a5272fe2..942d65758 100644 --- a/orchestrator/gravity_utils/src/types/signatures.rs +++ b/orchestrator/gravity_utils/src/types/signatures.rs @@ -58,8 +58,9 @@ pub fn to_arrays(input: Vec) -> GravitySignatureArrays { // TODO(bolten): we're also throwing panics if we encounter downcast errors in // ethereum_gravity/src/utils.rs, we should consider broadly how to handle // these sorts of error conditions - let v = input.iter().map(|sig| - u8::try_from(sig.v).expect("Gravity Signature v overflow! Bridge halt!")) + let v = input + .iter() + .map(|sig| u8::try_from(sig.v).expect("Gravity Signature v overflow! Bridge halt!")) .collect(); let r = input.iter().map(|sig| sig.r.into()).collect(); let s = input.iter().map(|sig| sig.s.into()).collect(); diff --git a/orchestrator/gravity_utils/src/types/valsets.rs b/orchestrator/gravity_utils/src/types/valsets.rs index 5e7000cf5..d07b9c869 100644 --- a/orchestrator/gravity_utils/src/types/valsets.rs +++ b/orchestrator/gravity_utils/src/types/valsets.rs @@ -1,14 +1,13 @@ use super::*; use crate::error::GravityError; -use ethers::types::{Address as EthAddress, Signature as EthSignature}; use deep_space::error::CosmosGrpcError; +use ethers::types::{Address as EthAddress, Signature as EthSignature}; use std::convert::TryFrom; use std::fmt::Debug; use std::{ cmp::Ordering, collections::{HashMap, HashSet}, - fmt, - str, + fmt, str, }; /// The total power in the Gravity bridge is normalized to u32 max every diff --git a/orchestrator/orchestrator/src/ethereum_event_watcher.rs b/orchestrator/orchestrator/src/ethereum_event_watcher.rs index 77cf4c418..79e207358 100644 --- a/orchestrator/orchestrator/src/ethereum_event_watcher.rs +++ b/orchestrator/orchestrator/src/ethereum_event_watcher.rs @@ -19,10 +19,10 @@ use gravity_utils::{ error::GravityError, ethereum::bytes_to_hex_str, types::{ - ERC20_DEPLOYED_EVENT_STR, LOGIC_CALL_EVENT_STR, SEND_TO_COSMOS_EVENT_STR, - TRANSACTION_BATCH_EXECUTED_EVENT_STR, VALSET_UPDATED_EVENT_STR, Erc20DeployedEvent, LogicCallExecutedEvent, SendToCosmosEvent, - TransactionBatchExecutedEvent, ValsetUpdatedEvent, + TransactionBatchExecutedEvent, ValsetUpdatedEvent, ERC20_DEPLOYED_EVENT_STR, + LOGIC_CALL_EVENT_STR, SEND_TO_COSMOS_EVENT_STR, TRANSACTION_BATCH_EXECUTED_EVENT_STR, + VALSET_UPDATED_EVENT_STR, }, }; use std::time; @@ -47,15 +47,20 @@ pub async fn check_for_events( let filter_gravity_contract_address = ValueOrArray::Value(gravity_contract_address); - let mut erc20_deployed_filter = Filter::new().address(filter_gravity_contract_address.clone()) + let mut erc20_deployed_filter = Filter::new() + .address(filter_gravity_contract_address.clone()) .event(&ERC20_DEPLOYED_EVENT_STR); - let mut logic_call_filter = Filter::new().address(filter_gravity_contract_address.clone()) + let mut logic_call_filter = Filter::new() + .address(filter_gravity_contract_address.clone()) .event(&LOGIC_CALL_EVENT_STR); - let mut send_to_cosmos_filter = Filter::new().address(filter_gravity_contract_address.clone()) + let mut send_to_cosmos_filter = Filter::new() + .address(filter_gravity_contract_address.clone()) .event(&SEND_TO_COSMOS_EVENT_STR); - let mut transaction_batch_filter = Filter::new().address(filter_gravity_contract_address.clone()) + let mut transaction_batch_filter = Filter::new() + .address(filter_gravity_contract_address.clone()) .event(&TRANSACTION_BATCH_EXECUTED_EVENT_STR); - let mut valset_updated_filter = Filter::new().address(filter_gravity_contract_address.clone()) + let mut valset_updated_filter = Filter::new() + .address(filter_gravity_contract_address.clone()) .event(&VALSET_UPDATED_EVENT_STR); let search_range = starting_block..latest_block; @@ -84,7 +89,8 @@ pub async fn check_for_events( let transaction_batch_events = eth_client.get_logs(&transaction_batch_filter).await?; debug!("Batch events detected {:?}", transaction_batch_events); - let transaction_batch_events = TransactionBatchExecutedEvent::from_logs(&transaction_batch_events)?; + let transaction_batch_events = + TransactionBatchExecutedEvent::from_logs(&transaction_batch_events)?; debug!("parsed batches {:?}", transaction_batch_events); let valset_updated_events = eth_client.get_logs(&valset_updated_filter).await?; @@ -107,7 +113,10 @@ pub async fn check_for_events( let send_to_cosmos_events: Vec = SendToCosmosEvent::filter_by_event_nonce(last_event_nonce, &send_to_cosmos_events); let transaction_batch_events: Vec = - TransactionBatchExecutedEvent::filter_by_event_nonce(last_event_nonce, &transaction_batch_events); + TransactionBatchExecutedEvent::filter_by_event_nonce( + last_event_nonce, + &transaction_batch_events, + ); let valset_updated_events: Vec = ValsetUpdatedEvent::filter_by_event_nonce(last_event_nonce, &valset_updated_events); @@ -249,9 +258,10 @@ pub async fn get_block_delay(eth_client: EthClient) -> Result let chain_id_result = get_chain_id_with_retry(eth_client.clone()).await; let chain_id = downcast_to_u64(chain_id_result); if chain_id.is_none() { - return Err(GravityError::EthereumBadDataError( - format!("Chain ID is larger than u64 max: {}", chain_id_result)) - ); + return Err(GravityError::EthereumBadDataError(format!( + "Chain ID is larger than u64 max: {}", + chain_id_result + ))); } match chain_id.unwrap() { diff --git a/orchestrator/orchestrator/src/main_loop.rs b/orchestrator/orchestrator/src/main_loop.rs index 27664ff11..0dd5a72aa 100644 --- a/orchestrator/orchestrator/src/main_loop.rs +++ b/orchestrator/orchestrator/src/main_loop.rs @@ -293,7 +293,8 @@ pub async fn eth_signer_main_loop( valsets, cosmos_key, gravity_id.clone(), - ).await; + ) + .await; msg_sender .send(messages) .await @@ -326,7 +327,8 @@ pub async fn eth_signer_main_loop( transaction_batches, cosmos_key, gravity_id.clone(), - ).await; + ) + .await; msg_sender .send(messages) .await @@ -358,7 +360,8 @@ pub async fn eth_signer_main_loop( logic_calls, cosmos_key, gravity_id.clone(), - ).await; + ) + .await; msg_sender .send(messages) .await @@ -383,7 +386,10 @@ pub async fn eth_signer_main_loop( } pub async fn check_for_eth(orchestrator_address: EthAddress, eth_client: EthClient) { - let balance = eth_client.get_balance(orchestrator_address, None).await.unwrap(); + let balance = eth_client + .get_balance(orchestrator_address, None) + .await + .unwrap(); if balance == 0u8.into() { warn!("You don't have any Ethereum! You will need to send some to {} for this program to work. Dust will do for basic operations, more info about average relaying costs will be presented as the program runs", orchestrator_address); } diff --git a/orchestrator/orchestrator/src/oracle_resync.rs b/orchestrator/orchestrator/src/oracle_resync.rs index 656270091..102480b56 100644 --- a/orchestrator/orchestrator/src/oracle_resync.rs +++ b/orchestrator/orchestrator/src/oracle_resync.rs @@ -3,13 +3,12 @@ use ethereum_gravity::types::EthClient; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use gravity_utils::types::{FromLog, FromLogWithPrefix}; use gravity_utils::types::{ - ERC20_DEPLOYED_EVENT_STR, LOGIC_CALL_EVENT_STR, SEND_TO_COSMOS_EVENT_STR, + Erc20DeployedEvent, LogicCallExecutedEvent, SendToCosmosEvent, TransactionBatchExecutedEvent, + ValsetUpdatedEvent, ERC20_DEPLOYED_EVENT_STR, LOGIC_CALL_EVENT_STR, SEND_TO_COSMOS_EVENT_STR, TRANSACTION_BATCH_EXECUTED_EVENT_STR, VALSET_UPDATED_EVENT_STR, - Erc20DeployedEvent, LogicCallExecutedEvent, SendToCosmosEvent, - TransactionBatchExecutedEvent, ValsetUpdatedEvent, }; +use gravity_utils::types::{FromLog, FromLogWithPrefix}; use tokio::time::sleep as delay_for; use tonic::transport::Channel; @@ -43,15 +42,20 @@ pub async fn get_last_checked_block( let filter_gravity_contract_address = ValueOrArray::Value(gravity_contract_address); - let mut erc20_deployed_filter = Filter::new().address(filter_gravity_contract_address.clone()) + let mut erc20_deployed_filter = Filter::new() + .address(filter_gravity_contract_address.clone()) .event(&ERC20_DEPLOYED_EVENT_STR); - let mut logic_call_filter = Filter::new().address(filter_gravity_contract_address.clone()) + let mut logic_call_filter = Filter::new() + .address(filter_gravity_contract_address.clone()) .event(&LOGIC_CALL_EVENT_STR); - let mut send_to_cosmos_filter = Filter::new().address(filter_gravity_contract_address.clone()) + let mut send_to_cosmos_filter = Filter::new() + .address(filter_gravity_contract_address.clone()) .event(&SEND_TO_COSMOS_EVENT_STR); - let mut transaction_batch_filter = Filter::new().address(filter_gravity_contract_address.clone()) + let mut transaction_batch_filter = Filter::new() + .address(filter_gravity_contract_address.clone()) .event(&TRANSACTION_BATCH_EXECUTED_EVENT_STR); - let mut valset_updated_filter = Filter::new().address(filter_gravity_contract_address.clone()) + let mut valset_updated_filter = Filter::new() + .address(filter_gravity_contract_address.clone()) .event(&VALSET_UPDATED_EVENT_STR); let mut end_search_block = get_block_number_with_retry(eth_client.clone()).await; diff --git a/orchestrator/register_delegate_keys/src/main.rs b/orchestrator/register_delegate_keys/src/main.rs index 8cb057b28..5b0105091 100644 --- a/orchestrator/register_delegate_keys/src/main.rs +++ b/orchestrator/register_delegate_keys/src/main.rs @@ -125,7 +125,7 @@ async fn main() { cosmos_address, validator_key, ethereum_wallet, - (0f64,"".to_string()), + (0f64, "".to_string()), 1.0f64, ) .await diff --git a/orchestrator/relayer/src/batch_relaying.rs b/orchestrator/relayer/src/batch_relaying.rs index 3e15ada7d..5a3f85c1e 100644 --- a/orchestrator/relayer/src/batch_relaying.rs +++ b/orchestrator/relayer/src/batch_relaying.rs @@ -1,7 +1,9 @@ use cosmos_gravity::query::get_latest_transaction_batches; use cosmos_gravity::query::get_transaction_batch_signatures; -use ethereum_gravity::{one_eth_f32, submit_batch::send_eth_transaction_batch, types::EthClient, - utils::get_tx_batch_nonce}; +use ethereum_gravity::{ + one_eth_f32, submit_batch::send_eth_transaction_batch, types::EthClient, + utils::get_tx_batch_nonce, +}; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; @@ -52,7 +54,6 @@ pub async fn relay_batches( .await; } - /// This function retrieves the latest batches from the Cosmos module and then /// iterates through the signatures for each batch, determining if they are ready /// to submit. It is possible for a batch to not have valid signatures for two reasons @@ -110,7 +111,6 @@ async fn get_batches_and_signatures( return possible_batches; } - /// Attempts to submit batches with valid signatures, checking the state /// of the Ethereum chain to ensure that it is valid to submit a given batch /// more specifically that the correctly signed batch has not timed out or already @@ -145,12 +145,8 @@ async fn submit_batches( // do that though. for (token_type, possible_batches) in possible_batches { let erc20_contract = token_type; - let latest_ethereum_batch = get_tx_batch_nonce( - gravity_contract_address, - erc20_contract, - eth_client.clone(), - ) - .await; + let latest_ethereum_batch = + get_tx_batch_nonce(gravity_contract_address, erc20_contract, eth_client.clone()).await; if latest_ethereum_batch.is_err() { error!( "Failed to get latest Ethereum batch with {:?}", @@ -192,7 +188,10 @@ async fn submit_batches( let mut cost = cost.unwrap(); let total_cost = downcast_to_f32(cost.get_total()); if total_cost.is_none() { - error!("Total gas cost greater than f32 max, skipping batch submission: {}", oldest_signed_batch.nonce); + error!( + "Total gas cost greater than f32 max, skipping batch submission: {}", + oldest_signed_batch.nonce + ); continue; } let total_cost = total_cost.unwrap(); @@ -226,4 +225,4 @@ async fn submit_batches( } } } -} \ No newline at end of file +} diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index 295a6f446..84efe0680 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -2,7 +2,7 @@ use ethereum_gravity::types::EthClient; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use gravity_utils::types::{FromLog, VALSET_UPDATED_EVENT_STR, ValsetUpdatedEvent}; +use gravity_utils::types::{FromLog, ValsetUpdatedEvent, VALSET_UPDATED_EVENT_STR}; use gravity_utils::{error::GravityError, ethereum::downcast_to_u64, types::Valset}; use std::panic; use tonic::transport::Channel; @@ -44,7 +44,10 @@ pub async fn find_latest_valset( Ok(valset_updated_event) => { let downcast_nonce = downcast_to_u64(valset_updated_event.valset_nonce); if downcast_nonce.is_none() { - error!("ValsetUpdatedEvent has nonce larger than u64: {:?}", valset_updated_event); + error!( + "ValsetUpdatedEvent has nonce larger than u64: {:?}", + valset_updated_event + ); continue; } diff --git a/orchestrator/relayer/src/logic_call_relaying.rs b/orchestrator/relayer/src/logic_call_relaying.rs index fc02b30db..bc7c4ee57 100644 --- a/orchestrator/relayer/src/logic_call_relaying.rs +++ b/orchestrator/relayer/src/logic_call_relaying.rs @@ -1,9 +1,7 @@ use cosmos_gravity::query::{get_latest_logic_calls, get_logic_call_signatures}; use ethereum_gravity::one_eth_f32; use ethereum_gravity::{ - logic_call::send_eth_logic_call, - types::EthClient, - utils::get_logic_call_nonce, + logic_call::send_eth_logic_call, types::EthClient, utils::get_logic_call_nonce, }; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; @@ -102,7 +100,10 @@ pub async fn relay_logic_calls( let mut cost = cost.unwrap(); let total_cost = downcast_to_f32(cost.get_total()); if total_cost.is_none() { - error!("Total gas cost greater than f32 max, skipping logic call submission: {}", oldest_signed_call.invalidation_nonce); + error!( + "Total gas cost greater than f32 max, skipping logic call submission: {}", + oldest_signed_call.invalidation_nonce + ); return; } let total_cost = total_cost.unwrap(); diff --git a/orchestrator/relayer/src/main.rs b/orchestrator/relayer/src/main.rs index 5ffe12e65..66a6547d3 100644 --- a/orchestrator/relayer/src/main.rs +++ b/orchestrator/relayer/src/main.rs @@ -82,7 +82,10 @@ async fn main() { LOOP_SPEED, ) .await; - let eth_client = SignerMiddleware::new(connections.eth_provider.clone().unwrap(), ethereum_wallet.clone()); + let eth_client = SignerMiddleware::new( + connections.eth_provider.clone().unwrap(), + ethereum_wallet.clone(), + ); let eth_client = Arc::new(eth_client); let public_eth_key = eth_client.address(); diff --git a/orchestrator/relayer/src/main_loop.rs b/orchestrator/relayer/src/main_loop.rs index 39699b34b..0aba43a02 100644 --- a/orchestrator/relayer/src/main_loop.rs +++ b/orchestrator/relayer/src/main_loop.rs @@ -23,16 +23,19 @@ pub async fn relayer_main_loop( loop { let loop_start = Instant::now(); - let current_eth_valset = - find_latest_valset(&mut grpc_client, gravity_contract_address, eth_client.clone()).await; + let current_eth_valset = find_latest_valset( + &mut grpc_client, + gravity_contract_address, + eth_client.clone(), + ) + .await; if current_eth_valset.is_err() { error!("Could not get current valset! {:?}", current_eth_valset); continue; } let current_eth_valset = current_eth_valset.unwrap(); - let gravity_id = - get_gravity_id(gravity_contract_address, eth_client.clone()).await; + let gravity_id = get_gravity_id(gravity_contract_address, eth_client.clone()).await; if gravity_id.is_err() { error!("Failed to get GravityID, check your Eth node"); return; @@ -67,7 +70,7 @@ pub async fn relayer_main_loop( gravity_contract_address, gravity_id.clone(), LOOP_SPEED, - eth_gas_price_multiplier + eth_gas_price_multiplier, ) .await; diff --git a/orchestrator/relayer/src/valset_relaying.rs b/orchestrator/relayer/src/valset_relaying.rs index f8c459070..f41f4fcad 100644 --- a/orchestrator/relayer/src/valset_relaying.rs +++ b/orchestrator/relayer/src/valset_relaying.rs @@ -8,8 +8,10 @@ use cosmos_gravity::query::{get_all_valset_confirms, get_valset}; use ethereum_gravity::{one_eth_f32, types::EthClient, valset_update::send_eth_valset_update}; use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use gravity_utils::{ethereum::downcast_to_f32, ethereum::bytes_to_hex_str, - message_signatures::encode_valset_confirm_hashed, types::Valset}; +use gravity_utils::{ + ethereum::bytes_to_hex_str, ethereum::downcast_to_f32, + message_signatures::encode_valset_confirm_hashed, types::Valset, +}; use tonic::transport::Channel; /// Check the last validator set on Ethereum, if it's lower than our latest validator @@ -145,7 +147,10 @@ pub async fn relay_valsets( let cost = cost.unwrap(); let total_cost = downcast_to_f32(cost.get_total()); if total_cost.is_none() { - error!("Total gas cost greater than f32 max, skipping valset submission: {}", latest_cosmos_valset.nonce); + error!( + "Total gas cost greater than f32 max, skipping valset submission: {}", + latest_cosmos_valset.nonce + ); return; } let total_cost = total_cost.unwrap(); diff --git a/orchestrator/src/lib.rs b/orchestrator/src/lib.rs index 8b5f4e9b3..5b0c122bf 100644 --- a/orchestrator/src/lib.rs +++ b/orchestrator/src/lib.rs @@ -1,7 +1,7 @@ -pub use orchestrator as orchestrator; -pub use cosmos_gravity as cosmos_gravity; -pub use ethereum_gravity as ethereum_gravity; -pub use gravity_utils as gravity_utils; -pub use gravity_proto as gravity_proto; -pub use gorc as gorc; -pub use relayer as relayer; \ No newline at end of file +pub use cosmos_gravity; +pub use ethereum_gravity; +pub use gorc; +pub use gravity_proto; +pub use gravity_utils; +pub use orchestrator; +pub use relayer; diff --git a/orchestrator/test_runner/src/bootstrapping.rs b/orchestrator/test_runner/src/bootstrapping.rs index cbf32999c..1d9e12338 100644 --- a/orchestrator/test_runner/src/bootstrapping.rs +++ b/orchestrator/test_runner/src/bootstrapping.rs @@ -1,7 +1,7 @@ use crate::utils::ValidatorKeys; +use deep_space::private_key::PrivateKey as CosmosPrivateKey; use ethers::core::k256::ecdsa::SigningKey; use ethers::types::Address as EthAddress; -use deep_space::private_key::PrivateKey as CosmosPrivateKey; use std::fs::File; use std::io::{BufRead, BufReader, Read}; diff --git a/orchestrator/test_runner/src/happy_path.rs b/orchestrator/test_runner/src/happy_path.rs index af0a15abc..b9c61594c 100644 --- a/orchestrator/test_runner/src/happy_path.rs +++ b/orchestrator/test_runner/src/happy_path.rs @@ -318,7 +318,7 @@ async fn test_batch( amount: amount.clone(), }, bridge_denom_fee.clone(), - (10f64,"footoken".to_string()), + (10f64, "footoken".to_string()), &contact, 1.0, ) @@ -330,7 +330,7 @@ async fn test_batch( send_request_batch_tx( requester_cosmos_private_key, token_name.clone(), - (10f64,"footoken".to_string()), + (10f64, "footoken".to_string()), &contact, 1.0, ) @@ -386,7 +386,9 @@ async fn test_batch( // we have to send this address one eth so that it can perform contract calls send_one_eth(dest_eth_address, eth_client.clone()).await; assert_eq!( - get_erc20_balance(erc20_contract, dest_eth_address, eth_client.clone()).await.unwrap(), + get_erc20_balance(erc20_contract, dest_eth_address, eth_client.clone()) + .await + .unwrap(), amount_u256 ); info!( diff --git a/orchestrator/test_runner/src/happy_path_v2.rs b/orchestrator/test_runner/src/happy_path_v2.rs index c4cb9ffc1..ac27c7fde 100644 --- a/orchestrator/test_runner/src/happy_path_v2.rs +++ b/orchestrator/test_runner/src/happy_path_v2.rs @@ -1,8 +1,8 @@ //! This is the happy path test for Cosmos to Ethereum asset transfers, meaning assets originated on Cosmos -use crate::MINER_CLIENT; use crate::utils::get_user_key; use crate::utils::send_one_eth; +use crate::MINER_CLIENT; use crate::TOTAL_TIMEOUT; use crate::{get_fee, utils::ValidatorKeys}; use clarity::Uint256; @@ -32,12 +32,9 @@ pub async fn happy_path_test_v2( let mut grpc_client = grpc_client; let eth_wallet = LocalWallet::from(keys[0].eth_key.clone()); let eth_client = Arc::new(SignerMiddleware::new(eth_provider.clone(), eth_wallet)); - let starting_event_nonce = get_event_nonce( - gravity_address, - eth_client.clone() - ) - .await - .unwrap(); + let starting_event_nonce = get_event_nonce(gravity_address, eth_client.clone()) + .await + .unwrap(); let token_to_send_to_eth = "footoken".to_string(); let token_to_send_to_eth_display_name = "mfootoken".to_string(); @@ -49,16 +46,13 @@ pub async fn happy_path_test_v2( 6, gravity_address, Some(TOTAL_TIMEOUT), - eth_client.clone() - ) - .await - .unwrap(); - let ending_event_nonce = get_event_nonce( - gravity_address, - eth_client.clone() + eth_client.clone(), ) .await .unwrap(); + let ending_event_nonce = get_event_nonce(gravity_address, eth_client.clone()) + .await + .unwrap(); assert!(starting_event_nonce != ending_event_nonce); info!( @@ -146,7 +140,7 @@ pub async fn happy_path_test_v2( user.eth_address, send_to_eth_coin, get_fee(), - (10f64,"footoken".to_string()), + (10f64, "footoken".to_string()), contact, 1.0, ) @@ -161,7 +155,7 @@ pub async fn happy_path_test_v2( let res = send_request_batch_tx( keys[0].validator_key, token_to_send_to_eth.clone(), - (10f64,"footoken".to_string()), + (10f64, "footoken".to_string()), contact, 1.0, ) @@ -173,9 +167,8 @@ pub async fn happy_path_test_v2( info!("Waiting for batch to be signed and relayed to Ethereum"); let start = Instant::now(); while Instant::now() - start < TOTAL_TIMEOUT { - let balance = get_erc20_balance( - erc20_contract, user.eth_address, (*MINER_CLIENT).clone() - ).await; + let balance = + get_erc20_balance(erc20_contract, user.eth_address, (*MINER_CLIENT).clone()).await; if balance.is_err() { continue; } diff --git a/orchestrator/test_runner/src/main.rs b/orchestrator/test_runner/src/main.rs index 668260c45..9f3b68cf8 100644 --- a/orchestrator/test_runner/src/main.rs +++ b/orchestrator/test_runner/src/main.rs @@ -197,7 +197,14 @@ pub async fn main() { CosmosAddress::DEFAULT_PREFIX, ) .unwrap(); - transaction_stress_test(ð_provider, &contact, keys, gravity_address, erc20_addresses).await; + transaction_stress_test( + ð_provider, + &contact, + keys, + gravity_address, + erc20_addresses, + ) + .await; return; } else if test_type == "VALSET_STRESS" { info!("Starting valset stress test"); diff --git a/orchestrator/test_runner/src/orch_keys_update.rs b/orchestrator/test_runner/src/orch_keys_update.rs index 054fd3a76..a61a3ca0f 100644 --- a/orchestrator/test_runner/src/orch_keys_update.rs +++ b/orchestrator/test_runner/src/orch_keys_update.rs @@ -5,8 +5,8 @@ use cosmos_gravity::send::update_gravity_delegate_addresses; use deep_space::address::Address as CosmosAddress; use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::Contact; -use ethers::{core::k256::ecdsa::SigningKey, prelude::*}; use ethers::types::Address as EthAddress; +use ethers::{core::k256::ecdsa::SigningKey, prelude::*}; use gravity_proto::gravity::{ query_client::QueryClient as GravityQueryClient, DelegateKeysByEthereumSignerRequest, DelegateKeysByOrchestratorRequest, @@ -81,7 +81,7 @@ pub async fn orch_keys_update( cosmos_address, k.validator_key, ethereum_wallet, - (0f64,"".to_string()), + (0f64, "".to_string()), 2.0, ) .await diff --git a/orchestrator/test_runner/src/transaction_stress_test.rs b/orchestrator/test_runner/src/transaction_stress_test.rs index 195189705..57f164f88 100644 --- a/orchestrator/test_runner/src/transaction_stress_test.rs +++ b/orchestrator/test_runner/src/transaction_stress_test.rs @@ -1,13 +1,22 @@ -use crate::{MINER_CLIENT, one_eth, one_hundred_eth, one_hundred_eth_uint256, utils::*, TOTAL_TIMEOUT}; +use crate::{ + one_eth, one_hundred_eth, one_hundred_eth_uint256, utils::*, MINER_CLIENT, TOTAL_TIMEOUT, +}; use clarity::Uint256; use cosmos_gravity::send::{send_request_batch_tx, send_to_eth}; use deep_space::coin::Coin; use deep_space::Contact; -use ethereum_gravity::{erc20_utils::get_erc20_balance, send_to_cosmos::send_to_cosmos, utils::get_tx_batch_nonce}; +use ethereum_gravity::{ + erc20_utils::get_erc20_balance, send_to_cosmos::send_to_cosmos, utils::get_tx_batch_nonce, +}; use ethers::prelude::*; use ethers::types::Address as EthAddress; use futures::future::join_all; -use std::{collections::HashSet, str::FromStr, sync::Arc, time::{Duration, Instant}}; +use std::{ + collections::HashSet, + str::FromStr, + sync::Arc, + time::{Duration, Instant}, +}; use tokio::time::sleep as delay_for; const TIMEOUT: Duration = Duration::from_secs(120); @@ -51,7 +60,13 @@ pub async fn transaction_stress_test( // now we need to send all the sending eth addresses erc20's to send for token in erc20_addresses.iter() { - send_erc20_bulk(one_hundred_eth(), *token, &sending_eth_addresses, (*MINER_CLIENT).clone()).await; + send_erc20_bulk( + one_hundred_eth(), + *token, + &sending_eth_addresses, + (*MINER_CLIENT).clone(), + ) + .await; info!("Sent {} addresses 100 {}", NUM_USERS, token); } for token in erc20_addresses.iter() { @@ -141,7 +156,15 @@ pub async fn transaction_stress_test( denom: send_coin.denom.clone(), amount: 1u8.into(), }; - let res = send_to_eth(c_key, e_dest_addr, send_coin, send_fee, (0f64,"".to_string()), &contact, 1.0); + let res = send_to_eth( + c_key, + e_dest_addr, + send_coin, + send_fee, + (0f64, "".to_string()), + &contact, + 1.0, + ); futs.push(res); } let results = join_all(futs).await; @@ -157,9 +180,15 @@ pub async fn transaction_stress_test( for denom in denoms { info!("Requesting batch for {}", denom); - let res = send_request_batch_tx(keys[0].validator_key, denom, (0f64,"".to_string()), &contact, 1.0) - .await - .unwrap(); + let res = send_request_batch_tx( + keys[0].validator_key, + denom, + (0f64, "".to_string()), + &contact, + 1.0, + ) + .await + .unwrap(); info!("batch request response is {:?}", res); } @@ -170,7 +199,9 @@ pub async fn transaction_stress_test( for keys in user_keys.iter() { let e_dest_addr = keys.eth_dest_address; for token in erc20_addresses.iter() { - let bal = get_erc20_balance(*token, e_dest_addr, (*MINER_CLIENT).clone()).await.unwrap(); + let bal = get_erc20_balance(*token, e_dest_addr, (*MINER_CLIENT).clone()) + .await + .unwrap(); let bal = Uint256::from_str(bal.to_string().as_str()).unwrap(); if bal != send_amount.clone() { good = false; @@ -199,13 +230,9 @@ pub async fn transaction_stress_test( let eth_client = Arc::new(SignerMiddleware::new(eth_provider.clone(), eth_wallet)); for token in erc20_addresses { assert!( - get_tx_batch_nonce( - gravity_address, - token, - eth_client.clone() - ) - .await - .unwrap() + get_tx_batch_nonce(gravity_address, token, eth_client.clone()) + .await + .unwrap() > 0 ) } diff --git a/orchestrator/test_runner/src/utils.rs b/orchestrator/test_runner/src/utils.rs index 4185e5fe0..338250c35 100644 --- a/orchestrator/test_runner/src/utils.rs +++ b/orchestrator/test_runner/src/utils.rs @@ -4,8 +4,8 @@ use deep_space::coin::Coin; use deep_space::private_key::PrivateKey as CosmosPrivateKey; use deep_space::Contact; use ethereum_gravity::{erc20_utils::get_erc20_balance, types::EthClient}; -use ethers::prelude::*; use ethers::core::k256::ecdsa::SigningKey; +use ethers::prelude::*; use ethers::types::Address as EthAddress; use futures::future::join_all; use gravity_abi::erc20::ERC20; @@ -52,14 +52,28 @@ pub async fn send_erc20_bulk( destinations: &[EthAddress], eth_client: EthClient, ) { - let miner_balance = get_erc20_balance(erc20, eth_client.address(), eth_client.clone()).await.unwrap(); - assert!(miner_balance > amount.clone().checked_mul(destinations.len().into()).unwrap()); - - let mut nonce = eth_client.get_transaction_count(eth_client.address(), None).await.unwrap(); + let miner_balance = get_erc20_balance(erc20, eth_client.address(), eth_client.clone()) + .await + .unwrap(); + assert!( + miner_balance + > amount + .clone() + .checked_mul(destinations.len().into()) + .unwrap() + ); + + let mut nonce = eth_client + .get_transaction_count(eth_client.address(), None) + .await + .unwrap(); let mut transactions = Vec::new(); for address in destinations { - let data = ERC20::new(erc20, eth_client.clone()).transfer(*address, amount).calldata().unwrap(); + let data = ERC20::new(erc20, eth_client.clone()) + .transfer(*address, amount) + .calldata() + .unwrap(); let tx = TransactionRequest { from: Some(eth_client.address()), @@ -85,7 +99,9 @@ pub async fn send_erc20_bulk( join_all(pending_txs).await; for address in destinations { - let new_balance = get_erc20_balance(erc20, *address, eth_client.clone()).await.unwrap(); + let new_balance = get_erc20_balance(erc20, *address, eth_client.clone()) + .await + .unwrap(); assert!(new_balance >= amount.clone()); } } @@ -95,7 +111,10 @@ pub async fn send_erc20_bulk( /// single address without your sequence getting out of whack. By manually setting the nonce /// here we can quickly send thousands of transactions in only a few blocks pub async fn send_eth_bulk(amount: U256, destinations: &[EthAddress], eth_client: EthClient) { - let mut nonce = eth_client.get_transaction_count(eth_client.address(), None).await.unwrap(); + let mut nonce = eth_client + .get_transaction_count(eth_client.address(), None) + .await + .unwrap(); let mut transactions = Vec::new(); for address in destinations { From 8d5e6e4f56399cda0175949ab2dfa6227cdb1062 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Sat, 20 Nov 2021 01:03:53 -0800 Subject: [PATCH 089/115] Remove the unused erc20_transfer function --- .../ethereum_gravity/src/erc20_utils.rs | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs index feb987231..81b5edcbf 100644 --- a/orchestrator/ethereum_gravity/src/erc20_utils.rs +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -73,37 +73,3 @@ pub async fn get_erc20_balance( Ok(contract_call.call().await?) } - -// TODO(bolten): is this dead code? -pub async fn erc20_transfer( - erc20: Address, - destination: Address, - amount: U256, - eth_client: EthClient, -) -> Result { - let erc20_contract = ERC20::new(erc20, eth_client.clone()); - let contract_call = erc20_contract.transfer(destination, amount); - - let pending_tx = contract_call.send().await?; - let tx_hash = *pending_tx; - info!( - "Transferring {} ERC-20 {} from {} to {} with txid {}", - amount, - erc20, - eth_client.address(), - destination, - tx_hash - ); - // TODO(bolten): ethers interval default is 7s, this mirrors what web30 was doing, should we adjust? - // additionally we are mirroring only waiting for 1 confirmation by leaving that as default - let pending_tx = pending_tx.interval(Duration::from_secs(1)); - let potential_error = GravityError::GravityContractError(format!( - "Did not receive transaction receipt when transferring ERC-20 {}: {}", - erc20, tx_hash - )); - - match pending_tx.await? { - Some(receipt) => Ok(receipt.transaction_hash), - None => Err(potential_error), - } -} From cef865e61586979fee28f27aeca6cba082c3a30e Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Sat, 20 Nov 2021 01:49:03 -0800 Subject: [PATCH 090/115] Some cleanup --- orchestrator/ethereum_gravity/src/erc20_utils.rs | 4 ++-- orchestrator/ethereum_gravity/src/send_to_cosmos.rs | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs index 81b5edcbf..6aa61a40f 100644 --- a/orchestrator/ethereum_gravity/src/erc20_utils.rs +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -11,12 +11,12 @@ use std::time::Duration; /// contract A it can manipulate your ERC20 balances. This function checks if that has already been done. pub async fn check_erc20_approved( erc20: Address, - gravity_contract: Address, + target_contract: Address, address: Address, eth_client: EthClient, ) -> Result { let erc20_contract = ERC20::new(erc20, eth_client.clone()); - let contract_call = erc20_contract.allowance(address, gravity_contract); + let contract_call = erc20_contract.allowance(address, target_contract); let allowance = contract_call.call().await?; // TODO(bolten): verify if this check is sufficient/correct diff --git a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs index 0b35e2e01..0b0e65b47 100644 --- a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs +++ b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs @@ -10,9 +10,6 @@ use gravity_abi::gravity::*; use gravity_utils::error::GravityError; use std::time::Duration; -// TODO(bolten): no callers of this function ever sent any SendTxOptions -// for gas or anything else, but will apply this default hard limit as it was -// done originally -- should we change this? const SEND_TO_COSMOS_GAS_LIMIT: u128 = 100_000; #[allow(clippy::too_many_arguments)] From a1ec3abd0fb12ff96506fc595bf6634f29a3e322 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Sat, 20 Nov 2021 01:55:54 -0800 Subject: [PATCH 091/115] Add downcast tests to make sure overflows are safe --- orchestrator/gravity_utils/src/ethereum.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/orchestrator/gravity_utils/src/ethereum.rs b/orchestrator/gravity_utils/src/ethereum.rs index fa70943b6..a35dee59e 100644 --- a/orchestrator/gravity_utils/src/ethereum.rs +++ b/orchestrator/gravity_utils/src/ethereum.rs @@ -53,7 +53,23 @@ pub fn hex_str_to_bytes(s: &str) -> Result, GravityError> { Ok(bytes) } -// TODO(bolten): add tests to make sure the downcast panics catch +#[test] +fn overflow_f32() { + assert_eq!(downcast_to_f32(42.into()), Some(42f32)); + assert_eq!(downcast_to_f32(U256::MAX), None); +} + +#[test] +fn overflow_u64() { + assert_eq!(downcast_to_u64(42.into()), Some(42u64)); + assert_eq!(downcast_to_u64(U256::MAX), None); +} + +#[test] +fn overflow_u128() { + assert_eq!(downcast_to_u128(42.into()), Some(42u128)); + assert_eq!(downcast_to_u128(U256::MAX), None); +} #[test] fn encode_bytes() { From 6fcc182929b5be91275172c35dd6de9ebec8578f Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Sat, 20 Nov 2021 02:19:20 -0800 Subject: [PATCH 092/115] Add a TODO around event ABI strings --- orchestrator/orchestrator/src/oracle_resync.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/orchestrator/orchestrator/src/oracle_resync.rs b/orchestrator/orchestrator/src/oracle_resync.rs index 102480b56..808af407d 100644 --- a/orchestrator/orchestrator/src/oracle_resync.rs +++ b/orchestrator/orchestrator/src/oracle_resync.rs @@ -42,6 +42,8 @@ pub async fn get_last_checked_block( let filter_gravity_contract_address = ValueOrArray::Value(gravity_contract_address); + // TODO(bolten): there might be a cleaner way to get these event ABI signature strings + // from the generated ABI files, should look into that let mut erc20_deployed_filter = Filter::new() .address(filter_gravity_contract_address.clone()) .event(&ERC20_DEPLOYED_EVENT_STR); From ac8e6acd6bd4e437b931cadbd1b00152bb770153 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 22 Nov 2021 15:09:24 -0800 Subject: [PATCH 093/115] Fixing a bug another PR noticed in main --- orchestrator/gorc/src/commands/cosmos_to_eth.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchestrator/gorc/src/commands/cosmos_to_eth.rs b/orchestrator/gorc/src/commands/cosmos_to_eth.rs index b36644517..bb53a525d 100644 --- a/orchestrator/gorc/src/commands/cosmos_to_eth.rs +++ b/orchestrator/gorc/src/commands/cosmos_to_eth.rs @@ -57,7 +57,7 @@ impl Runnable for CosmosToEthCmd { let cosmos_prefix = config.cosmos.prefix.trim(); let cosmos_address = cosmos_key.to_address(cosmos_prefix).unwrap(); - let cosmos_grpc = config.cosmos.prefix.trim(); + let cosmos_grpc = config.cosmos.grpc.trim(); println!("Sending from Cosmos address {}", cosmos_address); abscissa_tokio::run_with_actix(&APP, async { let connections = create_rpc_connections( From 9a33e2b5976a81cb3f8743255ca80512ef21005c Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 22 Nov 2021 23:31:59 -0800 Subject: [PATCH 094/115] Fix eth address string formatting The ethers Address to_string() implementation returns a truncated string rather than the full address (e.g. 0xaaaa...bbbb). We have to manually format the full address by parsing the Address bytes. --- orchestrator/cosmos_gravity/src/build.rs | 18 +++++++++--------- orchestrator/cosmos_gravity/src/query.rs | 3 ++- orchestrator/cosmos_gravity/src/send.rs | 3 ++- .../gorc/src/commands/orchestrator/start.rs | 9 +++++---- orchestrator/gorc/src/commands/tx/eth.rs | 7 +++++-- .../gravity_utils/src/connection_prep.rs | 3 ++- orchestrator/gravity_utils/src/ethereum.rs | 5 +++++ .../gravity_utils/src/types/valsets.rs | 6 +++--- orchestrator/relayer/src/main.rs | 7 ++++--- .../test_runner/src/orch_keys_update.rs | 5 +++-- 10 files changed, 40 insertions(+), 26 deletions(-) diff --git a/orchestrator/cosmos_gravity/src/build.rs b/orchestrator/cosmos_gravity/src/build.rs index 6ec96498b..8b2cc31e7 100644 --- a/orchestrator/cosmos_gravity/src/build.rs +++ b/orchestrator/cosmos_gravity/src/build.rs @@ -6,7 +6,7 @@ use ethers::prelude::*; use ethers::utils::keccak256; use gravity_proto::gravity as proto; use gravity_proto::ToAny; -use gravity_utils::ethereum::{bytes_to_hex_str, downcast_to_u64}; +use gravity_utils::ethereum::{bytes_to_hex_str, downcast_to_u64, format_eth_address}; use gravity_utils::message_signatures::{ encode_logic_call_confirm, encode_tx_batch_confirm, encode_valset_confirm, }; @@ -30,7 +30,7 @@ pub async fn signer_set_tx_confirmation_messages( // will never throw an error let signature = eth_client.signer().sign_message(data).await.unwrap(); let confirmation = proto::SignerSetTxConfirmation { - ethereum_signer: ethereum_address.to_string(), + ethereum_signer: format_eth_address(ethereum_address), signer_set_nonce: valset.nonce, signature: signature.into(), }; @@ -61,9 +61,9 @@ pub async fn batch_tx_confirmation_messages( // will never throw an error let signature = eth_client.signer().sign_message(data).await.unwrap(); let confirmation = proto::BatchTxConfirmation { - token_contract: batch.token_contract.to_string(), + token_contract: format_eth_address(batch.token_contract), batch_nonce: batch.nonce, - ethereum_signer: ethereum_address.to_string(), + ethereum_signer: format_eth_address(ethereum_address), signature: signature.into(), }; let msg = proto::MsgSubmitEthereumEvent { @@ -94,7 +94,7 @@ pub async fn contract_call_tx_confirmation_messages( // will never throw an error let signature = eth_client.signer().sign_message(data).await.unwrap(); let confirmation = proto::ContractCallTxConfirmation { - ethereum_signer: ethereum_address.to_string(), + ethereum_signer: format_eth_address(ethereum_address), signature: signature.into(), invalidation_scope: bytes_to_hex_str(&logic_call.invalidation_id) .as_bytes() @@ -135,10 +135,10 @@ pub fn ethereum_event_messages( let event = proto::SendToCosmosEvent { event_nonce: downcast_to_u64(deposit.event_nonce.clone()).unwrap(), ethereum_height: downcast_to_u64(deposit.block_height).unwrap(), - token_contract: deposit.erc20.to_string(), + token_contract: format_eth_address(deposit.erc20), amount: deposit.amount.to_string(), cosmos_receiver: deposit.destination.to_string(), - ethereum_sender: deposit.sender.to_string(), + ethereum_sender: format_eth_address(deposit.sender), }; let msg = proto::MsgSubmitEthereumEvent { signer: cosmos_address.to_string(), @@ -152,7 +152,7 @@ pub fn ethereum_event_messages( event_nonce: downcast_to_u64(batch.event_nonce.clone()).unwrap(), batch_nonce: downcast_to_u64(batch.batch_nonce.clone()).unwrap(), ethereum_height: downcast_to_u64(batch.block_height).unwrap(), - token_contract: batch.erc20.to_string(), + token_contract: format_eth_address(batch.erc20), }; let msg = proto::MsgSubmitEthereumEvent { signer: cosmos_address.to_string(), @@ -166,7 +166,7 @@ pub fn ethereum_event_messages( event_nonce: downcast_to_u64(deploy.event_nonce.clone()).unwrap(), ethereum_height: downcast_to_u64(deploy.block_height).unwrap(), cosmos_denom: deploy.cosmos_denom, - token_contract: deploy.erc20_address.to_string(), + token_contract: format_eth_address(deploy.erc20_address), erc20_name: deploy.name, erc20_symbol: deploy.symbol, erc20_decimals: deploy.decimals as u64, diff --git a/orchestrator/cosmos_gravity/src/query.rs b/orchestrator/cosmos_gravity/src/query.rs index dab3d7eb7..783ba83b9 100644 --- a/orchestrator/cosmos_gravity/src/query.rs +++ b/orchestrator/cosmos_gravity/src/query.rs @@ -3,6 +3,7 @@ use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_proto::gravity::*; use gravity_utils::error::GravityError; +use gravity_utils::ethereum::format_eth_address; use gravity_utils::types::*; use tonic::transport::Channel; @@ -109,7 +110,7 @@ pub async fn get_transaction_batch_signatures( let request = client .batch_tx_confirmations(BatchTxConfirmationsRequest { batch_nonce: nonce, - token_contract: contract_address.to_string(), + token_contract: format_eth_address(contract_address), }) .await?; let batch_confirms = request.into_inner().signatures; diff --git a/orchestrator/cosmos_gravity/src/send.rs b/orchestrator/cosmos_gravity/src/send.rs index a66937d56..ee343d7f5 100644 --- a/orchestrator/cosmos_gravity/src/send.rs +++ b/orchestrator/cosmos_gravity/src/send.rs @@ -13,6 +13,7 @@ use gravity_proto::cosmos_sdk_proto::cosmos::base::abci::v1beta1::TxResponse; use gravity_proto::cosmos_sdk_proto::cosmos::tx::v1beta1::BroadcastMode; use gravity_proto::gravity as proto; use gravity_utils::error::GravityError; +use gravity_utils::ethereum::format_eth_address; use prost::Message; use std::cmp; use std::collections::HashSet; @@ -60,7 +61,7 @@ pub async fn update_gravity_delegate_addresses( let msg = proto::MsgDelegateKeys { validator_address: our_valoper_address.to_string(), orchestrator_address: delegate_cosmos_address.to_string(), - ethereum_address: delegate_eth_address.to_string(), + ethereum_address: format_eth_address(delegate_eth_address), eth_signature: eth_signature.to_vec(), }; let msg = Msg::new("/gravity.v1.MsgDelegateKeys", msg); diff --git a/orchestrator/gorc/src/commands/orchestrator/start.rs b/orchestrator/gorc/src/commands/orchestrator/start.rs index 39cb4602a..fd6ce9b59 100644 --- a/orchestrator/gorc/src/commands/orchestrator/start.rs +++ b/orchestrator/gorc/src/commands/orchestrator/start.rs @@ -1,9 +1,10 @@ use crate::{application::APP, prelude::*}; use abscissa_core::{Clap, Command, Runnable}; use ethers::{prelude::*, types::Address as EthAddress}; -use gravity_utils::connection_prep::{ - check_delegate_addresses, check_for_eth, check_for_fee_denom, create_rpc_connections, - wait_for_cosmos_node_ready, +use gravity_utils::{ + connection_prep::{check_delegate_addresses, check_for_eth, check_for_fee_denom, + create_rpc_connections,wait_for_cosmos_node_ready,}, + ethereum::format_eth_address, }; use orchestrator::main_loop::{ orchestrator_main_loop, ETH_ORACLE_LOOP_SPEED, ETH_SIGNER_LOOP_SPEED, @@ -68,7 +69,7 @@ impl Runnable for StartCommand { let eth_client = Arc::new(eth_client); info!("Starting Relayer + Oracle + Ethereum Signer"); - info!("Ethereum Address: {}", ethereum_address); + info!("Ethereum Address: {}", format_eth_address(ethereum_address)); info!("Cosmos Address {}", cosmos_address); // check if the cosmos node is syncing, if so wait for it diff --git a/orchestrator/gorc/src/commands/tx/eth.rs b/orchestrator/gorc/src/commands/tx/eth.rs index 863781e98..b79a1ba3a 100644 --- a/orchestrator/gorc/src/commands/tx/eth.rs +++ b/orchestrator/gorc/src/commands/tx/eth.rs @@ -7,7 +7,10 @@ use ethereum_gravity::erc20_utils::get_erc20_balance; use ethereum_gravity::send_to_cosmos::send_to_cosmos; use ethers::prelude::*; use ethers::types::Address as EthAddress; -use gravity_utils::connection_prep::{check_for_eth, create_rpc_connections}; +use gravity_utils::{ + connection_prep::{check_for_eth, create_rpc_connections}, + ethereum::format_eth_address, +}; use std::sync::Arc; /// Create transactions in Eth chain @@ -51,7 +54,7 @@ impl Runnable for SendToCosmos { let erc20_amount = self.free[3].clone(); let ethereum_wallet = lookup_eth_key(from_eth_key); - println!("Sending from Eth address {}", ethereum_wallet.address()); + println!("Sending from Eth address {}", format_eth_address(ethereum_wallet.address())); let config = APP.config(); let cosmos_prefix = config.cosmos.prefix.clone(); let cosmso_grpc = config.cosmos.grpc.clone(); diff --git a/orchestrator/gravity_utils/src/connection_prep.rs b/orchestrator/gravity_utils/src/connection_prep.rs index 931608dd2..3d815c500 100644 --- a/orchestrator/gravity_utils/src/connection_prep.rs +++ b/orchestrator/gravity_utils/src/connection_prep.rs @@ -2,6 +2,7 @@ //! It's a common problem to have conflicts between ipv4 and ipv6 localhost and this module is first and foremost supposed to resolve that problem //! by trying more than one thing to handle potentially misconfigured inputs. +use crate::ethereum::format_eth_address; use deep_space::client::ChainStatus; use deep_space::Address as CosmosAddress; use deep_space::Contact; @@ -268,7 +269,7 @@ pub async fn check_delegate_addresses( ) { let eth_response = client .delegate_keys_by_ethereum_signer(DelegateKeysByEthereumSignerRequest { - ethereum_signer: delegate_eth_address.to_string(), + ethereum_signer: format_eth_address(delegate_eth_address), }) .await; let orchestrator_response = client diff --git a/orchestrator/gravity_utils/src/ethereum.rs b/orchestrator/gravity_utils/src/ethereum.rs index a35dee59e..8cbefc70b 100644 --- a/orchestrator/gravity_utils/src/ethereum.rs +++ b/orchestrator/gravity_utils/src/ethereum.rs @@ -1,5 +1,6 @@ use crate::error::GravityError; use ethers::prelude::*; +use ethers::types::Address as EthAddress; use std::panic; pub fn downcast_to_f32(input: U256) -> Option { @@ -27,6 +28,10 @@ pub fn downcast_to_u128(input: U256) -> Option { } } +pub fn format_eth_address(address: EthAddress) -> String { + format!("0x{}", bytes_to_hex_str(address.as_bytes())) +} + pub fn bytes_to_hex_str(bytes: &[u8]) -> String { bytes .iter() diff --git a/orchestrator/gravity_utils/src/types/valsets.rs b/orchestrator/gravity_utils/src/types/valsets.rs index b53bbf6cc..99ef48ea2 100644 --- a/orchestrator/gravity_utils/src/types/valsets.rs +++ b/orchestrator/gravity_utils/src/types/valsets.rs @@ -1,5 +1,5 @@ use super::*; -use crate::error::GravityError; +use crate::{error::GravityError, ethereum::format_eth_address}; use deep_space::error::CosmosGrpcError; use ethers::types::{Address as EthAddress, Signature as EthSignature}; use std::convert::TryFrom; @@ -360,7 +360,7 @@ impl ValsetMember { impl fmt::Display for ValsetMember { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.eth_address { - Some(a) => write!(f, "Address: {} Power: {}", a, self.power), + Some(a) => write!(f, "Address: {} Power: {}", format_eth_address(a), self.power), None => write!(f, "Address: None Power: {}", self.power), } } @@ -395,7 +395,7 @@ impl From<&gravity_proto::gravity::EthereumSigner> for ValsetMember { impl From<&ValsetMember> for gravity_proto::gravity::EthereumSigner { fn from(input: &ValsetMember) -> gravity_proto::gravity::EthereumSigner { let ethereum_address = match input.eth_address { - Some(e) => e.to_string(), + Some(e) => format_eth_address(e), None => String::new(), }; gravity_proto::gravity::EthereumSigner { diff --git a/orchestrator/relayer/src/main.rs b/orchestrator/relayer/src/main.rs index 66a6547d3..dfa693a85 100644 --- a/orchestrator/relayer/src/main.rs +++ b/orchestrator/relayer/src/main.rs @@ -7,8 +7,9 @@ use env_logger::Env; use ethers::prelude::*; use ethers::signers::LocalWallet as EthWallet; use ethers::types::Address as EthAddress; -use gravity_utils::connection_prep::{ - check_for_eth, create_rpc_connections, wait_for_cosmos_node_ready, +use gravity_utils::{ + connection_prep::{check_for_eth, create_rpc_connections, wait_for_cosmos_node_ready,}, + ethereum::format_eth_address, }; pub mod batch_relaying; @@ -90,7 +91,7 @@ async fn main() { let public_eth_key = eth_client.address(); info!("Starting Gravity Relayer"); - info!("Ethereum Address: {}", public_eth_key); + info!("Ethereum Address: {}", format_eth_address(public_eth_key)); let contact = connections.contact.clone().unwrap(); diff --git a/orchestrator/test_runner/src/orch_keys_update.rs b/orchestrator/test_runner/src/orch_keys_update.rs index a61a3ca0f..c29cb2d23 100644 --- a/orchestrator/test_runner/src/orch_keys_update.rs +++ b/orchestrator/test_runner/src/orch_keys_update.rs @@ -11,6 +11,7 @@ use gravity_proto::gravity::{ query_client::QueryClient as GravityQueryClient, DelegateKeysByEthereumSignerRequest, DelegateKeysByOrchestratorRequest, }; +use gravity_utils::ethereum::format_eth_address; use rand::Rng; use std::time::Duration; use tonic::transport::Channel; @@ -31,7 +32,7 @@ pub async fn orch_keys_update( let orch_address = k.orch_key.to_address(&contact.get_prefix()).unwrap(); let eth_response = grpc_client .delegate_keys_by_ethereum_signer(DelegateKeysByEthereumSignerRequest { - ethereum_signer: eth_address.to_string(), + ethereum_signer: format_eth_address(eth_address), }) .await .unwrap() @@ -71,7 +72,7 @@ pub async fn orch_keys_update( info!( "Signing and submitting Delegate addresses {} for validator {}", - ethereum_wallet.address(), + format_eth_address(ethereum_wallet.address()), cosmos_address, ); // send in the new delegate keys signed by the validator address From 7e49276253808b8890bffce084aa4464776bb5fe Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 23 Nov 2021 00:03:42 -0800 Subject: [PATCH 095/115] Conversion of variable length u8s to fixed 32 There are several cases where we may want to convert a Vec or &[u8] to a [u8; 32], so add some generic functions for that and remove the specific case for invalidation ids. Additionally, during testing, it appears that the recovery of the correct address during valset updates was not working correctly. The Signature object of ethers can accept different types of inputs, and if it's a vec of u8s rather than a [u8; 32] it will hash the message again. We must convert out signature explicitly into a [u8; 32] as it is already a hashed value in order to get the correct address back from recover. --- .../ethereum_gravity/src/logic_call.rs | 9 +++---- orchestrator/ethereum_gravity/src/utils.rs | 19 ++------------- orchestrator/gravity_utils/src/ethereum.rs | 24 +++++++++++++++++++ .../gravity_utils/src/types/valsets.rs | 5 ++-- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/logic_call.rs b/orchestrator/ethereum_gravity/src/logic_call.rs index 11561dd36..9a722972c 100644 --- a/orchestrator/ethereum_gravity/src/logic_call.rs +++ b/orchestrator/ethereum_gravity/src/logic_call.rs @@ -1,15 +1,16 @@ use crate::{ types::{EthClient, EthSignerMiddleware}, utils::{ - convert_invalidation_id_to_fixed_array, get_logic_call_nonce, - get_send_transaction_gas_price, GasCost, + get_logic_call_nonce, + get_send_transaction_gas_price, + GasCost, }, }; use ethers::contract::builders::ContractCall; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_abi::gravity::*; -use gravity_utils::ethereum::bytes_to_hex_str; +use gravity_utils::ethereum::{bytes_to_hex_str, vec_u8_to_fixed_32}; use gravity_utils::types::*; use gravity_utils::{error::GravityError, message_signatures::encode_logic_call_confirm_hashed}; use std::time::Duration; @@ -161,7 +162,7 @@ pub fn build_send_logic_call_contract_call( .iter() .map(|fee| fee.token_contract_address) .collect(); - let invalidation_id = convert_invalidation_id_to_fixed_array(call.invalidation_id.clone())?; + let invalidation_id = vec_u8_to_fixed_32(call.invalidation_id.clone())?; let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) .submit_logic_call( diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index c8bf13e39..8c82639a1 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -7,7 +7,7 @@ use ethers::types::Address as EthAddress; use ethers::utils::keccak256; use gravity_abi::gravity::*; use gravity_utils::error::GravityError; -use gravity_utils::ethereum::downcast_to_u64; +use gravity_utils::ethereum::{downcast_to_u64, vec_u8_to_fixed_32}; use gravity_utils::types::*; use std::cmp::min; @@ -97,7 +97,7 @@ pub async fn get_logic_call_nonce( invalidation_id: Vec, eth_client: EthClient, ) -> Result { - let invalidation_id = convert_invalidation_id_to_fixed_array(invalidation_id)?; + let invalidation_id = vec_u8_to_fixed_32(invalidation_id)?; let contract_call = Gravity::new(gravity_contract_address, eth_client.clone()) .last_logic_call_nonce(invalidation_id) @@ -204,21 +204,6 @@ pub async fn get_send_transaction_gas_price(eth_client: EthClient) -> Result, -) -> Result<[u8; 32], GravityError> { - if invalidation_id.len() != 32 { - return Err(GravityError::InvalidArgumentError(format!( - "Error getting logic call nonce, invalidation id is not 32 bytes: {:?}", - invalidation_id - ))); - } - - let mut invalidation_id_slice: [u8; 32] = Default::default(); - invalidation_id_slice.copy_from_slice(&invalidation_id[..]); - Ok(invalidation_id_slice) -} - /// Just a helper struct to represent the cost of actions on Ethereum #[derive(Debug, Default, Clone)] pub struct GasCost { diff --git a/orchestrator/gravity_utils/src/ethereum.rs b/orchestrator/gravity_utils/src/ethereum.rs index 8cbefc70b..999fd1480 100644 --- a/orchestrator/gravity_utils/src/ethereum.rs +++ b/orchestrator/gravity_utils/src/ethereum.rs @@ -58,6 +58,30 @@ pub fn hex_str_to_bytes(s: &str) -> Result, GravityError> { Ok(bytes) } +pub fn vec_u8_to_fixed_32(v: Vec) -> Result<[u8; 32], GravityError> { + if v.len() != 32 { + return Err(GravityError::InvalidArgumentError(format!( + "Error converting Vec to [u8; 32], length is not 32: {:?}", + v + ))); + } + + Ok(u8_slice_to_fixed_32(&v[..])?) +} + +pub fn u8_slice_to_fixed_32(v: &[u8]) -> Result<[u8; 32], GravityError> { + if v.len() != 32 { + return Err(GravityError::InvalidArgumentError(format!( + "Error converting &[u8] to [u8; 32], length is not 32: {:?}", + v + ))); + } + + let mut v_slice: [u8; 32] = Default::default(); + v_slice.copy_from_slice(v); + Ok(v_slice) +} + #[test] fn overflow_f32() { assert_eq!(downcast_to_f32(42.into()), Some(42f32)); diff --git a/orchestrator/gravity_utils/src/types/valsets.rs b/orchestrator/gravity_utils/src/types/valsets.rs index 99ef48ea2..31da11e72 100644 --- a/orchestrator/gravity_utils/src/types/valsets.rs +++ b/orchestrator/gravity_utils/src/types/valsets.rs @@ -1,5 +1,5 @@ use super::*; -use crate::{error::GravityError, ethereum::format_eth_address}; +use crate::{error::GravityError, ethereum::{format_eth_address, u8_slice_to_fixed_32}}; use deep_space::error::CosmosGrpcError; use ethers::types::{Address as EthAddress, Signature as EthSignature}; use std::convert::TryFrom; @@ -147,7 +147,8 @@ impl Valset { if let Some(eth_address) = member.eth_address { if let Some(sig) = signatures_hashmap.get(ð_address) { assert_eq!(sig.get_eth_address(), eth_address); - let recover_key = sig.get_signature().recover(signed_message)?; + let sig_hash = u8_slice_to_fixed_32(signed_message)?; + let recover_key = sig.get_signature().recover(sig_hash)?; if recover_key == sig.get_eth_address() { out.push(GravitySignature { power: member.power, From 91cda001941bf8451fa8d61a991c490a8ef69831 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 23 Nov 2021 00:10:07 -0800 Subject: [PATCH 096/115] Ran cargo fmt again, not sure why some changed --- orchestrator/cosmos_gravity/src/send.rs | 10 ++++++---- orchestrator/gorc/src/commands/deploy/erc20.rs | 5 +---- orchestrator/gorc/src/commands/orchestrator/start.rs | 6 ++++-- orchestrator/gorc/src/commands/tx/eth.rs | 5 ++++- orchestrator/gravity_utils/src/types/valsets.rs | 7 ++++++- orchestrator/orchestrator/src/main_loop.rs | 9 ++++----- orchestrator/relayer/src/main.rs | 2 +- orchestrator/relayer/src/valset_relaying.rs | 1 + orchestrator/test_runner/src/happy_path.rs | 7 ++++--- .../test_runner/src/transaction_stress_test.rs | 11 +++-------- 10 files changed, 34 insertions(+), 29 deletions(-) diff --git a/orchestrator/cosmos_gravity/src/send.rs b/orchestrator/cosmos_gravity/src/send.rs index ee343d7f5..82be6574e 100644 --- a/orchestrator/cosmos_gravity/src/send.rs +++ b/orchestrator/cosmos_gravity/src/send.rs @@ -81,10 +81,12 @@ pub async fn send_to_eth( gas_adjustment: f64, ) -> Result { if amount.denom != bridge_fee.denom { - return Err(GravityError::CosmosGrpcError(CosmosGrpcError::BadInput(format!( - "The amount ({}) and bridge_fee ({}) denominations do not match.", - amount.denom, bridge_fee.denom, - )))); + return Err(GravityError::CosmosGrpcError(CosmosGrpcError::BadInput( + format!( + "The amount ({}) and bridge_fee ({}) denominations do not match.", + amount.denom, bridge_fee.denom, + ), + ))); } let cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); diff --git a/orchestrator/gorc/src/commands/deploy/erc20.rs b/orchestrator/gorc/src/commands/deploy/erc20.rs index 6f1ebe83b..07dc1c465 100644 --- a/orchestrator/gorc/src/commands/deploy/erc20.rs +++ b/orchestrator/gorc/src/commands/deploy/erc20.rs @@ -6,10 +6,7 @@ use gravity_proto::gravity::{DenomToErc20ParamsRequest, DenomToErc20Request}; use gravity_utils::connection_prep::{check_for_eth, create_rpc_connections}; use std::convert::TryFrom; use std::process::exit; -use std::{ - sync::Arc, - time::Duration, -}; +use std::{sync::Arc, time::Duration}; use tokio::time::sleep as delay_for; /// Deploy Erc20 diff --git a/orchestrator/gorc/src/commands/orchestrator/start.rs b/orchestrator/gorc/src/commands/orchestrator/start.rs index fd6ce9b59..ae0ed801e 100644 --- a/orchestrator/gorc/src/commands/orchestrator/start.rs +++ b/orchestrator/gorc/src/commands/orchestrator/start.rs @@ -2,8 +2,10 @@ use crate::{application::APP, prelude::*}; use abscissa_core::{Clap, Command, Runnable}; use ethers::{prelude::*, types::Address as EthAddress}; use gravity_utils::{ - connection_prep::{check_delegate_addresses, check_for_eth, check_for_fee_denom, - create_rpc_connections,wait_for_cosmos_node_ready,}, + connection_prep::{ + check_delegate_addresses, check_for_eth, check_for_fee_denom, create_rpc_connections, + wait_for_cosmos_node_ready, + }, ethereum::format_eth_address, }; use orchestrator::main_loop::{ diff --git a/orchestrator/gorc/src/commands/tx/eth.rs b/orchestrator/gorc/src/commands/tx/eth.rs index b79a1ba3a..895255d8b 100644 --- a/orchestrator/gorc/src/commands/tx/eth.rs +++ b/orchestrator/gorc/src/commands/tx/eth.rs @@ -54,7 +54,10 @@ impl Runnable for SendToCosmos { let erc20_amount = self.free[3].clone(); let ethereum_wallet = lookup_eth_key(from_eth_key); - println!("Sending from Eth address {}", format_eth_address(ethereum_wallet.address())); + println!( + "Sending from Eth address {}", + format_eth_address(ethereum_wallet.address()) + ); let config = APP.config(); let cosmos_prefix = config.cosmos.prefix.clone(); let cosmso_grpc = config.cosmos.grpc.clone(); diff --git a/orchestrator/gravity_utils/src/types/valsets.rs b/orchestrator/gravity_utils/src/types/valsets.rs index 31da11e72..872d8f6ed 100644 --- a/orchestrator/gravity_utils/src/types/valsets.rs +++ b/orchestrator/gravity_utils/src/types/valsets.rs @@ -361,7 +361,12 @@ impl ValsetMember { impl fmt::Display for ValsetMember { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.eth_address { - Some(a) => write!(f, "Address: {} Power: {}", format_eth_address(a), self.power), + Some(a) => write!( + f, + "Address: {} Power: {}", + format_eth_address(a), + self.power + ), None => write!(f, "Address: None Power: {}", self.power), } } diff --git a/orchestrator/orchestrator/src/main_loop.rs b/orchestrator/orchestrator/src/main_loop.rs index 55e5feb25..907961cb0 100644 --- a/orchestrator/orchestrator/src/main_loop.rs +++ b/orchestrator/orchestrator/src/main_loop.rs @@ -27,10 +27,7 @@ use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::ethereum::bytes_to_hex_str; use relayer::main_loop::relayer_main_loop; use std::convert::TryInto; -use std::{ - net, - time::Duration, -}; +use std::{net, time::Duration}; use tokio::time::sleep as delay_for; use tonic::transport::Channel; @@ -300,7 +297,9 @@ pub async fn eth_signer_main_loop( } // sign the last unsigned batch, TODO check if we already have signed this - match get_oldest_unsigned_transaction_batch(&mut grpc_client, our_cosmos_address).await { + match get_oldest_unsigned_transaction_batch(&mut grpc_client, our_cosmos_address) + .await + { Ok(Some(last_unsigned_batch)) => { info!( "Sending batch confirm for {}:{} fees {} timeout {}", diff --git a/orchestrator/relayer/src/main.rs b/orchestrator/relayer/src/main.rs index dfa693a85..7ca8e0df7 100644 --- a/orchestrator/relayer/src/main.rs +++ b/orchestrator/relayer/src/main.rs @@ -8,7 +8,7 @@ use ethers::prelude::*; use ethers::signers::LocalWallet as EthWallet; use ethers::types::Address as EthAddress; use gravity_utils::{ - connection_prep::{check_for_eth, create_rpc_connections, wait_for_cosmos_node_ready,}, + connection_prep::{check_for_eth, create_rpc_connections, wait_for_cosmos_node_ready}, ethereum::format_eth_address, }; diff --git a/orchestrator/relayer/src/valset_relaying.rs b/orchestrator/relayer/src/valset_relaying.rs index f41f4fcad..050c87586 100644 --- a/orchestrator/relayer/src/valset_relaying.rs +++ b/orchestrator/relayer/src/valset_relaying.rs @@ -69,6 +69,7 @@ pub async fn relay_valsets( for confirm in confirms.iter() { assert_eq!(cosmos_valset.nonce, confirm.nonce); } + let hash = encode_valset_confirm_hashed(gravity_id.clone(), cosmos_valset.clone()); // there are two possible encoding problems that could cause the very rare sig failure bug, diff --git a/orchestrator/test_runner/src/happy_path.rs b/orchestrator/test_runner/src/happy_path.rs index ea96b7607..758b201e8 100644 --- a/orchestrator/test_runner/src/happy_path.rs +++ b/orchestrator/test_runner/src/happy_path.rs @@ -110,9 +110,10 @@ pub async fn happy_path_test( pub async fn wait_for_nonzero_valset(gravity_address: EthAddress) { match tokio::time::timeout(TOTAL_TIMEOUT, async { - let mut current_eth_valset_nonce = get_valset_nonce(gravity_address, (*MINER_CLIENT).clone()) - .await - .expect("Failed to get current eth valset"); + let mut current_eth_valset_nonce = + get_valset_nonce(gravity_address, (*MINER_CLIENT).clone()) + .await + .expect("Failed to get current eth valset"); while 0 == current_eth_valset_nonce { info!("Validator set is not yet updated to >0, waiting"); diff --git a/orchestrator/test_runner/src/transaction_stress_test.rs b/orchestrator/test_runner/src/transaction_stress_test.rs index 0fc95b5fd..e7923e24d 100644 --- a/orchestrator/test_runner/src/transaction_stress_test.rs +++ b/orchestrator/test_runner/src/transaction_stress_test.rs @@ -11,12 +11,7 @@ use ethereum_gravity::{ use ethers::prelude::*; use ethers::types::Address as EthAddress; use futures::future::join_all; -use std::{ - collections::HashSet, - str::FromStr, - sync::Arc, - time::Duration, -}; +use std::{collections::HashSet, str::FromStr, sync::Arc, time::Duration}; const TIMEOUT: Duration = Duration::from_secs(120); @@ -204,8 +199,8 @@ pub async fn transaction_stress_test( let e_dest_addr = keys.eth_dest_address; for token in erc20_addresses.iter() { let bal = get_erc20_balance(*token, e_dest_addr, (*MINER_CLIENT).clone()) - .await - .unwrap(); + .await + .unwrap(); let bal = Uint256::from_str(bal.to_string().as_str()).unwrap(); if bal != send_amount.clone() { good = false; From 69d40539a0d8f68ee2a82857462d9558d5cdfa9b Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 23 Nov 2021 08:44:12 -0800 Subject: [PATCH 097/115] Update tests to how signature recover should work --- .../gravity_utils/src/message_signatures.rs | 32 +++++++++++-------- .../gravity_utils/src/types/valsets.rs | 5 ++- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/orchestrator/gravity_utils/src/message_signatures.rs b/orchestrator/gravity_utils/src/message_signatures.rs index 2bafd1b00..345d2d800 100644 --- a/orchestrator/gravity_utils/src/message_signatures.rs +++ b/orchestrator/gravity_utils/src/message_signatures.rs @@ -139,7 +139,7 @@ pub fn encode_tx_batch_confirm_hashed(gravity_id: String, batch: TransactionBatc #[tokio::test] async fn test_batch_signature() { use crate::{ - ethereum::hex_str_to_bytes, + ethereum::{hex_str_to_bytes, u8_slice_to_fixed_32}, types::{BatchTransaction, Erc20Token}, }; use ethers::core::k256::ecdsa::SigningKey; @@ -189,21 +189,25 @@ async fn test_batch_signature() { let eth_key = SigningKey::from_bytes(&secret).unwrap(); let eth_wallet = LocalWallet::from(eth_key); let eth_address = eth_wallet.address(); - let checkpoint = encode_tx_batch_confirm_hashed("foo".to_string(), batch); + let checkpoint = + keccak256(encode_tx_batch_confirm("foo".to_string(), batch.clone()).as_slice()); + let checkpoint_hash = encode_tx_batch_confirm_hashed("foo".to_string(), batch.clone()); + let checkpoint_hash = u8_slice_to_fixed_32(&checkpoint_hash).unwrap(); - let eth_signature = eth_wallet.sign_message(checkpoint.clone()).await.unwrap(); + let eth_signature = eth_wallet.sign_message(checkpoint).await.unwrap(); - assert_eq!( - eth_address, - eth_signature.recover(checkpoint.clone()).unwrap() - ); + assert_eq!(eth_address, eth_signature.recover(checkpoint_hash).unwrap()); } #[tokio::test] async fn test_specific_batch_signature() { - use crate::types::{BatchTransaction, Erc20Token}; + use crate::{ + ethereum::u8_slice_to_fixed_32, + types::{BatchTransaction, Erc20Token}, + }; use ethers::core::k256::ecdsa::SigningKey; use ethers::prelude::*; + use ethers::utils::keccak256; use rand::Rng; let erc20_addr = "0x0635FF793Edf48cf5dB294916720A78e6e490E40" @@ -241,14 +245,14 @@ async fn test_specific_batch_signature() { let eth_wallet = LocalWallet::from(eth_key); let eth_address = eth_wallet.address(); - let checkpoint = encode_tx_batch_confirm_hashed("foo".to_string(), batch); + let checkpoint = + keccak256(encode_tx_batch_confirm("foo".to_string(), batch.clone()).as_slice()); + let checkpoint_hash = encode_tx_batch_confirm_hashed("foo".to_string(), batch.clone()); + let checkpoint_hash = u8_slice_to_fixed_32(&checkpoint_hash).unwrap(); - let eth_signature = eth_wallet.sign_message(checkpoint.clone()).await.unwrap(); + let eth_signature = eth_wallet.sign_message(checkpoint).await.unwrap(); - assert_eq!( - eth_address, - eth_signature.recover(checkpoint.clone()).unwrap() - ); + assert_eq!(eth_address, eth_signature.recover(checkpoint_hash).unwrap()); } /// takes the required input data and produces the required signature to confirm a logic diff --git a/orchestrator/gravity_utils/src/types/valsets.rs b/orchestrator/gravity_utils/src/types/valsets.rs index 872d8f6ed..46692c426 100644 --- a/orchestrator/gravity_utils/src/types/valsets.rs +++ b/orchestrator/gravity_utils/src/types/valsets.rs @@ -1,5 +1,8 @@ use super::*; -use crate::{error::GravityError, ethereum::{format_eth_address, u8_slice_to_fixed_32}}; +use crate::{ + error::GravityError, + ethereum::{format_eth_address, u8_slice_to_fixed_32}, +}; use deep_space::error::CosmosGrpcError; use ethers::types::{Address as EthAddress, Signature as EthSignature}; use std::convert::TryFrom; From 994ab47400ba992503d121c5612806c6b173fd1c Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 23 Nov 2021 09:52:28 -0800 Subject: [PATCH 098/115] Remove unnnecessary match in Cosmos send returns --- orchestrator/cosmos_gravity/src/send.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/orchestrator/cosmos_gravity/src/send.rs b/orchestrator/cosmos_gravity/src/send.rs index 82be6574e..d1faf8213 100644 --- a/orchestrator/cosmos_gravity/src/send.rs +++ b/orchestrator/cosmos_gravity/src/send.rs @@ -163,10 +163,7 @@ async fn __send_messages( .send_transaction(msg_bytes, BroadcastMode::Sync) .await?; - match contact.wait_for_tx(response, TIMEOUT).await { - Ok(res) => Ok(res), - Err(e) => Err(GravityError::CosmosGrpcError(e)), - } + Ok(contact.wait_for_tx(response, TIMEOUT).await?) } pub async fn send_messages( @@ -213,10 +210,7 @@ pub async fn send_messages( .send_transaction(msg_bytes, BroadcastMode::Sync) .await?; - match contact.wait_for_tx(response, TIMEOUT).await { - Ok(res) => Ok(res), - Err(e) => Err(GravityError::CosmosGrpcError(e)), - } + Ok(contact.wait_for_tx(response, TIMEOUT).await?) } pub async fn send_main_loop( From b8d4c03b9d9a4696fd7ea6a96755d8a22d99cd44 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 23 Nov 2021 12:56:13 -0800 Subject: [PATCH 099/115] Remove duplicated error type --- orchestrator/gravity_utils/src/error.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index 684143c46..d295410fc 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -26,7 +26,6 @@ use tonic::Status; #[derive(Debug)] #[allow(clippy::large_enum_variant)] pub enum GravityError { - InvalidBigInt(ParseBigIntError), CosmosGrpcError(CosmosGrpcError), CosmosAddressError(CosmosAddressError), CosmosPrivateKeyError(CosmosPrivateKeyError), @@ -62,9 +61,6 @@ impl fmt::Display for GravityError { match self { GravityError::GravityGrpcError(val) => write!(f, "Gravity gRPC error {}", val), GravityError::CosmosGrpcError(val) => write!(f, "Cosmos gRPC error {}", val), - GravityError::InvalidBigInt(val) => { - write!(f, "Got invalid BigInt from cosmos! {}", val) - } GravityError::CosmosAddressError(val) => write!(f, "Cosmos Address error {}", val), GravityError::CosmosPrivateKeyError(val) => { write!(f, "Cosmos private key error: {}", val) @@ -217,7 +213,7 @@ impl From for GravityError { impl From for GravityError { fn from(error: ParseBigIntError) -> Self { - GravityError::InvalidBigInt(error) + GravityError::ParseBigIntError(error) } } From 7fb852732f86e67811efc7a5f81d9dcea7db109a Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 23 Nov 2021 17:15:11 -0800 Subject: [PATCH 100/115] set the LocalWallet's chain ID --- orchestrator/gorc/src/commands/deploy/erc20.rs | 16 +++++++++++++--- orchestrator/gorc/src/commands/eth_to_cosmos.rs | 14 ++++++++++++-- .../gorc/src/commands/orchestrator/start.rs | 11 +++++++++-- orchestrator/gorc/src/commands/tx/eth.rs | 11 +++++++++-- orchestrator/relayer/src/main.rs | 10 ++++++++-- orchestrator/test_runner/src/happy_path_v2.rs | 12 +++++++++++- .../test_runner/src/transaction_stress_test.rs | 13 ++++++++++++- 7 files changed, 74 insertions(+), 13 deletions(-) diff --git a/orchestrator/gorc/src/commands/deploy/erc20.rs b/orchestrator/gorc/src/commands/deploy/erc20.rs index 07dc1c465..f83330912 100644 --- a/orchestrator/gorc/src/commands/deploy/erc20.rs +++ b/orchestrator/gorc/src/commands/deploy/erc20.rs @@ -3,7 +3,10 @@ use abscissa_core::{Clap, Command, Runnable}; use ethereum_gravity::deploy_erc20::deploy_erc20; use ethers::prelude::*; use gravity_proto::gravity::{DenomToErc20ParamsRequest, DenomToErc20Request}; -use gravity_utils::connection_prep::{check_for_eth, create_rpc_connections}; +use gravity_utils::{ + connection_prep::{check_for_eth, create_rpc_connections}, + ethereum::downcast_to_u64, +}; use std::convert::TryFrom; use std::process::exit; use std::{sync::Arc, time::Duration}; @@ -52,12 +55,19 @@ impl Erc20 { ) .await; - let mut grpc = connections.grpc.clone().unwrap(); + let provider = connections.eth_provider.clone().unwrap(); + let chain_id = provider + .get_chainid() + .await + .expect("Could not retrieve chain ID"); + let chain_id = + downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); let eth_client = SignerMiddleware::new( connections.eth_provider.clone().unwrap(), - ethereum_wallet.clone(), + ethereum_wallet.clone().with_chain_id(chain_id), ); let eth_client = Arc::new(eth_client); + let mut grpc = connections.grpc.clone().unwrap(); check_for_eth(eth_client.address(), eth_client.clone()).await; diff --git a/orchestrator/gorc/src/commands/eth_to_cosmos.rs b/orchestrator/gorc/src/commands/eth_to_cosmos.rs index 8566d32f9..290370032 100644 --- a/orchestrator/gorc/src/commands/eth_to_cosmos.rs +++ b/orchestrator/gorc/src/commands/eth_to_cosmos.rs @@ -5,7 +5,10 @@ use ethereum_gravity::erc20_utils::get_erc20_balance; use ethereum_gravity::send_to_cosmos::send_to_cosmos; use ethers::prelude::*; use ethers::types::Address as EthAddress; -use gravity_utils::connection_prep::{check_for_eth, create_rpc_connections}; +use gravity_utils::{ + connection_prep::{check_for_eth, create_rpc_connections}, + ethereum::downcast_to_u64, +}; use std::{sync::Arc, time::Duration}; const TIMEOUT: Duration = Duration::from_secs(60); @@ -43,9 +46,16 @@ impl Runnable for EthToCosmosCmd { ) .await; + let provider = connections.eth_provider.clone().unwrap(); + let chain_id = provider + .get_chainid() + .await + .expect("Could not retrieve chain ID"); + let chain_id = + downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); let eth_client = SignerMiddleware::new( connections.eth_provider.clone().unwrap(), - ethereum_wallet.clone(), + ethereum_wallet.clone().with_chain_id(chain_id), ); let eth_client = Arc::new(eth_client); let cosmos_dest = self.args.get(3).expect("cosmos destination is required"); diff --git a/orchestrator/gorc/src/commands/orchestrator/start.rs b/orchestrator/gorc/src/commands/orchestrator/start.rs index ae0ed801e..1ed27d4b3 100644 --- a/orchestrator/gorc/src/commands/orchestrator/start.rs +++ b/orchestrator/gorc/src/commands/orchestrator/start.rs @@ -6,7 +6,7 @@ use gravity_utils::{ check_delegate_addresses, check_for_eth, check_for_fee_denom, create_rpc_connections, wait_for_cosmos_node_ready, }, - ethereum::format_eth_address, + ethereum::{downcast_to_u64, format_eth_address}, }; use orchestrator::main_loop::{ orchestrator_main_loop, ETH_ORACLE_LOOP_SPEED, ETH_SIGNER_LOOP_SPEED, @@ -64,9 +64,16 @@ impl Runnable for StartCommand { let mut grpc = connections.grpc.clone().unwrap(); let contact = connections.contact.clone().unwrap(); + let provider = connections.eth_provider.clone().unwrap(); + let chain_id = provider + .get_chainid() + .await + .expect("Could not retrieve chain ID during orchestrator start"); + let chain_id = + downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); let eth_client = SignerMiddleware::new( connections.eth_provider.clone().unwrap(), - ethereum_wallet.clone(), + ethereum_wallet.clone().with_chain_id(chain_id), ); let eth_client = Arc::new(eth_client); diff --git a/orchestrator/gorc/src/commands/tx/eth.rs b/orchestrator/gorc/src/commands/tx/eth.rs index 895255d8b..5aee4a87e 100644 --- a/orchestrator/gorc/src/commands/tx/eth.rs +++ b/orchestrator/gorc/src/commands/tx/eth.rs @@ -9,7 +9,7 @@ use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_utils::{ connection_prep::{check_for_eth, create_rpc_connections}, - ethereum::format_eth_address, + ethereum::{downcast_to_u64, format_eth_address}, }; use std::sync::Arc; @@ -73,9 +73,16 @@ impl Runnable for SendToCosmos { let connections = create_rpc_connections(cosmos_prefix, Some(cosmso_grpc), Some(eth_rpc), TIMEOUT) .await; + let provider = connections.eth_provider.clone().unwrap(); + let chain_id = provider + .get_chainid() + .await + .expect("Could not retrieve chain ID"); + let chain_id = + downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); let eth_client = SignerMiddleware::new( connections.eth_provider.clone().unwrap(), - ethereum_wallet.clone(), + ethereum_wallet.clone().with_chain_id(chain_id), ); let eth_client = Arc::new(eth_client); check_for_eth(eth_client.address(), eth_client.clone()).await; diff --git a/orchestrator/relayer/src/main.rs b/orchestrator/relayer/src/main.rs index 7ca8e0df7..9142fe28d 100644 --- a/orchestrator/relayer/src/main.rs +++ b/orchestrator/relayer/src/main.rs @@ -9,7 +9,7 @@ use ethers::signers::LocalWallet as EthWallet; use ethers::types::Address as EthAddress; use gravity_utils::{ connection_prep::{check_for_eth, create_rpc_connections, wait_for_cosmos_node_ready}, - ethereum::format_eth_address, + ethereum::{downcast_to_u64, format_eth_address}, }; pub mod batch_relaying; @@ -83,9 +83,15 @@ async fn main() { LOOP_SPEED, ) .await; + let provider = connections.eth_provider.clone().unwrap(); + let chain_id = provider + .get_chainid() + .await + .expect("Could not retrieve chain ID during relayer start"); + let chain_id = downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); let eth_client = SignerMiddleware::new( connections.eth_provider.clone().unwrap(), - ethereum_wallet.clone(), + ethereum_wallet.clone().with_chain_id(chain_id), ); let eth_client = Arc::new(eth_client); diff --git a/orchestrator/test_runner/src/happy_path_v2.rs b/orchestrator/test_runner/src/happy_path_v2.rs index 5c0476230..5681c2daf 100644 --- a/orchestrator/test_runner/src/happy_path_v2.rs +++ b/orchestrator/test_runner/src/happy_path_v2.rs @@ -15,6 +15,7 @@ use ethers::types::Address as EthAddress; use gravity_proto::gravity::{ query_client::QueryClient as GravityQueryClient, DenomToErc20Request, }; +use gravity_utils::ethereum::downcast_to_u64; use std::str::FromStr; use std::sync::Arc; use tonic::transport::Channel; @@ -28,7 +29,16 @@ pub async fn happy_path_test_v2( ) { let mut grpc_client = grpc_client; let eth_wallet = LocalWallet::from(keys[0].eth_key.clone()); - let eth_client = Arc::new(SignerMiddleware::new(eth_provider.clone(), eth_wallet)); + let provider = eth_provider.clone(); + let chain_id = provider + .get_chainid() + .await + .expect("Could not retrieve chain ID"); + let chain_id = downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); + let eth_client = Arc::new(SignerMiddleware::new( + eth_provider.clone(), + eth_wallet.with_chain_id(chain_id), + )); let starting_event_nonce = get_event_nonce(gravity_address, eth_client.clone()) .await .unwrap(); diff --git a/orchestrator/test_runner/src/transaction_stress_test.rs b/orchestrator/test_runner/src/transaction_stress_test.rs index e7923e24d..ceac72015 100644 --- a/orchestrator/test_runner/src/transaction_stress_test.rs +++ b/orchestrator/test_runner/src/transaction_stress_test.rs @@ -11,6 +11,7 @@ use ethereum_gravity::{ use ethers::prelude::*; use ethers::types::Address as EthAddress; use futures::future::join_all; +use gravity_utils::ethereum::downcast_to_u64; use std::{collections::HashSet, str::FromStr, sync::Arc, time::Duration}; const TIMEOUT: Duration = Duration::from_secs(120); @@ -67,7 +68,17 @@ pub async fn transaction_stress_test( let mut sends = Vec::new(); for keys in user_keys.iter() { let eth_wallet = LocalWallet::from(keys.eth_key.clone()); - let eth_client = Arc::new(SignerMiddleware::new(eth_provider.clone(), eth_wallet)); + let provider = eth_provider.clone(); + let chain_id = provider + .get_chainid() + .await + .expect("Could not retrieve chain ID"); + let chain_id = + downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); + let eth_client = Arc::new(SignerMiddleware::new( + eth_provider.clone(), + eth_wallet.with_chain_id(chain_id), + )); let fut = send_to_cosmos( *token, gravity_address, From a943a3c52ca308db288e3a786911235ecd794cd5 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 23 Nov 2021 17:26:01 -0800 Subject: [PATCH 101/115] No need to clone the provider twice --- orchestrator/gorc/src/commands/deploy/erc20.rs | 2 +- orchestrator/gorc/src/commands/eth_to_cosmos.rs | 2 +- orchestrator/gorc/src/commands/orchestrator/start.rs | 2 +- orchestrator/gorc/src/commands/tx/eth.rs | 2 +- orchestrator/relayer/src/main.rs | 2 +- orchestrator/test_runner/src/happy_path_v2.rs | 2 +- orchestrator/test_runner/src/transaction_stress_test.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/orchestrator/gorc/src/commands/deploy/erc20.rs b/orchestrator/gorc/src/commands/deploy/erc20.rs index f83330912..702127387 100644 --- a/orchestrator/gorc/src/commands/deploy/erc20.rs +++ b/orchestrator/gorc/src/commands/deploy/erc20.rs @@ -63,7 +63,7 @@ impl Erc20 { let chain_id = downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); let eth_client = SignerMiddleware::new( - connections.eth_provider.clone().unwrap(), + provider, ethereum_wallet.clone().with_chain_id(chain_id), ); let eth_client = Arc::new(eth_client); diff --git a/orchestrator/gorc/src/commands/eth_to_cosmos.rs b/orchestrator/gorc/src/commands/eth_to_cosmos.rs index 290370032..ae32a903a 100644 --- a/orchestrator/gorc/src/commands/eth_to_cosmos.rs +++ b/orchestrator/gorc/src/commands/eth_to_cosmos.rs @@ -54,7 +54,7 @@ impl Runnable for EthToCosmosCmd { let chain_id = downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); let eth_client = SignerMiddleware::new( - connections.eth_provider.clone().unwrap(), + provider, ethereum_wallet.clone().with_chain_id(chain_id), ); let eth_client = Arc::new(eth_client); diff --git a/orchestrator/gorc/src/commands/orchestrator/start.rs b/orchestrator/gorc/src/commands/orchestrator/start.rs index 1ed27d4b3..76b9cbd05 100644 --- a/orchestrator/gorc/src/commands/orchestrator/start.rs +++ b/orchestrator/gorc/src/commands/orchestrator/start.rs @@ -72,7 +72,7 @@ impl Runnable for StartCommand { let chain_id = downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); let eth_client = SignerMiddleware::new( - connections.eth_provider.clone().unwrap(), + provider, ethereum_wallet.clone().with_chain_id(chain_id), ); let eth_client = Arc::new(eth_client); diff --git a/orchestrator/gorc/src/commands/tx/eth.rs b/orchestrator/gorc/src/commands/tx/eth.rs index 5aee4a87e..b618f3871 100644 --- a/orchestrator/gorc/src/commands/tx/eth.rs +++ b/orchestrator/gorc/src/commands/tx/eth.rs @@ -81,7 +81,7 @@ impl Runnable for SendToCosmos { let chain_id = downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); let eth_client = SignerMiddleware::new( - connections.eth_provider.clone().unwrap(), + provider, ethereum_wallet.clone().with_chain_id(chain_id), ); let eth_client = Arc::new(eth_client); diff --git a/orchestrator/relayer/src/main.rs b/orchestrator/relayer/src/main.rs index 9142fe28d..f0c7f9e82 100644 --- a/orchestrator/relayer/src/main.rs +++ b/orchestrator/relayer/src/main.rs @@ -90,7 +90,7 @@ async fn main() { .expect("Could not retrieve chain ID during relayer start"); let chain_id = downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); let eth_client = SignerMiddleware::new( - connections.eth_provider.clone().unwrap(), + provider, ethereum_wallet.clone().with_chain_id(chain_id), ); let eth_client = Arc::new(eth_client); diff --git a/orchestrator/test_runner/src/happy_path_v2.rs b/orchestrator/test_runner/src/happy_path_v2.rs index 5681c2daf..caa42d6d6 100644 --- a/orchestrator/test_runner/src/happy_path_v2.rs +++ b/orchestrator/test_runner/src/happy_path_v2.rs @@ -36,7 +36,7 @@ pub async fn happy_path_test_v2( .expect("Could not retrieve chain ID"); let chain_id = downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); let eth_client = Arc::new(SignerMiddleware::new( - eth_provider.clone(), + provider, eth_wallet.with_chain_id(chain_id), )); let starting_event_nonce = get_event_nonce(gravity_address, eth_client.clone()) diff --git a/orchestrator/test_runner/src/transaction_stress_test.rs b/orchestrator/test_runner/src/transaction_stress_test.rs index ceac72015..863b00f45 100644 --- a/orchestrator/test_runner/src/transaction_stress_test.rs +++ b/orchestrator/test_runner/src/transaction_stress_test.rs @@ -76,7 +76,7 @@ pub async fn transaction_stress_test( let chain_id = downcast_to_u64(chain_id).expect("Chain ID overflowed when downcasting to u64"); let eth_client = Arc::new(SignerMiddleware::new( - eth_provider.clone(), + provider, eth_wallet.with_chain_id(chain_id), )); let fut = send_to_cosmos( From bb0c9ef9596fea052248bf8be6079becca4b80de Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 24 Nov 2021 16:41:30 -0800 Subject: [PATCH 102/115] ethers-rs -> master, update abigen, bump deps A required bugfix for contracts to function correctly is on ethers-rs master. Here we depend on master and lock to that commit. Also have re-run the ABI build with the new version of ethers, as well as fixed up some use statements and type errors introduced in the newer version. Additionally, we had to bump versions on actix and futures in order to maintain compatibility with the latest version of ethers. We're explicitly using std::result::Result because the new ethers prelude includes a published type that is also called Result. --- orchestrator/Cargo.lock | 272 +++++--- orchestrator/abi_build/Cargo.toml | 2 +- orchestrator/cosmos_gravity/Cargo.toml | 4 +- orchestrator/cosmos_gravity/src/send.rs | 2 +- orchestrator/ethereum_gravity/Cargo.toml | 2 +- .../ethereum_gravity/src/deploy_erc20.rs | 2 +- .../ethereum_gravity/src/erc20_utils.rs | 2 +- .../ethereum_gravity/src/logic_call.rs | 4 +- .../ethereum_gravity/src/send_to_cosmos.rs | 2 +- .../ethereum_gravity/src/submit_batch.rs | 2 +- orchestrator/ethereum_gravity/src/utils.rs | 2 +- .../ethereum_gravity/src/valset_update.rs | 2 +- orchestrator/gorc/Cargo.toml | 4 +- orchestrator/gravity_abi/Cargo.toml | 2 +- orchestrator/gravity_abi/src/erc20.rs | 368 ++++++++++- orchestrator/gravity_abi/src/gravity.rs | 591 ++++++++++++++++-- orchestrator/gravity_utils/Cargo.toml | 4 +- orchestrator/gravity_utils/src/ethereum.rs | 2 +- .../gravity_utils/src/types/batches.rs | 2 +- .../src/types/ethereum_events.rs | 3 +- .../gravity_utils/src/types/logic_call.rs | 2 +- orchestrator/gravity_utils/src/types/mod.rs | 2 + orchestrator/orchestrator/Cargo.toml | 6 +- .../src/ethereum_event_watcher.rs | 2 +- .../register_delegate_keys/Cargo.toml | 4 +- orchestrator/relayer/Cargo.toml | 6 +- .../relayer/src/find_latest_valset.rs | 2 +- orchestrator/test_runner/Cargo.toml | 8 +- 28 files changed, 1114 insertions(+), 192 deletions(-) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index a9906b6d7..c1e8ada89 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -69,17 +69,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f38df9084daf34a7822ccc39e85598f23fd80e8451003ea41441ed5123fc012" dependencies = [ "abscissa_core", - "actix-rt 2.2.0", + "actix-rt 2.5.0", "tokio 1.13.0", ] [[package]] name = "actix" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "543c47e7827f8fcc9d1445bd98ba402137bfce80ee2187429de49c52b5131bd3" +checksum = "3720d0064a0ce5c0de7bd93bdb0a6caebab2a9b5668746145d7b3b0c5da02914" dependencies = [ - "actix-rt 2.2.0", + "actix-rt 2.5.0", "actix_derive", "bitflags", "bytes 1.1.0", @@ -205,7 +205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd38a862fa7fead2b47ee55e550982aba583ebc7365ccf0155b49934ad6f16f9" dependencies = [ "actix-codec 0.4.0", - "actix-rt 2.2.0", + "actix-rt 2.5.0", "actix-service 2.0.0", "actix-tls 3.0.0-beta.5", "actix-utils 3.0.0", @@ -253,9 +253,9 @@ dependencies = [ [[package]] name = "actix-macros" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbcb2b608f0accc2f5bcf3dd872194ce13d94ee45b571487035864cf966b04ef" +checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" dependencies = [ "quote", "syn", @@ -291,11 +291,11 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.2.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7d7cd957c9ed92288a7c3c96af81fa5291f65247a76a34dac7b6af74e52ba0" +checksum = "05c2f80ce8d0c990941c7a7a931f69fd0701b76d521f8d36298edf59cd3fbf1f" dependencies = [ - "actix-macros 0.2.0", + "actix-macros 0.2.3", "futures-core", "tokio 1.13.0", ] @@ -391,7 +391,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65b7bb60840962ef0332f7ea01a57d73a24d2cb663708511ff800250bbfef569" dependencies = [ "actix-codec 0.4.0", - "actix-rt 2.2.0", + "actix-rt 2.5.0", "actix-service 2.0.0", "actix-utils 3.0.0", "derive_more", @@ -640,9 +640,9 @@ dependencies = [ [[package]] name = "auto_impl" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cbf586c80ada5e5ccdecae80d3ef0854f224e2dd74435f8d87e6831b8d0a38" +checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" dependencies = [ "proc-macro-error", "proc-macro2", @@ -689,7 +689,7 @@ checksum = "5b276021b5aa1df71969acc8adc03973e4fc7d00bba0cbb6338e6f8ad0d7a3c2" dependencies = [ "actix-codec 0.4.0", "actix-http 3.0.0-beta.10", - "actix-rt 2.2.0", + "actix-rt 2.5.0", "actix-service 2.0.0", "base64 0.13.0", "bytes 1.1.0", @@ -1174,12 +1174,29 @@ dependencies = [ "owo-colors", ] +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi 0.3.9", +] + [[package]] name = "const-oid" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" +[[package]] +name = "const-oid" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d355758f44afa81c21e66e1301d47cbffbbcde4b405cbe46b8b19f213abf9f60" + [[package]] name = "const_fn" version = "0.4.6" @@ -1341,6 +1358,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array 0.14.4", + "rand_core 0.6.2", + "subtle", + "zeroize", +] + [[package]] name = "crypto-mac" version = "0.8.0" @@ -1475,7 +1504,16 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2" dependencies = [ - "const-oid", + "const-oid 0.6.2", +] + +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid 0.7.0", ] [[package]] @@ -1532,8 +1570,8 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" dependencies = [ - "der", - "elliptic-curve", + "der 0.4.4", + "elliptic-curve 0.10.6", "hmac 0.11.0", "signature", ] @@ -1550,7 +1588,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b" dependencies = [ - "crypto-bigint", + "crypto-bigint 0.2.11", "ff", "generic-array 0.14.4", "group", @@ -1560,6 +1598,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "elliptic-curve" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73d21281779c2c22cade2a4ab34eee34271869942546a364f7d552d30c62434" +dependencies = [ + "crypto-bigint 0.3.2", + "der 0.5.1", + "generic-array 0.14.4", + "rand_core 0.6.2", + "subtle", + "zeroize", +] + [[package]] name = "encoding_rs" version = "0.8.28" @@ -1686,22 +1738,22 @@ dependencies = [ [[package]] name = "ethers" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3329c24c9cece2606e76f6de9870754283c6f615b0dff2e16809e40ace8a0d" +version = "0.6.0" +source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" dependencies = [ "ethers-contract", "ethers-core", + "ethers-etherscan", "ethers-middleware", "ethers-providers", "ethers-signers", + "ethers-solc", ] [[package]] name = "ethers-contract" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d25bee65967910fae113f5beb85c632b14152c2eea209e991605d2a8fbd8531" +version = "0.6.0" +source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" dependencies = [ "ethers-contract-abigen", "ethers-contract-derive", @@ -1718,13 +1770,11 @@ dependencies = [ [[package]] name = "ethers-contract-abigen" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ffd490c3590bb310daaeac902b745a14bfcc1c5cd5e02fc0f3707893d5cf997" +version = "0.6.0" +source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" dependencies = [ "Inflector", "anyhow", - "cargo_metadata", "cfg-if 1.0.0", "ethers-core", "getrandom 0.2.3", @@ -1741,9 +1791,8 @@ dependencies = [ [[package]] name = "ethers-contract-derive" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0aabf97b4bc98bc966e296998dfd91724b6d64ca463ec4e10c4cd3450e2289d" +version = "0.6.0" +source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" dependencies = [ "ethers-contract-abigen", "ethers-core", @@ -1756,19 +1805,17 @@ dependencies = [ [[package]] name = "ethers-core" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cf3fa1d6d46f4f0ff62b03d1e8062b80b6fde7138bcca03d6759dab22a9d8d6" +version = "0.6.0" +source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" dependencies = [ "arrayvec 0.7.2", "bytes 1.1.0", + "cargo_metadata", "convert_case", "ecdsa", - "elliptic-curve", + "elliptic-curve 0.11.1", "ethabi", - "futures-util", "generic-array 0.14.4", - "glob", "hex", "k256", "once_cell", @@ -1777,20 +1824,29 @@ dependencies = [ "rand 0.8.4", "rlp", "rlp-derive", - "semver 1.0.4", "serde", "serde_json", "syn", "thiserror", "tiny-keccak", - "tokio 1.13.0", +] + +[[package]] +name = "ethers-etherscan" +version = "0.2.0" +source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" +dependencies = [ + "ethers-core", + "reqwest", + "serde", + "serde_json", + "thiserror", ] [[package]] name = "ethers-middleware" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d24ec324ed07af7d21be7fc9de709566c93d701eec415eee4a34ac5b7ecdd39" +version = "0.6.0" +source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" dependencies = [ "async-trait", "ethers-contract", @@ -1812,9 +1868,8 @@ dependencies = [ [[package]] name = "ethers-providers" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b36bbe42435a740f05f5ed8a136a347411c9961af210d5ef8aceec781a58728" +version = "0.6.0" +source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" dependencies = [ "async-trait", "auto_impl", @@ -1842,24 +1897,44 @@ dependencies = [ [[package]] name = "ethers-signers" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b0b2520fc6290abc5ab20be1f294fc5ac558261f45bb7cd9261b45512a905ea" +version = "0.6.0" +source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" dependencies = [ "async-trait", "coins-bip32", "coins-bip39", - "elliptic-curve", + "elliptic-curve 0.11.1", "eth-keystore", "ethers-core", "futures-executor", "futures-util", "hex", "rand 0.8.4", + "semver 1.0.4", "sha2 0.9.8", "thiserror", ] +[[package]] +name = "ethers-solc" +version = "0.1.0" +source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" +dependencies = [ + "colored", + "ethers-core", + "glob", + "hex", + "home", + "md-5", + "once_cell", + "regex", + "semver 1.0.4", + "serde", + "serde_json", + "thiserror", + "walkdir", +] + [[package]] name = "eyre" version = "0.6.5" @@ -1983,9 +2058,9 @@ checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" [[package]] name = "futures" -version = "0.3.14" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253" +checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e" dependencies = [ "futures-channel", "futures-core", @@ -1998,9 +2073,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" dependencies = [ "futures-core", "futures-sink", @@ -2008,15 +2083,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" +checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" [[package]] name = "futures-executor" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97" dependencies = [ "futures-core", "futures-task", @@ -2025,18 +2100,16 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" +checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11" [[package]] name = "futures-macro" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd" dependencies = [ - "autocfg", - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -2044,15 +2117,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" +checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af" [[package]] name = "futures-task" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" +checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12" [[package]] name = "futures-timer" @@ -2062,11 +2135,10 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e" dependencies = [ - "autocfg", "futures-channel", "futures-core", "futures-io", @@ -2076,8 +2148,6 @@ dependencies = [ "memchr", "pin-project-lite 0.2.6", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] @@ -2151,7 +2221,7 @@ version = "0.2.23" dependencies = [ "abscissa_core", "abscissa_tokio", - "actix-rt 2.2.0", + "actix-rt 2.5.0", "bip32", "bytes 1.1.0", "clap", @@ -2363,6 +2433,15 @@ dependencies = [ "digest 0.9.0", ] +[[package]] +name = "home" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "hostname" version = "0.3.1" @@ -2617,7 +2696,7 @@ checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea" dependencies = [ "cfg-if 1.0.0", "ecdsa", - "elliptic-curve", + "elliptic-curve 0.10.6", "sha2 0.9.8", "sha3", ] @@ -2734,6 +2813,17 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +[[package]] +name = "md-5" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + [[package]] name = "memchr" version = "2.4.0" @@ -3105,7 +3195,7 @@ dependencies = [ name = "orchestrator" version = "0.4.1" dependencies = [ - "actix-rt 2.2.0", + "actix-rt 2.5.0", "axum", "clarity", "cosmos_gravity", @@ -3366,7 +3456,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" dependencies = [ - "der", + "der 0.4.4", "pem-rfc7468", "spki", "zeroize", @@ -3437,12 +3527,6 @@ version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" version = "1.0.32" @@ -3721,7 +3805,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" name = "register_delegate_keys" version = "0.4.1" dependencies = [ - "actix-rt 2.2.0", + "actix-rt 2.5.0", "clarity", "contact", "cosmos_gravity", @@ -3747,7 +3831,7 @@ name = "relayer" version = "0.4.1" dependencies = [ "actix", - "actix-rt 2.2.0", + "actix-rt 2.5.0", "clarity", "cosmos_gravity", "deep_space 2.4.7", @@ -4101,18 +4185,18 @@ checksum = "930c0acf610d3fdb5e2ab6213019aaa04e227ebe9547b0649ba599b16d788bd7" [[package]] name = "serde" -version = "1.0.125" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] [[package]] name = "serde-aux" -version = "2.3.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907c320ef8f45ce134b28ca9567ec58ec0d51dcae4e1ffe7ee0cc15517243810" +checksum = "93abf9799c576f004252b2a05168d58527fb7c54de12e94b4d12fe3475ffad24" dependencies = [ "serde", "serde_json", @@ -4141,9 +4225,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ "proc-macro2", "quote", @@ -4314,7 +4398,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32" dependencies = [ - "der", + "der 0.4.4", ] [[package]] @@ -4404,9 +4488,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ "proc-macro2", "quote", @@ -4488,7 +4572,7 @@ name = "test_runner" version = "0.1.0" dependencies = [ "actix", - "actix-rt 2.2.0", + "actix-rt 2.5.0", "actix-web", "clarity", "cosmos_gravity", diff --git a/orchestrator/abi_build/Cargo.toml b/orchestrator/abi_build/Cargo.toml index 02f1f3d9a..13141a39b 100644 --- a/orchestrator/abi_build/Cargo.toml +++ b/orchestrator/abi_build/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ethers = { version = "0.5.4", features=["abigen"] } +ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } serde_derive = "1.0" serde_json = "1.0.69" serde = "1.0" diff --git a/orchestrator/cosmos_gravity/Cargo.toml b/orchestrator/cosmos_gravity/Cargo.toml index f24a00a37..e3668473f 100644 --- a/orchestrator/cosmos_gravity/Cargo.toml +++ b/orchestrator/cosmos_gravity/Cargo.toml @@ -12,7 +12,7 @@ ethereum_gravity = {path = "../ethereum_gravity"} gravity_proto = {path = "../gravity_proto/"} deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} -ethers = { version = "0.5.4", features=["abigen"] } +ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } clarity = "0.4.11" serde = "1.0" log = "0.4" @@ -28,4 +28,4 @@ bytes = "1" [dev-dependencies] env_logger = "0.8" rand = "0.8" -actix = "0.11" +actix = "0.12" diff --git a/orchestrator/cosmos_gravity/src/send.rs b/orchestrator/cosmos_gravity/src/send.rs index d1faf8213..4c51d5eb5 100644 --- a/orchestrator/cosmos_gravity/src/send.rs +++ b/orchestrator/cosmos_gravity/src/send.rs @@ -17,7 +17,7 @@ use gravity_utils::ethereum::format_eth_address; use prost::Message; use std::cmp; use std::collections::HashSet; -use std::time::Duration; +use std::{result::Result, time::Duration}; pub const MEMO: &str = "Sent using Gravity Bridge Orchestrator"; pub const TIMEOUT: Duration = Duration::from_secs(60); diff --git a/orchestrator/ethereum_gravity/Cargo.toml b/orchestrator/ethereum_gravity/Cargo.toml index da616360b..6903bf2d6 100644 --- a/orchestrator/ethereum_gravity/Cargo.toml +++ b/orchestrator/ethereum_gravity/Cargo.toml @@ -11,7 +11,7 @@ gravity_abi = { path = "../gravity_abi" } gravity_utils = { path = "../gravity_utils" } deep_space = { git="https://github.com/iqlusioninc/deep_space/", branch="master" } -ethers = { version = "0.5.4", features=["abigen"] } +ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } clarity = "0.4.11" web30 = "0.15.4" log = "0.4" diff --git a/orchestrator/ethereum_gravity/src/deploy_erc20.rs b/orchestrator/ethereum_gravity/src/deploy_erc20.rs index 1b7486f90..9dd1d4575 100644 --- a/orchestrator/ethereum_gravity/src/deploy_erc20.rs +++ b/orchestrator/ethereum_gravity/src/deploy_erc20.rs @@ -6,7 +6,7 @@ use crate::{types::EthClient, utils::get_send_transaction_gas_price}; use ethers::prelude::*; use gravity_abi::gravity::*; use gravity_utils::error::GravityError; -use std::time::Duration; +use std::{result::Result, time::Duration}; /// Calls the Gravity ethereum contract to deploy the ERC20 representation of the given Cosmos asset /// denom. If an existing contract is already deployed representing this asset this call will cost diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs index 6aa61a40f..3f1e9f5f6 100644 --- a/orchestrator/ethereum_gravity/src/erc20_utils.rs +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -2,7 +2,7 @@ use crate::types::EthClient; use ethers::prelude::*; use gravity_abi::erc20::ERC20; use gravity_utils::error::GravityError; -use std::time::Duration; +use std::{result::Result, time::Duration}; /// Checks if any given contract is approved to spend money from any given erc20 contract /// using any given address. What exactly this does can be hard to grok, essentially when diff --git a/orchestrator/ethereum_gravity/src/logic_call.rs b/orchestrator/ethereum_gravity/src/logic_call.rs index 9a722972c..ade51dcc7 100644 --- a/orchestrator/ethereum_gravity/src/logic_call.rs +++ b/orchestrator/ethereum_gravity/src/logic_call.rs @@ -13,7 +13,7 @@ use gravity_abi::gravity::*; use gravity_utils::ethereum::{bytes_to_hex_str, vec_u8_to_fixed_32}; use gravity_utils::types::*; use gravity_utils::{error::GravityError, message_signatures::encode_logic_call_confirm_hashed}; -use std::time::Duration; +use std::{result::Result, time::Duration}; /// this function generates an appropriate Ethereum transaction /// to submit the provided logic call @@ -178,7 +178,7 @@ pub fn build_send_logic_call_contract_call( fee_amounts, fee_token_contracts, logic_contract_address: call.logic_contract_address, - payload: call.payload.clone(), + payload: call.payload.clone().into(), time_out: call.timeout.into(), invalidation_id, invalidation_nonce: call.invalidation_nonce.into(), diff --git a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs index 0b0e65b47..e875fdee5 100644 --- a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs +++ b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs @@ -8,7 +8,7 @@ use deep_space::address::Address as CosmosAddress; use ethers::prelude::*; use gravity_abi::gravity::*; use gravity_utils::error::GravityError; -use std::time::Duration; +use std::{result::Result, time::Duration}; const SEND_TO_COSMOS_GAS_LIMIT: u128 = 100_000; diff --git a/orchestrator/ethereum_gravity/src/submit_batch.rs b/orchestrator/ethereum_gravity/src/submit_batch.rs index 447e80a8f..3fcd052b1 100644 --- a/orchestrator/ethereum_gravity/src/submit_batch.rs +++ b/orchestrator/ethereum_gravity/src/submit_batch.rs @@ -9,7 +9,7 @@ use gravity_abi::gravity::*; use gravity_utils::error::GravityError; use gravity_utils::message_signatures::encode_tx_batch_confirm_hashed; use gravity_utils::types::*; -use std::time::Duration; +use std::{result::Result, time::Duration}; /// this function generates an appropriate Ethereum transaction /// to submit the provided transaction batch diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 8c82639a1..2bfca4df1 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -9,7 +9,7 @@ use gravity_abi::gravity::*; use gravity_utils::error::GravityError; use gravity_utils::ethereum::{downcast_to_u64, vec_u8_to_fixed_32}; use gravity_utils::types::*; -use std::cmp::min; +use std::{cmp::min, result::Result}; pub fn get_checkpoint_abi_encode( valset: &Valset, diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index a15922ad8..136042423 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -9,7 +9,7 @@ use gravity_abi::gravity::*; use gravity_utils::{ error::GravityError, message_signatures::encode_valset_confirm_hashed, types::*, }; -use std::time::Duration; +use std::{result::Result, time::Duration}; /// this function generates an appropriate Ethereum transaction /// to submit the provided validator set and signatures. diff --git a/orchestrator/gorc/Cargo.toml b/orchestrator/gorc/Cargo.toml index 71919e9f7..f43659110 100644 --- a/orchestrator/gorc/Cargo.toml +++ b/orchestrator/gorc/Cargo.toml @@ -19,9 +19,9 @@ orchestrator = { path = "../orchestrator" } relayer = { path = "../relayer" } deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} -ethers = { version = "0.5.4", features=["abigen"] } +ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } clarity = "0.4.12" -actix-rt = "2.2" +actix-rt = "2.5" rpassword = "5" bip32 = "0.2" k256 = { version = "0.9", features = ["pem"] } diff --git a/orchestrator/gravity_abi/Cargo.toml b/orchestrator/gravity_abi/Cargo.toml index 8e8379e0b..ef285a530 100644 --- a/orchestrator/gravity_abi/Cargo.toml +++ b/orchestrator/gravity_abi/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ethers = { version = "0.5.4", features=["abigen"] } +ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } serde = "1.0" serde_derive = "1.0" serde_json = "1.0.69" \ No newline at end of file diff --git a/orchestrator/gravity_abi/src/erc20.rs b/orchestrator/gravity_abi/src/erc20.rs index f59ce5511..08a6b45e2 100644 --- a/orchestrator/gravity_abi/src/erc20.rs +++ b/orchestrator/gravity_abi/src/erc20.rs @@ -163,6 +163,7 @@ mod erc20_mod { Eq, PartialEq, ethers :: contract :: EthEvent, + ethers :: contract :: EthDisplay, serde :: Deserialize, serde :: Serialize, )] @@ -181,6 +182,7 @@ mod erc20_mod { Eq, PartialEq, ethers :: contract :: EthEvent, + ethers :: contract :: EthDisplay, serde :: Deserialize, serde :: Serialize, )] @@ -192,48 +194,366 @@ mod erc20_mod { pub to: ethers::core::types::Address, pub value: ethers::core::types::U256, } - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, ethers :: contract :: EthAbiType)] pub enum ERC20Events { ApprovalFilter(ApprovalFilter), TransferFilter(TransferFilter), } - impl ethers::core::abi::Tokenizable for ERC20Events { - fn from_token( - token: ethers::core::abi::Token, - ) -> Result + impl ethers::contract::EthLogDecode for ERC20Events { + fn decode_log(log: ðers::core::abi::RawLog) -> Result where Self: Sized, { - if let Ok(decoded) = ApprovalFilter::from_token(token.clone()) { + if let Ok(decoded) = ApprovalFilter::decode_log(log) { return Ok(ERC20Events::ApprovalFilter(decoded)); } - if let Ok(decoded) = TransferFilter::from_token(token.clone()) { + if let Ok(decoded) = TransferFilter::decode_log(log) { return Ok(ERC20Events::TransferFilter(decoded)); } - Err(ethers::core::abi::InvalidOutputType( - "Failed to decode all event variants".to_string(), - )) + Err(ethers::core::abi::Error::InvalidData) } - fn into_token(self) -> ethers::core::abi::Token { + } + impl ::std::fmt::Display for ERC20Events { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match self { - ERC20Events::ApprovalFilter(element) => element.into_token(), - ERC20Events::TransferFilter(element) => element.into_token(), + ERC20Events::ApprovalFilter(element) => element.fmt(f), + ERC20Events::TransferFilter(element) => element.fmt(f), } } } - impl ethers::core::abi::TokenizableItem for ERC20Events {} - impl ethers::contract::EthLogDecode for ERC20Events { - fn decode_log(log: ðers::core::abi::RawLog) -> Result - where - Self: Sized, - { - if let Ok(decoded) = ApprovalFilter::decode_log(log) { - return Ok(ERC20Events::ApprovalFilter(decoded)); + #[doc = "Container type for all input parameters for the `allowance`function with signature `allowance(address,address)` and selector `[221, 98, 237, 62]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "allowance", abi = "allowance(address,address)")] + pub struct AllowanceCall { + pub owner: ethers::core::types::Address, + pub spender: ethers::core::types::Address, + } + #[doc = "Container type for all input parameters for the `approve`function with signature `approve(address,uint256)` and selector `[9, 94, 167, 179]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "approve", abi = "approve(address,uint256)")] + pub struct ApproveCall { + pub spender: ethers::core::types::Address, + pub amount: ethers::core::types::U256, + } + #[doc = "Container type for all input parameters for the `balanceOf`function with signature `balanceOf(address)` and selector `[112, 160, 130, 49]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "balanceOf", abi = "balanceOf(address)")] + pub struct BalanceOfCall { + pub account: ethers::core::types::Address, + } + #[doc = "Container type for all input parameters for the `decimals`function with signature `decimals()` and selector `[49, 60, 229, 103]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "decimals", abi = "decimals()")] + pub struct DecimalsCall; + #[doc = "Container type for all input parameters for the `decreaseAllowance`function with signature `decreaseAllowance(address,uint256)` and selector `[164, 87, 194, 215]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "decreaseAllowance", abi = "decreaseAllowance(address,uint256)")] + pub struct DecreaseAllowanceCall { + pub spender: ethers::core::types::Address, + pub subtracted_value: ethers::core::types::U256, + } + #[doc = "Container type for all input parameters for the `increaseAllowance`function with signature `increaseAllowance(address,uint256)` and selector `[57, 80, 147, 81]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "increaseAllowance", abi = "increaseAllowance(address,uint256)")] + pub struct IncreaseAllowanceCall { + pub spender: ethers::core::types::Address, + pub added_value: ethers::core::types::U256, + } + #[doc = "Container type for all input parameters for the `name`function with signature `name()` and selector `[6, 253, 222, 3]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "name", abi = "name()")] + pub struct NameCall; + #[doc = "Container type for all input parameters for the `symbol`function with signature `symbol()` and selector `[149, 216, 155, 65]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "symbol", abi = "symbol()")] + pub struct SymbolCall; + #[doc = "Container type for all input parameters for the `totalSupply`function with signature `totalSupply()` and selector `[24, 22, 13, 221]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "totalSupply", abi = "totalSupply()")] + pub struct TotalSupplyCall; + #[doc = "Container type for all input parameters for the `transfer`function with signature `transfer(address,uint256)` and selector `[169, 5, 156, 187]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "transfer", abi = "transfer(address,uint256)")] + pub struct TransferCall { + pub recipient: ethers::core::types::Address, + pub amount: ethers::core::types::U256, + } + #[doc = "Container type for all input parameters for the `transferFrom`function with signature `transferFrom(address,address,uint256)` and selector `[35, 184, 114, 221]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "transferFrom", abi = "transferFrom(address,address,uint256)")] + pub struct TransferFromCall { + pub sender: ethers::core::types::Address, + pub recipient: ethers::core::types::Address, + pub amount: ethers::core::types::U256, + } + #[derive(Debug, Clone, PartialEq, Eq, ethers :: contract :: EthAbiType)] + pub enum ERC20Calls { + Allowance(AllowanceCall), + Approve(ApproveCall), + BalanceOf(BalanceOfCall), + Decimals(DecimalsCall), + DecreaseAllowance(DecreaseAllowanceCall), + IncreaseAllowance(IncreaseAllowanceCall), + Name(NameCall), + Symbol(SymbolCall), + TotalSupply(TotalSupplyCall), + Transfer(TransferCall), + TransferFrom(TransferFromCall), + } + impl ethers::core::abi::AbiDecode for ERC20Calls { + fn decode(data: impl AsRef<[u8]>) -> Result { + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(ERC20Calls::Allowance(decoded)); } - if let Ok(decoded) = TransferFilter::decode_log(log) { - return Ok(ERC20Events::TransferFilter(decoded)); + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(ERC20Calls::Approve(decoded)); } - Err(ethers::core::abi::Error::InvalidData) + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(ERC20Calls::BalanceOf(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(ERC20Calls::Decimals(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(ERC20Calls::DecreaseAllowance(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(ERC20Calls::IncreaseAllowance(decoded)); + } + if let Ok(decoded) = ::decode(data.as_ref()) { + return Ok(ERC20Calls::Name(decoded)); + } + if let Ok(decoded) = ::decode(data.as_ref()) + { + return Ok(ERC20Calls::Symbol(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(ERC20Calls::TotalSupply(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(ERC20Calls::Transfer(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(ERC20Calls::TransferFrom(decoded)); + } + Err(ethers::core::abi::Error::InvalidData.into()) + } + } + impl ethers::core::abi::AbiEncode for ERC20Calls { + fn encode(self) -> Vec { + match self { + ERC20Calls::Allowance(element) => element.encode(), + ERC20Calls::Approve(element) => element.encode(), + ERC20Calls::BalanceOf(element) => element.encode(), + ERC20Calls::Decimals(element) => element.encode(), + ERC20Calls::DecreaseAllowance(element) => element.encode(), + ERC20Calls::IncreaseAllowance(element) => element.encode(), + ERC20Calls::Name(element) => element.encode(), + ERC20Calls::Symbol(element) => element.encode(), + ERC20Calls::TotalSupply(element) => element.encode(), + ERC20Calls::Transfer(element) => element.encode(), + ERC20Calls::TransferFrom(element) => element.encode(), + } + } + } + impl ::std::fmt::Display for ERC20Calls { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match self { + ERC20Calls::Allowance(element) => element.fmt(f), + ERC20Calls::Approve(element) => element.fmt(f), + ERC20Calls::BalanceOf(element) => element.fmt(f), + ERC20Calls::Decimals(element) => element.fmt(f), + ERC20Calls::DecreaseAllowance(element) => element.fmt(f), + ERC20Calls::IncreaseAllowance(element) => element.fmt(f), + ERC20Calls::Name(element) => element.fmt(f), + ERC20Calls::Symbol(element) => element.fmt(f), + ERC20Calls::TotalSupply(element) => element.fmt(f), + ERC20Calls::Transfer(element) => element.fmt(f), + ERC20Calls::TransferFrom(element) => element.fmt(f), + } + } + } + impl ::std::convert::From for ERC20Calls { + fn from(var: AllowanceCall) -> Self { + ERC20Calls::Allowance(var) + } + } + impl ::std::convert::From for ERC20Calls { + fn from(var: ApproveCall) -> Self { + ERC20Calls::Approve(var) + } + } + impl ::std::convert::From for ERC20Calls { + fn from(var: BalanceOfCall) -> Self { + ERC20Calls::BalanceOf(var) + } + } + impl ::std::convert::From for ERC20Calls { + fn from(var: DecimalsCall) -> Self { + ERC20Calls::Decimals(var) + } + } + impl ::std::convert::From for ERC20Calls { + fn from(var: DecreaseAllowanceCall) -> Self { + ERC20Calls::DecreaseAllowance(var) + } + } + impl ::std::convert::From for ERC20Calls { + fn from(var: IncreaseAllowanceCall) -> Self { + ERC20Calls::IncreaseAllowance(var) + } + } + impl ::std::convert::From for ERC20Calls { + fn from(var: NameCall) -> Self { + ERC20Calls::Name(var) + } + } + impl ::std::convert::From for ERC20Calls { + fn from(var: SymbolCall) -> Self { + ERC20Calls::Symbol(var) + } + } + impl ::std::convert::From for ERC20Calls { + fn from(var: TotalSupplyCall) -> Self { + ERC20Calls::TotalSupply(var) + } + } + impl ::std::convert::From for ERC20Calls { + fn from(var: TransferCall) -> Self { + ERC20Calls::Transfer(var) + } + } + impl ::std::convert::From for ERC20Calls { + fn from(var: TransferFromCall) -> Self { + ERC20Calls::TransferFrom(var) } } } diff --git a/orchestrator/gravity_abi/src/gravity.rs b/orchestrator/gravity_abi/src/gravity.rs index 4ead5a8f9..151dd6f2f 100644 --- a/orchestrator/gravity_abi/src/gravity.rs +++ b/orchestrator/gravity_abi/src/gravity.rs @@ -319,6 +319,7 @@ mod gravity_mod { Eq, PartialEq, ethers :: contract :: EthEvent, + ethers :: contract :: EthDisplay, serde :: Deserialize, serde :: Serialize, )] @@ -342,6 +343,7 @@ mod gravity_mod { Eq, PartialEq, ethers :: contract :: EthEvent, + ethers :: contract :: EthDisplay, serde :: Deserialize, serde :: Serialize, )] @@ -352,7 +354,7 @@ mod gravity_mod { pub struct LogicCallEventFilter { pub invalidation_id: [u8; 32], pub invalidation_nonce: ethers::core::types::U256, - pub return_data: Vec, + pub return_data: ethers::core::types::Bytes, pub event_nonce: ethers::core::types::U256, } #[derive( @@ -362,6 +364,7 @@ mod gravity_mod { Eq, PartialEq, ethers :: contract :: EthEvent, + ethers :: contract :: EthDisplay, serde :: Deserialize, serde :: Serialize, )] @@ -386,6 +389,7 @@ mod gravity_mod { Eq, PartialEq, ethers :: contract :: EthEvent, + ethers :: contract :: EthDisplay, serde :: Deserialize, serde :: Serialize, )] @@ -407,6 +411,7 @@ mod gravity_mod { Eq, PartialEq, ethers :: contract :: EthEvent, + ethers :: contract :: EthDisplay, serde :: Deserialize, serde :: Serialize, )] @@ -421,7 +426,7 @@ mod gravity_mod { pub validators: Vec, pub powers: Vec, } - #[derive(Debug, Clone, PartialEq, Eq)] + #[derive(Debug, Clone, PartialEq, Eq, ethers :: contract :: EthAbiType)] pub enum GravityEvents { Erc20DeployedEventFilter(Erc20DeployedEventFilter), LogicCallEventFilter(LogicCallEventFilter), @@ -429,64 +434,574 @@ mod gravity_mod { TransactionBatchExecutedEventFilter(TransactionBatchExecutedEventFilter), ValsetUpdatedEventFilter(ValsetUpdatedEventFilter), } - impl ethers::core::abi::Tokenizable for GravityEvents { - fn from_token( - token: ethers::core::abi::Token, - ) -> Result + impl ethers::contract::EthLogDecode for GravityEvents { + fn decode_log(log: ðers::core::abi::RawLog) -> Result where Self: Sized, { - if let Ok(decoded) = Erc20DeployedEventFilter::from_token(token.clone()) { + if let Ok(decoded) = Erc20DeployedEventFilter::decode_log(log) { return Ok(GravityEvents::Erc20DeployedEventFilter(decoded)); } - if let Ok(decoded) = LogicCallEventFilter::from_token(token.clone()) { + if let Ok(decoded) = LogicCallEventFilter::decode_log(log) { return Ok(GravityEvents::LogicCallEventFilter(decoded)); } - if let Ok(decoded) = SendToCosmosEventFilter::from_token(token.clone()) { + if let Ok(decoded) = SendToCosmosEventFilter::decode_log(log) { return Ok(GravityEvents::SendToCosmosEventFilter(decoded)); } - if let Ok(decoded) = TransactionBatchExecutedEventFilter::from_token(token.clone()) { + if let Ok(decoded) = TransactionBatchExecutedEventFilter::decode_log(log) { return Ok(GravityEvents::TransactionBatchExecutedEventFilter(decoded)); } - if let Ok(decoded) = ValsetUpdatedEventFilter::from_token(token.clone()) { + if let Ok(decoded) = ValsetUpdatedEventFilter::decode_log(log) { return Ok(GravityEvents::ValsetUpdatedEventFilter(decoded)); } - Err(ethers::core::abi::InvalidOutputType( - "Failed to decode all event variants".to_string(), - )) + Err(ethers::core::abi::Error::InvalidData) } - fn into_token(self) -> ethers::core::abi::Token { + } + impl ::std::fmt::Display for GravityEvents { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { match self { - GravityEvents::Erc20DeployedEventFilter(element) => element.into_token(), - GravityEvents::LogicCallEventFilter(element) => element.into_token(), - GravityEvents::SendToCosmosEventFilter(element) => element.into_token(), - GravityEvents::TransactionBatchExecutedEventFilter(element) => element.into_token(), - GravityEvents::ValsetUpdatedEventFilter(element) => element.into_token(), + GravityEvents::Erc20DeployedEventFilter(element) => element.fmt(f), + GravityEvents::LogicCallEventFilter(element) => element.fmt(f), + GravityEvents::SendToCosmosEventFilter(element) => element.fmt(f), + GravityEvents::TransactionBatchExecutedEventFilter(element) => element.fmt(f), + GravityEvents::ValsetUpdatedEventFilter(element) => element.fmt(f), } } } - impl ethers::core::abi::TokenizableItem for GravityEvents {} - impl ethers::contract::EthLogDecode for GravityEvents { - fn decode_log(log: ðers::core::abi::RawLog) -> Result - where - Self: Sized, - { - if let Ok(decoded) = Erc20DeployedEventFilter::decode_log(log) { - return Ok(GravityEvents::Erc20DeployedEventFilter(decoded)); + #[doc = "Container type for all input parameters for the `deployERC20`function with signature `deployERC20(string,string,string,uint8)` and selector `[247, 149, 86, 55]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "deployERC20", abi = "deployERC20(string,string,string,uint8)")] + pub struct DeployERC20Call { + pub cosmos_denom: String, + pub name: String, + pub symbol: String, + pub decimals: u8, + } + #[doc = "Container type for all input parameters for the `lastBatchNonce`function with signature `lastBatchNonce(address)` and selector `[1, 27, 33, 116]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "lastBatchNonce", abi = "lastBatchNonce(address)")] + pub struct LastBatchNonceCall { + pub erc_20_address: ethers::core::types::Address, + } + #[doc = "Container type for all input parameters for the `lastLogicCallNonce`function with signature `lastLogicCallNonce(bytes32)` and selector `[201, 209, 148, 213]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "lastLogicCallNonce", abi = "lastLogicCallNonce(bytes32)")] + pub struct LastLogicCallNonceCall { + pub invalidation_id: [u8; 32], + } + #[doc = "Container type for all input parameters for the `sendToCosmos`function with signature `sendToCosmos(address,bytes32,uint256)` and selector `[31, 251, 231, 249]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "sendToCosmos", abi = "sendToCosmos(address,bytes32,uint256)")] + pub struct SendToCosmosCall { + pub token_contract: ethers::core::types::Address, + pub destination: [u8; 32], + pub amount: ethers::core::types::U256, + } + #[doc = "Container type for all input parameters for the `state_gravityId`function with signature `state_gravityId()` and selector `[189, 218, 129, 212]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "state_gravityId", abi = "state_gravityId()")] + pub struct StateGravityIdCall; + #[doc = "Container type for all input parameters for the `state_invalidationMapping`function with signature `state_invalidationMapping(bytes32)` and selector `[125, 251, 111, 134]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall( + name = "state_invalidationMapping", + abi = "state_invalidationMapping(bytes32)" + )] + pub struct StateInvalidationMappingCall(pub [u8; 32]); + #[doc = "Container type for all input parameters for the `state_lastBatchNonces`function with signature `state_lastBatchNonces(address)` and selector `[223, 151, 23, 75]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "state_lastBatchNonces", abi = "state_lastBatchNonces(address)")] + pub struct StateLastBatchNoncesCall(pub ethers::core::types::Address); + #[doc = "Container type for all input parameters for the `state_lastEventNonce`function with signature `state_lastEventNonce()` and selector `[115, 178, 5, 71]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "state_lastEventNonce", abi = "state_lastEventNonce()")] + pub struct StateLastEventNonceCall; + #[doc = "Container type for all input parameters for the `state_lastValsetCheckpoint`function with signature `state_lastValsetCheckpoint()` and selector `[242, 181, 51, 7]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall( + name = "state_lastValsetCheckpoint", + abi = "state_lastValsetCheckpoint()" + )] + pub struct StateLastValsetCheckpointCall; + #[doc = "Container type for all input parameters for the `state_lastValsetNonce`function with signature `state_lastValsetNonce()` and selector `[181, 101, 97, 254]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "state_lastValsetNonce", abi = "state_lastValsetNonce()")] + pub struct StateLastValsetNonceCall; + #[doc = "Container type for all input parameters for the `state_powerThreshold`function with signature `state_powerThreshold()` and selector `[229, 162, 181, 210]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall(name = "state_powerThreshold", abi = "state_powerThreshold()")] + pub struct StatePowerThresholdCall; + #[doc = "Container type for all input parameters for the `submitBatch`function with signature `submitBatch(address[],uint256[],uint256,uint8[],bytes32[],bytes32[],uint256[],address[],uint256[],uint256,address,uint256)` and selector `[131, 180, 53, 219]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall( + name = "submitBatch", + abi = "submitBatch(address[],uint256[],uint256,uint8[],bytes32[],bytes32[],uint256[],address[],uint256[],uint256,address,uint256)" + )] + pub struct SubmitBatchCall { + pub current_validators: ::std::vec::Vec, + pub current_powers: ::std::vec::Vec, + pub current_valset_nonce: ethers::core::types::U256, + pub v: ::std::vec::Vec, + pub r: ::std::vec::Vec<[u8; 32]>, + pub s: ::std::vec::Vec<[u8; 32]>, + pub amounts: ::std::vec::Vec, + pub destinations: ::std::vec::Vec, + pub fees: ::std::vec::Vec, + pub batch_nonce: ethers::core::types::U256, + pub token_contract: ethers::core::types::Address, + pub batch_timeout: ethers::core::types::U256, + } + #[doc = "Container type for all input parameters for the `submitLogicCall`function with signature `submitLogicCall(address[],uint256[],uint256,uint8[],bytes32[],bytes32[],(uint256[],address[],uint256[],address[],address,bytes,uint256,bytes32,uint256))` and selector `[12, 36, 108, 130]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall( + name = "submitLogicCall", + abi = "submitLogicCall(address[],uint256[],uint256,uint8[],bytes32[],bytes32[],(uint256[],address[],uint256[],address[],address,bytes,uint256,bytes32,uint256))" + )] + pub struct SubmitLogicCallCall { + pub current_validators: ::std::vec::Vec, + pub current_powers: ::std::vec::Vec, + pub current_valset_nonce: ethers::core::types::U256, + pub v: ::std::vec::Vec, + pub r: ::std::vec::Vec<[u8; 32]>, + pub s: ::std::vec::Vec<[u8; 32]>, + pub args: LogicCallArgs, + } + #[doc = "Container type for all input parameters for the `testCheckValidatorSignatures`function with signature `testCheckValidatorSignatures(address[],uint256[],uint8[],bytes32[],bytes32[],bytes32,uint256)` and selector `[219, 124, 78, 87]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall( + name = "testCheckValidatorSignatures", + abi = "testCheckValidatorSignatures(address[],uint256[],uint8[],bytes32[],bytes32[],bytes32,uint256)" + )] + pub struct TestCheckValidatorSignaturesCall { + pub current_validators: ::std::vec::Vec, + pub current_powers: ::std::vec::Vec, + pub v: ::std::vec::Vec, + pub r: ::std::vec::Vec<[u8; 32]>, + pub s: ::std::vec::Vec<[u8; 32]>, + pub the_hash: [u8; 32], + pub power_threshold: ethers::core::types::U256, + } + #[doc = "Container type for all input parameters for the `testMakeCheckpoint`function with signature `testMakeCheckpoint(address[],uint256[],uint256,bytes32)` and selector `[194, 39, 195, 11]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall( + name = "testMakeCheckpoint", + abi = "testMakeCheckpoint(address[],uint256[],uint256,bytes32)" + )] + pub struct TestMakeCheckpointCall { + pub validators: ::std::vec::Vec, + pub powers: ::std::vec::Vec, + pub valset_nonce: ethers::core::types::U256, + pub gravity_id: [u8; 32], + } + #[doc = "Container type for all input parameters for the `updateValset`function with signature `updateValset(address[],uint256[],uint256,address[],uint256[],uint256,uint8[],bytes32[],bytes32[])` and selector `[227, 203, 159, 98]`"] + #[derive( + Clone, + Debug, + Default, + Eq, + PartialEq, + ethers :: contract :: EthCall, + ethers :: contract :: EthDisplay, + serde :: Deserialize, + serde :: Serialize, + )] + #[ethcall( + name = "updateValset", + abi = "updateValset(address[],uint256[],uint256,address[],uint256[],uint256,uint8[],bytes32[],bytes32[])" + )] + pub struct UpdateValsetCall { + pub new_validators: ::std::vec::Vec, + pub new_powers: ::std::vec::Vec, + pub new_valset_nonce: ethers::core::types::U256, + pub current_validators: ::std::vec::Vec, + pub current_powers: ::std::vec::Vec, + pub current_valset_nonce: ethers::core::types::U256, + pub v: ::std::vec::Vec, + pub r: ::std::vec::Vec<[u8; 32]>, + pub s: ::std::vec::Vec<[u8; 32]>, + } + #[derive(Debug, Clone, PartialEq, Eq, ethers :: contract :: EthAbiType)] + pub enum GravityCalls { + DeployERC20(DeployERC20Call), + LastBatchNonce(LastBatchNonceCall), + LastLogicCallNonce(LastLogicCallNonceCall), + SendToCosmos(SendToCosmosCall), + StateGravityId(StateGravityIdCall), + StateInvalidationMapping(StateInvalidationMappingCall), + StateLastBatchNonces(StateLastBatchNoncesCall), + StateLastEventNonce(StateLastEventNonceCall), + StateLastValsetCheckpoint(StateLastValsetCheckpointCall), + StateLastValsetNonce(StateLastValsetNonceCall), + StatePowerThreshold(StatePowerThresholdCall), + SubmitBatch(SubmitBatchCall), + SubmitLogicCall(SubmitLogicCallCall), + TestCheckValidatorSignatures(TestCheckValidatorSignaturesCall), + TestMakeCheckpoint(TestMakeCheckpointCall), + UpdateValset(UpdateValsetCall), + } + impl ethers::core::abi::AbiDecode for GravityCalls { + fn decode(data: impl AsRef<[u8]>) -> Result { + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(GravityCalls::DeployERC20(decoded)); } - if let Ok(decoded) = LogicCallEventFilter::decode_log(log) { - return Ok(GravityEvents::LogicCallEventFilter(decoded)); + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(GravityCalls::LastBatchNonce(decoded)); } - if let Ok(decoded) = SendToCosmosEventFilter::decode_log(log) { - return Ok(GravityEvents::SendToCosmosEventFilter(decoded)); + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(GravityCalls::LastLogicCallNonce(decoded)); } - if let Ok(decoded) = TransactionBatchExecutedEventFilter::decode_log(log) { - return Ok(GravityEvents::TransactionBatchExecutedEventFilter(decoded)); + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(GravityCalls::SendToCosmos(decoded)); } - if let Ok(decoded) = ValsetUpdatedEventFilter::decode_log(log) { - return Ok(GravityEvents::ValsetUpdatedEventFilter(decoded)); + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(GravityCalls::StateGravityId(decoded)); } - Err(ethers::core::abi::Error::InvalidData) + if let Ok(decoded) = + ::decode( + data.as_ref(), + ) + { + return Ok(GravityCalls::StateInvalidationMapping(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(GravityCalls::StateLastBatchNonces(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(GravityCalls::StateLastEventNonce(decoded)); + } + if let Ok(decoded) = + ::decode( + data.as_ref(), + ) + { + return Ok(GravityCalls::StateLastValsetCheckpoint(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(GravityCalls::StateLastValsetNonce(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(GravityCalls::StatePowerThreshold(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(GravityCalls::SubmitBatch(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(GravityCalls::SubmitLogicCall(decoded)); + } + if let Ok(decoded) = + ::decode( + data.as_ref(), + ) + { + return Ok(GravityCalls::TestCheckValidatorSignatures(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(GravityCalls::TestMakeCheckpoint(decoded)); + } + if let Ok(decoded) = + ::decode(data.as_ref()) + { + return Ok(GravityCalls::UpdateValset(decoded)); + } + Err(ethers::core::abi::Error::InvalidData.into()) + } + } + impl ethers::core::abi::AbiEncode for GravityCalls { + fn encode(self) -> Vec { + match self { + GravityCalls::DeployERC20(element) => element.encode(), + GravityCalls::LastBatchNonce(element) => element.encode(), + GravityCalls::LastLogicCallNonce(element) => element.encode(), + GravityCalls::SendToCosmos(element) => element.encode(), + GravityCalls::StateGravityId(element) => element.encode(), + GravityCalls::StateInvalidationMapping(element) => element.encode(), + GravityCalls::StateLastBatchNonces(element) => element.encode(), + GravityCalls::StateLastEventNonce(element) => element.encode(), + GravityCalls::StateLastValsetCheckpoint(element) => element.encode(), + GravityCalls::StateLastValsetNonce(element) => element.encode(), + GravityCalls::StatePowerThreshold(element) => element.encode(), + GravityCalls::SubmitBatch(element) => element.encode(), + GravityCalls::SubmitLogicCall(element) => element.encode(), + GravityCalls::TestCheckValidatorSignatures(element) => element.encode(), + GravityCalls::TestMakeCheckpoint(element) => element.encode(), + GravityCalls::UpdateValset(element) => element.encode(), + } + } + } + impl ::std::fmt::Display for GravityCalls { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + match self { + GravityCalls::DeployERC20(element) => element.fmt(f), + GravityCalls::LastBatchNonce(element) => element.fmt(f), + GravityCalls::LastLogicCallNonce(element) => element.fmt(f), + GravityCalls::SendToCosmos(element) => element.fmt(f), + GravityCalls::StateGravityId(element) => element.fmt(f), + GravityCalls::StateInvalidationMapping(element) => element.fmt(f), + GravityCalls::StateLastBatchNonces(element) => element.fmt(f), + GravityCalls::StateLastEventNonce(element) => element.fmt(f), + GravityCalls::StateLastValsetCheckpoint(element) => element.fmt(f), + GravityCalls::StateLastValsetNonce(element) => element.fmt(f), + GravityCalls::StatePowerThreshold(element) => element.fmt(f), + GravityCalls::SubmitBatch(element) => element.fmt(f), + GravityCalls::SubmitLogicCall(element) => element.fmt(f), + GravityCalls::TestCheckValidatorSignatures(element) => element.fmt(f), + GravityCalls::TestMakeCheckpoint(element) => element.fmt(f), + GravityCalls::UpdateValset(element) => element.fmt(f), + } + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: DeployERC20Call) -> Self { + GravityCalls::DeployERC20(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: LastBatchNonceCall) -> Self { + GravityCalls::LastBatchNonce(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: LastLogicCallNonceCall) -> Self { + GravityCalls::LastLogicCallNonce(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: SendToCosmosCall) -> Self { + GravityCalls::SendToCosmos(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: StateGravityIdCall) -> Self { + GravityCalls::StateGravityId(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: StateInvalidationMappingCall) -> Self { + GravityCalls::StateInvalidationMapping(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: StateLastBatchNoncesCall) -> Self { + GravityCalls::StateLastBatchNonces(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: StateLastEventNonceCall) -> Self { + GravityCalls::StateLastEventNonce(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: StateLastValsetCheckpointCall) -> Self { + GravityCalls::StateLastValsetCheckpoint(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: StateLastValsetNonceCall) -> Self { + GravityCalls::StateLastValsetNonce(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: StatePowerThresholdCall) -> Self { + GravityCalls::StatePowerThreshold(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: SubmitBatchCall) -> Self { + GravityCalls::SubmitBatch(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: SubmitLogicCallCall) -> Self { + GravityCalls::SubmitLogicCall(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: TestCheckValidatorSignaturesCall) -> Self { + GravityCalls::TestCheckValidatorSignatures(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: TestMakeCheckpointCall) -> Self { + GravityCalls::TestMakeCheckpoint(var) + } + } + impl ::std::convert::From for GravityCalls { + fn from(var: UpdateValsetCall) -> Self { + GravityCalls::UpdateValset(var) } } #[doc = "`LogicCallArgs(uint256[],address[],uint256[],address[],address,bytes,uint256,bytes32,uint256)`"] @@ -506,7 +1021,7 @@ mod gravity_mod { pub fee_amounts: Vec, pub fee_token_contracts: Vec, pub logic_contract_address: ethers::core::types::Address, - pub payload: Vec, + pub payload: ethers::core::types::Bytes, pub time_out: ethers::core::types::U256, pub invalidation_id: [u8; 32], pub invalidation_nonce: ethers::core::types::U256, diff --git a/orchestrator/gravity_utils/Cargo.toml b/orchestrator/gravity_utils/Cargo.toml index 0f02ff252..e4b9bc3b6 100644 --- a/orchestrator/gravity_utils/Cargo.toml +++ b/orchestrator/gravity_utils/Cargo.toml @@ -11,7 +11,7 @@ gravity_abi = { path = "../gravity_abi" } gravity_proto = { path = "../gravity_proto/" } cosmos-sdk-proto = "0.6.3" deep_space = { git="https://github.com/iqlusioninc/deep_space/", branch="master" } -ethers = { version = "0.5.4", features=["abigen"] } +ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } web30 = "0.15" clarity = "0.4.11" num256 = "0.3" @@ -27,4 +27,4 @@ sha3 = "0.9" rustc-hex = "2.1.0" [dev_dependencies] rand = "0.8" -actix = "0.11" +actix = "0.12" diff --git a/orchestrator/gravity_utils/src/ethereum.rs b/orchestrator/gravity_utils/src/ethereum.rs index 999fd1480..7130dfd48 100644 --- a/orchestrator/gravity_utils/src/ethereum.rs +++ b/orchestrator/gravity_utils/src/ethereum.rs @@ -1,7 +1,7 @@ use crate::error::GravityError; use ethers::prelude::*; use ethers::types::Address as EthAddress; -use std::panic; +use std::{panic, result::Result}; pub fn downcast_to_f32(input: U256) -> Option { // technically the max value of u128 is larger than f32, but diff --git a/orchestrator/gravity_utils/src/types/batches.rs b/orchestrator/gravity_utils/src/types/batches.rs index 05c9e42d5..dcfba1757 100644 --- a/orchestrator/gravity_utils/src/types/batches.rs +++ b/orchestrator/gravity_utils/src/types/batches.rs @@ -3,7 +3,7 @@ use crate::error::GravityError; use deep_space::Address as CosmosAddress; use ethers::core::abi::Token; use ethers::types::{Address as EthAddress, Signature as EthSignature}; -use std::convert::TryFrom; +use std::{convert::TryFrom, result::Result}; /// This represents an individual transaction being bridged over to Ethereum /// parallel is the OutgoingTransferTx in x/gravity/types/batch.go diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 34bdd87fd..118d218a9 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -13,6 +13,7 @@ use ethers::abi::RawLog; use ethers::prelude::*; use ethers::types::Address as EthAddress; use gravity_abi::gravity::*; +use std::result::Result; pub const ERC20_DEPLOYED_EVENT_STR: &'static str = "ERC20DeployedEvent(string,address,string,string,uint8,uint256)"; @@ -305,7 +306,7 @@ impl FromLog for LogicCallExecutedEvent { Ok(LogicCallExecutedEvent { invalidation_id: event.invalidation_id.into(), invalidation_nonce: event.invalidation_nonce, - return_data: event.return_data.into(), + return_data: event.return_data.to_vec(), event_nonce: event.event_nonce, block_height: block_height_from_log(&input)?, }) diff --git a/orchestrator/gravity_utils/src/types/logic_call.rs b/orchestrator/gravity_utils/src/types/logic_call.rs index 5a5cbf429..a89afe0ec 100644 --- a/orchestrator/gravity_utils/src/types/logic_call.rs +++ b/orchestrator/gravity_utils/src/types/logic_call.rs @@ -1,7 +1,7 @@ use super::*; use crate::error::GravityError; use ethers::types::{Address as EthAddress, Signature as EthSignature}; -use std::convert::TryFrom; +use std::{convert::TryFrom, result::Result}; /// the response we get when querying for a valset confirmation #[derive(Serialize, Deserialize, Debug, Default, Clone)] diff --git a/orchestrator/gravity_utils/src/types/mod.rs b/orchestrator/gravity_utils/src/types/mod.rs index 68cdd208e..801b88525 100644 --- a/orchestrator/gravity_utils/src/types/mod.rs +++ b/orchestrator/gravity_utils/src/types/mod.rs @@ -3,9 +3,11 @@ mod ethereum_events; mod logic_call; mod signatures; mod valsets; + use crate::error::GravityError; use ethers::prelude::*; use ethers::types::Address as EthAddress; +use std::result::Result; pub use batches::*; pub use ethereum_events::*; diff --git a/orchestrator/orchestrator/Cargo.toml b/orchestrator/orchestrator/Cargo.toml index e9929278d..c903bcd10 100644 --- a/orchestrator/orchestrator/Cargo.toml +++ b/orchestrator/orchestrator/Cargo.toml @@ -16,12 +16,12 @@ gravity_utils = { path = "../gravity_utils" } gravity_proto = { path = "../gravity_proto" } deep_space={git="https://github.com/iqlusioninc/deep_space/", branch = "master" } -ethers = { version = "0.5.4", features=["abigen"] } +ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } serde_derive = "1.0" clarity = "0.4.11" docopt = "1" serde = "1.0" -actix-rt = "2.2" +actix-rt = "2.5" lazy_static = "1" web30 = "0.15" log = "0.4" @@ -30,7 +30,7 @@ serde_json = "1.0" tokio = "1.4.0" rand = "0.8" tonic = "0.4" -futures = "0.3" +futures = "0.3.18" openssl-probe = "0.1" axum = "0.1.2" diff --git a/orchestrator/orchestrator/src/ethereum_event_watcher.rs b/orchestrator/orchestrator/src/ethereum_event_watcher.rs index 79e207358..61b4fcb3f 100644 --- a/orchestrator/orchestrator/src/ethereum_event_watcher.rs +++ b/orchestrator/orchestrator/src/ethereum_event_watcher.rs @@ -25,7 +25,7 @@ use gravity_utils::{ VALSET_UPDATED_EVENT_STR, }, }; -use std::time; +use std::{result::Result, time}; use tonic::transport::Channel; pub async fn check_for_events( diff --git a/orchestrator/register_delegate_keys/Cargo.toml b/orchestrator/register_delegate_keys/Cargo.toml index 5cd4b4fe3..56d2a1cfd 100644 --- a/orchestrator/register_delegate_keys/Cargo.toml +++ b/orchestrator/register_delegate_keys/Cargo.toml @@ -16,13 +16,13 @@ gravity_utils = {path = "../gravity_utils"} gravity_proto = {path = "../gravity_proto/"} deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} -ethers = { version = "0.5.4", features=["abigen"] } +ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } contact = "0.4" serde_derive = "1.0" clarity = "0.4.11" docopt = "1" serde = "1.0" -actix-rt = "2.2.0" +actix-rt = "2.5" lazy_static = "1" web30 = "0.15" env_logger = "0.8" diff --git a/orchestrator/relayer/Cargo.toml b/orchestrator/relayer/Cargo.toml index 93c78bbed..46df19d2a 100644 --- a/orchestrator/relayer/Cargo.toml +++ b/orchestrator/relayer/Cargo.toml @@ -19,12 +19,12 @@ gravity_utils = { path = "../gravity_utils" } gravity_proto = { path = "../gravity_proto" } deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} -ethers = { version = "0.5.4", features=["abigen"] } +ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } serde_derive = "1.0" clarity = "0.4.11" docopt = "1" serde = "1.0" -actix-rt = "2" +actix-rt = "2.5" lazy_static = "1" web30 = "0.15" log = "0.4" @@ -35,4 +35,4 @@ openssl-probe = "0.1" [dev-dependencies] -actix = "0.11" +actix = "0.12" diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index 7f0e7d4ae..8f81b0610 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -4,7 +4,7 @@ use ethers::types::Address as EthAddress; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::types::{FromLog, ValsetUpdatedEvent, VALSET_UPDATED_EVENT_STR}; use gravity_utils::{error::GravityError, ethereum::downcast_to_u64, types::Valset}; -use std::panic; +use std::{panic, result::Result}; use tonic::transport::Channel; /// This function finds the latest valset on the Gravity contract by looking back through the event diff --git a/orchestrator/test_runner/Cargo.toml b/orchestrator/test_runner/Cargo.toml index b6e4af85e..f893ec4df 100644 --- a/orchestrator/test_runner/Cargo.toml +++ b/orchestrator/test_runner/Cargo.toml @@ -21,11 +21,11 @@ deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} serde_derive = "1.0" clarity = "0.4.11" docopt = "1" -ethers = "0.5.4" +ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } serde = "1.0" -actix = "0.11" +actix = "0.12" actix-web = {version = "3", features=["openssl"]} -actix-rt = "2.2" +actix-rt = "2.5" lazy_static = "1" url = "2" web30 = "0.15.4" @@ -34,5 +34,5 @@ env_logger = "0.8" tokio = "1.4.0" rand = "0.8" tonic = "0.4" -futures = "0.3" +futures = "0.3.18" hex = "0.4.3" From d9b36cb7afad94e1d63488b812b127b7ef7d9cb2 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 24 Nov 2021 16:46:20 -0800 Subject: [PATCH 103/115] Porting rust changes from mvid/contract-call --- orchestrator/cosmos_gravity/src/build.rs | 6 ++---- orchestrator/gravity_utils/src/types/logic_call.rs | 5 ----- orchestrator/relayer/src/batch_relaying.rs | 6 +++--- orchestrator/relayer/src/find_latest_valset.rs | 4 ++-- orchestrator/relayer/src/logic_call_relaying.rs | 6 +++--- 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/orchestrator/cosmos_gravity/src/build.rs b/orchestrator/cosmos_gravity/src/build.rs index 8b2cc31e7..ad7eb798b 100644 --- a/orchestrator/cosmos_gravity/src/build.rs +++ b/orchestrator/cosmos_gravity/src/build.rs @@ -6,7 +6,7 @@ use ethers::prelude::*; use ethers::utils::keccak256; use gravity_proto::gravity as proto; use gravity_proto::ToAny; -use gravity_utils::ethereum::{bytes_to_hex_str, downcast_to_u64, format_eth_address}; +use gravity_utils::ethereum::{downcast_to_u64, format_eth_address}; use gravity_utils::message_signatures::{ encode_logic_call_confirm, encode_tx_batch_confirm, encode_valset_confirm, }; @@ -96,9 +96,7 @@ pub async fn contract_call_tx_confirmation_messages( let confirmation = proto::ContractCallTxConfirmation { ethereum_signer: format_eth_address(ethereum_address), signature: signature.into(), - invalidation_scope: bytes_to_hex_str(&logic_call.invalidation_id) - .as_bytes() - .to_vec(), + invalidation_scope: logic_call.invalidation_id, invalidation_nonce: logic_call.invalidation_nonce, }; let msg = proto::MsgSubmitEthereumTxConfirmation { diff --git a/orchestrator/gravity_utils/src/types/logic_call.rs b/orchestrator/gravity_utils/src/types/logic_call.rs index a89afe0ec..ddc37e26a 100644 --- a/orchestrator/gravity_utils/src/types/logic_call.rs +++ b/orchestrator/gravity_utils/src/types/logic_call.rs @@ -25,11 +25,6 @@ impl LogicCall { for fee in input.fees { fees.push(Erc20Token::from_proto(fee)?) } - if transfers.is_empty() || fees.is_empty() { - return Err(GravityError::InvalidBridgeStateError( - "Transaction batch containing no transactions!".to_string(), - )); - } Ok(LogicCall { transfers, diff --git a/orchestrator/relayer/src/batch_relaying.rs b/orchestrator/relayer/src/batch_relaying.rs index 84f6bd9d1..c6896c1c9 100644 --- a/orchestrator/relayer/src/batch_relaying.rs +++ b/orchestrator/relayer/src/batch_relaying.rs @@ -41,7 +41,7 @@ pub async fn relay_batches( let possible_batches = get_batches_and_signatures(current_valset.clone(), grpc_client, gravity_id.clone()).await; - trace!("possible batches {:?}", possible_batches); + debug!("possible batches {:?}", possible_batches); submit_batches( current_valset, @@ -73,13 +73,13 @@ async fn get_batches_and_signatures( } else { return HashMap::new(); }; - trace!("Latest batches {:?}", latest_batches); + debug!("Latest batches {:?}", latest_batches); let mut possible_batches = HashMap::new(); for batch in latest_batches { let sigs = get_transaction_batch_signatures(grpc_client, batch.nonce, batch.token_contract).await; - trace!("Got sigs {:?}", sigs); + debug!("Got sigs {:?}", sigs); if let Ok(sigs) = sigs { // this checks that the signatures for the batch are actually possible to submit to the chain let hash = encode_tx_batch_confirm_hashed(gravity_id.clone(), batch.clone()); diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index 8f81b0610..2c7f36408 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -26,7 +26,7 @@ pub async fn find_latest_valset( let mut end_filter_block = eth_client.get_block_number().await?; while end_filter_block > 0u64.into() { - trace!("About to submit a Valset or Batch, looking back into the history to find the last Valset Update, on block {}", end_filter_block); + debug!("About to submit a Valset or Batch, looking back into the history to find the last Valset Update, on block {}", end_filter_block); let start_filter_block = end_filter_block.saturating_sub(BLOCKS_TO_SEARCH.into()); filter = filter.select(start_filter_block..end_filter_block); @@ -38,7 +38,7 @@ pub async fn find_latest_valset( // filtered blockspace...need more clarity on how severe an error it is if one of these events is malformed, and if // we should return early with an error or just log it the way the previous version did for logged_event in filtered_logged_events { - trace!("Found event {:?}", logged_event); + debug!("Found event {:?}", logged_event); match ValsetUpdatedEvent::from_log(&logged_event) { Ok(valset_updated_event) => { diff --git a/orchestrator/relayer/src/logic_call_relaying.rs b/orchestrator/relayer/src/logic_call_relaying.rs index e3b2e9164..e82fc4770 100644 --- a/orchestrator/relayer/src/logic_call_relaying.rs +++ b/orchestrator/relayer/src/logic_call_relaying.rs @@ -23,7 +23,7 @@ pub async fn relay_logic_calls( eth_gas_price_multiplier: f32, ) { let latest_calls = get_latest_logic_calls(grpc_client).await; - trace!("Latest Logic calls {:?}", latest_calls); + debug!("Latest Logic calls {:?}", latest_calls); if latest_calls.is_err() { return; } @@ -37,7 +37,7 @@ pub async fn relay_logic_calls( call.invalidation_nonce, ) .await; - trace!("Got sigs {:?}", sigs); + debug!("Got sigs {:?}", sigs); if let Ok(sigs) = sigs { let hash = encode_logic_call_confirm_hashed(gravity_id.clone(), call.clone()); // this checks that the signatures for the batch are actually possible to submit to the chain @@ -61,7 +61,7 @@ pub async fn relay_logic_calls( } } if oldest_signed_call.is_none() { - trace!("Could not find Call with signatures! exiting"); + debug!("Could not find Call with signatures! exiting"); return; } let oldest_signed_call = oldest_signed_call.unwrap(); From 8cbc5bb18fb39cb025bd2486c2275984bf06cfea Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Wed, 24 Nov 2021 17:06:07 -0800 Subject: [PATCH 104/115] Take allowance threshold as argument for erc20 --- orchestrator/ethereum_gravity/src/erc20_utils.rs | 9 ++++----- orchestrator/ethereum_gravity/src/send_to_cosmos.rs | 5 +++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/erc20_utils.rs b/orchestrator/ethereum_gravity/src/erc20_utils.rs index 3f1e9f5f6..1b9485a81 100644 --- a/orchestrator/ethereum_gravity/src/erc20_utils.rs +++ b/orchestrator/ethereum_gravity/src/erc20_utils.rs @@ -8,21 +8,20 @@ use std::{result::Result, time::Duration}; /// using any given address. What exactly this does can be hard to grok, essentially when /// you want contract A to be able to spend your erc20 contract funds you need to call 'approve' /// on the ERC20 contract with your own address and A's address so that in the future when you call -/// contract A it can manipulate your ERC20 balances. This function checks if that has already been done. +/// contract A it can manipulate your ERC20 balances. This function checks if that has already been done +/// and that the allowed amount is greater than the provided allowance threshold. pub async fn check_erc20_approved( erc20: Address, target_contract: Address, address: Address, + allowance_threshold: U256, eth_client: EthClient, ) -> Result { let erc20_contract = ERC20::new(erc20, eth_client.clone()); let contract_call = erc20_contract.allowance(address, target_contract); let allowance = contract_call.call().await?; - // TODO(bolten): verify if this check is sufficient/correct - // Check if the allowance remaining is greater than half of a U256 - it's as good - // a test as any. - Ok(allowance > (U256::MAX.div_mod(2u32.into()).0)) + Ok(allowance > allowance_threshold) } /// Approves a given contract to spend erc20 funds from the given address from the erc20 contract provided. diff --git a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs index e875fdee5..ce91e4955 100644 --- a/orchestrator/ethereum_gravity/src/send_to_cosmos.rs +++ b/orchestrator/ethereum_gravity/src/send_to_cosmos.rs @@ -21,10 +21,15 @@ pub async fn send_to_cosmos( wait_timeout: Option, eth_client: EthClient, ) -> Result { + // TODO(bolten): this value is ported from web30, does it match our expectations? + // Check if the allowance remaining is greater than half of a U256 - it's as good + // a test as any. + let allowance_threshold = U256::MAX.div_mod(2u32.into()).0; let approved = check_erc20_approved( erc20, gravity_contract, eth_client.address(), + allowance_threshold, eth_client.clone(), ) .await?; From e6fbf1fd975810d196bfc3587b2746e99468c3b8 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 29 Nov 2021 14:08:09 -0800 Subject: [PATCH 105/115] Update to ethers 0.6.1 instead of master Also remove unnecessary feature inclusion of abigen except for the abi_build crate. --- orchestrator/Cargo.lock | 69 ++++++++++++------- orchestrator/abi_build/Cargo.toml | 2 +- orchestrator/cosmos_gravity/Cargo.toml | 2 +- orchestrator/ethereum_gravity/Cargo.toml | 2 +- orchestrator/gorc/Cargo.toml | 2 +- orchestrator/gravity_abi/Cargo.toml | 2 +- orchestrator/gravity_utils/Cargo.toml | 2 +- orchestrator/orchestrator/Cargo.toml | 2 +- .../register_delegate_keys/Cargo.toml | 2 +- orchestrator/relayer/Cargo.toml | 2 +- orchestrator/test_runner/Cargo.toml | 2 +- 11 files changed, 56 insertions(+), 33 deletions(-) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index c1e8ada89..951a511ce 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -1738,8 +1738,9 @@ dependencies = [ [[package]] name = "ethers" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39d16b7455aa6e3de419d9e7d270605f402f87ffdbcfcd1c2d036d4cfceafdba" dependencies = [ "ethers-contract", "ethers-core", @@ -1752,8 +1753,9 @@ dependencies = [ [[package]] name = "ethers-contract" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb2b42ed54282b47225563f8f8ecb5356337ecb6342cf7a6129421413574947" dependencies = [ "ethers-contract-abigen", "ethers-contract-derive", @@ -1770,8 +1772,9 @@ dependencies = [ [[package]] name = "ethers-contract-abigen" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02185a49bdd3bc4cdbb59164ab5a2c6c99eb50d1162d051d40e3ec7fd9b77b9" dependencies = [ "Inflector", "anyhow", @@ -1791,8 +1794,9 @@ dependencies = [ [[package]] name = "ethers-contract-derive" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbfe93d0ab5f7eb3656f78a56d73e8da4cdef11b22ded7a2015afc5fddc54d8f" dependencies = [ "ethers-contract-abigen", "ethers-core", @@ -1805,8 +1809,9 @@ dependencies = [ [[package]] name = "ethers-core" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e101557a375366496ecdc53b69a1bfdebf393b6c0691f5d667659e4580164b68" dependencies = [ "arrayvec 0.7.2", "bytes 1.1.0", @@ -1833,31 +1838,34 @@ dependencies = [ [[package]] name = "ethers-etherscan" -version = "0.2.0" -source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75615bf40e98ad5100b5854608238d7f6cda6ba2779141b6d7c7d9f27246dfc4" dependencies = [ "ethers-core", "reqwest", "serde", + "serde-aux", "serde_json", "thiserror", ] [[package]] name = "ethers-middleware" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af5d80cc912cf090997b1bc1d01138cc1efed44445e64621cb7f8b29d2bb1bc6" dependencies = [ "async-trait", "ethers-contract", "ethers-core", + "ethers-etherscan", "ethers-providers", "ethers-signers", "futures-util", "instant", "reqwest", "serde", - "serde-aux", "serde_json", "thiserror", "tokio 1.13.0", @@ -1868,8 +1876,9 @@ dependencies = [ [[package]] name = "ethers-providers" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "254efa7740027e29145f4674324ad3745a569244d2f8932c3bb9847992324b78" dependencies = [ "async-trait", "auto_impl", @@ -1897,8 +1906,9 @@ dependencies = [ [[package]] name = "ethers-signers" -version = "0.6.0" -source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d1b5ef38b0159c99324abb1db1b131e80944968ae1227032d3a84d2368bd79c" dependencies = [ "async-trait", "coins-bip32", @@ -1917,8 +1927,9 @@ dependencies = [ [[package]] name = "ethers-solc" -version = "0.1.0" -source = "git+https://github.com/gakonst/ethers-rs?branch=master#2c30468b70dadba1263ca9660487bd1223519395" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca81cc5875d2194ba552e7b0c9262f7b6dd8268c69d0db42ddc15deb04dc2348" dependencies = [ "colored", "ethers-core", @@ -1931,7 +1942,9 @@ dependencies = [ "semver 1.0.4", "serde", "serde_json", + "sha2 0.9.8", "thiserror", + "tracing", "walkdir", ] @@ -4299,6 +4312,16 @@ dependencies = [ "cpufeatures", "digest 0.9.0", "opaque-debug 0.3.0", + "sha2-asm", +] + +[[package]] +name = "sha2-asm" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf27176fb5d15398e3a479c652c20459d9dac830dedd1fa55b42a77dbcdbfcea" +dependencies = [ + "cc", ] [[package]] @@ -4488,9 +4511,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" dependencies = [ "proc-macro2", "quote", diff --git a/orchestrator/abi_build/Cargo.toml b/orchestrator/abi_build/Cargo.toml index 13141a39b..2cbe5b304 100644 --- a/orchestrator/abi_build/Cargo.toml +++ b/orchestrator/abi_build/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } +ethers = { version = "0.6.1", features = ["abigen"] } serde_derive = "1.0" serde_json = "1.0.69" serde = "1.0" diff --git a/orchestrator/cosmos_gravity/Cargo.toml b/orchestrator/cosmos_gravity/Cargo.toml index e3668473f..94dff5019 100644 --- a/orchestrator/cosmos_gravity/Cargo.toml +++ b/orchestrator/cosmos_gravity/Cargo.toml @@ -12,7 +12,7 @@ ethereum_gravity = {path = "../ethereum_gravity"} gravity_proto = {path = "../gravity_proto/"} deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} -ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } +ethers = "0.6.1" clarity = "0.4.11" serde = "1.0" log = "0.4" diff --git a/orchestrator/ethereum_gravity/Cargo.toml b/orchestrator/ethereum_gravity/Cargo.toml index 6903bf2d6..bf26eec0f 100644 --- a/orchestrator/ethereum_gravity/Cargo.toml +++ b/orchestrator/ethereum_gravity/Cargo.toml @@ -11,7 +11,7 @@ gravity_abi = { path = "../gravity_abi" } gravity_utils = { path = "../gravity_utils" } deep_space = { git="https://github.com/iqlusioninc/deep_space/", branch="master" } -ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } +ethers = "0.6.1" clarity = "0.4.11" web30 = "0.15.4" log = "0.4" diff --git a/orchestrator/gorc/Cargo.toml b/orchestrator/gorc/Cargo.toml index f43659110..15a963fb6 100644 --- a/orchestrator/gorc/Cargo.toml +++ b/orchestrator/gorc/Cargo.toml @@ -19,7 +19,7 @@ orchestrator = { path = "../orchestrator" } relayer = { path = "../relayer" } deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} -ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } +ethers = "0.6.1" clarity = "0.4.12" actix-rt = "2.5" rpassword = "5" diff --git a/orchestrator/gravity_abi/Cargo.toml b/orchestrator/gravity_abi/Cargo.toml index ef285a530..b76c5e281 100644 --- a/orchestrator/gravity_abi/Cargo.toml +++ b/orchestrator/gravity_abi/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } +ethers = "0.6.1" serde = "1.0" serde_derive = "1.0" serde_json = "1.0.69" \ No newline at end of file diff --git a/orchestrator/gravity_utils/Cargo.toml b/orchestrator/gravity_utils/Cargo.toml index e4b9bc3b6..98f10a420 100644 --- a/orchestrator/gravity_utils/Cargo.toml +++ b/orchestrator/gravity_utils/Cargo.toml @@ -11,7 +11,7 @@ gravity_abi = { path = "../gravity_abi" } gravity_proto = { path = "../gravity_proto/" } cosmos-sdk-proto = "0.6.3" deep_space = { git="https://github.com/iqlusioninc/deep_space/", branch="master" } -ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } +ethers = "0.6.1" web30 = "0.15" clarity = "0.4.11" num256 = "0.3" diff --git a/orchestrator/orchestrator/Cargo.toml b/orchestrator/orchestrator/Cargo.toml index c903bcd10..8c7057ef6 100644 --- a/orchestrator/orchestrator/Cargo.toml +++ b/orchestrator/orchestrator/Cargo.toml @@ -16,7 +16,7 @@ gravity_utils = { path = "../gravity_utils" } gravity_proto = { path = "../gravity_proto" } deep_space={git="https://github.com/iqlusioninc/deep_space/", branch = "master" } -ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } +ethers = "0.6.1" serde_derive = "1.0" clarity = "0.4.11" docopt = "1" diff --git a/orchestrator/register_delegate_keys/Cargo.toml b/orchestrator/register_delegate_keys/Cargo.toml index 56d2a1cfd..9281979c3 100644 --- a/orchestrator/register_delegate_keys/Cargo.toml +++ b/orchestrator/register_delegate_keys/Cargo.toml @@ -16,7 +16,7 @@ gravity_utils = {path = "../gravity_utils"} gravity_proto = {path = "../gravity_proto/"} deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} -ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } +ethers = "0.6.1" contact = "0.4" serde_derive = "1.0" clarity = "0.4.11" diff --git a/orchestrator/relayer/Cargo.toml b/orchestrator/relayer/Cargo.toml index 46df19d2a..f00603eac 100644 --- a/orchestrator/relayer/Cargo.toml +++ b/orchestrator/relayer/Cargo.toml @@ -19,7 +19,7 @@ gravity_utils = { path = "../gravity_utils" } gravity_proto = { path = "../gravity_proto" } deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} -ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } +ethers = "0.6.1" serde_derive = "1.0" clarity = "0.4.11" docopt = "1" diff --git a/orchestrator/test_runner/Cargo.toml b/orchestrator/test_runner/Cargo.toml index f893ec4df..b44ab38fa 100644 --- a/orchestrator/test_runner/Cargo.toml +++ b/orchestrator/test_runner/Cargo.toml @@ -21,7 +21,7 @@ deep_space ={git="https://github.com/iqlusioninc/deep_space/", branch="master"} serde_derive = "1.0" clarity = "0.4.11" docopt = "1" -ethers = { git = "https://github.com/gakonst/ethers-rs", branch = "master", features = ["abigen"] } +ethers = "0.6.1" serde = "1.0" actix = "0.12" actix-web = {version = "3", features=["openssl"]} From 50c384fdf6fd93e1dbb0367099f723ac6da556c3 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 29 Nov 2021 14:09:12 -0800 Subject: [PATCH 106/115] Update the Etherscan oracle for ethers 0.6.1 --- orchestrator/ethereum_gravity/src/utils.rs | 8 ++++---- orchestrator/gravity_utils/src/error.rs | 9 +++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 2bfca4df1..a7aff8e21 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -1,6 +1,6 @@ use crate::types::EthClient; use ethers::core::abi::{self, Token}; -use ethers::middleware::gas_oracle::{Etherscan, GasCategory}; +use ethers::middleware::gas_oracle::Etherscan; use ethers::prelude::gas_oracle::GasOracle; use ethers::prelude::*; use ethers::types::Address as EthAddress; @@ -195,9 +195,9 @@ pub async fn get_call_gas_cost(eth_client: EthClient) -> Result Result { - if let Ok(api_key) = std::env::var("ETHERSCAN_API_KEY") { - let etherscan_oracle = - Etherscan::new(Some(api_key.as_str())).category(GasCategory::Standard); + if let Ok(_) = std::env::var("ETHERSCAN_API_KEY") { + let etherscan_client = Client::new_from_env(Chain::Mainnet)?; + let etherscan_oracle = Etherscan::new(etherscan_client); return Ok(etherscan_oracle.fetch().await?); } diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index d295410fc..d8998d209 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -8,6 +8,7 @@ use deep_space::error::PrivateKeyError as CosmosPrivateKeyError; use ethers::abi::ethereum_types::FromDecStrErr as EthersParseUintError; use ethers::abi::Error as EthersAbiError; use ethers::contract::AbiError as EthersContractAbiError; +use ethers::prelude::errors::EtherscanError; use ethers::prelude::gas_oracle::GasOracleError as EthersGasOracleError; use ethers::prelude::signer::SignerMiddlewareError; use ethers::prelude::ContractError; @@ -40,6 +41,7 @@ pub enum GravityError { EthersProviderError(EthersProviderError), EthersSignatureError(EthersSignatureError), EthersWalletError(EthersWalletError), + EtherscanError(EtherscanError), GravityContractError(String), InvalidArgumentError(String), InvalidBridgeStateError(String), @@ -86,6 +88,7 @@ impl fmt::Display for GravityError { GravityError::EthersProviderError(val) => write!(f, "Ethers provider error: {}", val), GravityError::EthersSignatureError(val) => write!(f, "Ethers signature error: {}", val), GravityError::EthersWalletError(val) => write!(f, "Ethers wallet error: {}", val), + GravityError::EtherscanError(val) => write!(f, "Etherscan error: {}", val), GravityError::GravityContractError(val) => write!(f, "Gravity contract error: {}", val), GravityError::InvalidArgumentError(val) => write!(f, "Invalid argument error: {}", val), GravityError::InvalidOptionsError(val) => { @@ -205,6 +208,12 @@ impl From for GravityError { } } +impl From for GravityError { + fn from(error: EtherscanError) -> Self { + GravityError::EtherscanError(error) + } +} + impl From for GravityError { fn from(error: Status) -> Self { GravityError::GravityGrpcError(error) From 7ff2d985ee52768c01593a6faccada03af9101d6 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 29 Nov 2021 18:42:06 -0800 Subject: [PATCH 107/115] Fix eth address formatting instance I missed --- orchestrator/cosmos_gravity/src/send.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchestrator/cosmos_gravity/src/send.rs b/orchestrator/cosmos_gravity/src/send.rs index 4c51d5eb5..fb56aaa43 100644 --- a/orchestrator/cosmos_gravity/src/send.rs +++ b/orchestrator/cosmos_gravity/src/send.rs @@ -93,7 +93,7 @@ pub async fn send_to_eth( let msg = proto::MsgSendToEthereum { sender: cosmos_address.to_string(), - ethereum_recipient: destination.to_string(), + ethereum_recipient: format_eth_address(destination), amount: Some(amount.into()), bridge_fee: Some(bridge_fee.clone().into()), }; From 9bc5cc5be4c851b963242490a9ea1e76abac2b30 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 29 Nov 2021 18:51:08 -0800 Subject: [PATCH 108/115] delete duplicated __send_messages for cosmos send_messages and __send_messages were exactly the same, so I deleted __send_messages --- orchestrator/cosmos_gravity/src/send.rs | 55 ++----------------------- 1 file changed, 3 insertions(+), 52 deletions(-) diff --git a/orchestrator/cosmos_gravity/src/send.rs b/orchestrator/cosmos_gravity/src/send.rs index fb56aaa43..09a830dc1 100644 --- a/orchestrator/cosmos_gravity/src/send.rs +++ b/orchestrator/cosmos_gravity/src/send.rs @@ -66,7 +66,7 @@ pub async fn update_gravity_delegate_addresses( }; let msg = Msg::new("/gravity.v1.MsgDelegateKeys", msg); - __send_messages(contact, cosmos_key, gas_price, vec![msg], gas_adjustment).await + send_messages(contact, cosmos_key, gas_price, vec![msg], gas_adjustment).await } /// Sends tokens from Cosmos to Ethereum. These tokens will not be sent immediately instead @@ -98,7 +98,7 @@ pub async fn send_to_eth( bridge_fee: Some(bridge_fee.clone().into()), }; let msg = Msg::new("/gravity.v1.MsgSendToEthereum", msg); - __send_messages(contact, cosmos_key, gas_price, vec![msg], gas_adjustment).await + send_messages(contact, cosmos_key, gas_price, vec![msg], gas_adjustment).await } pub async fn send_request_batch_tx( @@ -114,56 +114,7 @@ pub async fn send_request_batch_tx( denom, }; let msg = Msg::new("/gravity.v1.MsgRequestBatchTx", msg_request_batch); - __send_messages(contact, cosmos_key, gas_price, vec![msg], gas_adjustment).await -} - -// TODO(Levi) teach this branch to accept gas_prices -async fn __send_messages( - contact: &Contact, - cosmos_key: CosmosPrivateKey, - gas_price: (f64, String), - messages: Vec, - gas_adjustment: f64, -) -> Result { - let cosmos_address = cosmos_key.to_address(&contact.get_prefix()).unwrap(); - - let fee_amount = Coin { - denom: gas_price.1.clone(), - amount: 0u32.into(), - }; - - let fee = Fee { - amount: vec![fee_amount], - gas_limit: 0, - granter: None, - payer: None, - }; - - let mut args = contact.get_message_args(cosmos_address, fee).await?; - - let tx_parts = cosmos_key.build_tx(&messages, args.clone(), MEMO)?; - let gas = contact.simulate_tx(tx_parts).await?; - - // multiply the estimated gas by the configured gas adjustment - let gas_limit: f64 = (gas.gas_used as f64) * gas_adjustment; - args.fee.gas_limit = cmp::max(gas_limit as u64, 500000 * messages.len() as u64); - - // compute the fee as fee=ceil(gas_limit * gas_price) - - let fee_amount: f64 = args.fee.gas_limit as f64 * gas_price.0; - let fee_amount: u64 = fee_amount.abs().ceil() as u64; - let fee_amount = Coin { - denom: gas_price.1, - amount: fee_amount.into(), - }; - args.fee.amount = vec![fee_amount]; - - let msg_bytes = cosmos_key.sign_std_msg(&messages, args, MEMO)?; - let response = contact - .send_transaction(msg_bytes, BroadcastMode::Sync) - .await?; - - Ok(contact.wait_for_tx(response, TIMEOUT).await?) + send_messages(contact, cosmos_key, gas_price, vec![msg], gas_adjustment).await } pub async fn send_messages( From b48a8ee66dd70cd2ae672aa067e59ceca5fb0b77 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Mon, 29 Nov 2021 19:18:21 -0800 Subject: [PATCH 109/115] Remove dead checkpoint abi encoding functions --- orchestrator/ethereum_gravity/src/utils.rs | 32 ---------------------- 1 file changed, 32 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index a7aff8e21..5942c7d18 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -1,45 +1,13 @@ use crate::types::EthClient; -use ethers::core::abi::{self, Token}; use ethers::middleware::gas_oracle::Etherscan; use ethers::prelude::gas_oracle::GasOracle; use ethers::prelude::*; use ethers::types::Address as EthAddress; -use ethers::utils::keccak256; use gravity_abi::gravity::*; use gravity_utils::error::GravityError; use gravity_utils::ethereum::{downcast_to_u64, vec_u8_to_fixed_32}; -use gravity_utils::types::*; use std::{cmp::min, result::Result}; -pub fn get_checkpoint_abi_encode( - valset: &Valset, - gravity_id: &str, -) -> Result, GravityError> { - let (eth_addresses, powers) = valset.filter_empty_addresses(); - let eth_addresses = eth_addresses - .iter() - .map(|address| Token::Address(*address)) - .collect(); - let powers = powers - .iter() - .map(|power| Token::Uint((*power).into())) - .collect(); - - Ok(abi::encode(&[ - Token::FixedBytes(gravity_id.as_bytes().to_vec()), - Token::FixedBytes("checkpoint".as_bytes().to_vec()), - Token::Uint(valset.nonce.into()), - Token::Array(eth_addresses), - Token::Array(powers), - ])) -} - -pub fn get_checkpoint_hash(valset: &Valset, gravity_id: &str) -> Result, GravityError> { - let locally_computed_abi_encode = get_checkpoint_abi_encode(&valset, &gravity_id)?; - let locally_computed_digest = keccak256(locally_computed_abi_encode.as_slice()); - Ok(locally_computed_digest.to_vec()) -} - /// Gets the latest validator set nonce pub async fn get_valset_nonce( gravity_contract_address: EthAddress, From 69ce9c85dfe474921b5076bf3c4946bf043e6779 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 30 Nov 2021 15:15:00 -0800 Subject: [PATCH 110/115] use checked_add when aggregating fees --- orchestrator/gravity_utils/src/error.rs | 4 +++- orchestrator/gravity_utils/src/types/batches.rs | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/orchestrator/gravity_utils/src/error.rs b/orchestrator/gravity_utils/src/error.rs index d8998d209..832460546 100644 --- a/orchestrator/gravity_utils/src/error.rs +++ b/orchestrator/gravity_utils/src/error.rs @@ -56,6 +56,7 @@ pub enum GravityError { ParseBigIntError(ParseBigIntError), ParseIntError(ParseIntError), FromUtf8Error(FromUtf8Error), + OverflowError(String), } impl fmt::Display for GravityError { @@ -111,7 +112,8 @@ impl fmt::Display for GravityError { GravityError::ParseIntError(val) => write!(f, "Failed to parse integer: {}", val), GravityError::FromUtf8Error(val) => { write!(f, "Failed to parse bytes to UTF-8: {}", val) - } + }, + GravityError::OverflowError(val) => write!(f, "Overflow error: {}", val), } } } diff --git a/orchestrator/gravity_utils/src/types/batches.rs b/orchestrator/gravity_utils/src/types/batches.rs index dcfba1757..4975d1724 100644 --- a/orchestrator/gravity_utils/src/types/batches.rs +++ b/orchestrator/gravity_utils/src/types/batches.rs @@ -92,9 +92,16 @@ impl TransactionBatch { for tx in input.transactions { let tx = BatchTransaction::from_proto(tx)?; if let Some(total_fee) = running_total_fee { + let running_amount = total_fee.amount.checked_add(tx.erc20_fee.amount); + if running_amount.is_none() { + return Err(GravityError::OverflowError( + format!("U256 overflow when adding all fees together for transaction batch with nonce {}", input.batch_nonce) + )) + } + running_total_fee = Some(Erc20Token { token_contract_address: total_fee.token_contract_address, - amount: total_fee.amount + tx.erc20_fee.amount, + amount: running_amount.unwrap(), }); } else { running_total_fee = Some(tx.erc20_fee.clone()) From ab58996a27de6cb2efebb5a4add0c3e6c7f58675 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 30 Nov 2021 16:11:21 -0800 Subject: [PATCH 111/115] Use generated abi signatures when filtering events --- orchestrator/Cargo.lock | 2 ++ .../gravity_utils/src/types/ethereum_events.rs | 10 ---------- orchestrator/orchestrator/Cargo.toml | 1 + .../orchestrator/src/ethereum_event_watcher.rs | 15 +++++++-------- orchestrator/orchestrator/src/oracle_resync.rs | 14 +++++++------- orchestrator/relayer/Cargo.toml | 1 + orchestrator/relayer/src/find_latest_valset.rs | 5 +++-- 7 files changed, 21 insertions(+), 27 deletions(-) diff --git a/orchestrator/Cargo.lock b/orchestrator/Cargo.lock index 951a511ce..f7a96193c 100644 --- a/orchestrator/Cargo.lock +++ b/orchestrator/Cargo.lock @@ -3218,6 +3218,7 @@ dependencies = [ "ethereum_gravity", "ethers", "futures", + "gravity_abi", "gravity_proto", "gravity_utils", "hyper", @@ -3852,6 +3853,7 @@ dependencies = [ "env_logger", "ethereum_gravity", "ethers", + "gravity_abi", "gravity_proto", "gravity_utils", "lazy_static", diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index 118d218a9..a096322fb 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -15,16 +15,6 @@ use ethers::types::Address as EthAddress; use gravity_abi::gravity::*; use std::result::Result; -pub const ERC20_DEPLOYED_EVENT_STR: &'static str = - "ERC20DeployedEvent(string,address,string,string,uint8,uint256)"; -pub const LOGIC_CALL_EVENT_STR: &'static str = "LogicCallEvent(bytes32,uint256,bytes,uint256)"; -pub const SEND_TO_COSMOS_EVENT_STR: &'static str = - "SendToCosmosEvent(address,address,bytes32,uint256,uint256)"; -pub const TRANSACTION_BATCH_EXECUTED_EVENT_STR: &'static str = - "TransactionBatchExecutedEvent(uint256,address,uint256)"; -pub const VALSET_UPDATED_EVENT_STR: &'static str = - "ValsetUpdatedEvent(uint256,uint256,address[],uint256[])"; - // given a Log retrieved by querying the Ethereum chain, decode it into one of // the types we are generating using abigen! above for the Gravity contract fn log_to_ethers_event(log: &Log) -> Result { diff --git a/orchestrator/orchestrator/Cargo.toml b/orchestrator/orchestrator/Cargo.toml index 8c7057ef6..1462fd140 100644 --- a/orchestrator/orchestrator/Cargo.toml +++ b/orchestrator/orchestrator/Cargo.toml @@ -12,6 +12,7 @@ path = "src/lib.rs" relayer = { path = "../relayer" } ethereum_gravity = { path = "../ethereum_gravity" } cosmos_gravity = { path = "../cosmos_gravity" } +gravity_abi = { path = "../gravity_abi" } gravity_utils = { path = "../gravity_utils" } gravity_proto = { path = "../gravity_proto" } diff --git a/orchestrator/orchestrator/src/ethereum_event_watcher.rs b/orchestrator/orchestrator/src/ethereum_event_watcher.rs index 61b4fcb3f..520a56312 100644 --- a/orchestrator/orchestrator/src/ethereum_event_watcher.rs +++ b/orchestrator/orchestrator/src/ethereum_event_watcher.rs @@ -11,6 +11,7 @@ use deep_space::{Contact, Msg}; use ethereum_gravity::types::EthClient; use ethers::prelude::*; use ethers::types::Address as EthAddress; +use gravity_abi::gravity::*; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::ethereum::downcast_to_u64; use gravity_utils::types::EventNonceFilter; @@ -20,9 +21,7 @@ use gravity_utils::{ ethereum::bytes_to_hex_str, types::{ Erc20DeployedEvent, LogicCallExecutedEvent, SendToCosmosEvent, - TransactionBatchExecutedEvent, ValsetUpdatedEvent, ERC20_DEPLOYED_EVENT_STR, - LOGIC_CALL_EVENT_STR, SEND_TO_COSMOS_EVENT_STR, TRANSACTION_BATCH_EXECUTED_EVENT_STR, - VALSET_UPDATED_EVENT_STR, + TransactionBatchExecutedEvent, ValsetUpdatedEvent, }, }; use std::{result::Result, time}; @@ -49,19 +48,19 @@ pub async fn check_for_events( let mut erc20_deployed_filter = Filter::new() .address(filter_gravity_contract_address.clone()) - .event(&ERC20_DEPLOYED_EVENT_STR); + .event(&Erc20DeployedEventFilter::abi_signature()); let mut logic_call_filter = Filter::new() .address(filter_gravity_contract_address.clone()) - .event(&LOGIC_CALL_EVENT_STR); + .event(&LogicCallEventFilter::abi_signature()); let mut send_to_cosmos_filter = Filter::new() .address(filter_gravity_contract_address.clone()) - .event(&SEND_TO_COSMOS_EVENT_STR); + .event(&SendToCosmosEventFilter::abi_signature()); let mut transaction_batch_filter = Filter::new() .address(filter_gravity_contract_address.clone()) - .event(&TRANSACTION_BATCH_EXECUTED_EVENT_STR); + .event(&TransactionBatchExecutedEventFilter::abi_signature()); let mut valset_updated_filter = Filter::new() .address(filter_gravity_contract_address.clone()) - .event(&VALSET_UPDATED_EVENT_STR); + .event(&ValsetUpdatedEventFilter::abi_signature()); let search_range = starting_block..latest_block; diff --git a/orchestrator/orchestrator/src/oracle_resync.rs b/orchestrator/orchestrator/src/oracle_resync.rs index 808af407d..9606d05cf 100644 --- a/orchestrator/orchestrator/src/oracle_resync.rs +++ b/orchestrator/orchestrator/src/oracle_resync.rs @@ -2,11 +2,11 @@ use deep_space::address::Address as CosmosAddress; use ethereum_gravity::types::EthClient; use ethers::prelude::*; use ethers::types::Address as EthAddress; +use gravity_abi::gravity::*; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; use gravity_utils::types::{ Erc20DeployedEvent, LogicCallExecutedEvent, SendToCosmosEvent, TransactionBatchExecutedEvent, - ValsetUpdatedEvent, ERC20_DEPLOYED_EVENT_STR, LOGIC_CALL_EVENT_STR, SEND_TO_COSMOS_EVENT_STR, - TRANSACTION_BATCH_EXECUTED_EVENT_STR, VALSET_UPDATED_EVENT_STR, + ValsetUpdatedEvent, }; use gravity_utils::types::{FromLog, FromLogWithPrefix}; use tokio::time::sleep as delay_for; @@ -46,19 +46,19 @@ pub async fn get_last_checked_block( // from the generated ABI files, should look into that let mut erc20_deployed_filter = Filter::new() .address(filter_gravity_contract_address.clone()) - .event(&ERC20_DEPLOYED_EVENT_STR); + .event(&Erc20DeployedEventFilter::abi_signature()); let mut logic_call_filter = Filter::new() .address(filter_gravity_contract_address.clone()) - .event(&LOGIC_CALL_EVENT_STR); + .event(&LogicCallEventFilter::abi_signature()); let mut send_to_cosmos_filter = Filter::new() .address(filter_gravity_contract_address.clone()) - .event(&SEND_TO_COSMOS_EVENT_STR); + .event(&SendToCosmosEventFilter::abi_signature()); let mut transaction_batch_filter = Filter::new() .address(filter_gravity_contract_address.clone()) - .event(&TRANSACTION_BATCH_EXECUTED_EVENT_STR); + .event(&TransactionBatchExecutedEventFilter::abi_signature()); let mut valset_updated_filter = Filter::new() .address(filter_gravity_contract_address.clone()) - .event(&VALSET_UPDATED_EVENT_STR); + .event(&ValsetUpdatedEventFilter::abi_signature()); let mut end_search_block = get_block_number_with_retry(eth_client.clone()).await; let blocks_to_search: U64 = blocks_to_search.into(); diff --git a/orchestrator/relayer/Cargo.toml b/orchestrator/relayer/Cargo.toml index f00603eac..791466925 100644 --- a/orchestrator/relayer/Cargo.toml +++ b/orchestrator/relayer/Cargo.toml @@ -15,6 +15,7 @@ path = "src/main.rs" [dependencies] ethereum_gravity = { path = "../ethereum_gravity" } cosmos_gravity = { path = "../cosmos_gravity" } +gravity_abi = { path = "../gravity_abi" } gravity_utils = { path = "../gravity_utils" } gravity_proto = { path = "../gravity_proto" } diff --git a/orchestrator/relayer/src/find_latest_valset.rs b/orchestrator/relayer/src/find_latest_valset.rs index 2c7f36408..64b59425f 100644 --- a/orchestrator/relayer/src/find_latest_valset.rs +++ b/orchestrator/relayer/src/find_latest_valset.rs @@ -1,8 +1,9 @@ use ethereum_gravity::types::EthClient; use ethers::prelude::*; use ethers::types::Address as EthAddress; +use gravity_abi::gravity::*; use gravity_proto::gravity::query_client::QueryClient as GravityQueryClient; -use gravity_utils::types::{FromLog, ValsetUpdatedEvent, VALSET_UPDATED_EVENT_STR}; +use gravity_utils::types::{FromLog, ValsetUpdatedEvent}; use gravity_utils::{error::GravityError, ethereum::downcast_to_u64, types::Valset}; use std::{panic, result::Result}; use tonic::transport::Channel; @@ -22,7 +23,7 @@ pub async fn find_latest_valset( let mut filter = Filter::new() .address(ValueOrArray::Value(gravity_contract_address)) - .event(&VALSET_UPDATED_EVENT_STR); + .event(&ValsetUpdatedEventFilter::abi_signature()); let mut end_filter_block = eth_client.get_block_number().await?; while end_filter_block > 0u64.into() { From 7db297885b233af7a83cd3019a6acfd58722b554 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 30 Nov 2021 19:55:44 -0800 Subject: [PATCH 112/115] sanity checking, comment fixes, remove dead code --- .../src/types/ethereum_events.rs | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/orchestrator/gravity_utils/src/types/ethereum_events.rs b/orchestrator/gravity_utils/src/types/ethereum_events.rs index a096322fb..01f681312 100644 --- a/orchestrator/gravity_utils/src/types/ethereum_events.rs +++ b/orchestrator/gravity_utils/src/types/ethereum_events.rs @@ -7,7 +7,6 @@ use super::ValsetMember; use crate::error::GravityError; use crate::ethereum::downcast_to_u64; -use deep_space::utils::bytes_to_hex_str; use deep_space::Address as CosmosAddress; use ethers::abi::RawLog; use ethers::prelude::*; @@ -16,7 +15,7 @@ use gravity_abi::gravity::*; use std::result::Result; // given a Log retrieved by querying the Ethereum chain, decode it into one of -// the types we are generating using abigen! above for the Gravity contract +// the generated event types for the Gravity contract fn log_to_ethers_event(log: &Log) -> Result { T::decode_log(&RawLog { topics: log.topics.clone(), @@ -101,6 +100,12 @@ impl FromLog for ValsetUpdatedEvent { /// not hard at all to extract data like this by hand. fn from_log(input: &Log) -> Result { let event: ValsetUpdatedEventFilter = log_to_ethers_event(input)?; + if event.powers.len() != event.validators.len() { + return Err(GravityError::InvalidEventLogError(format!( + "ValsetUpdatedEvent powers and validators have different length: {:?}", + event + ))); + } let mut powers: Vec = Vec::new(); for power in &event.powers { @@ -310,14 +315,3 @@ impl EventNonce for LogicCallExecutedEvent { } } impl EventNonceFilter for LogicCallExecutedEvent {} - -/// Function used for debug printing hex dumps -/// of ethereum events -fn _debug_print_data(input: &[u8]) { - let count = input.len() / 32; - println!("data hex dump"); - for i in 0..count { - println!("0x{}", bytes_to_hex_str(&input[(i * 32)..((i * 32) + 32)])) - } - println!("end dump"); -} From 38376ca80ae6c982ebbfd916dd118f67ae171558 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 30 Nov 2021 19:56:26 -0800 Subject: [PATCH 113/115] Remove TODO, question answered --- orchestrator/gorc/src/commands/sign_delegate_keys.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchestrator/gorc/src/commands/sign_delegate_keys.rs b/orchestrator/gorc/src/commands/sign_delegate_keys.rs index bf069509a..fac2cf383 100644 --- a/orchestrator/gorc/src/commands/sign_delegate_keys.rs +++ b/orchestrator/gorc/src/commands/sign_delegate_keys.rs @@ -47,7 +47,7 @@ impl Runnable for SignDelegateKeysCmd { let mut buf = bytes::BytesMut::with_capacity(size); prost::Message::encode(&msg, &mut buf).expect("Failed to encode DelegateKeysSignMsg!"); - let data = keccak256(buf); // TODO(bolten): the rest of the orchestrator expects a hash as a message...here too? + let data = keccak256(buf); let signature = ethereum_wallet .sign_message(data) .await From 234a62a3d0b5b6f9fdb3c5b20670835fead282b3 Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 30 Nov 2021 20:08:56 -0800 Subject: [PATCH 114/115] Fix U256 parse attempts from Strings U256 appears to expect hex input by default when parsing a string. In the few cases where we're taking in a string to convert to U256, use from_dec_str explicitly. The particular usage in eth.rs probably didn't work originally as described in the expect comment anyway, but it also appears to be dead code, so just fixing it up to be more sane. If a float was expected a bunch of different conversion would be necessary, and it would also be losing information anyway. --- orchestrator/gorc/src/commands/eth_to_cosmos.rs | 2 +- orchestrator/gorc/src/commands/tx/eth.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/orchestrator/gorc/src/commands/eth_to_cosmos.rs b/orchestrator/gorc/src/commands/eth_to_cosmos.rs index ae32a903a..6c5079298 100644 --- a/orchestrator/gorc/src/commands/eth_to_cosmos.rs +++ b/orchestrator/gorc/src/commands/eth_to_cosmos.rs @@ -73,7 +73,7 @@ impl Runnable for EthToCosmosCmd { let times = self.args.get(5).expect("times is required"); let times_usize = times.parse::().expect("cannot parse times"); - let times_u256 = times.parse::().expect("cannot parse times"); + let times_u256 = U256::from_dec_str(times).expect("cannot parse times"); if erc20_balance == 0u8.into() { panic!( diff --git a/orchestrator/gorc/src/commands/tx/eth.rs b/orchestrator/gorc/src/commands/tx/eth.rs index b618f3871..948ec5c3f 100644 --- a/orchestrator/gorc/src/commands/tx/eth.rs +++ b/orchestrator/gorc/src/commands/tx/eth.rs @@ -87,9 +87,8 @@ impl Runnable for SendToCosmos { let eth_client = Arc::new(eth_client); check_for_eth(eth_client.address(), eth_client.clone()).await; - let amount: U256 = erc20_amount - .parse() - .expect("Expected amount in xx.yy format"); + let amount = U256::from_dec_str(erc20_amount.as_str()) + .expect("Could not parse amount to U256"); let erc20_balance = get_erc20_balance(erc20_contract, eth_client.address(), eth_client.clone()) From 8830a8be9dae91337d2b1ecc902f8a045853e74b Mon Sep 17 00:00:00 2001 From: Eric Bolten Date: Tue, 30 Nov 2021 21:29:57 -0800 Subject: [PATCH 115/115] Use the same method to calculate gas for call/send --- .../ethereum_gravity/src/deploy_erc20.rs | 4 +- .../ethereum_gravity/src/logic_call.rs | 4 +- .../ethereum_gravity/src/submit_batch.rs | 4 +- orchestrator/ethereum_gravity/src/utils.rs | 56 ++++++------------- .../ethereum_gravity/src/valset_update.rs | 4 +- 5 files changed, 25 insertions(+), 47 deletions(-) diff --git a/orchestrator/ethereum_gravity/src/deploy_erc20.rs b/orchestrator/ethereum_gravity/src/deploy_erc20.rs index 9dd1d4575..96fa032ac 100644 --- a/orchestrator/ethereum_gravity/src/deploy_erc20.rs +++ b/orchestrator/ethereum_gravity/src/deploy_erc20.rs @@ -2,7 +2,7 @@ //! the event for this deployment is then ferried over to Cosmos where the validators will accept the ERC20 contract address //! as the representation of this asset on Ethereum -use crate::{types::EthClient, utils::get_send_transaction_gas_price}; +use crate::{types::EthClient, utils::get_gas_price}; use ethers::prelude::*; use gravity_abi::gravity::*; use gravity_utils::error::GravityError; @@ -27,7 +27,7 @@ pub async fn deploy_erc20( erc20_symbol.clone(), decimals, ); - let gas_price = get_send_transaction_gas_price(eth_client.clone()).await?; + let gas_price = get_gas_price(eth_client.clone()).await?; let contract_call = contract_call.gas_price(gas_price); let pending_tx = contract_call.send().await?; diff --git a/orchestrator/ethereum_gravity/src/logic_call.rs b/orchestrator/ethereum_gravity/src/logic_call.rs index ade51dcc7..79b46258f 100644 --- a/orchestrator/ethereum_gravity/src/logic_call.rs +++ b/orchestrator/ethereum_gravity/src/logic_call.rs @@ -2,7 +2,7 @@ use crate::{ types::{EthClient, EthSignerMiddleware}, utils::{ get_logic_call_nonce, - get_send_transaction_gas_price, + get_gas_price, GasCost, }, }; @@ -127,7 +127,7 @@ pub async fn estimate_logic_call_cost( Ok(GasCost { gas: contract_call.estimate_gas().await?, - gas_price: get_send_transaction_gas_price(eth_client.clone()).await?, + gas_price: get_gas_price(eth_client.clone()).await?, }) } diff --git a/orchestrator/ethereum_gravity/src/submit_batch.rs b/orchestrator/ethereum_gravity/src/submit_batch.rs index 3fcd052b1..689235c08 100644 --- a/orchestrator/ethereum_gravity/src/submit_batch.rs +++ b/orchestrator/ethereum_gravity/src/submit_batch.rs @@ -1,6 +1,6 @@ use crate::{ types::{EthClient, EthSignerMiddleware}, - utils::{get_send_transaction_gas_price, get_tx_batch_nonce, GasCost}, + utils::{get_gas_price, get_tx_batch_nonce, GasCost}, }; use ethers::contract::builders::ContractCall; use ethers::prelude::*; @@ -120,7 +120,7 @@ pub async fn estimate_tx_batch_cost( Ok(GasCost { gas: contract_call.estimate_gas().await?, - gas_price: get_send_transaction_gas_price(eth_client.clone()).await?, + gas_price: get_gas_price(eth_client.clone()).await?, }) } diff --git a/orchestrator/ethereum_gravity/src/utils.rs b/orchestrator/ethereum_gravity/src/utils.rs index 5942c7d18..90b2b78dd 100644 --- a/orchestrator/ethereum_gravity/src/utils.rs +++ b/orchestrator/ethereum_gravity/src/utils.rs @@ -6,7 +6,7 @@ use ethers::types::Address as EthAddress; use gravity_abi::gravity::*; use gravity_utils::error::GravityError; use gravity_utils::ethereum::{downcast_to_u64, vec_u8_to_fixed_32}; -use std::{cmp::min, result::Result}; +use std::result::Result; /// Gets the latest validator set nonce pub async fn get_valset_nonce( @@ -17,10 +17,10 @@ pub async fn get_valset_nonce( .state_last_valset_nonce() .from(eth_client.address()) .value(U256::zero()); - let gas_cost = get_call_gas_cost(eth_client.clone()).await?; + let gas_estimate = contract_call.estimate_gas().await?; let contract_call = contract_call - .gas(gas_cost.gas) - .gas_price(gas_cost.gas_price); + .gas(gas_estimate) + .gas_price(get_gas_price(eth_client.clone()).await?); let valset_nonce = contract_call.call().await?; @@ -43,10 +43,10 @@ pub async fn get_tx_batch_nonce( .last_batch_nonce(erc20_contract_address) .from(eth_client.address()) .value(U256::zero()); - let gas_cost = get_call_gas_cost(eth_client.clone()).await?; + let gas_estimate = contract_call.estimate_gas().await?; let contract_call = contract_call - .gas(gas_cost.gas) - .gas_price(gas_cost.gas_price); + .gas(gas_estimate) + .gas_price(get_gas_price(eth_client.clone()).await?); let tx_batch_nonce = contract_call.call().await?; @@ -71,10 +71,10 @@ pub async fn get_logic_call_nonce( .last_logic_call_nonce(invalidation_id) .from(eth_client.address()) .value(U256::zero()); - let gas_cost = get_call_gas_cost(eth_client.clone()).await?; + let gas_estimate = contract_call.estimate_gas().await?; let contract_call = contract_call - .gas(gas_cost.gas) - .gas_price(gas_cost.gas_price); + .gas(gas_estimate) + .gas_price(get_gas_price(eth_client.clone()).await?); let logic_call_nonce = contract_call.call().await?; @@ -96,10 +96,10 @@ pub async fn get_event_nonce( .state_last_event_nonce() .from(eth_client.address()) .value(U256::zero()); - let gas_cost = get_call_gas_cost(eth_client.clone()).await?; + let gas_estimate = contract_call.estimate_gas().await?; let contract_call = contract_call - .gas(gas_cost.gas) - .gas_price(gas_cost.gas_price); + .gas(gas_estimate) + .gas_price(get_gas_price(eth_client.clone()).await?); let event_nonce = contract_call.call().await?; @@ -121,10 +121,10 @@ pub async fn get_gravity_id( .state_gravity_id() .from(eth_client.address()) .value(U256::zero()); - let gas_cost = get_call_gas_cost(eth_client.clone()).await?; + let gas_estimate = contract_call.estimate_gas().await?; let contract_call = contract_call - .gas(gas_cost.gas) - .gas_price(gas_cost.gas_price); + .gas(gas_estimate) + .gas_price(get_gas_price(eth_client.clone()).await?); let gravity_id = contract_call.call().await?; let id_as_string = String::from_utf8(gravity_id.to_vec()); @@ -138,31 +138,9 @@ pub async fn get_gravity_id( } } -/// Retrieve gas price and limit in a similar fashion to web30's simulate_transaction. -/// These values are intended to be used in conjunction with eth_call rather than -/// eth_sendtransaction. In ethers this is represented by `call()` on a ContractCall rather -/// than `send()`. Using `call()` will not send a transaction from the caller account or -/// spend gas. -pub async fn get_call_gas_cost(eth_client: EthClient) -> Result { - const GAS_LIMIT: u128 = 12450000; // the most Hardhat will allow, will work on Geth - - let caller_balance = eth_client.get_balance(eth_client.address(), None).await?; - let latest_block = eth_client.get_block(BlockNumber::Latest).await?.unwrap(); - let gas_price = latest_block.base_fee_per_gas.unwrap_or(1u8.into()); // "or" clause shouldn't happen unless pre-London - if gas_price == U256::zero() { - return Err(GravityError::EthereumBadDataError( - "Latest block returned base fee per gas of zero".to_string(), - )); - } - - let gas = min(GAS_LIMIT.into(), caller_balance.div_mod(gas_price).0); - - Ok(GasCost { gas, gas_price }) -} - /// If ETHERSCAN_API_KEY env var is set, we'll call out to Etherscan for a gas estimate. /// Otherwise, just call eth_gasPrice. -pub async fn get_send_transaction_gas_price(eth_client: EthClient) -> Result { +pub async fn get_gas_price(eth_client: EthClient) -> Result { if let Ok(_) = std::env::var("ETHERSCAN_API_KEY") { let etherscan_client = Client::new_from_env(Chain::Mainnet)?; let etherscan_oracle = Etherscan::new(etherscan_client); diff --git a/orchestrator/ethereum_gravity/src/valset_update.rs b/orchestrator/ethereum_gravity/src/valset_update.rs index 136042423..1657f12f8 100644 --- a/orchestrator/ethereum_gravity/src/valset_update.rs +++ b/orchestrator/ethereum_gravity/src/valset_update.rs @@ -1,6 +1,6 @@ use crate::{ types::{EthClient, EthSignerMiddleware}, - utils::{get_send_transaction_gas_price, get_valset_nonce, GasCost}, + utils::{get_gas_price, get_valset_nonce, GasCost}, }; use ethers::contract::builders::ContractCall; use ethers::prelude::*; @@ -104,7 +104,7 @@ pub async fn estimate_valset_cost( Ok(GasCost { gas: contract_call.estimate_gas().await?, - gas_price: get_send_transaction_gas_price(eth_client.clone()).await?, + gas_price: get_gas_price(eth_client.clone()).await?, }) }