Compare commits

..

13 Commits

Author SHA1 Message Date
Andreas Bigger 18e99eea35 small fix 2023-03-17 09:52:33 -04:00
Andreas Bigger 4279c65cda builder refactor 2023-03-17 09:51:40 -04:00
Andreas Bigger f679a7c5c8 bad merge 2023-03-16 23:18:49 -04:00
Andreas Bigger 43850702c2 large upstream sync ♻️ 2023-03-16 23:18:00 -04:00
Andreas Bigger 2a37dbcb22 ♻️ upstream sync 2022-12-03 08:14:21 -08:00
Andreas Bigger 38091aaa00 :caution: rfc 2022-12-03 07:58:58 -08:00
Andreas Bigger 4f99cfef95 more websocket progress 2022-12-02 13:39:57 -08:00
Andreas Bigger 81e5a08828 stash websocket progress 2022-12-02 13:30:16 -08:00
Andreas Bigger f28483dfd7 ⚙️ upstream sync 2022-12-02 11:45:53 -08:00
Andreas Bigger cda8f39b4c ⚙️ examples 2022-12-02 08:24:03 -08:00
Andreas Bigger 2b1aeba534 ⚙️ examples and more cleanup 2022-12-02 07:21:28 -08:00
andreas 8d240c2fe3
Merge pull request #119 from abigger87/@abigger87/websockets 2022-11-30 19:10:04 -08:00
Andreas Bigger 55839e5479 🏗️ start websocket support 2022-11-30 09:01:43 -08:00
31 changed files with 885 additions and 644 deletions

258
Cargo.lock generated
View File

@ -407,7 +407,7 @@ checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07"
dependencies = [ dependencies = [
"camino", "camino",
"cargo-platform", "cargo-platform",
"semver 1.0.16", "semver 1.0.17",
"serde", "serde",
"serde_json", "serde_json",
"thiserror", "thiserror",
@ -433,9 +433,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.23" version = "0.4.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b"
dependencies = [ dependencies = [
"iana-time-zone", "iana-time-zone",
"js-sys", "js-sys",
@ -524,13 +524,12 @@ dependencies = [
[[package]] [[package]]
name = "cli" name = "cli"
version = "0.3.0" version = "0.2.0"
dependencies = [ dependencies = [
"clap", "clap",
"client", "client",
"common", "common",
"config", "config",
"ctrlc",
"dirs", "dirs",
"env_logger", "env_logger",
"eyre", "eyre",
@ -541,11 +540,12 @@ dependencies = [
[[package]] [[package]]
name = "client" name = "client"
version = "0.3.0" version = "0.2.0"
dependencies = [ dependencies = [
"common", "common",
"config", "config",
"consensus", "consensus",
"ctrlc",
"ethers", "ethers",
"execution", "execution",
"eyre", "eyre",
@ -645,7 +645,7 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]] [[package]]
name = "common" name = "common"
version = "0.3.0" version = "0.2.0"
dependencies = [ dependencies = [
"ethers", "ethers",
"eyre", "eyre",
@ -657,7 +657,7 @@ dependencies = [
[[package]] [[package]]
name = "config" name = "config"
version = "0.3.0" version = "0.2.0"
dependencies = [ dependencies = [
"common", "common",
"ethers", "ethers",
@ -677,7 +677,7 @@ dependencies = [
[[package]] [[package]]
name = "consensus" name = "consensus"
version = "0.3.0" version = "0.2.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"bytes", "bytes",
@ -695,7 +695,6 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"ssz-rs", "ssz-rs",
"superstruct",
"thiserror", "thiserror",
"tokio", "tokio",
"toml", "toml",
@ -976,41 +975,6 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "darling"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]] [[package]]
name = "der" name = "der"
version = "0.6.1" version = "0.6.1"
@ -1433,7 +1397,7 @@ dependencies = [
"ethers-core", "ethers-core",
"getrandom 0.2.8", "getrandom 0.2.8",
"reqwest", "reqwest",
"semver 1.0.16", "semver 1.0.17",
"serde", "serde",
"serde-aux", "serde-aux",
"serde_json", "serde_json",
@ -1477,6 +1441,7 @@ dependencies = [
"auto_impl 1.0.1", "auto_impl 1.0.1",
"base64 0.13.1", "base64 0.13.1",
"ethers-core", "ethers-core",
"futures-channel",
"futures-core", "futures-core",
"futures-timer", "futures-timer",
"futures-util", "futures-util",
@ -1492,6 +1457,7 @@ dependencies = [
"serde_json", "serde_json",
"thiserror", "thiserror",
"tokio", "tokio",
"tokio-tungstenite",
"tracing", "tracing",
"tracing-futures", "tracing-futures",
"url", "url",
@ -1528,7 +1494,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]] [[package]]
name = "execution" name = "execution"
version = "0.3.0" version = "0.2.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"bytes", "bytes",
@ -1724,9 +1690,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.26" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@ -1739,9 +1705,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.26" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
@ -1749,15 +1715,15 @@ dependencies = [
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.26" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd"
[[package]] [[package]]
name = "futures-executor" name = "futures-executor"
version = "0.3.26" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-task", "futures-task",
@ -1766,9 +1732,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.26" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91"
[[package]] [[package]]
name = "futures-locks" name = "futures-locks"
@ -1782,9 +1748,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-macro" name = "futures-macro"
version = "0.3.26" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1793,15 +1759,15 @@ dependencies = [
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.26" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.26" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879"
[[package]] [[package]]
name = "futures-timer" name = "futures-timer"
@ -1815,9 +1781,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.26" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@ -2026,7 +1992,7 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "helios" name = "helios"
version = "0.3.0" version = "0.2.0"
dependencies = [ dependencies = [
"client", "client",
"common", "common",
@ -2085,6 +2051,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "hermit-abi"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]] [[package]]
name = "hex" name = "hex"
version = "0.4.3" version = "0.4.3"
@ -2145,9 +2117,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "0.14.24" version = "0.14.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
@ -2220,12 +2192,6 @@ dependencies = [
"cxx-build", "cxx-build",
] ]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]] [[package]]
name = "idna" name = "idna"
version = "0.3.0" version = "0.3.0"
@ -2370,10 +2336,11 @@ dependencies = [
[[package]] [[package]]
name = "io-lifetimes" name = "io-lifetimes"
version = "1.0.6" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" checksum = "76e86b86ae312accbf05ade23ce76b625e0e47a255712b7414037385a1c05380"
dependencies = [ dependencies = [
"hermit-abi 0.3.1",
"libc", "libc",
"windows-sys 0.45.0", "windows-sys 0.45.0",
] ]
@ -2950,9 +2917,9 @@ dependencies = [
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.45" version = "0.10.46"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" checksum = "fd2523381e46256e40930512c7fd25562b9eae4812cb52078f155e87217c9d1e"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if", "cfg-if",
@ -2991,9 +2958,9 @@ dependencies = [
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.80" version = "0.9.81"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" checksum = "176be2629957c157240f68f61f2d0053ad3a4ecfdd9ebf1e6521d18d9635cf67"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cc", "cc",
@ -3376,9 +3343,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.51" version = "1.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -3398,9 +3365,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.23" version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -3727,7 +3694,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [ dependencies = [
"semver 1.0.16", "semver 1.0.17",
] ]
[[package]] [[package]]
@ -3922,9 +3889,9 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.16" version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -3952,9 +3919,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.154" version = "1.0.156"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cdd151213925e7f1ab45a9bbfb129316bd00799784b174b7cc7bcd16961c49e" checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -3982,9 +3949,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.154" version = "1.0.156"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fc80d722935453bcafdc2c9a73cd6fac4dc1938f0346035d84bf99fa9e33217" checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -4040,6 +4007,17 @@ dependencies = [
"opaque-debug 0.3.0", "opaque-debug 0.3.0",
] ]
[[package]]
name = "sha-1"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c"
dependencies = [
"cfg-if",
"cpufeatures",
"digest 0.10.6",
]
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.8.2" version = "0.8.2"
@ -4151,7 +4129,7 @@ dependencies = [
"httparse", "httparse",
"log", "log",
"rand 0.8.5", "rand 0.8.5",
"sha-1", "sha-1 0.9.8",
] ]
[[package]] [[package]]
@ -4248,20 +4226,6 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "superstruct"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f4e1f478a7728f8855d7e620e9a152cf8932c6614f86564c886f9b8141f3201"
dependencies = [
"darling",
"itertools",
"proc-macro2",
"quote",
"smallvec",
"syn",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.109" version = "1.0.109"
@ -4454,6 +4418,18 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "tokio-tungstenite"
version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181"
dependencies = [
"futures-util",
"log",
"tokio",
"tungstenite",
]
[[package]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.7.7" version = "0.7.7"
@ -4486,9 +4462,9 @@ checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
version = "0.19.4" version = "0.19.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825" checksum = "dc18466501acd8ac6a3f615dd29a3438f8ca6bb3b19537138b3106e575621274"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"toml_datetime", "toml_datetime",
@ -4628,6 +4604,25 @@ version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd"
[[package]]
name = "tungstenite"
version = "0.17.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0"
dependencies = [
"base64 0.13.1",
"byteorder",
"bytes",
"http",
"httparse",
"log",
"rand 0.8.5",
"sha-1 0.10.1",
"thiserror",
"url",
"utf-8",
]
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.16.0" version = "1.16.0"
@ -4744,6 +4739,12 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "0.8.2" version = "0.8.2"
@ -4774,12 +4775,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.3.2" version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
dependencies = [ dependencies = [
"same-file", "same-file",
"winapi",
"winapi-util", "winapi-util",
] ]
@ -4984,9 +4984,9 @@ dependencies = [
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.42.1" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm",
"windows_aarch64_msvc", "windows_aarch64_msvc",
@ -4999,51 +4999,51 @@ dependencies = [
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.42.1" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.42.1" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.42.1" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.42.1" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.42.1" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.42.1" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.42.1" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.3.5" version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee7b2c67f962bf5042bfd8b6a916178df33a26eec343ae064cb8e069f638fa6f" checksum = "23d020b441f92996c80d94ae9166e8501e59c7bb56121189dc9eab3bd8216966"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]

View File

@ -1,6 +1,6 @@
[package] [package]
name = "helios" name = "helios"
version = "0.3.0" version = "0.2.0"
edition = "2021" edition = "2021"
autobenches = false autobenches = false
exclude = [ exclude = [
@ -17,7 +17,6 @@ members = [
"execution", "execution",
"helios-ts", "helios-ts",
] ]
default-members = ["cli"]
[profile.bench] [profile.bench]
debug = true debug = true

View File

@ -2,7 +2,7 @@ cargo-features = ["different-binary-name"]
[package] [package]
name = "cli" name = "cli"
version = "0.3.0" version = "0.2.0"
edition = "2021" edition = "2021"
[[bin]] [[bin]]
@ -17,7 +17,6 @@ eyre = "0.6.8"
dirs = "4.0.0" dirs = "4.0.0"
env_logger = "0.9.0" env_logger = "0.9.0"
log = "0.4.17" log = "0.4.17"
ctrlc = "3.2.3"
futures = "0.3.23" futures = "0.3.23"
client = { path = "../client" } client = { path = "../client" }

View File

@ -6,16 +6,16 @@ use std::{
}; };
use clap::Parser; use clap::Parser;
use common::utils::hex_str_to_bytes;
use dirs::home_dir; use dirs::home_dir;
use env_logger::Env; use env_logger::Env;
use eyre::Result; use eyre::Result;
use client::{database::FileDB, Client, ClientBuilder};
use config::{CliConfig, Config};
use futures::executor::block_on; use futures::executor::block_on;
use log::{error, info}; use log::{error, info};
use client::{database::FileDB, Client, ClientBuilder};
use common::utils::hex_str_to_bytes;
use config::{CliConfig, Config};
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
@ -34,7 +34,7 @@ async fn main() -> Result<()> {
exit(1); exit(1);
} }
register_shutdown_handler(client); Client::register_shutdown_handler(client);
std::future::pending().await std::future::pending().await
} }
@ -80,8 +80,6 @@ fn get_config() -> Config {
} }
#[derive(Parser)] #[derive(Parser)]
#[clap(version, about)]
/// Helios is a fast, secure, and portable light client for Ethereum
struct Cli { struct Cli {
#[clap(short, long, default_value = "mainnet")] #[clap(short, long, default_value = "mainnet")]
network: String, network: String,
@ -101,6 +99,10 @@ struct Cli {
load_external_fallback: bool, load_external_fallback: bool,
#[clap(short = 's', long, env)] #[clap(short = 's', long, env)]
strict_checkpoint_age: bool, strict_checkpoint_age: bool,
#[clap(short = 's', long, env)]
with_ws: bool,
#[clap(short = 'h', long, env)]
with_http: bool,
} }
impl Cli { impl Cli {
@ -119,6 +121,8 @@ impl Cli {
fallback: self.fallback.clone(), fallback: self.fallback.clone(),
load_external_fallback: self.load_external_fallback, load_external_fallback: self.load_external_fallback,
strict_checkpoint_age: self.strict_checkpoint_age, strict_checkpoint_age: self.strict_checkpoint_age,
with_ws: self.with_ws,
with_http: self.with_http,
} }
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "client" name = "client"
version = "0.3.0" version = "0.2.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
@ -8,10 +8,12 @@ eyre = "0.6.8"
serde = { version = "1.0.143", features = ["derive"] } serde = { version = "1.0.143", features = ["derive"] }
hex = "0.4.3" hex = "0.4.3"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" } ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" }
ethers = "1.0.0" ethers = { version = "1.0.2", features = [ "ws", "default" ] }
jsonrpsee = { version = "0.15.1", features = ["full"] }
futures = "0.3.23" futures = "0.3.23"
log = "0.4.17" log = "0.4.17"
thiserror = "1.0.37" thiserror = "1.0.37"
ctrlc = "3.2.3"
common = { path = "../common" } common = { path = "../common" }
consensus = { path = "../consensus" } consensus = { path = "../consensus" }

236
client/src/builder.rs Normal file
View File

@ -0,0 +1,236 @@
use eyre::{eyre, Result};
use config::{Config, Network};
use execution::rpc::WsRpc;
use crate::{database::FileDB, Client};
#[cfg(not(target_arch = "wasm32"))]
use std::path::PathBuf;
#[derive(Default)]
pub struct ClientBuilder {
pub network: Option<Network>,
pub consensus_rpc: Option<String>,
pub execution_rpc: Option<String>,
pub checkpoint: Option<Vec<u8>>,
#[cfg(not(target_arch = "wasm32"))]
pub rpc_port: Option<u16>,
#[cfg(not(target_arch = "wasm32"))]
pub data_dir: Option<PathBuf>,
pub config: Option<Config>,
pub fallback: Option<String>,
pub load_external_fallback: bool,
pub strict_checkpoint_age: bool,
pub with_ws: bool,
pub with_http: bool,
}
impl ClientBuilder {
pub fn new() -> Self {
Self::default().with_http(true)
}
pub fn network(mut self, network: Network) -> Self {
self.network = Some(network);
self
}
pub fn consensus_rpc(mut self, consensus_rpc: &str) -> Self {
self.consensus_rpc = Some(consensus_rpc.to_string());
self
}
pub fn execution_rpc(mut self, execution_rpc: &str) -> Self {
self.execution_rpc = Some(execution_rpc.to_string());
self
}
pub fn checkpoint(mut self, checkpoint: &str) -> Self {
let checkpoint = hex::decode(checkpoint.strip_prefix("0x").unwrap_or(checkpoint))
.expect("cannot parse checkpoint");
self.checkpoint = Some(checkpoint);
self
}
/// Enables the client to serve a websocket connection.
///
/// # Example
/// ```rust
/// let mut client_builder = client::ClientBuilder::new().with_ws(true);
/// assert_eq!(client_builder.with_ws, true);
/// client_builder = client_builder.with_ws(false);
/// assert_eq!(client_builder.with_ws, false);
/// ```
#[cfg(not(target_arch = "wasm32"))]
pub fn with_ws(mut self, option: bool) -> Self {
self.with_ws = option;
self
}
/// Enables the client to serve an http connection (enabled by default).
///
/// # Example
/// ```rust
/// let mut client_builder = client::ClientBuilder::new();
/// assert_eq!(client_builder.with_http, true);
/// client_builder = client_builder.with_http(false);
/// assert_eq!(client_builder.with_http, false);
/// ```
#[cfg(not(target_arch = "wasm32"))]
pub fn with_http(mut self, option: bool) -> Self {
self.with_http = option;
self
}
/// Sets the port for the client to serve an RPC server.
#[cfg(not(target_arch = "wasm32"))]
pub fn rpc_port(mut self, port: u16) -> Self {
self.rpc_port = Some(port);
self
}
#[cfg(not(target_arch = "wasm32"))]
pub fn data_dir(mut self, data_dir: PathBuf) -> Self {
self.data_dir = Some(data_dir);
self
}
pub fn config(mut self, config: Config) -> Self {
self.config = Some(config);
self
}
pub fn fallback(mut self, fallback: &str) -> Self {
self.fallback = Some(fallback.to_string());
self
}
pub fn load_external_fallback(mut self) -> Self {
self.load_external_fallback = true;
self
}
pub fn strict_checkpoint_age(mut self) -> Self {
self.strict_checkpoint_age = true;
self
}
fn build_config(&self) -> Result<Config> {
let base_config = if let Some(network) = self.network {
network.to_base_config()
} else {
let config = self
.config
.as_ref()
.ok_or(eyre!("missing network config"))?;
config.to_base_config()
};
let consensus_rpc = self.consensus_rpc.clone().unwrap_or_else(|| {
self.config
.as_ref()
.expect("missing consensus rpc")
.consensus_rpc
.clone()
});
let execution_rpc = self.execution_rpc.clone().unwrap_or_else(|| {
self.config
.as_ref()
.expect("missing execution rpc")
.execution_rpc
.clone()
});
let checkpoint = if let Some(checkpoint) = self.checkpoint {
Some(checkpoint)
} else if let Some(config) = &self.config {
config.checkpoint.clone()
} else {
None
};
let default_checkpoint = if let Some(config) = &self.config {
config.default_checkpoint.clone()
} else {
base_config.default_checkpoint.clone()
};
#[cfg(not(target_arch = "wasm32"))]
let rpc_port = if self.rpc_port.is_some() {
self.rpc_port
} else if let Some(config) = &self.config {
config.rpc_port
} else {
None
};
#[cfg(not(target_arch = "wasm32"))]
let data_dir = if self.data_dir.is_some() {
self.data_dir.clone()
} else if let Some(config) = &self.config {
config.data_dir.clone()
} else {
None
};
let fallback = if self.fallback.is_some() {
self.fallback.clone()
} else if let Some(config) = &self.config {
config.fallback.clone()
} else {
None
};
let load_external_fallback = if let Some(config) = &self.config {
self.load_external_fallback || config.load_external_fallback
} else {
self.load_external_fallback
};
let with_ws = if let Some(config) = &self.config {
self.with_ws || config.with_ws
} else {
self.with_ws
};
let with_http = if let Some(config) = &self.config {
self.with_http || config.with_http
} else {
self.with_http
};
let strict_checkpoint_age = if let Some(config) = &self.config {
self.strict_checkpoint_age || config.strict_checkpoint_age
} else {
self.strict_checkpoint_age
};
Ok(Config {
consensus_rpc,
execution_rpc,
checkpoint,
default_checkpoint,
#[cfg(not(target_arch = "wasm32"))]
rpc_port,
#[cfg(not(target_arch = "wasm32"))]
data_dir,
chain: base_config.chain,
forks: base_config.forks,
max_checkpoint_age: base_config.max_checkpoint_age,
fallback,
load_external_fallback,
strict_checkpoint_age,
with_ws,
with_http,
})
}
}
impl ClientBuilder {
pub fn build(self) -> Result<Client<FileDB, WsRpc>> {
let config = self.build_config()?;
Client::new(config)
}
}

View File

@ -6,17 +6,16 @@ use ethers::prelude::{Address, U256};
use ethers::types::{ use ethers::types::{
FeeHistory, Filter, Log, SyncingStatus, Transaction, TransactionReceipt, H256, FeeHistory, Filter, Log, SyncingStatus, Transaction, TransactionReceipt, H256,
}; };
use eyre::{eyre, Result}; use eyre::Result;
use common::types::BlockTag; use common::types::BlockTag;
use config::{CheckpointFallback, Config}; use config::{CheckpointFallback, Config};
use consensus::{types::Header, ConsensusClient}; use consensus::{types::Header, ConsensusClient};
use execution::rpc::ExecutionRpc;
use execution::types::{CallOpts, ExecutionBlock}; use execution::types::{CallOpts, ExecutionBlock};
use log::{error, info, warn}; use log::{error, info, warn};
use tokio::sync::RwLock; use tokio::sync::RwLock;
#[cfg(not(target_arch = "wasm32"))]
use std::path::PathBuf;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use tokio::spawn; use tokio::spawn;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@ -34,196 +33,19 @@ use crate::node::Node;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use crate::rpc::Rpc; use crate::rpc::Rpc;
#[derive(Default)] pub struct Client<DB: Database, R: ExecutionRpc> {
pub struct ClientBuilder { node: Arc<RwLock<Node<R>>>,
network: Option<Network>,
consensus_rpc: Option<String>,
execution_rpc: Option<String>,
checkpoint: Option<Vec<u8>>,
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
rpc_port: Option<u16>, rpc: Option<Rpc<R>>,
#[cfg(not(target_arch = "wasm32"))]
data_dir: Option<PathBuf>,
config: Option<Config>,
fallback: Option<String>,
load_external_fallback: bool,
strict_checkpoint_age: bool,
}
impl ClientBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn network(mut self, network: Network) -> Self {
self.network = Some(network);
self
}
pub fn consensus_rpc(mut self, consensus_rpc: &str) -> Self {
self.consensus_rpc = Some(consensus_rpc.to_string());
self
}
pub fn execution_rpc(mut self, execution_rpc: &str) -> Self {
self.execution_rpc = Some(execution_rpc.to_string());
self
}
pub fn checkpoint(mut self, checkpoint: &str) -> Self {
let checkpoint = hex::decode(checkpoint.strip_prefix("0x").unwrap_or(checkpoint))
.expect("cannot parse checkpoint");
self.checkpoint = Some(checkpoint);
self
}
#[cfg(not(target_arch = "wasm32"))]
pub fn rpc_port(mut self, port: u16) -> Self {
self.rpc_port = Some(port);
self
}
#[cfg(not(target_arch = "wasm32"))]
pub fn data_dir(mut self, data_dir: PathBuf) -> Self {
self.data_dir = Some(data_dir);
self
}
pub fn config(mut self, config: Config) -> Self {
self.config = Some(config);
self
}
pub fn fallback(mut self, fallback: &str) -> Self {
self.fallback = Some(fallback.to_string());
self
}
pub fn load_external_fallback(mut self) -> Self {
self.load_external_fallback = true;
self
}
pub fn strict_checkpoint_age(mut self) -> Self {
self.strict_checkpoint_age = true;
self
}
pub fn build<DB: Database>(self) -> Result<Client<DB>> {
let base_config = if let Some(network) = self.network {
network.to_base_config()
} else {
let config = self
.config
.as_ref()
.ok_or(eyre!("missing network config"))?;
config.to_base_config()
};
let consensus_rpc = self.consensus_rpc.unwrap_or_else(|| {
self.config
.as_ref()
.expect("missing consensus rpc")
.consensus_rpc
.clone()
});
let execution_rpc = self.execution_rpc.unwrap_or_else(|| {
self.config
.as_ref()
.expect("missing execution rpc")
.execution_rpc
.clone()
});
let checkpoint = if let Some(checkpoint) = self.checkpoint {
Some(checkpoint)
} else if let Some(config) = &self.config {
config.checkpoint.clone()
} else {
None
};
let default_checkpoint = if let Some(config) = &self.config {
config.default_checkpoint.clone()
} else {
base_config.default_checkpoint.clone()
};
#[cfg(not(target_arch = "wasm32"))]
let rpc_port = if self.rpc_port.is_some() {
self.rpc_port
} else if let Some(config) = &self.config {
config.rpc_port
} else {
None
};
#[cfg(not(target_arch = "wasm32"))]
let data_dir = if self.data_dir.is_some() {
self.data_dir
} else if let Some(config) = &self.config {
config.data_dir.clone()
} else {
None
};
let fallback = if self.fallback.is_some() {
self.fallback
} else if let Some(config) = &self.config {
config.fallback.clone()
} else {
None
};
let load_external_fallback = if let Some(config) = &self.config {
self.load_external_fallback || config.load_external_fallback
} else {
self.load_external_fallback
};
let strict_checkpoint_age = if let Some(config) = &self.config {
self.strict_checkpoint_age || config.strict_checkpoint_age
} else {
self.strict_checkpoint_age
};
let config = Config {
consensus_rpc,
execution_rpc,
checkpoint,
default_checkpoint,
#[cfg(not(target_arch = "wasm32"))]
rpc_port,
#[cfg(target_arch = "wasm32")]
rpc_port: None,
#[cfg(not(target_arch = "wasm32"))]
data_dir,
#[cfg(target_arch = "wasm32")]
data_dir: None,
chain: base_config.chain,
forks: base_config.forks,
max_checkpoint_age: base_config.max_checkpoint_age,
fallback,
load_external_fallback,
strict_checkpoint_age,
};
Client::new(config)
}
}
pub struct Client<DB: Database> {
node: Arc<RwLock<Node>>,
#[cfg(not(target_arch = "wasm32"))]
rpc: Option<Rpc>,
db: DB, db: DB,
fallback: Option<String>, fallback: Option<String>,
load_external_fallback: bool, load_external_fallback: bool,
ws: bool,
http: bool,
} }
impl<DB: Database> Client<DB> { impl<DB: Database, R: ExecutionRpc> Client<DB, R> {
fn new(mut config: Config) -> Result<Self> { pub fn new(mut config: Config) -> Result<Self> {
let db = DB::new(&config)?; let db = DB::new(&config)?;
if config.checkpoint.is_none() { if config.checkpoint.is_none() {
let checkpoint = db.load_checkpoint()?; let checkpoint = db.load_checkpoint()?;
@ -231,11 +53,14 @@ impl<DB: Database> Client<DB> {
} }
let config = Arc::new(config); let config = Arc::new(config);
let node = Node::new(config.clone())?; let node = Node::new(config.clone())?;
let node = Arc::new(RwLock::new(node)); let node = Arc::new(RwLock::new(node));
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
let rpc = config.rpc_port.map(|port| Rpc::new(node.clone(), port)); let rpc = config
.rpc_port
.map(|port| Rpc::new(node.clone(), config.with_http, config.with_ws, port));
Ok(Client { Ok(Client {
node, node,
@ -244,13 +69,20 @@ impl<DB: Database> Client<DB> {
db, db,
fallback: config.fallback.clone(), fallback: config.fallback.clone(),
load_external_fallback: config.load_external_fallback, load_external_fallback: config.load_external_fallback,
ws: config.with_ws,
http: config.with_http,
}) })
} }
pub async fn start(&mut self) -> Result<()> { pub async fn start(&mut self) -> Result<()> {
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
if let Some(rpc) = &mut self.rpc { if let Some(rpc) = &mut self.rpc {
rpc.start().await?; if self.ws {
rpc.start_ws().await?;
}
if self.http {
rpc.start_http().await?;
}
} }
let sync_res = self.node.write().await.sync().await; let sync_res = self.node.write().await.sync().await;
@ -407,7 +239,7 @@ impl<DB: Database> Client<DB> {
} }
} }
pub async fn call(&self, opts: &CallOpts, block: BlockTag) -> Result<Vec<u8>> { pub async fn call(&self, opts: &CallOpts, block: BlockTag) -> eyre::Result<Vec<u8>> {
self.node self.node
.read() .read()
.await .await
@ -416,7 +248,7 @@ impl<DB: Database> Client<DB> {
.map_err(|err| err.into()) .map_err(|err| err.into())
} }
pub async fn estimate_gas(&self, opts: &CallOpts) -> Result<u64> { pub async fn estimate_gas(&self, opts: &CallOpts) -> eyre::Result<u64> {
self.node self.node
.read() .read()
.await .await
@ -425,11 +257,11 @@ impl<DB: Database> Client<DB> {
.map_err(|err| err.into()) .map_err(|err| err.into())
} }
pub async fn get_balance(&self, address: &Address, block: BlockTag) -> Result<U256> { pub async fn get_balance(&self, address: &Address, block: BlockTag) -> eyre::Result<U256> {
self.node.read().await.get_balance(address, block).await self.node.read().await.get_balance(address, block).await
} }
pub async fn get_nonce(&self, address: &Address, block: BlockTag) -> Result<u64> { pub async fn get_nonce(&self, address: &Address, block: BlockTag) -> eyre::Result<u64> {
self.node.read().await.get_nonce(address, block).await self.node.read().await.get_nonce(address, block).await
} }
@ -464,14 +296,14 @@ impl<DB: Database> Client<DB> {
.await .await
} }
pub async fn send_raw_transaction(&self, bytes: &[u8]) -> Result<H256> { pub async fn send_raw_transaction(&self, bytes: &[u8]) -> eyre::Result<H256> {
self.node.read().await.send_raw_transaction(bytes).await self.node.read().await.send_raw_transaction(bytes).await
} }
pub async fn get_transaction_receipt( pub async fn get_transaction_receipt(
&self, &self,
tx_hash: &H256, tx_hash: &H256,
) -> Result<Option<TransactionReceipt>> { ) -> eyre::Result<Option<TransactionReceipt>> {
self.node self.node
.read() .read()
.await .await
@ -479,7 +311,10 @@ impl<DB: Database> Client<DB> {
.await .await
} }
pub async fn get_transaction_by_hash(&self, tx_hash: &H256) -> Result<Option<Transaction>> { pub async fn get_transaction_by_hash(
&self,
tx_hash: &H256,
) -> eyre::Result<Option<Transaction>> {
self.node self.node
.read() .read()
.await .await
@ -487,19 +322,19 @@ impl<DB: Database> Client<DB> {
.await .await
} }
pub async fn get_logs(&self, filter: &Filter) -> Result<Vec<Log>> { pub async fn get_logs(&self, filter: &Filter) -> eyre::Result<Vec<Log>> {
self.node.read().await.get_logs(filter).await self.node.read().await.get_logs(filter).await
} }
pub async fn get_gas_price(&self) -> Result<U256> { pub async fn get_gas_price(&self) -> eyre::Result<U256> {
self.node.read().await.get_gas_price() self.node.read().await.get_gas_price()
} }
pub async fn get_priority_fee(&self) -> Result<U256> { pub async fn get_priority_fee(&self) -> eyre::Result<U256> {
self.node.read().await.get_priority_fee() self.node.read().await.get_priority_fee()
} }
pub async fn get_block_number(&self) -> Result<u64> { pub async fn get_block_number(&self) -> eyre::Result<u64> {
self.node.read().await.get_block_number() self.node.read().await.get_block_number()
} }
@ -520,7 +355,7 @@ impl<DB: Database> Client<DB> {
&self, &self,
block: BlockTag, block: BlockTag,
full_tx: bool, full_tx: bool,
) -> Result<Option<ExecutionBlock>> { ) -> eyre::Result<Option<ExecutionBlock>> {
self.node self.node
.read() .read()
.await .await
@ -532,7 +367,7 @@ impl<DB: Database> Client<DB> {
&self, &self,
hash: &Vec<u8>, hash: &Vec<u8>,
full_tx: bool, full_tx: bool,
) -> Result<Option<ExecutionBlock>> { ) -> eyre::Result<Option<ExecutionBlock>> {
self.node self.node
.read() .read()
.await .await

View File

@ -1,10 +1,20 @@
/// Re-export builder logic
mod builder;
pub use crate::builder::*;
/// Re-export client logic
mod client; mod client;
pub use crate::client::*; pub use crate::client::*;
/// Expose database module
pub mod database; pub mod database;
/// Expose errors module
pub mod errors; pub mod errors;
/// Expose rpc module
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub mod rpc; pub mod rpc;
/// Node module is internal to the client crate
pub mod node; pub mod node;

View File

@ -3,9 +3,12 @@ use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use ethers::prelude::{Address, U256}; use ethers::prelude::{Address, U256};
use ethers::types::{ use ethers::types::{
FeeHistory, Filter, Log, SyncProgress, SyncingStatus, Transaction, TransactionReceipt, H256, FeeHistory, Filter, Log, SyncProgress, SyncingStatus, Transaction, TransactionReceipt, H256,
}; };
use execution::rpc::{ExecutionRpc, WsRpc};
use eyre::{eyre, Result}; use eyre::{eyre, Result};
use common::errors::BlockNotFoundError; use common::errors::BlockNotFoundError;
@ -16,15 +19,15 @@ use consensus::rpc::nimbus_rpc::NimbusRpc;
use consensus::types::{ExecutionPayload, Header}; use consensus::types::{ExecutionPayload, Header};
use consensus::ConsensusClient; use consensus::ConsensusClient;
use execution::evm::Evm; use execution::evm::Evm;
use execution::rpc::http_rpc::HttpRpc; // use execution::rpc::http_rpc::HttpRpc;
use execution::types::{CallOpts, ExecutionBlock}; use execution::types::{CallOpts, ExecutionBlock};
use execution::ExecutionClient; use execution::ExecutionClient;
use crate::errors::NodeError; use crate::errors::NodeError;
pub struct Node { pub struct Node<R: ExecutionRpc> {
pub consensus: ConsensusClient<NimbusRpc>, pub consensus: ConsensusClient<NimbusRpc>,
pub execution: Arc<ExecutionClient<HttpRpc>>, pub execution: Arc<ExecutionClient<R>>,
pub config: Arc<Config>, pub config: Arc<Config>,
payloads: BTreeMap<u64, ExecutionPayload>, payloads: BTreeMap<u64, ExecutionPayload>,
finalized_payloads: BTreeMap<u64, ExecutionPayload>, finalized_payloads: BTreeMap<u64, ExecutionPayload>,
@ -32,7 +35,7 @@ pub struct Node {
pub history_size: usize, pub history_size: usize,
} }
impl Node { impl Node<WsRpc> {
pub fn new(config: Arc<Config>) -> Result<Self, NodeError> { pub fn new(config: Arc<Config>) -> Result<Self, NodeError> {
let consensus_rpc = &config.consensus_rpc; let consensus_rpc = &config.consensus_rpc;
let checkpoint_hash = &config.checkpoint.as_ref().unwrap(); let checkpoint_hash = &config.checkpoint.as_ref().unwrap();
@ -40,9 +43,18 @@ impl Node {
let consensus = ConsensusClient::new(consensus_rpc, checkpoint_hash, config.clone()) let consensus = ConsensusClient::new(consensus_rpc, checkpoint_hash, config.clone())
.map_err(NodeError::ConsensusClientCreationError)?; .map_err(NodeError::ConsensusClientCreationError)?;
let execution = Arc::new(
ExecutionClient::new(execution_rpc).map_err(NodeError::ExecutionClientCreationError)?, let execution = if config.with_ws {
); Arc::new(
ExecutionClient::new_with_ws(execution_rpc)
.map_err(NodeError::ExecutionClientCreationError)?,
)
} else {
Arc::new(
ExecutionClient::new(execution_rpc)
.map_err(NodeError::ExecutionClientCreationError)?,
)
};
let payloads = BTreeMap::new(); let payloads = BTreeMap::new();
let finalized_payloads = BTreeMap::new(); let finalized_payloads = BTreeMap::new();
@ -57,7 +69,12 @@ impl Node {
history_size: 64, history_size: 64,
}) })
} }
}
impl<R> Node<R>
where
R: ExecutionRpc,
{
pub async fn sync(&mut self) -> Result<(), NodeError> { pub async fn sync(&mut self) -> Result<(), NodeError> {
let chain_id = self.config.chain.chain_id; let chain_id = self.config.chain.chain_id;
self.execution self.execution
@ -109,11 +126,11 @@ impl Node {
.map_err(NodeError::ConsensusPayloadError)?; .map_err(NodeError::ConsensusPayloadError)?;
self.payloads self.payloads
.insert(*latest_payload.block_number(), latest_payload); .insert(latest_payload.block_number, latest_payload);
self.payloads self.payloads
.insert(*finalized_payload.block_number(), finalized_payload.clone()); .insert(finalized_payload.block_number, finalized_payload.clone());
self.finalized_payloads self.finalized_payloads
.insert(*finalized_payload.block_number(), finalized_payload); .insert(finalized_payload.block_number, finalized_payload);
let start_slot = self let start_slot = self
.current_slot .current_slot
@ -124,7 +141,7 @@ impl Node {
.await .await
.map_err(NodeError::ConsensusPayloadError)?; .map_err(NodeError::ConsensusPayloadError)?;
for payload in backfill_payloads { for payload in backfill_payloads {
self.payloads.insert(*payload.block_number(), payload); self.payloads.insert(payload.block_number, payload);
} }
self.current_slot = Some(latest_header.slot); self.current_slot = Some(latest_header.slot);
@ -188,14 +205,14 @@ impl Node {
pub fn get_block_transaction_count_by_hash(&self, hash: &Vec<u8>) -> Result<u64> { pub fn get_block_transaction_count_by_hash(&self, hash: &Vec<u8>) -> Result<u64> {
let payload = self.get_payload_by_hash(hash)?; let payload = self.get_payload_by_hash(hash)?;
let transaction_count = payload.1.transactions().len(); let transaction_count = payload.1.transactions.len();
Ok(transaction_count as u64) Ok(transaction_count as u64)
} }
pub fn get_block_transaction_count_by_number(&self, block: BlockTag) -> Result<u64> { pub fn get_block_transaction_count_by_number(&self, block: BlockTag) -> Result<u64> {
let payload = self.get_payload(block)?; let payload = self.get_payload(block)?;
let transaction_count = payload.transactions().len(); let transaction_count = payload.transactions.len();
Ok(transaction_count as u64) Ok(transaction_count as u64)
} }
@ -269,7 +286,7 @@ impl Node {
self.check_head_age()?; self.check_head_age()?;
let payload = self.get_payload(BlockTag::Latest)?; let payload = self.get_payload(BlockTag::Latest)?;
let base_fee = U256::from_little_endian(&payload.base_fee_per_gas().to_bytes_le()); let base_fee = U256::from_little_endian(&payload.base_fee_per_gas.to_bytes_le());
let tip = U256::from(10_u64.pow(9)); let tip = U256::from(10_u64.pow(9));
Ok(base_fee + tip) Ok(base_fee + tip)
} }
@ -284,7 +301,7 @@ impl Node {
self.check_head_age()?; self.check_head_age()?;
let payload = self.get_payload(BlockTag::Latest)?; let payload = self.get_payload(BlockTag::Latest)?;
Ok(*payload.block_number()) Ok(payload.block_number)
} }
pub async fn get_block_by_number( pub async fn get_block_by_number(
@ -367,7 +384,7 @@ impl Node {
pub fn get_coinbase(&self) -> Result<Address> { pub fn get_coinbase(&self) -> Result<Address> {
self.check_head_age()?; self.check_head_age()?;
let payload = self.get_payload(BlockTag::Latest)?; let payload = self.get_payload(BlockTag::Latest)?;
let coinbase_address = Address::from_slice(payload.fee_recipient()); let coinbase_address = Address::from_slice(&payload.fee_recipient);
Ok(coinbase_address) Ok(coinbase_address)
} }
@ -398,7 +415,7 @@ impl Node {
let payloads = self let payloads = self
.payloads .payloads
.iter() .iter()
.filter(|entry| &entry.1.block_hash().to_vec() == hash) .filter(|entry| &entry.1.block_hash.to_vec() == hash)
.collect::<Vec<(&u64, &ExecutionPayload)>>(); .collect::<Vec<(&u64, &ExecutionPayload)>>();
payloads payloads

View File

@ -3,7 +3,6 @@ use ethers::{
types::{Address, Filter, Log, SyncingStatus, Transaction, TransactionReceipt, H256, U256}, types::{Address, Filter, Log, SyncingStatus, Transaction, TransactionReceipt, H256, U256},
}; };
use eyre::Result; use eyre::Result;
use log::info;
use std::{fmt::Display, net::SocketAddr, str::FromStr, sync::Arc}; use std::{fmt::Display, net::SocketAddr, str::FromStr, sync::Arc};
use tokio::sync::RwLock; use tokio::sync::RwLock;
@ -11,6 +10,7 @@ use jsonrpsee::{
core::{async_trait, server::rpc_module::Methods, Error}, core::{async_trait, server::rpc_module::Methods, Error},
http_server::{HttpServerBuilder, HttpServerHandle}, http_server::{HttpServerBuilder, HttpServerHandle},
proc_macros::rpc, proc_macros::rpc,
ws_server::{WsServerBuilder, WsServerHandle},
}; };
use crate::{errors::NodeError, node::Node}; use crate::{errors::NodeError, node::Node};
@ -19,35 +19,50 @@ use common::{
types::BlockTag, types::BlockTag,
utils::{hex_str_to_bytes, u64_to_hex_string}, utils::{hex_str_to_bytes, u64_to_hex_string},
}; };
use execution::types::{CallOpts, ExecutionBlock}; use execution::{
rpc::ExecutionRpc,
types::{CallOpts, ExecutionBlock},
};
pub struct Rpc { pub struct Rpc<R: ExecutionRpc> {
node: Arc<RwLock<Node>>, node: Arc<RwLock<Node<R>>>,
handle: Option<HttpServerHandle>, http_handle: Option<HttpServerHandle>,
ws_handle: Option<WsServerHandle>,
pub with_http: bool,
pub with_ws: bool,
port: u16, port: u16,
} }
impl Rpc { impl<R: ExecutionRpc> Rpc<R> {
pub fn new(node: Arc<RwLock<Node>>, port: u16) -> Self { pub fn new(node: Arc<RwLock<Node<R>>>, with_http: bool, with_ws: bool, port: u16) -> Self {
Rpc { Rpc {
node, node,
handle: None, http_handle: None,
ws_handle: None,
with_http,
with_ws,
port, port,
} }
} }
pub async fn start(&mut self) -> Result<SocketAddr> { pub async fn start_http(&mut self) -> Result<Option<SocketAddr>> {
let rpc_inner = RpcInner { if self.with_http {
node: self.node.clone(), let (handle, addr) = RpcInner::from(&*self).start_http().await?;
port: self.port, self.http_handle = Some(handle);
}; log::info!("http rpc server started at {}", addr);
return Ok(Some(addr));
}
Ok(None)
}
let (handle, addr) = start(rpc_inner).await?; pub async fn start_ws(&mut self) -> Result<Option<SocketAddr>> {
self.handle = Some(handle); if self.with_ws {
let (handle, addr) = RpcInner::from(&*self).start_ws().await?;
info!("rpc server started at {}", addr); self.ws_handle = Some(handle);
log::info!("http rpc server started at {}", addr);
Ok(addr) return Ok(Some(addr));
}
Ok(None)
} }
} }
@ -125,19 +140,68 @@ trait NetRpc {
} }
#[derive(Clone)] #[derive(Clone)]
struct RpcInner { struct RpcInner<R: ExecutionRpc> {
node: Arc<RwLock<Node>>, node: Arc<RwLock<Node<R>>>,
port: u16, http_port: u16,
ws_port: u16,
}
impl<R: ExecutionRpc> From<&Rpc<R>> for RpcInner<R> {
fn from(rpc: &Rpc<R>) -> Self {
RpcInner {
node: Arc::clone(&rpc.node),
http_port: rpc.port,
ws_port: 4443,
}
}
}
impl<R: ExecutionRpc> RpcInner<R> {
pub async fn start_http(&self) -> Result<(HttpServerHandle, SocketAddr)> {
let addr = format!("127.0.0.1:{}", self.http_port);
let server = HttpServerBuilder::default().build(addr).await?;
let addr = server.local_addr()?;
let mut methods = Methods::new();
let eth_methods: Methods = EthRpcServer::into_rpc(self.clone()).into();
let net_methods: Methods = NetRpcServer::into_rpc(self.clone()).into();
methods.merge(eth_methods)?;
methods.merge(net_methods)?;
let handle = server.start(methods)?;
Ok((handle, addr))
}
pub async fn start_ws(&self) -> Result<(WsServerHandle, SocketAddr)> {
let addr = format!("127.0.0.1:{}", self.ws_port);
let server = WsServerBuilder::default().build(addr).await?;
let addr = server.local_addr()?;
let mut methods = Methods::new();
let eth_methods: Methods = EthRpcServer::into_rpc(self.clone()).into();
let net_methods: Methods = NetRpcServer::into_rpc(self.clone()).into();
methods.merge(eth_methods)?;
methods.merge(net_methods)?;
let handle = server.start(methods)?;
Ok((handle, addr))
}
} }
#[async_trait] #[async_trait]
impl EthRpcServer for RpcInner { impl<R: ExecutionRpc> EthRpcServer for RpcInner<R> {
async fn get_balance(&self, address: &str, block: BlockTag) -> Result<String, Error> { async fn get_balance(&self, address: &str, block: BlockTag) -> Result<String, Error> {
let address = convert_err(Address::from_str(address))?; let address = convert_err(Address::from_str(address))?;
let node = self.node.read().await; let node = self.node.read().await;
let balance = convert_err(node.get_balance(&address, block).await)?; let balance = convert_err(node.get_balance(&address, block).await)?;
Ok(format_hex(&balance)) Ok(common::utils::format_hex(&balance))
} }
async fn get_transaction_count(&self, address: &str, block: BlockTag) -> Result<String, Error> { async fn get_transaction_count(&self, address: &str, block: BlockTag) -> Result<String, Error> {
@ -203,13 +267,13 @@ impl EthRpcServer for RpcInner {
async fn gas_price(&self) -> Result<String, Error> { async fn gas_price(&self) -> Result<String, Error> {
let node = self.node.read().await; let node = self.node.read().await;
let gas_price = convert_err(node.get_gas_price())?; let gas_price = convert_err(node.get_gas_price())?;
Ok(format_hex(&gas_price)) Ok(common::utils::format_hex(&gas_price))
} }
async fn max_priority_fee_per_gas(&self) -> Result<String, Error> { async fn max_priority_fee_per_gas(&self) -> Result<String, Error> {
let node = self.node.read().await; let node = self.node.read().await;
let tip = convert_err(node.get_priority_fee())?; let tip = convert_err(node.get_priority_fee())?;
Ok(format_hex(&tip)) Ok(common::utils::format_hex(&tip))
} }
async fn block_number(&self) -> Result<String, Error> { async fn block_number(&self) -> Result<String, Error> {
@ -305,31 +369,13 @@ impl EthRpcServer for RpcInner {
} }
#[async_trait] #[async_trait]
impl NetRpcServer for RpcInner { impl<R: ExecutionRpc> NetRpcServer for RpcInner<R> {
async fn version(&self) -> Result<String, Error> { async fn version(&self) -> Result<String, Error> {
let node = self.node.read().await; let node = self.node.read().await;
Ok(node.chain_id().to_string()) Ok(node.chain_id().to_string())
} }
} }
async fn start(rpc: RpcInner) -> Result<(HttpServerHandle, SocketAddr)> {
let addr = format!("127.0.0.1:{}", rpc.port);
let server = HttpServerBuilder::default().build(addr).await?;
let addr = server.local_addr()?;
let mut methods = Methods::new();
let eth_methods: Methods = EthRpcServer::into_rpc(rpc.clone()).into();
let net_methods: Methods = NetRpcServer::into_rpc(rpc).into();
methods.merge(eth_methods)?;
methods.merge(net_methods)?;
let handle = server.start(methods)?;
Ok((handle, addr))
}
fn convert_err<T, E: Display>(res: Result<T, E>) -> Result<T, Error> { fn convert_err<T, E: Display>(res: Result<T, E>) -> Result<T, Error> {
res.map_err(|err| Error::Custom(err.to_string())) res.map_err(|err| Error::Custom(err.to_string()))
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "common" name = "common"
version = "0.3.0" version = "0.2.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
@ -8,5 +8,5 @@ eyre = "0.6.8"
serde = { version = "1.0.143", features = ["derive"] } serde = { version = "1.0.143", features = ["derive"] }
hex = "0.4.3" hex = "0.4.3"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" } ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" }
ethers = "1.0.0" ethers = { version = "1.0.2", features = [ "ws", "default" ] }
thiserror = "1.0.37" thiserror = "1.0.37"

View File

@ -1,9 +1,22 @@
use ethers::prelude::Address; use ethers::{
abi::AbiEncode,
types::{Address, U256},
};
use eyre::Result; use eyre::Result;
use ssz_rs::{Node, Vector}; use ssz_rs::{Node, Vector};
use super::types::Bytes32; use super::types::Bytes32;
pub fn format_hex(num: &U256) -> String {
let stripped = num
.encode_hex()
.strip_prefix("0x")
.unwrap()
.trim_start_matches('0')
.to_string();
format!("0x{stripped}")
}
pub fn hex_str_to_bytes(s: &str) -> Result<Vec<u8>> { pub fn hex_str_to_bytes(s: &str) -> Result<Vec<u8>> {
let stripped = s.strip_prefix("0x").unwrap_or(s); let stripped = s.strip_prefix("0x").unwrap_or(s);
Ok(hex::decode(stripped)?) Ok(hex::decode(stripped)?)

View File

@ -1,7 +1,7 @@
[package] [package]
name = "config" name = "config"
version = "0.3.0" version = "0.2.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
@ -9,7 +9,7 @@ eyre = "0.6.8"
serde = { version = "1.0.143", features = ["derive"] } serde = { version = "1.0.143", features = ["derive"] }
hex = "0.4.3" hex = "0.4.3"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" } ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" }
ethers = "1.0.0" ethers = { version = "1.0.2", features = [ "ws", "default" ] }
figment = { version = "0.10.7", features = ["toml", "env"] } figment = { version = "0.10.7", features = ["toml", "env"] }
thiserror = "1.0.37" thiserror = "1.0.37"
log = "0.4.17" log = "0.4.17"

View File

@ -14,6 +14,8 @@ pub struct CliConfig {
pub fallback: Option<String>, pub fallback: Option<String>,
pub load_external_fallback: bool, pub load_external_fallback: bool,
pub strict_checkpoint_age: bool, pub strict_checkpoint_age: bool,
pub with_ws: bool,
pub with_http: bool,
} }
impl CliConfig { impl CliConfig {
@ -52,6 +54,10 @@ impl CliConfig {
Value::from(self.strict_checkpoint_age), Value::from(self.strict_checkpoint_age),
); );
user_dict.insert("with_ws", Value::from(self.with_ws));
user_dict.insert("with_http", Value::from(self.with_http));
Serialized::from(user_dict, network) Serialized::from(user_dict, network)
} }
} }

View File

@ -28,6 +28,8 @@ pub struct Config {
pub fallback: Option<String>, pub fallback: Option<String>,
pub load_external_fallback: bool, pub load_external_fallback: bool,
pub strict_checkpoint_age: bool, pub strict_checkpoint_age: bool,
pub with_ws: bool,
pub with_http: bool,
} }
impl Config { impl Config {
@ -73,9 +75,7 @@ impl Config {
pub fn fork_version(&self, slot: u64) -> Vec<u8> { pub fn fork_version(&self, slot: u64) -> Vec<u8> {
let epoch = slot / 32; let epoch = slot / 32;
if epoch >= self.forks.capella.epoch { if epoch >= self.forks.bellatrix.epoch {
self.forks.capella.fork_version.clone()
} else if epoch >= self.forks.bellatrix.epoch {
self.forks.bellatrix.fork_version.clone() self.forks.bellatrix.fork_version.clone()
} else if epoch >= self.forks.altair.epoch { } else if epoch >= self.forks.altair.epoch {
self.forks.altair.fork_version.clone() self.forks.altair.fork_version.clone()

View File

@ -62,10 +62,6 @@ pub fn mainnet() -> BaseConfig {
epoch: 144896, epoch: 144896,
fork_version: hex_str_to_bytes("0x02000000").unwrap(), fork_version: hex_str_to_bytes("0x02000000").unwrap(),
}, },
capella: Fork {
epoch: u64::MAX, // TODO: set epoch when known
fork_version: hex_str_to_bytes("0x03000000").unwrap(),
},
}, },
max_checkpoint_age: 1_209_600, // 14 days max_checkpoint_age: 1_209_600, // 14 days
} }
@ -100,10 +96,6 @@ pub fn goerli() -> BaseConfig {
epoch: 112260, epoch: 112260,
fork_version: hex_str_to_bytes("0x02001020").unwrap(), fork_version: hex_str_to_bytes("0x02001020").unwrap(),
}, },
capella: Fork {
epoch: 162304,
fork_version: hex_str_to_bytes("0x03001020").unwrap(),
},
}, },
max_checkpoint_age: 1_209_600, // 14 days max_checkpoint_age: 1_209_600, // 14 days
} }

View File

@ -18,7 +18,6 @@ pub struct Forks {
pub genesis: Fork, pub genesis: Fork,
pub altair: Fork, pub altair: Fork,
pub bellatrix: Fork, pub bellatrix: Fork,
pub capella: Fork,
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]

View File

@ -1,6 +1,6 @@
[package] [package]
name = "consensus" name = "consensus"
version = "0.3.0" version = "0.2.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
@ -11,7 +11,7 @@ serde_json = "1.0.85"
hex = "0.4.3" hex = "0.4.3"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" } ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" }
milagro_bls = { git = "https://github.com/Snowfork/milagro_bls" } milagro_bls = { git = "https://github.com/Snowfork/milagro_bls" }
ethers = "1.0.0" ethers = { version = "1.0.2", features = [ "ws", "default" ] }
bytes = "1.2.1" bytes = "1.2.1"
toml = "0.5.9" toml = "0.5.9"
async-trait = "0.1.57" async-trait = "0.1.57"
@ -19,7 +19,6 @@ log = "0.4.17"
chrono = "0.4.23" chrono = "0.4.23"
thiserror = "1.0.37" thiserror = "1.0.37"
reqwest = { version = "0.11.13", features = ["json"] } reqwest = { version = "0.11.13", features = ["json"] }
superstruct = "0.7.0"
common = { path = "../common" } common = { path = "../common" }
config = { path = "../config" } config = { path = "../config" }

View File

@ -103,7 +103,7 @@ impl<R: ConsensusRpc> ConsensusClient<R> {
) )
.into()) .into())
} else { } else {
Ok(block.body.execution_payload().clone()) Ok(block.body.execution_payload)
} }
} }
@ -115,33 +115,30 @@ impl<R: ConsensusRpc> ConsensusClient<R> {
let payloads_fut = (start_slot..end_slot) let payloads_fut = (start_slot..end_slot)
.rev() .rev()
.map(|slot| self.rpc.get_block(slot)); .map(|slot| self.rpc.get_block(slot));
let mut prev_parent_hash: Bytes32 = self let mut prev_parent_hash: Bytes32 = self
.rpc .rpc
.get_block(end_slot) .get_block(end_slot)
.await? .await?
.body .body
.execution_payload() .execution_payload
.parent_hash() .parent_hash;
.clone();
let mut payloads: Vec<ExecutionPayload> = Vec::new(); let mut payloads: Vec<ExecutionPayload> = Vec::new();
for result in join_all(payloads_fut).await { for result in join_all(payloads_fut).await {
if result.is_err() { if result.is_err() {
continue; continue;
} }
let payload = result.unwrap().body.execution_payload().clone(); let payload = result.unwrap().body.execution_payload;
if payload.block_hash() != &prev_parent_hash { if payload.block_hash != prev_parent_hash {
warn!( warn!(
"error while backfilling blocks: {}", "error while backfilling blocks: {}",
ConsensusError::InvalidHeaderHash( ConsensusError::InvalidHeaderHash(
format!("{prev_parent_hash:02X?}"), format!("{prev_parent_hash:02X?}"),
format!("{:02X?}", payload.parent_hash()), format!("{:02X?}", payload.parent_hash),
) )
); );
break; break;
} }
prev_parent_hash = payload.parent_hash().clone(); prev_parent_hash = payload.parent_hash.clone();
payloads.push(payload); payloads.push(payload);
} }
Ok(payloads) Ok(payloads)

View File

@ -4,7 +4,6 @@ use ssz_rs::prelude::*;
use common::types::Bytes32; use common::types::Bytes32;
use common::utils::hex_str_to_bytes; use common::utils::hex_str_to_bytes;
use superstruct::superstruct;
pub type BLSPubKey = Vector<u8, 48>; pub type BLSPubKey = Vector<u8, 48>;
pub type SignatureBytes = Vector<u8, 96>; pub type SignatureBytes = Vector<u8, 96>;
@ -25,15 +24,7 @@ pub struct BeaconBlock {
pub body: BeaconBlockBody, pub body: BeaconBlockBody,
} }
#[superstruct( #[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
variants(Bellatrix, Capella),
variant_attributes(
derive(serde::Deserialize, Clone, Debug, SimpleSerialize, Default),
serde(deny_unknown_fields)
)
)]
#[derive(serde::Deserialize, Debug, Clone)]
#[serde(untagged)]
pub struct BeaconBlockBody { pub struct BeaconBlockBody {
#[serde(deserialize_with = "signature_deserialize")] #[serde(deserialize_with = "signature_deserialize")]
randao_reveal: SignatureBytes, randao_reveal: SignatureBytes,
@ -47,79 +38,9 @@ pub struct BeaconBlockBody {
voluntary_exits: List<SignedVoluntaryExit, 16>, voluntary_exits: List<SignedVoluntaryExit, 16>,
sync_aggregate: SyncAggregate, sync_aggregate: SyncAggregate,
pub execution_payload: ExecutionPayload, pub execution_payload: ExecutionPayload,
#[superstruct(only(Capella))]
bls_to_execution_changes: List<SignedBlsToExecutionChange, 16>,
} }
impl ssz_rs::Merkleized for BeaconBlockBody { #[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
fn hash_tree_root(&mut self) -> Result<Node, MerkleizationError> {
match self {
BeaconBlockBody::Bellatrix(body) => body.hash_tree_root(),
BeaconBlockBody::Capella(body) => body.hash_tree_root(),
}
}
}
impl ssz_rs::Sized for BeaconBlockBody {
fn is_variable_size() -> bool {
true
}
fn size_hint() -> usize {
0
}
}
impl ssz_rs::Serialize for BeaconBlockBody {
fn serialize(&self, buffer: &mut Vec<u8>) -> Result<usize, SerializeError> {
match self {
BeaconBlockBody::Bellatrix(body) => body.serialize(buffer),
BeaconBlockBody::Capella(body) => body.serialize(buffer),
}
}
}
impl ssz_rs::Deserialize for BeaconBlockBody {
fn deserialize(_encoding: &[u8]) -> Result<Self, DeserializeError>
where
Self: Sized,
{
panic!("not implemented");
}
}
#[derive(Default, Clone, Debug, SimpleSerialize, serde::Deserialize)]
pub struct SignedBlsToExecutionChange {
message: BlsToExecutionChange,
#[serde(deserialize_with = "signature_deserialize")]
signature: SignatureBytes,
}
#[derive(Default, Clone, Debug, SimpleSerialize, serde::Deserialize)]
pub struct BlsToExecutionChange {
#[serde(deserialize_with = "u64_deserialize")]
validator_index: u64,
#[serde(deserialize_with = "pubkey_deserialize")]
from_bls_pubkey: BLSPubKey,
#[serde(deserialize_with = "address_deserialize")]
to_execution_address: Address,
}
impl Default for BeaconBlockBody {
fn default() -> Self {
BeaconBlockBody::Bellatrix(BeaconBlockBodyBellatrix::default())
}
}
#[superstruct(
variants(Bellatrix, Capella),
variant_attributes(
derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone),
serde(deny_unknown_fields)
)
)]
#[derive(serde::Deserialize, Debug, Clone)]
#[serde(untagged)]
pub struct ExecutionPayload { pub struct ExecutionPayload {
#[serde(deserialize_with = "bytes32_deserialize")] #[serde(deserialize_with = "bytes32_deserialize")]
pub parent_hash: Bytes32, pub parent_hash: Bytes32,
@ -149,67 +70,10 @@ pub struct ExecutionPayload {
pub block_hash: Bytes32, pub block_hash: Bytes32,
#[serde(deserialize_with = "transactions_deserialize")] #[serde(deserialize_with = "transactions_deserialize")]
pub transactions: List<Transaction, 1048576>, pub transactions: List<Transaction, 1048576>,
#[superstruct(only(Capella))]
withdrawals: List<Withdrawal, 16>,
}
#[derive(Default, Clone, Debug, SimpleSerialize, serde::Deserialize)]
pub struct Withdrawal {
#[serde(deserialize_with = "u64_deserialize")]
index: u64,
#[serde(deserialize_with = "u64_deserialize")]
validator_index: u64,
#[serde(deserialize_with = "address_deserialize")]
address: Address,
#[serde(deserialize_with = "u64_deserialize")]
amount: u64,
}
impl ssz_rs::Merkleized for ExecutionPayload {
fn hash_tree_root(&mut self) -> Result<Node, MerkleizationError> {
match self {
ExecutionPayload::Bellatrix(payload) => payload.hash_tree_root(),
ExecutionPayload::Capella(payload) => payload.hash_tree_root(),
}
}
}
impl ssz_rs::Sized for ExecutionPayload {
fn is_variable_size() -> bool {
true
}
fn size_hint() -> usize {
0
}
}
impl ssz_rs::Serialize for ExecutionPayload {
fn serialize(&self, buffer: &mut Vec<u8>) -> Result<usize, SerializeError> {
match self {
ExecutionPayload::Bellatrix(payload) => payload.serialize(buffer),
ExecutionPayload::Capella(payload) => payload.serialize(buffer),
}
}
}
impl ssz_rs::Deserialize for ExecutionPayload {
fn deserialize(_encoding: &[u8]) -> Result<Self, DeserializeError>
where
Self: Sized,
{
panic!("not implemented");
}
}
impl Default for ExecutionPayload {
fn default() -> Self {
ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix::default())
}
} }
#[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)] #[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
pub struct ProposerSlashing { struct ProposerSlashing {
signed_header_1: SignedBeaconBlockHeader, signed_header_1: SignedBeaconBlockHeader,
signed_header_2: SignedBeaconBlockHeader, signed_header_2: SignedBeaconBlockHeader,
} }
@ -236,7 +100,7 @@ struct BeaconBlockHeader {
} }
#[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)] #[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
pub struct AttesterSlashing { struct AttesterSlashing {
attestation_1: IndexedAttestation, attestation_1: IndexedAttestation,
attestation_2: IndexedAttestation, attestation_2: IndexedAttestation,
} }
@ -251,7 +115,7 @@ struct IndexedAttestation {
} }
#[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)] #[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
pub struct Attestation { struct Attestation {
aggregation_bits: Bitlist<2048>, aggregation_bits: Bitlist<2048>,
data: AttestationData, data: AttestationData,
#[serde(deserialize_with = "signature_deserialize")] #[serde(deserialize_with = "signature_deserialize")]
@ -279,7 +143,7 @@ struct Checkpoint {
} }
#[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)] #[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
pub struct SignedVoluntaryExit { struct SignedVoluntaryExit {
message: VoluntaryExit, message: VoluntaryExit,
#[serde(deserialize_with = "signature_deserialize")] #[serde(deserialize_with = "signature_deserialize")]
signature: SignatureBytes, signature: SignatureBytes,
@ -294,7 +158,7 @@ struct VoluntaryExit {
} }
#[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)] #[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)]
pub struct Deposit { struct Deposit {
#[serde(deserialize_with = "bytes_vector_deserialize")] #[serde(deserialize_with = "bytes_vector_deserialize")]
proof: Vector<Bytes32, 33>, proof: Vector<Bytes32, 33>,
data: DepositData, data: DepositData,

View File

@ -38,5 +38,5 @@ async fn test_get_payload() {
client.sync().await.unwrap(); client.sync().await.unwrap();
let payload = client.get_execution_payload(&None).await.unwrap(); let payload = client.get_execution_payload(&None).await.unwrap();
assert_eq!(*payload.block_number(), 7530932); assert_eq!(payload.block_number, 7530932);
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "execution" name = "execution"
version = "0.3.0" version = "0.2.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
@ -10,8 +10,8 @@ serde = { version = "1.0.143", features = ["derive"] }
serde_json = "1.0.85" serde_json = "1.0.85"
hex = "0.4.3" hex = "0.4.3"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" } ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" }
ethers = { version = "1.0.2", features = [ "ws", "default" ] }
revm = { version = "2.3", default-features = false, features = ["std", "k256", "with-serde"] } revm = { version = "2.3", default-features = false, features = ["std", "k256", "with-serde"] }
ethers = "1.0.0"
bytes = "1.2.1" bytes = "1.2.1"
futures = "0.3.23" futures = "0.3.23"
toml = "0.5.9" toml = "0.5.9"

View File

@ -111,7 +111,7 @@ impl<'a, R: ExecutionRpc> Evm<'a, R> {
let rpc = db.execution.rpc.clone(); let rpc = db.execution.rpc.clone();
let payload = db.current_payload.clone(); let payload = db.current_payload.clone();
let execution = db.execution.clone(); let execution = db.execution.clone();
let block = *db.current_payload.block_number(); let block = db.current_payload.block_number;
let opts_moved = CallOpts { let opts_moved = CallOpts {
from: opts.from, from: opts.from,
@ -139,7 +139,7 @@ impl<'a, R: ExecutionRpc> Evm<'a, R> {
}; };
let producer_account = AccessListItem { let producer_account = AccessListItem {
address: Address::from_slice(payload.fee_recipient()), address: Address::from_slice(&payload.fee_recipient),
storage_keys: Vec::default(), storage_keys: Vec::default(),
}; };
@ -182,10 +182,10 @@ impl<'a, R: ExecutionRpc> Evm<'a, R> {
env.tx.gas_limit = opts.gas.map(|v| v.as_u64()).unwrap_or(u64::MAX); env.tx.gas_limit = opts.gas.map(|v| v.as_u64()).unwrap_or(u64::MAX);
env.tx.gas_price = opts.gas_price.unwrap_or(U256::zero()); env.tx.gas_price = opts.gas_price.unwrap_or(U256::zero());
env.block.number = U256::from(*payload.block_number()); env.block.number = U256::from(payload.block_number);
env.block.coinbase = Address::from_slice(payload.fee_recipient()); env.block.coinbase = Address::from_slice(&payload.fee_recipient);
env.block.timestamp = U256::from(*payload.timestamp()); env.block.timestamp = U256::from(payload.timestamp);
env.block.difficulty = U256::from_little_endian(payload.prev_randao()); env.block.difficulty = U256::from_little_endian(&payload.prev_randao);
env.cfg.chain_id = self.chain_id.into(); env.cfg.chain_id = self.chain_id.into();
@ -266,7 +266,7 @@ impl<'a, R: ExecutionRpc> Database for ProofDB<'a, R> {
.payloads .payloads
.get(&number) .get(&number)
.ok_or(BlockNotFoundError::new(BlockTag::Number(number)))?; .ok_or(BlockNotFoundError::new(BlockTag::Number(number)))?;
Ok(H256::from_slice(payload.block_hash())) Ok(H256::from_slice(&payload.block_hash))
} }
fn storage(&mut self, address: H160, slot: U256) -> Result<U256, Report> { fn storage(&mut self, address: H160, slot: U256) -> Result<U256, Report> {
@ -304,7 +304,6 @@ fn is_precompile(address: &Address) -> bool {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use common::utils::hex_str_to_bytes; use common::utils::hex_str_to_bytes;
use consensus::types::ExecutionPayloadBellatrix;
use ssz_rs::Vector; use ssz_rs::Vector;
use crate::rpc::mock_rpc::MockRpc; use crate::rpc::mock_rpc::MockRpc;
@ -320,16 +319,15 @@ mod tests {
// Construct proofdb params // Construct proofdb params
let execution = get_client(); let execution = get_client();
let address = Address::from_str("14f9D4aF749609c1438528C0Cce1cC3f6D411c47").unwrap(); let address = Address::from_str("14f9D4aF749609c1438528C0Cce1cC3f6D411c47").unwrap();
let payload = ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix { let payload = ExecutionPayload {
state_root: Vector::from_iter( state_root: Vector::from_iter(
hex_str_to_bytes( hex_str_to_bytes(
"0xaa02f5db2ee75e3da400d10f3c30e894b6016ce8a2501680380a907b6674ce0d", "0xaa02f5db2ee75e3da400d10f3c30e894b6016ce8a2501680380a907b6674ce0d",
) )
.unwrap(), .unwrap(),
), ),
..ExecutionPayloadBellatrix::default() ..ExecutionPayload::default()
}); };
let mut payloads = BTreeMap::new(); let mut payloads = BTreeMap::new();
payloads.insert(7530933, payload.clone()); payloads.insert(7530933, payload.clone());

View File

@ -15,6 +15,7 @@ use revm::KECCAK_EMPTY;
use triehash_ethereum::ordered_trie_root; use triehash_ethereum::ordered_trie_root;
use crate::errors::ExecutionError; use crate::errors::ExecutionError;
use crate::rpc::WsRpc;
use crate::types::Transactions; use crate::types::Transactions;
use super::proof::{encode_account, verify_proof}; use super::proof::{encode_account, verify_proof};
@ -30,6 +31,13 @@ pub struct ExecutionClient<R: ExecutionRpc> {
pub rpc: R, pub rpc: R,
} }
impl ExecutionClient<WsRpc> {
pub fn new_with_ws(rpc: &str) -> Result<Self> {
let rpc = WsRpc::new(rpc)?;
Ok(Self { rpc })
}
}
impl<R: ExecutionRpc> ExecutionClient<R> { impl<R: ExecutionRpc> ExecutionClient<R> {
pub fn new(rpc: &str) -> Result<Self> { pub fn new(rpc: &str) -> Result<Self> {
let rpc: R = ExecutionRpc::new(rpc)?; let rpc: R = ExecutionRpc::new(rpc)?;
@ -54,7 +62,7 @@ impl<R: ExecutionRpc> ExecutionClient<R> {
let proof = self let proof = self
.rpc .rpc
.get_proof(address, slots, *payload.block_number()) .get_proof(address, slots, payload.block_number)
.await?; .await?;
let account_path = keccak256(address.as_bytes()).to_vec(); let account_path = keccak256(address.as_bytes()).to_vec();
@ -62,7 +70,7 @@ impl<R: ExecutionRpc> ExecutionClient<R> {
let is_valid = verify_proof( let is_valid = verify_proof(
&proof.account_proof, &proof.account_proof,
payload.state_root(), &payload.state_root,
&account_path, &account_path,
&account_encoded, &account_encoded,
); );
@ -98,7 +106,7 @@ impl<R: ExecutionRpc> ExecutionClient<R> {
let code = if proof.code_hash == KECCAK_EMPTY { let code = if proof.code_hash == KECCAK_EMPTY {
Vec::new() Vec::new()
} else { } else {
let code = self.rpc.get_code(address, *payload.block_number()).await?; let code = self.rpc.get_code(address, payload.block_number).await?;
let code_hash = keccak256(&code).into(); let code_hash = keccak256(&code).into();
if proof.code_hash != code_hash { if proof.code_hash != code_hash {
@ -136,7 +144,7 @@ impl<R: ExecutionRpc> ExecutionClient<R> {
let empty_uncle_hash = "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"; let empty_uncle_hash = "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347";
let tx_hashes = payload let tx_hashes = payload
.transactions() .transactions
.iter() .iter()
.map(|tx| H256::from_slice(&keccak256(tx))) .map(|tx| H256::from_slice(&keccak256(tx)))
.collect::<Vec<H256>>(); .collect::<Vec<H256>>();
@ -144,7 +152,7 @@ impl<R: ExecutionRpc> ExecutionClient<R> {
let txs = if full_tx { let txs = if full_tx {
let txs_fut = tx_hashes.iter().map(|hash| async move { let txs_fut = tx_hashes.iter().map(|hash| async move {
let mut payloads = BTreeMap::new(); let mut payloads = BTreeMap::new();
payloads.insert(*payload.block_number(), payload.clone()); payloads.insert(payload.block_number, payload.clone());
let tx = self let tx = self
.get_transaction(hash, &payloads) .get_transaction(hash, &payloads)
.await? .await?
@ -163,22 +171,22 @@ impl<R: ExecutionRpc> ExecutionClient<R> {
}; };
Ok(ExecutionBlock { Ok(ExecutionBlock {
number: *payload.block_number(), number: payload.block_number,
base_fee_per_gas: U256::from_little_endian(&payload.base_fee_per_gas().to_bytes_le()), base_fee_per_gas: U256::from_little_endian(&payload.base_fee_per_gas.to_bytes_le()),
difficulty: U256::from(0), difficulty: U256::from(0),
extra_data: payload.extra_data().to_vec(), extra_data: payload.extra_data.to_vec(),
gas_limit: *payload.gas_limit(), gas_limit: payload.gas_limit,
gas_used: *payload.gas_used(), gas_used: payload.gas_used,
hash: H256::from_slice(payload.block_hash()), hash: H256::from_slice(&payload.block_hash),
logs_bloom: payload.logs_bloom().to_vec(), logs_bloom: payload.logs_bloom.to_vec(),
miner: Address::from_slice(payload.fee_recipient()), miner: Address::from_slice(&payload.fee_recipient),
parent_hash: H256::from_slice(payload.parent_hash()), parent_hash: H256::from_slice(&payload.parent_hash),
receipts_root: H256::from_slice(payload.receipts_root()), receipts_root: H256::from_slice(&payload.receipts_root),
state_root: H256::from_slice(payload.state_root()), state_root: H256::from_slice(&payload.state_root),
timestamp: *payload.timestamp(), timestamp: payload.timestamp,
total_difficulty: 0, total_difficulty: 0,
transactions: txs, transactions: txs,
mix_hash: H256::from_slice(payload.prev_randao()), mix_hash: H256::from_slice(&payload.prev_randao),
nonce: empty_nonce, nonce: empty_nonce,
sha3_uncles: H256::from_str(empty_uncle_hash)?, sha3_uncles: H256::from_str(empty_uncle_hash)?,
size: 0, size: 0,
@ -192,10 +200,10 @@ impl<R: ExecutionRpc> ExecutionClient<R> {
payload: &ExecutionPayload, payload: &ExecutionPayload,
index: usize, index: usize,
) -> Result<Option<Transaction>> { ) -> Result<Option<Transaction>> {
let tx = payload.transactions()[index].clone(); let tx = payload.transactions[index].clone();
let tx_hash = H256::from_slice(&keccak256(tx)); let tx_hash = H256::from_slice(&keccak256(tx));
let mut payloads = BTreeMap::new(); let mut payloads = BTreeMap::new();
payloads.insert(*payload.block_number(), payload.clone()); payloads.insert(payload.block_number, payload.clone());
let tx_option = self.get_transaction(&tx_hash, &payloads).await?; let tx_option = self.get_transaction(&tx_hash, &payloads).await?;
let tx = tx_option.ok_or(eyre::eyre!("not reachable"))?; let tx = tx_option.ok_or(eyre::eyre!("not reachable"))?;
@ -222,7 +230,7 @@ impl<R: ExecutionRpc> ExecutionClient<R> {
let payload = payload.unwrap(); let payload = payload.unwrap();
let tx_hashes = payload let tx_hashes = payload
.transactions() .transactions
.iter() .iter()
.map(|tx| H256::from_slice(&keccak256(tx))) .map(|tx| H256::from_slice(&keccak256(tx)))
.collect::<Vec<H256>>(); .collect::<Vec<H256>>();
@ -239,7 +247,7 @@ impl<R: ExecutionRpc> ExecutionClient<R> {
let expected_receipt_root = ordered_trie_root(receipts_encoded); let expected_receipt_root = ordered_trie_root(receipts_encoded);
let expected_receipt_root = H256::from_slice(&expected_receipt_root.to_fixed_bytes()); let expected_receipt_root = H256::from_slice(&expected_receipt_root.to_fixed_bytes());
let payload_receipt_root = H256::from_slice(payload.receipts_root()); let payload_receipt_root = H256::from_slice(&payload.receipts_root);
if expected_receipt_root != payload_receipt_root || !receipts.contains(&receipt) { if expected_receipt_root != payload_receipt_root || !receipts.contains(&receipt) {
return Err(ExecutionError::ReceiptRootMismatch(tx_hash.to_string()).into()); return Err(ExecutionError::ReceiptRootMismatch(tx_hash.to_string()).into());
@ -275,7 +283,7 @@ impl<R: ExecutionRpc> ExecutionClient<R> {
let tx_encoded = tx.rlp().to_vec(); let tx_encoded = tx.rlp().to_vec();
let txs_encoded = payload let txs_encoded = payload
.transactions() .transactions
.iter() .iter()
.map(|tx| tx.to_vec()) .map(|tx| tx.to_vec())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -396,19 +404,29 @@ impl<R: ExecutionRpc> ExecutionClient<R> {
.get(&block_id) .get(&block_id)
.ok_or(ExecutionError::EmptyExecutionPayload())?; .ok_or(ExecutionError::EmptyExecutionPayload())?;
let converted_base_fee_per_gas = ethers::types::U256::from_little_endian( let converted_base_fee_per_gas = ethers::types::U256::from_little_endian(
&execution_payload.base_fee_per_gas().to_bytes_le(), &execution_payload.base_fee_per_gas.to_bytes_le(),
); );
fee_history fee_history
.base_fee_per_gas .base_fee_per_gas
.push(converted_base_fee_per_gas); .push(converted_base_fee_per_gas);
let gas_used_ratio_helios = ((*execution_payload.gas_used() as f64 let gas_used_ratio_helios = ((execution_payload.gas_used as f64
/ *execution_payload.gas_limit() as f64) / execution_payload.gas_limit as f64)
* 10.0_f64.powi(12)) * 10.0_f64.powi(12))
.round() .round()
/ 10.0_f64.powi(12); / 10.0_f64.powi(12);
fee_history.gas_used_ratio.push(gas_used_ratio_helios); fee_history.gas_used_ratio.push(gas_used_ratio_helios);
} }
// TODO: Maybe place behind a query option param?
// Optionally verify the computed fee history using the rpc
// verify_fee_history(
// &self.rpc,
// &fee_history,
// fee_history.base_fee_per_gas.len(),
// request_latest_block,
// reward_percentiles,
// ).await?;
Ok(Some(fee_history)) Ok(Some(fee_history))
} }
} }

View File

@ -43,6 +43,10 @@ impl ExecutionRpc for HttpRpc {
}) })
} }
async fn connect(&mut self) -> Result<()> {
Ok(())
}
async fn get_proof( async fn get_proof(
&self, &self,
address: &Address, address: &Address,

View File

@ -25,6 +25,10 @@ impl ExecutionRpc for MockRpc {
Ok(MockRpc { path }) Ok(MockRpc { path })
} }
async fn connect(&mut self) -> Result<()> {
Ok(())
}
async fn get_proof( async fn get_proof(
&self, &self,
_address: &Address, _address: &Address,

View File

@ -8,6 +8,9 @@ use eyre::Result;
use crate::types::CallOpts; use crate::types::CallOpts;
pub mod http_rpc; pub mod http_rpc;
pub use http_rpc::*;
pub mod ws_rpc;
pub use ws_rpc::*;
pub mod mock_rpc; pub mod mock_rpc;
#[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(not(target_arch = "wasm32"), async_trait)]
@ -17,6 +20,9 @@ pub trait ExecutionRpc: Send + Clone + Sync + 'static {
where where
Self: Sized; Self: Sized;
/// Connect allows the rpc to connect if asynchronous connection is required (eg websockets).
async fn connect(&mut self) -> Result<()>;
async fn get_proof( async fn get_proof(
&self, &self,
address: &Address, address: &Address,

195
execution/src/rpc/ws_rpc.rs Normal file
View File

@ -0,0 +1,195 @@
use async_trait::async_trait;
use common::errors::RpcError;
use ethers::{
prelude::*,
types::transaction::{eip2718::TypedTransaction, eip2930::AccessList},
};
use eyre::Result;
use crate::types::CallOpts;
use super::ExecutionRpc;
pub struct WsRpc {
pub url: String,
pub provider: Option<Provider<Ws>>,
}
impl Clone for WsRpc {
fn clone(&self) -> Self {
Self::new(&self.url).unwrap()
}
}
#[async_trait]
impl ExecutionRpc for WsRpc {
fn new(rpc: &str) -> Result<Self> {
Ok(Self {
url: rpc.to_string(),
provider: None::<Provider<Ws>>,
})
}
async fn connect(&mut self) -> Result<()> {
let provider = Provider::<Ws>::connect(&self.url).await?;
self.provider = Some(provider);
Ok(())
}
async fn get_proof(
&self,
address: &Address,
slots: &[H256],
block: u64,
) -> Result<EIP1186ProofResponse> {
let block = Some(BlockId::from(block));
let proof_response = self
.provider
.as_ref()
.ok_or(RpcError::new(
"get_proof",
eyre::eyre!("Provider not connected!"),
))?
.get_proof(*address, slots.to_vec(), block)
.await
.map_err(|e| RpcError::new("get_proof", e))?;
Ok(proof_response)
}
async fn create_access_list(&self, opts: &CallOpts, block: u64) -> Result<AccessList> {
let block = Some(BlockId::from(block));
let mut raw_tx = Eip1559TransactionRequest::new();
raw_tx.to = opts.to.map(Into::into);
raw_tx.from = opts.from;
raw_tx.value = opts.value;
raw_tx.gas = Some(opts.gas.unwrap_or(U256::from(100_000_000)));
raw_tx.max_fee_per_gas = Some(U256::zero());
raw_tx.max_priority_fee_per_gas = Some(U256::zero());
raw_tx.data = opts
.data
.as_ref()
.map(|data| Bytes::from(data.as_slice().to_owned()));
let tx = TypedTransaction::Eip1559(raw_tx);
let list = self
.provider
.as_ref()
.ok_or(RpcError::new(
"create_access_list",
eyre::eyre!("Provider not connected!"),
))?
.create_access_list(&tx, block)
.await
.map_err(|e| RpcError::new("create_access_list", e))?;
Ok(list.access_list)
}
async fn get_code(&self, address: &Address, block: u64) -> Result<Vec<u8>> {
let block = Some(BlockId::from(block));
let code = self
.provider
.as_ref()
.ok_or(RpcError::new(
"get_code",
eyre::eyre!("Provider not connected!"),
))?
.get_code(*address, block)
.await
.map_err(|e| RpcError::new("get_code", e))?;
Ok(code.to_vec())
}
async fn send_raw_transaction(&self, bytes: &[u8]) -> Result<H256> {
let bytes = Bytes::from(bytes.to_owned());
let tx = self
.provider
.as_ref()
.ok_or(RpcError::new(
"send_raw_transaction",
eyre::eyre!("Provider not connected!"),
))?
.send_raw_transaction(bytes)
.await
.map_err(|e| RpcError::new("send_raw_transaction", e))?;
Ok(tx.tx_hash())
}
async fn get_transaction_receipt(&self, tx_hash: &H256) -> Result<Option<TransactionReceipt>> {
let receipt = self
.provider
.as_ref()
.ok_or(RpcError::new(
"get_transaction_receipt",
eyre::eyre!("Provider not connected!"),
))?
.get_transaction_receipt(*tx_hash)
.await
.map_err(|e| RpcError::new("get_transaction_receipt", e))?;
Ok(receipt)
}
async fn get_transaction(&self, tx_hash: &H256) -> Result<Option<Transaction>> {
Ok(self
.provider
.as_ref()
.ok_or(RpcError::new(
"get_transaction",
eyre::eyre!("Provider not connected!"),
))?
.get_transaction(*tx_hash)
.await
.map_err(|e| RpcError::new("get_transaction", e))?)
}
async fn get_logs(&self, filter: &Filter) -> Result<Vec<Log>> {
Ok(self
.provider
.as_ref()
.ok_or(RpcError::new(
"get_logs",
eyre::eyre!("Provider not connected!"),
))?
.get_logs(filter)
.await
.map_err(|e| RpcError::new("get_logs", e))?)
}
async fn chain_id(&self) -> Result<u64> {
Ok(self
.provider
.as_ref()
.ok_or(RpcError::new(
"get_chainid",
eyre::eyre!("Provider not connected!"),
))?
.get_chainid()
.await
.map_err(|e| RpcError::new("chain_id", e))?
.as_u64())
}
async fn get_fee_history(
&self,
block_count: u64,
last_block: u64,
reward_percentiles: &[f64],
) -> Result<FeeHistory> {
let block = BlockNumber::from(last_block);
Ok(self
.provider
.as_ref()
.ok_or(RpcError::new(
"fee_history",
eyre::eyre!("Provider not connected!"),
))?
.fee_history(block_count, block, reward_percentiles)
.await
.map_err(|e| RpcError::new("fee_history", e))?)
}
}

View File

@ -5,7 +5,7 @@ use ethers::types::{Address, Filter, H256, U256};
use ssz_rs::{List, Vector}; use ssz_rs::{List, Vector};
use common::utils::hex_str_to_bytes; use common::utils::hex_str_to_bytes;
use consensus::types::{ExecutionPayload, ExecutionPayloadBellatrix}; use consensus::types::ExecutionPayload;
use execution::rpc::mock_rpc::MockRpc; use execution::rpc::mock_rpc::MockRpc;
use execution::ExecutionClient; use execution::ExecutionClient;
@ -18,13 +18,13 @@ async fn test_get_account() {
let execution = get_client(); let execution = get_client();
let address = Address::from_str("14f9D4aF749609c1438528C0Cce1cC3f6D411c47").unwrap(); let address = Address::from_str("14f9D4aF749609c1438528C0Cce1cC3f6D411c47").unwrap();
let payload = ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix { let payload = ExecutionPayload {
state_root: Vector::from_iter( state_root: Vector::from_iter(
hex_str_to_bytes("0xaa02f5db2ee75e3da400d10f3c30e894b6016ce8a2501680380a907b6674ce0d") hex_str_to_bytes("0xaa02f5db2ee75e3da400d10f3c30e894b6016ce8a2501680380a907b6674ce0d")
.unwrap(), .unwrap(),
), ),
..ExecutionPayloadBellatrix::default() ..ExecutionPayload::default()
}); };
let account = execution let account = execution
.get_account(&address, None, &payload) .get_account(&address, None, &payload)
@ -55,7 +55,7 @@ async fn test_get_tx() {
H256::from_str("2dac1b27ab58b493f902dda8b63979a112398d747f1761c0891777c0983e591f").unwrap(); H256::from_str("2dac1b27ab58b493f902dda8b63979a112398d747f1761c0891777c0983e591f").unwrap();
let mut payload = ExecutionPayload::default(); let mut payload = ExecutionPayload::default();
payload.transactions_mut().push(List::from_iter(hex_str_to_bytes("0x02f8b20583623355849502f900849502f91082ea6094326c977e6efc84e512bb9c30f76e30c160ed06fb80b844a9059cbb0000000000000000000000007daccf9b3c1ae2fa5c55f1c978aeef700bc83be0000000000000000000000000000000000000000000000001158e460913d00000c080a0e1445466b058b6f883c0222f1b1f3e2ad9bee7b5f688813d86e3fa8f93aa868ca0786d6e7f3aefa8fe73857c65c32e4884d8ba38d0ecfb947fbffb82e8ee80c167").unwrap())); payload.transactions.push(List::from_iter(hex_str_to_bytes("0x02f8b20583623355849502f900849502f91082ea6094326c977e6efc84e512bb9c30f76e30c160ed06fb80b844a9059cbb0000000000000000000000007daccf9b3c1ae2fa5c55f1c978aeef700bc83be0000000000000000000000000000000000000000000000001158e460913d00000c080a0e1445466b058b6f883c0222f1b1f3e2ad9bee7b5f688813d86e3fa8f93aa868ca0786d6e7f3aefa8fe73857c65c32e4884d8ba38d0ecfb947fbffb82e8ee80c167").unwrap()));
let mut payloads = BTreeMap::new(); let mut payloads = BTreeMap::new();
payloads.insert(7530933, payload); payloads.insert(7530933, payload);
@ -104,15 +104,15 @@ async fn test_get_tx_not_included() {
#[tokio::test] #[tokio::test]
async fn test_get_logs() { async fn test_get_logs() {
let execution = get_client(); let execution = get_client();
let mut payload = ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix { let mut payload = ExecutionPayload {
receipts_root: Vector::from_iter( receipts_root: Vector::from_iter(
hex_str_to_bytes("dd82a78eccb333854f0c99e5632906e092d8a49c27a21c25cae12b82ec2a113f") hex_str_to_bytes("dd82a78eccb333854f0c99e5632906e092d8a49c27a21c25cae12b82ec2a113f")
.unwrap(), .unwrap(),
), ),
..ExecutionPayloadBellatrix::default() ..ExecutionPayload::default()
}); };
payload.transactions_mut().push(List::from_iter(hex_str_to_bytes("0x02f8b20583623355849502f900849502f91082ea6094326c977e6efc84e512bb9c30f76e30c160ed06fb80b844a9059cbb0000000000000000000000007daccf9b3c1ae2fa5c55f1c978aeef700bc83be0000000000000000000000000000000000000000000000001158e460913d00000c080a0e1445466b058b6f883c0222f1b1f3e2ad9bee7b5f688813d86e3fa8f93aa868ca0786d6e7f3aefa8fe73857c65c32e4884d8ba38d0ecfb947fbffb82e8ee80c167").unwrap())); payload.transactions.push(List::from_iter(hex_str_to_bytes("0x02f8b20583623355849502f900849502f91082ea6094326c977e6efc84e512bb9c30f76e30c160ed06fb80b844a9059cbb0000000000000000000000007daccf9b3c1ae2fa5c55f1c978aeef700bc83be0000000000000000000000000000000000000000000000001158e460913d00000c080a0e1445466b058b6f883c0222f1b1f3e2ad9bee7b5f688813d86e3fa8f93aa868ca0786d6e7f3aefa8fe73857c65c32e4884d8ba38d0ecfb947fbffb82e8ee80c167").unwrap()));
let mut payloads = BTreeMap::new(); let mut payloads = BTreeMap::new();
payloads.insert(7530933, payload); payloads.insert(7530933, payload);
@ -134,15 +134,15 @@ async fn test_get_receipt() {
let tx_hash = let tx_hash =
H256::from_str("2dac1b27ab58b493f902dda8b63979a112398d747f1761c0891777c0983e591f").unwrap(); H256::from_str("2dac1b27ab58b493f902dda8b63979a112398d747f1761c0891777c0983e591f").unwrap();
let mut payload = ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix { let mut payload = ExecutionPayload {
receipts_root: Vector::from_iter( receipts_root: Vector::from_iter(
hex_str_to_bytes("dd82a78eccb333854f0c99e5632906e092d8a49c27a21c25cae12b82ec2a113f") hex_str_to_bytes("dd82a78eccb333854f0c99e5632906e092d8a49c27a21c25cae12b82ec2a113f")
.unwrap(), .unwrap(),
), ),
..ExecutionPayloadBellatrix::default() ..ExecutionPayload::default()
}); };
payload.transactions_mut().push(List::from_iter(hex_str_to_bytes("0x02f8b20583623355849502f900849502f91082ea6094326c977e6efc84e512bb9c30f76e30c160ed06fb80b844a9059cbb0000000000000000000000007daccf9b3c1ae2fa5c55f1c978aeef700bc83be0000000000000000000000000000000000000000000000001158e460913d00000c080a0e1445466b058b6f883c0222f1b1f3e2ad9bee7b5f688813d86e3fa8f93aa868ca0786d6e7f3aefa8fe73857c65c32e4884d8ba38d0ecfb947fbffb82e8ee80c167").unwrap())); payload.transactions.push(List::from_iter(hex_str_to_bytes("0x02f8b20583623355849502f900849502f91082ea6094326c977e6efc84e512bb9c30f76e30c160ed06fb80b844a9059cbb0000000000000000000000007daccf9b3c1ae2fa5c55f1c978aeef700bc83be0000000000000000000000000000000000000000000000001158e460913d00000c080a0e1445466b058b6f883c0222f1b1f3e2ad9bee7b5f688813d86e3fa8f93aa868ca0786d6e7f3aefa8fe73857c65c32e4884d8ba38d0ecfb947fbffb82e8ee80c167").unwrap()));
let mut payloads = BTreeMap::new(); let mut payloads = BTreeMap::new();
payloads.insert(7530933, payload); payloads.insert(7530933, payload);
@ -163,7 +163,7 @@ async fn test_get_receipt_bad_proof() {
H256::from_str("2dac1b27ab58b493f902dda8b63979a112398d747f1761c0891777c0983e591f").unwrap(); H256::from_str("2dac1b27ab58b493f902dda8b63979a112398d747f1761c0891777c0983e591f").unwrap();
let mut payload = ExecutionPayload::default(); let mut payload = ExecutionPayload::default();
payload.transactions_mut().push(List::from_iter(hex_str_to_bytes("0x02f8b20583623355849502f900849502f91082ea6094326c977e6efc84e512bb9c30f76e30c160ed06fb80b844a9059cbb0000000000000000000000007daccf9b3c1ae2fa5c55f1c978aeef700bc83be0000000000000000000000000000000000000000000000001158e460913d00000c080a0e1445466b058b6f883c0222f1b1f3e2ad9bee7b5f688813d86e3fa8f93aa868ca0786d6e7f3aefa8fe73857c65c32e4884d8ba38d0ecfb947fbffb82e8ee80c167").unwrap())); payload.transactions.push(List::from_iter(hex_str_to_bytes("0x02f8b20583623355849502f900849502f91082ea6094326c977e6efc84e512bb9c30f76e30c160ed06fb80b844a9059cbb0000000000000000000000007daccf9b3c1ae2fa5c55f1c978aeef700bc83be0000000000000000000000000000000000000000000000001158e460913d00000c080a0e1445466b058b6f883c0222f1b1f3e2ad9bee7b5f688813d86e3fa8f93aa868ca0786d6e7f3aefa8fe73857c65c32e4884d8ba38d0ecfb947fbffb82e8ee80c167").unwrap()));
let mut payloads = BTreeMap::new(); let mut payloads = BTreeMap::new();
payloads.insert(7530933, payload); payloads.insert(7530933, payload);
@ -191,10 +191,10 @@ async fn test_get_receipt_not_included() {
#[tokio::test] #[tokio::test]
async fn test_get_block() { async fn test_get_block() {
let execution = get_client(); let execution = get_client();
let payload = ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix { let payload = ExecutionPayload {
block_number: 12345, block_number: 12345,
..ExecutionPayloadBellatrix::default() ..ExecutionPayload::default()
}); };
let block = execution.get_block(&payload, false).await.unwrap(); let block = execution.get_block(&payload, false).await.unwrap();
@ -207,11 +207,11 @@ async fn test_get_tx_by_block_hash_and_index() {
let tx_hash = let tx_hash =
H256::from_str("2dac1b27ab58b493f902dda8b63979a112398d747f1761c0891777c0983e591f").unwrap(); H256::from_str("2dac1b27ab58b493f902dda8b63979a112398d747f1761c0891777c0983e591f").unwrap();
let mut payload = ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix { let mut payload = ExecutionPayload {
block_number: 7530933, block_number: 7530933,
..ExecutionPayloadBellatrix::default() ..ExecutionPayload::default()
}); };
payload.transactions_mut().push(List::from_iter(hex_str_to_bytes("0x02f8b20583623355849502f900849502f91082ea6094326c977e6efc84e512bb9c30f76e30c160ed06fb80b844a9059cbb0000000000000000000000007daccf9b3c1ae2fa5c55f1c978aeef700bc83be0000000000000000000000000000000000000000000000001158e460913d00000c080a0e1445466b058b6f883c0222f1b1f3e2ad9bee7b5f688813d86e3fa8f93aa868ca0786d6e7f3aefa8fe73857c65c32e4884d8ba38d0ecfb947fbffb82e8ee80c167").unwrap())); payload.transactions.push(List::from_iter(hex_str_to_bytes("0x02f8b20583623355849502f900849502f91082ea6094326c977e6efc84e512bb9c30f76e30c160ed06fb80b844a9059cbb0000000000000000000000007daccf9b3c1ae2fa5c55f1c978aeef700bc83be0000000000000000000000000000000000000000000000001158e460913d00000c080a0e1445466b058b6f883c0222f1b1f3e2ad9bee7b5f688813d86e3fa8f93aa868ca0786d6e7f3aefa8fe73857c65c32e4884d8ba38d0ecfb947fbffb82e8ee80c167").unwrap()));
let tx = execution let tx = execution
.get_transaction_by_block_hash_and_index(&payload, 0) .get_transaction_by_block_hash_and_index(&payload, 0)

View File

@ -3,8 +3,6 @@ name = "helios-ts"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib] [lib]
crate-type = ["cdylib"] crate-type = ["cdylib"]

View File

@ -9,7 +9,7 @@
<script src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js"></script> <script src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js"></script>
<script> <script>
const config = { const config = {
executionRpc:"http://localhost:9001/proxy", executionRpc:"http://localhost:9001/proxy",
consensusRpc: "http://localhost:9002/proxy", consensusRpc: "http://localhost:9002/proxy",
checkpoint: "0x372342db81e3a42527e08dc19e33cd4f91f440f45b9ddb0a9865d407eceb08e4", checkpoint: "0x372342db81e3a42527e08dc19e33cd4f91f440f45b9ddb0a9865d407eceb08e4",
}; };