diff --git a/Cargo.lock b/Cargo.lock index 1e0e2bae..cc3b08bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,12 +18,14 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", + "discv5", "ethereum_ssz", "ethereum_ssz_derive", "libp2p", "silius-primitives", "silius-uopool", "snap", + "tokio", ] [[package]] @@ -90,6 +92,7 @@ dependencies = [ "cfg-if", "cipher 0.3.0", "cpufeatures", + "ctr 0.8.0", "opaque-debug", ] @@ -259,6 +262,15 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +[[package]] +name = "array-init" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72" +dependencies = [ + "nodrop", +] + [[package]] name = "arrayref" version = "0.3.7" @@ -732,6 +744,15 @@ dependencies = [ "sha2 0.9.9", ] +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "tinyvec", +] + [[package]] name = "bstr" version = "1.6.0" @@ -1007,7 +1028,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b30a84aab436fcb256a2ab3c80663d8aec686e6bae12827bb05fef3e1e439c9f" dependencies = [ "bincode", - "bs58", + "bs58 0.4.0", "coins-core", "digest 0.10.7", "getrandom 0.2.10", @@ -1044,7 +1065,7 @@ checksum = "9b949a1c63fb7eb591eb7ba438746326aedf0ae843e51ec92ba6bec5bb382c4f" dependencies = [ "base64 0.21.2", "bech32", - "bs58", + "bs58 0.4.0", "digest 0.10.7", "generic-array", "hex", @@ -1304,6 +1325,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" dependencies = [ "cfg-if", + "digest 0.10.7", "fiat-crypto", "packed_simd_2", "platforms", @@ -1455,6 +1477,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "delay_map" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4355c25cbf99edcb6b4a0e906f6bdc6956eda149e84455bea49696429b2f8e8" +dependencies = [ + "futures", + "tokio-util", +] + [[package]] name = "der" version = "0.6.1" @@ -1637,6 +1669,39 @@ dependencies = [ "winapi", ] +[[package]] +name = "discv5" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98c05fa26996c6141f78ac4fafbe297a7fa69690565ba4e0d1f2e60bde5ce501" +dependencies = [ + "aes 0.7.5", + "aes-gcm 0.9.4", + "arrayvec", + "delay_map", + "enr 0.9.0", + "fnv", + "futures", + "hashlink", + "hex", + "hkdf", + "lazy_static", + "libp2p-core 0.40.0", + "libp2p-identity 0.2.2", + "lru 0.7.8", + "more-asserts", + "parking_lot 0.11.2", + "rand 0.8.5", + "rlp", + "smallvec 1.11.0", + "socket2 0.4.9", + "tokio", + "tracing", + "tracing-subscriber", + "uint", + "zeroize", +] + [[package]] name = "displaydoc" version = "0.2.4" @@ -1695,6 +1760,16 @@ dependencies = [ "signature 1.6.4", ] +[[package]] +name = "ed25519" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963" +dependencies = [ + "pkcs8 0.10.2", + "signature 2.1.0", +] + [[package]] name = "ed25519-dalek" version = "1.0.1" @@ -1702,13 +1777,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ "curve25519-dalek 3.2.0", - "ed25519", + "ed25519 1.5.3", "rand 0.7.3", "serde", "sha2 0.9.9", "zeroize", ] +[[package]] +name = "ed25519-dalek" +version = "2.0.0-pre.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd577ba9d4bcab443cac60003d8fd32c638e7024a3ec92c200d7af5d2c397ed" +dependencies = [ + "curve25519-dalek 4.0.0-rc.1", + "ed25519 2.2.1", + "rand_core 0.6.4", + "serde", + "sha2 0.10.7", + "zeroize", +] + [[package]] name = "educe" version = "0.4.22" @@ -1804,6 +1893,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "enr" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be7b2ac146c1f99fe245c02d16af0696450d8e06c135db75e10eeb9e642c20d" +dependencies = [ + "base64 0.21.2", + "bytes", + "ed25519-dalek 2.0.0-pre.0", + "hex", + "k256", + "log", + "rand 0.8.5", + "rlp", + "serde", + "serde-hex", + "sha3", + "zeroize", +] + [[package]] name = "enum-as-inner" version = "0.5.1" @@ -1945,7 +2054,7 @@ checksum = "e61ffea29f26e8249d35128a82ec8d3bd4fbc80179ea5f5e5e3daafef6a80fcb" dependencies = [ "ethereum-types", "itertools", - "smallvec", + "smallvec 1.11.0", ] [[package]] @@ -2156,7 +2265,7 @@ dependencies = [ "auto_impl", "base64 0.21.2", "bytes", - "enr", + "enr 0.8.1", "ethers-core 2.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures-channel", "futures-core", @@ -2717,11 +2826,23 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.6", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.6", +] [[package]] name = "hashbrown" @@ -2748,6 +2869,15 @@ dependencies = [ "fxhash", ] +[[package]] +name = "hashlink" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" +dependencies = [ + "hashbrown 0.11.2", +] + [[package]] name = "heapless" version = "0.7.16" @@ -3419,7 +3549,7 @@ dependencies = [ "lalrpop-util", "petgraph", "regex", - "regex-syntax", + "regex-syntax 0.7.4", "string_cache", "term", "tiny-keccak", @@ -3479,11 +3609,11 @@ dependencies = [ "instant", "libp2p-allow-block-list", "libp2p-connection-limits", - "libp2p-core", + "libp2p-core 0.39.2", "libp2p-dns", "libp2p-gossipsub", "libp2p-identify", - "libp2p-identity", + "libp2p-identity 0.1.2", "libp2p-mdns", "libp2p-metrics", "libp2p-mplex", @@ -3494,7 +3624,7 @@ dependencies = [ "libp2p-tcp", "libp2p-webrtc", "libp2p-yamux", - "multiaddr", + "multiaddr 0.17.1", "pin-project", ] @@ -3504,8 +3634,8 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "510daa05efbc25184458db837f6f9a5143888f1caa742426d92e1833ddd38a50" dependencies = [ - "libp2p-core", - "libp2p-identity", + "libp2p-core 0.39.2", + "libp2p-identity 0.1.2", "libp2p-swarm", "void", ] @@ -3516,8 +3646,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4caa33f1d26ed664c4fe2cca81a08c8e07d4c1c04f2f4ac7655c2dd85467fda0" dependencies = [ - "libp2p-core", - "libp2p-identity", + "libp2p-core 0.39.2", + "libp2p-identity 0.1.2", "libp2p-swarm", "void", ] @@ -3533,18 +3663,46 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-identity", + "libp2p-identity 0.1.2", + "log", + "multiaddr 0.17.1", + "multihash 0.17.0", + "multistream-select 0.12.1", + "once_cell", + "parking_lot 0.12.1", + "pin-project", + "quick-protobuf", + "rand 0.8.5", + "rw-stream-sink 0.3.0", + "smallvec 1.11.0", + "thiserror", + "unsigned-varint", + "void", +] + +[[package]] +name = "libp2p-core" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef7dd7b09e71aac9271c60031d0e558966cdb3253ba0308ab369bb2de80630d0" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "instant", + "libp2p-identity 0.2.2", "log", - "multiaddr", - "multihash", - "multistream-select", + "multiaddr 0.18.0", + "multihash 0.19.0", + "multistream-select 0.13.0", "once_cell", "parking_lot 0.12.1", "pin-project", "quick-protobuf", "rand 0.8.5", - "rw-stream-sink", - "smallvec", + "rw-stream-sink 0.4.0", + "smallvec 1.11.0", "thiserror", "unsigned-varint", "void", @@ -3557,10 +3715,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146ff7034daae62077c415c2376b8057368042df6ab95f5432ad5e88568b1554" dependencies = [ "futures", - "libp2p-core", + "libp2p-core 0.39.2", "log", "parking_lot 0.12.1", - "smallvec", + "smallvec 1.11.0", "trust-dns-resolver", ] @@ -3579,8 +3737,8 @@ dependencies = [ "futures", "hex_fmt", "instant", - "libp2p-core", - "libp2p-identity", + "libp2p-core 0.39.2", + "libp2p-identity 0.1.2", "libp2p-swarm", "log", "prometheus-client", @@ -3589,7 +3747,7 @@ dependencies = [ "rand 0.8.5", "regex", "sha2 0.10.7", - "smallvec", + "smallvec 1.11.0", "thiserror", "unsigned-varint", "void", @@ -3606,14 +3764,14 @@ dependencies = [ "either", "futures", "futures-timer", - "libp2p-core", - "libp2p-identity", + "libp2p-core 0.39.2", + "libp2p-identity 0.1.2", "libp2p-swarm", "log", "lru 0.10.1", "quick-protobuf", "quick-protobuf-codec", - "smallvec", + "smallvec 1.11.0", "thiserror", "void", ] @@ -3625,12 +3783,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e2d584751cecb2aabaa56106be6be91338a60a0f4e420cf2af639204f596fc1" dependencies = [ "asn1_der", - "bs58", - "ed25519-dalek", + "bs58 0.4.0", + "ed25519-dalek 1.0.1", "libsecp256k1", "log", - "multiaddr", - "multihash", + "multiaddr 0.17.1", + "multihash 0.17.0", + "quick-protobuf", + "rand 0.8.5", + "sha2 0.10.7", + "thiserror", + "zeroize", +] + +[[package]] +name = "libp2p-identity" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38d6012784fe4cc14e6d443eb415b11fc7c456dc15d9f0d90d9b70bc7ac3ec1" +dependencies = [ + "asn1_der", + "bs58 0.5.0", + "ed25519-dalek 1.0.1", + "libsecp256k1", + "log", + "multihash 0.19.0", "quick-protobuf", "rand 0.8.5", "sha2 0.10.7", @@ -3647,12 +3824,12 @@ dependencies = [ "data-encoding", "futures", "if-watch", - "libp2p-core", - "libp2p-identity", + "libp2p-core 0.39.2", + "libp2p-identity 0.1.2", "libp2p-swarm", "log", "rand 0.8.5", - "smallvec", + "smallvec 1.11.0", "socket2 0.4.9", "tokio", "trust-dns-proto", @@ -3665,7 +3842,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a42ec91e227d7d0dafa4ce88b333cdf5f277253873ab087555c92798db2ddd46" dependencies = [ - "libp2p-core", + "libp2p-core 0.39.2", "libp2p-gossipsub", "libp2p-identify", "libp2p-swarm", @@ -3681,12 +3858,12 @@ dependencies = [ "asynchronous-codec", "bytes", "futures", - "libp2p-core", + "libp2p-core 0.39.2", "log", "nohash-hasher", "parking_lot 0.12.1", "rand 0.8.5", - "smallvec", + "smallvec 1.11.0", "unsigned-varint", ] @@ -3699,8 +3876,8 @@ dependencies = [ "bytes", "curve25519-dalek 3.2.0", "futures", - "libp2p-core", - "libp2p-identity", + "libp2p-core 0.39.2", + "libp2p-identity 0.1.2", "log", "once_cell", "quick-protobuf", @@ -3723,8 +3900,8 @@ dependencies = [ "futures", "futures-timer", "if-watch", - "libp2p-core", - "libp2p-identity", + "libp2p-core 0.39.2", + "libp2p-identity 0.1.2", "libp2p-tls", "log", "parking_lot 0.12.1", @@ -3744,11 +3921,11 @@ dependencies = [ "async-trait", "futures", "instant", - "libp2p-core", - "libp2p-identity", + "libp2p-core 0.39.2", + "libp2p-identity 0.1.2", "libp2p-swarm", "rand 0.8.5", - "smallvec", + "smallvec 1.11.0", ] [[package]] @@ -3762,12 +3939,12 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", - "libp2p-identity", + "libp2p-core 0.39.2", + "libp2p-identity 0.1.2", "libp2p-swarm-derive", "log", "rand 0.8.5", - "smallvec", + "smallvec 1.11.0", "tokio", "void", ] @@ -3793,7 +3970,7 @@ dependencies = [ "futures-timer", "if-watch", "libc", - "libp2p-core", + "libp2p-core 0.39.2", "log", "socket2 0.4.9", "tokio", @@ -3807,8 +3984,8 @@ checksum = "ff08d13d0dc66e5e9ba6279c1de417b84fa0d0adc3b03e5732928c180ec02781" dependencies = [ "futures", "futures-rustls", - "libp2p-core", - "libp2p-identity", + "libp2p-core 0.39.2", + "libp2p-identity 0.1.2", "rcgen 0.10.0", "ring", "rustls 0.20.8", @@ -3831,11 +4008,11 @@ dependencies = [ "futures-timer", "hex", "if-watch", - "libp2p-core", - "libp2p-identity", + "libp2p-core 0.39.2", + "libp2p-identity 0.1.2", "libp2p-noise", "log", - "multihash", + "multihash 0.17.0", "quick-protobuf", "quick-protobuf-codec", "rand 0.8.5", @@ -3856,7 +4033,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd21d950662700a385d4c6d68e2f5f54d778e97068cdd718522222ef513bda" dependencies = [ "futures", - "libp2p-core", + "libp2p-core 0.39.2", "log", "thiserror", "yamux", @@ -3944,6 +4121,15 @@ version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +[[package]] +name = "lru" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" +dependencies = [ + "hashbrown 0.12.3", +] + [[package]] name = "lru" version = "0.9.0" @@ -3977,6 +4163,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "matches" version = "0.1.10" @@ -3989,6 +4184,12 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + [[package]] name = "md-5" version = "0.10.5" @@ -4097,6 +4298,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "more-asserts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" + [[package]] name = "multiaddr" version = "0.17.1" @@ -4108,7 +4315,26 @@ dependencies = [ "data-encoding", "log", "multibase", - "multihash", + "multihash 0.17.0", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint", + "url", +] + +[[package]] +name = "multiaddr" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92a651988b3ed3ad1bc8c87d016bb92f6f395b84ed1db9b926b32b1fc5a2c8b5" +dependencies = [ + "arrayref", + "byteorder", + "data-encoding", + "libp2p-identity 0.2.2", + "multibase", + "multihash 0.19.0", "percent-encoding", "serde", "static_assertions", @@ -4140,6 +4366,16 @@ dependencies = [ "unsigned-varint", ] +[[package]] +name = "multihash" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd59dcc2bbe70baabeac52cd22ae52c55eefe6c38ff11a9439f16a350a939f2" +dependencies = [ + "core2", + "unsigned-varint", +] + [[package]] name = "multihash-derive" version = "0.8.1" @@ -4170,7 +4406,21 @@ dependencies = [ "futures", "log", "pin-project", - "smallvec", + "smallvec 1.11.0", + "unsigned-varint", +] + +[[package]] +name = "multistream-select" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" +dependencies = [ + "bytes", + "futures", + "log", + "pin-project", + "smallvec 1.11.0", "unsigned-varint", ] @@ -4258,6 +4508,12 @@ dependencies = [ "memoffset 0.6.5", ] +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + [[package]] name = "nohash-hasher" version = "0.2.0" @@ -4543,7 +4799,7 @@ dependencies = [ "instant", "libc", "redox_syscall 0.2.16", - "smallvec", + "smallvec 1.11.0", "winapi", ] @@ -4556,7 +4812,7 @@ dependencies = [ "cfg-if", "libc", "redox_syscall 0.3.5", - "smallvec", + "smallvec 1.11.0", "windows-targets", ] @@ -5296,8 +5552,17 @@ checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.3.3", + "regex-syntax 0.7.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -5308,9 +5573,15 @@ checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.7.4", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.7.4" @@ -5913,6 +6184,17 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "rw-stream-sink" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c9026ff5d2f23da5e45bbc283f156383001bfb09c4e44256d02c1a685fe9a1" +dependencies = [ + "futures", + "pin-project", + "static_assertions", +] + [[package]] name = "ryu" version = "1.0.15" @@ -6120,6 +6402,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-hex" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca37e3e4d1b39afd7ff11ee4e947efae85adfddf4841787bfa47c470e96dc26d" +dependencies = [ + "array-init", + "serde", + "smallvec 0.6.14", +] + [[package]] name = "serde_derive" version = "1.0.177" @@ -6468,6 +6761,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" +dependencies = [ + "maybe-uninit", +] + [[package]] name = "smallvec" version = "1.11.0" @@ -6593,9 +6895,9 @@ dependencies = [ [[package]] name = "ssz_rs" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f923762d556417668b192ac2fdc9827ea21e6df011d8a0a7e68f3d5da095a675" +checksum = "057291e5631f280978fa9c8009390663ca4613359fc1318e36a8c24c392f6d1f" dependencies = [ "bitvec 1.0.1", "hex", @@ -6603,14 +6905,13 @@ dependencies = [ "serde", "sha2 0.9.9", "ssz_rs_derive", - "thiserror", ] [[package]] name = "ssz_rs_derive" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c679ebd9c1ceeb0f9e5b839952b4a71bfe35a791b431ef7b3ee0b71b7588b565" +checksum = "f07d54c4d01a1713eb363b55ba51595da15f6f1211435b71466460da022aa140" dependencies = [ "proc-macro2", "quote", @@ -7048,6 +7349,7 @@ dependencies = [ "futures-io", "futures-sink", "pin-project-lite", + "slab", "tokio", "tracing", ] @@ -7251,10 +7553,14 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex", "sharded-slab", - "smallvec", + "smallvec 1.11.0", "thread_local", + "tracing", "tracing-core", "tracing-log", ] @@ -7286,7 +7592,7 @@ dependencies = [ "ipnet", "lazy_static", "rand 0.8.5", - "smallvec", + "smallvec 1.11.0", "socket2 0.4.9", "thiserror", "tinyvec", @@ -7308,7 +7614,7 @@ dependencies = [ "lru-cache", "parking_lot 0.12.1", "resolv-conf", - "smallvec", + "smallvec 1.11.0", "thiserror", "tokio", "tracing", diff --git a/crates/p2p/Cargo.toml b/crates/p2p/Cargo.toml index bfadb50b..50759686 100644 --- a/crates/p2p/Cargo.toml +++ b/crates/p2p/Cargo.toml @@ -20,9 +20,9 @@ ethereum_ssz_derive = "0.5.0" snap = "1" silius-primitives = { path = "../primitives" } silius-uopool = {path = "../uopool"} - +discv5 = {version = "0.3.0", features = ["libp2p"]} +tokio = { workspace = true } [dependencies.libp2p] version = "0.51.3" -default-features = false features = [ "identify", "mplex", "yamux", "noise", "gossipsub", "dns", "tcp", "tokio", "secp256k1", "macros", "request-response"] diff --git a/crates/p2p/src/behaviour.rs b/crates/p2p/src/behaviour.rs index 5ddf7e62..04de3158 100644 --- a/crates/p2p/src/behaviour.rs +++ b/crates/p2p/src/behaviour.rs @@ -1,5 +1,10 @@ +use crate::config::Config; +use crate::discovery::{self, Discovery}; +use crate::enr::{build_enr, CombineKeyPubExt}; use crate::gossipsub::Gossipsub; -use crate::reqrep::reqrep::{BundlerRequestResponse, Request, Response}; +use crate::reqrep::protocol::SUPPORTED_PROTOCOL; +use crate::reqrep::{BundlerCodec, BundlerRequestResponse, Request, Response}; +use discv5::enr::CombinedKey; use libp2p::gossipsub; use libp2p::request_response; use libp2p::swarm::NetworkBehaviour; @@ -9,11 +14,34 @@ use libp2p::swarm::NetworkBehaviour; pub struct Behaviour { gossipsub: Gossipsub, reqrep: BundlerRequestResponse, + discv5: Discovery, +} + +impl Behaviour { + pub fn new(key: CombinedKey, config: Config) -> anyhow::Result { + let enr = build_enr(&key, &config)?; + let gossipsub = Gossipsub::new( + gossipsub::MessageAuthenticity::Author(enr.public_key().to_peer_id()?), + gossipsub::Config::default(), + ) + .map_err(|e| anyhow::anyhow!(e))?; + let reqrep = BundlerRequestResponse::new( + BundlerCodec {}, + SUPPORTED_PROTOCOL.clone().into_iter(), + request_response::Config::default(), + ); + let discovery = Discovery::new(enr, key, config)?; + Ok(Self { + gossipsub, + reqrep, + discv5: discovery, + }) + } } impl From for Event { fn from(value: gossipsub::Event) -> Self { - Event::GossipSub(value) + Event::GossipSub(Box::new(value)) } } @@ -23,8 +51,15 @@ impl From> for Event { } } +impl From for Event { + fn from(_value: discovery::Event) -> Self { + Event::Discovery(discovery::Event::Nothing) + } +} + #[derive(Debug)] pub enum Event { - GossipSub(gossipsub::Event), + GossipSub(Box), Reqrep(request_response::Event), + Discovery(discovery::Event), } diff --git a/crates/p2p/src/config.rs b/crates/p2p/src/config.rs new file mode 100644 index 00000000..942e9712 --- /dev/null +++ b/crates/p2p/src/config.rs @@ -0,0 +1,60 @@ +use std::net::{Ipv4Addr, Ipv6Addr}; + +use discv5::ListenConfig; + +const DEFAULT_UDP_PORT: u16 = 9000; + +pub struct Config { + /// The ipv4 address to broadcast to peers about which address we are listening on. + pub ipv4_addr: Option, + + /// The ipv6 address to broadcast to peers about which address we are listening on. + pub ipv6_addr: Option, + + /// The udp4 port to broadcast to peers in order to reach back for discovery. + pub enr_udp4_port: Option, + + /// The tcp4 port to broadcast to peers in order to reach back for libp2p services. + pub enr_tcp4_port: Option, + + /// The udp6 port to broadcast to peers in order to reach back for discovery. + pub enr_udp6_port: Option, + + /// The tcp6 port to broadcast to peers in order to reach back for libp2p services. + pub enr_tcp6_port: Option, +} + +impl Default for Config { + fn default() -> Self { + Self { + ipv4_addr: Some(Ipv4Addr::UNSPECIFIED), + ipv6_addr: None, + enr_udp4_port: Some(DEFAULT_UDP_PORT), + enr_tcp4_port: None, + enr_udp6_port: None, + enr_tcp6_port: None, + } + } +} + +impl Config { + pub fn to_listen_config(&self) -> ListenConfig { + match (self.ipv4_addr, self.ipv6_addr) { + (None, None) => todo!(), + (None, Some(ip)) => ListenConfig::Ipv6 { + ip, + port: self.enr_udp6_port.unwrap_or(DEFAULT_UDP_PORT), + }, + (Some(ip), None) => ListenConfig::Ipv4 { + ip, + port: self.enr_udp4_port.unwrap_or(DEFAULT_UDP_PORT), + }, + (Some(ipv4), Some(ipv6)) => ListenConfig::DualStack { + ipv4, + ipv4_port: self.enr_udp4_port.unwrap_or(DEFAULT_UDP_PORT), + ipv6, + ipv6_port: self.enr_udp6_port.unwrap_or(DEFAULT_UDP_PORT), + }, + } + } +} diff --git a/crates/p2p/src/discovery.rs b/crates/p2p/src/discovery.rs index 54158779..4c7ae8d7 100644 --- a/crates/p2p/src/discovery.rs +++ b/crates/p2p/src/discovery.rs @@ -1 +1,51 @@ -pub struct Discovery {} +use std::task::Poll; + +use discv5::{enr::CombinedKey, Discv5, Discv5ConfigBuilder, Enr}; +use libp2p::swarm::{dummy::ConnectionHandler, NetworkBehaviour}; + +use crate::config::Config; + +pub struct Discovery { + pub discovery: Discv5, +} + +impl Discovery { + pub fn new(enr: Enr, key: CombinedKey, config: Config) -> anyhow::Result { + let config = Discv5ConfigBuilder::new(config.to_listen_config()).build(); + let discovery: Discv5<_> = Discv5::new(enr, key, config).map_err(|e| anyhow::anyhow!(e))?; + Ok(Self { discovery }) + } +} + +#[derive(Debug)] +pub enum Event { + Nothing, +} + +impl NetworkBehaviour for Discovery { + type ConnectionHandler = ConnectionHandler; + type OutEvent = Event; + fn new_handler(&mut self) -> Self::ConnectionHandler { + ConnectionHandler + } + + fn addresses_of_peer(&mut self, _: &libp2p::PeerId) -> Vec { + todo!() + } + fn poll( + &mut self, + _cx: &mut std::task::Context<'_>, + _params: &mut impl libp2p::swarm::PollParameters, + ) -> Poll>> { + Poll::Pending + } + fn on_swarm_event(&mut self, _event: libp2p::swarm::FromSwarm) {} + + fn on_connection_handler_event( + &mut self, + _peer_id: libp2p::PeerId, + _connection_id: libp2p::swarm::ConnectionId, + _event: libp2p::swarm::THandlerOutEvent, + ) { + } +} diff --git a/crates/p2p/src/enr.rs b/crates/p2p/src/enr.rs new file mode 100644 index 00000000..3241862d --- /dev/null +++ b/crates/p2p/src/enr.rs @@ -0,0 +1,68 @@ +use discv5::{ + enr::{ + k256::{ecdsa::VerifyingKey, CompressedPoint}, + CombinedKey, CombinedPublicKey, EnrBuilder, + }, + Enr, +}; +use libp2p::{ + identity::{secp256k1, Keypair, PublicKey}, + PeerId, +}; + +use crate::config::Config; + +pub fn keypair_to_combine(keypair: Keypair) -> anyhow::Result { + match keypair.try_into_secp256k1() { + Ok(key) => { + let secret = + discv5::enr::k256::ecdsa::SigningKey::from_bytes(&key.secret().to_bytes().into()) + .expect("libp2p key must be valid"); + Ok(CombinedKey::Secp256k1(secret)) + } + Err(_) => anyhow::bail!("libp2p key must be either secp256k1"), + } +} + +pub fn build_enr(enr_key: &CombinedKey, config: &Config) -> anyhow::Result { + let mut enr_builder = EnrBuilder::new("v4"); + if let Some(ip) = config.ipv4_addr { + enr_builder.ip4(ip); + } + if let Some(ip) = config.ipv6_addr { + enr_builder.ip6(ip); + } + if let Some(port) = config.enr_tcp4_port { + enr_builder.tcp4(port); + } + if let Some(port) = config.enr_tcp6_port { + enr_builder.tcp6(port); + } + if let Some(port) = config.enr_udp4_port { + enr_builder.udp4(port); + } + if let Some(port) = config.enr_udp6_port { + enr_builder.udp6(port); + } + + let enr = enr_builder.build(enr_key)?; + Ok(enr) +} + +pub trait CombineKeyPubExt { + fn to_peer_id(&self) -> anyhow::Result; +} + +impl CombineKeyPubExt for CombinedPublicKey { + fn to_peer_id(&self) -> anyhow::Result { + let pub_key: PublicKey = match self { + CombinedPublicKey::Secp256k1(pk) => { + PublicKey::from(secp256k1::PublicKey::try_from_bytes( + <&VerifyingKey as Into>::into(pk).as_slice(), + )?) + } + _ => anyhow::bail!("Only secp256k1 is supported"), + }; + Ok(PeerId::from_public_key(&pub_key)) + } +} diff --git a/crates/p2p/src/gossipsub.rs b/crates/p2p/src/gossipsub.rs index 05b7fcf0..3dea430c 100644 --- a/crates/p2p/src/gossipsub.rs +++ b/crates/p2p/src/gossipsub.rs @@ -31,6 +31,13 @@ impl SnappyTransform { } } } +impl Default for SnappyTransform { + fn default() -> Self { + SnappyTransform { + max_size_per_message: MAX_GOSSIP_SNAP_SIZE, + } + } +} impl DataTransform for SnappyTransform { // Provides the snappy decompression from RawGossipsubMessages diff --git a/crates/p2p/src/lib.rs b/crates/p2p/src/lib.rs index 98dce570..9511f2e8 100644 --- a/crates/p2p/src/lib.rs +++ b/crates/p2p/src/lib.rs @@ -1,18 +1,41 @@ use std::time::Duration; +use behaviour::Behaviour; +use enr::keypair_to_combine; +use enr::CombineKeyPubExt; use libp2p::core::muxing::StreamMuxerBox; use libp2p::core::transport::Boxed; use libp2p::identity::Keypair; use libp2p::noise; +use libp2p::swarm::SwarmBuilder; use libp2p::PeerId; +use libp2p::Swarm; use libp2p::{core, Transport}; pub mod behaviour; +pub mod config; pub mod discovery; +pub mod enr; pub mod gossipsub; pub mod reqrep; -pub fn setup() -> () {} +struct TokioExecutor; +impl libp2p::swarm::Executor for TokioExecutor { + fn exec(&self, future: std::pin::Pin + Send>>) { + tokio::spawn(future); + } +} + +pub fn setup(private_key: Keypair) -> anyhow::Result> { + let transport = build_transport(private_key.clone())?; + let combine_key = keypair_to_combine(private_key)?; + let config = config::Config::default(); + let enr = enr::build_enr(&combine_key, &config)?; + let behaviour = Behaviour::new(combine_key, config)?; + let peer_id = enr.public_key().to_peer_id()?; + + Ok(SwarmBuilder::with_executor(transport, behaviour, peer_id, TokioExecutor).build()) +} pub fn build_transport(private_key: Keypair) -> std::io::Result> { let tcp = libp2p::tcp::tokio::Transport::new(libp2p::tcp::Config::default().nodelay(true)); diff --git a/crates/p2p/src/reqrep/mod.rs b/crates/p2p/src/reqrep/mod.rs index 9d82c33e..f649c713 100644 --- a/crates/p2p/src/reqrep/mod.rs +++ b/crates/p2p/src/reqrep/mod.rs @@ -1,2 +1,281 @@ pub mod protocol; -pub mod reqrep; +use std::io; + +use aa_bundler_primitives::UserOperation; +use async_trait::async_trait; +use libp2p::{ + core::upgrade::read_length_prefixed, + futures::{AsyncRead, AsyncWrite}, + request_response::{self, Codec}, +}; +use ssz_rs::{Bitvector, Deserialize, DeserializeError, List, Serialize, Sized, Vector}; + +use self::protocol::{Protocol, ProtocolId}; + +pub type BundlerRequestResponse = request_response::Behaviour; + +#[derive(Clone)] +pub struct BundlerCodec {} + +#[async_trait] +impl Codec for BundlerCodec { + type Protocol = ProtocolId; + type Request = Request; + type Response = Response; + async fn read_request( + &mut self, + protocol: &Self::Protocol, + io: &mut T, + ) -> io::Result + where + T: AsyncRead + Unpin + Send, + { + let data = read_length_prefixed(io, 1_000_000).await?; + + if data.is_empty() { + return Err(std::io::ErrorKind::UnexpectedEof.into()); + } + let decompressed_data = snap::raw::Decoder::new().decompress_vec(&data)?; + Request::from_ssz_bytes(&decompressed_data, &protocol.message_name).map_err(|_| { + io::Error::new( + io::ErrorKind::InvalidInput, + "Could not read request data {decompressed_data:?}", + ) + }) + } + + async fn read_response( + &mut self, + protocol: &Self::Protocol, + io: &mut T, + ) -> io::Result + where + T: AsyncRead + Unpin + Send, + { + let data = read_length_prefixed(io, 1_000_000).await?; + + if data.is_empty() { + return Err(std::io::ErrorKind::UnexpectedEof.into()); + } + + let decompressed_data = snap::raw::Decoder::new().decompress_vec(&data)?; + + Response::from_ssz_bytes(&decompressed_data, &protocol.message_name).map_err(|_| { + io::Error::new( + io::ErrorKind::InvalidInput, + "Could not read response data {decompressed_data:?}", + ) + }) + } + + async fn write_request( + &mut self, + protocol: &Self::Protocol, + _io: &mut T, + req: Self::Request, + ) -> io::Result<()> + where + T: AsyncWrite + Unpin + Send, + { + let mut buffer = Vec::new(); + match (protocol.message_name, req) { + (Protocol::Goodbye, Request::Goodbye(data)) => { + Into::::into(data).serialize(&mut buffer) + } + (Protocol::MetaData, Request::GetMetaData) => Ok(0usize), + (Protocol::Ping, Request::Ping(data)) => data.serialize(&mut buffer), + (Protocol::Status, Request::Status(data)) => data.serialize(&mut buffer), + (Protocol::PooledUserOpHashes, Request::PooledUserOpHashesReq(data)) => { + data.serialize(&mut buffer) + } + (Protocol::PooledUserOpsByHash, Request::PooledUserOpsByHashReq(data)) => { + data.serialize(&mut buffer) + } + _ => { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Request {req:} is not correspond to the protocol {protocol:}", + )) + } + } + .map_err(|_| { + io::Error::new( + io::ErrorKind::InvalidInput, + "Could not write request data {req:?}", + ) + })?; + Ok(()) + } + + async fn write_response( + &mut self, + protocol: &Self::Protocol, + _io: &mut T, + res: Self::Response, + ) -> io::Result<()> + where + T: AsyncWrite + Unpin + Send, + { + let mut buffer = Vec::new(); + match (protocol.message_name, res) { + (Protocol::Goodbye, Response::Goodbye(data)) => { + Into::::into(data).serialize(&mut buffer) + } + (Protocol::MetaData, Response::MetaData(data)) => data.serialize(&mut buffer), + (Protocol::Ping, Response::Pong(data)) => data.serialize(&mut buffer), + (Protocol::Status, Response::Status(data)) => data.serialize(&mut buffer), + (Protocol::PooledUserOpHashes, Response::PooledUserOpHashes(data)) => { + data.serialize(&mut buffer) + } + (Protocol::PooledUserOpsByHash, Response::PooledUserOpsByHash(data)) => { + data.serialize(&mut buffer) + } + _ => { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Response {req:} is not correspond to the protocol {protocol:}", + )) + } + } + .map_err(|_| { + io::Error::new( + io::ErrorKind::InvalidInput, + "Could not write response data {req:?}", + ) + })?; + Ok(()) + } +} + +#[derive(Debug)] +pub enum Request { + Status(Status), + Goodbye(GoodbyeReason), + Ping(Ping), + GetMetaData, + PooledUserOpHashesReq(PooledUserOpHashesReq), + PooledUserOpsByHashReq(PooledUserOpsByHashReq), +} + +impl Request { + fn from_ssz_bytes(encoding: &[u8], protocol: &Protocol) -> Result { + let req = match protocol { + Protocol::Status => Request::Status(Status::deserialize(encoding)?), + Protocol::Goodbye => { + Request::Goodbye(::deserialize(encoding)?.into()) + } + Protocol::MetaData => Request::GetMetaData, + Protocol::Ping => Request::Ping(Ping::deserialize(encoding)?), + Protocol::PooledUserOpHashes => { + Request::PooledUserOpHashesReq(PooledUserOpHashesReq::deserialize(encoding)?) + } + Protocol::PooledUserOpsByHash => { + Request::PooledUserOpsByHashReq(PooledUserOpsByHashReq::deserialize(encoding)?) + } + }; + Ok(req) + } +} + +#[derive(ssz_rs_derive::SimpleSerialize, Clone, Debug, PartialEq, Default)] +pub struct Status { + supported_mempool: List<[u8; 32], 1024>, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum GoodbyeReason { + ClientShutdown, + IrrelevantNetwork, + Error, + Unknown(u64), +} + +impl From for GoodbyeReason { + fn from(value: u64) -> Self { + match value { + 1 => GoodbyeReason::ClientShutdown, + 2 => GoodbyeReason::IrrelevantNetwork, + 3 => GoodbyeReason::Error, + _ => GoodbyeReason::Unknown(value), + } + } +} +impl From for u64 { + fn from(value: GoodbyeReason) -> Self { + match value { + GoodbyeReason::ClientShutdown => 1, + GoodbyeReason::IrrelevantNetwork => 2, + GoodbyeReason::Error => 3, + GoodbyeReason::Unknown(v) => v, + } + } +} + +#[derive(ssz_rs_derive::SimpleSerialize, Clone, Debug, PartialEq, Default)] +pub struct Ping { + data: u64, +} + +#[derive(ssz_rs_derive::SimpleSerialize, Clone, Debug, PartialEq, Default)] +pub struct Pong { + data: u64, +} + +#[derive(ssz_rs_derive::SimpleSerialize, Clone, Debug, PartialEq, Default)] +pub struct PooledUserOpHashesReq { + mempool: [u8; 32], + offset: u64, +} + +#[derive(ssz_rs_derive::SimpleSerialize, Clone, Debug, PartialEq, Default)] +pub struct PooledUserOpsByHashReq { + hashes: List, 1024>, +} + +#[derive(ssz_rs_derive::SimpleSerialize, Clone, Debug, PartialEq, Default)] +pub struct MetaData { + seq_number: u64, + mempool_nets: Bitvector<32>, +} + +#[derive(Debug)] +pub enum Response { + Status(Status), + Goodbye(GoodbyeReason), + Pong(Pong), + MetaData(MetaData), + PooledUserOpHashes(PooledUserOpHashes), + PooledUserOpsByHash(PooledUserOpsByHash), +} + +impl Response { + fn from_ssz_bytes(encoding: &[u8], protocol: &Protocol) -> Result { + let resp = match protocol { + Protocol::Status => Response::Status(Status::deserialize(encoding)?), + Protocol::Goodbye => { + Response::Goodbye(::deserialize(encoding)?.into()) + } + Protocol::Ping => Response::Pong(Pong::deserialize(encoding)?), + Protocol::MetaData => Response::MetaData(MetaData::deserialize(encoding)?), + Protocol::PooledUserOpHashes => { + Response::PooledUserOpHashes(PooledUserOpHashes::deserialize(encoding)?) + } + Protocol::PooledUserOpsByHash => { + Response::PooledUserOpsByHash(PooledUserOpsByHash::deserialize(encoding)?) + } + }; + Ok(resp) + } +} + +#[derive(ssz_rs_derive::SimpleSerialize, Clone, Debug, PartialEq, Default)] + +pub struct PooledUserOpHashes { + more_flag: u64, + hashes: List<[u8; 32], 1024>, +} + +#[derive(ssz_rs_derive::SimpleSerialize, Clone, Debug, PartialEq, Default)] +pub struct PooledUserOpsByHash { + hashes: List, +} diff --git a/crates/p2p/src/reqrep/protocol.rs b/crates/p2p/src/reqrep/protocol.rs index aa352831..4ea6e345 100644 --- a/crates/p2p/src/reqrep/protocol.rs +++ b/crates/p2p/src/reqrep/protocol.rs @@ -1,8 +1,45 @@ +use lazy_static::lazy_static; +use libp2p::request_response::{ProtocolName, ProtocolSupport}; use std::fmt::Display; - -use libp2p::request_response::ProtocolName; const PROTOCOL_PREFIX: &str = "/account_abstraction/erc4337/req"; +lazy_static! { + pub static ref SUPPORTED_PROTOCOL: Vec<(ProtocolId, ProtocolSupport)> = vec![ + ( + ProtocolId::new(Protocol::Status, Version::V1, Encoding::SSZSnappy), + ProtocolSupport::Full + ), + ( + ProtocolId::new(Protocol::Goodbye, Version::V1, Encoding::SSZSnappy), + ProtocolSupport::Full + ), + ( + ProtocolId::new(Protocol::Ping, Version::V1, Encoding::SSZSnappy), + ProtocolSupport::Full + ), + ( + ProtocolId::new(Protocol::MetaData, Version::V1, Encoding::SSZSnappy), + ProtocolSupport::Full + ), + ( + ProtocolId::new( + Protocol::PooledUserOpHashes, + Version::V1, + Encoding::SSZSnappy + ), + ProtocolSupport::Full + ), + ( + ProtocolId::new( + Protocol::PooledUserOpsByHash, + Version::V1, + Encoding::SSZSnappy + ), + ProtocolSupport::Full + ), + ]; +} + #[derive(Clone, Debug, Copy)] pub enum Protocol { Status, @@ -43,10 +80,7 @@ pub struct ProtocolId { impl ProtocolId { fn new(message_name: Protocol, version: Version, encoding: Encoding) -> Self { - let protocol_id = format!( - "{}/{}/{}/{}", - PROTOCOL_PREFIX, message_name, version, encoding - ); + let protocol_id = format!("{PROTOCOL_PREFIX}/{message_name}/{version}/{encoding}"); Self { message_name, version, diff --git a/crates/p2p/src/reqrep/reqrep.rs b/crates/p2p/src/reqrep/reqrep.rs deleted file mode 100644 index 75175b77..00000000 --- a/crates/p2p/src/reqrep/reqrep.rs +++ /dev/null @@ -1,281 +0,0 @@ -use std::io; - -use aa_bundler_primitives::UserOperation; -use async_trait::async_trait; -use libp2p::{ - core::upgrade::read_length_prefixed, - futures::{AsyncRead, AsyncWrite}, - request_response::{self, Codec}, -}; -use ssz_rs::{Bitvector, Deserialize, DeserializeError, List, Serialize, Sized, Vector}; -use ssz_rs_derive::SimpleSerialize; - -use super::protocol::{Protocol, ProtocolId}; -pub type BundlerRequestResponse = request_response::Behaviour; - -#[derive(Clone)] -pub struct BundlerCodec {} - -#[async_trait] -impl Codec for BundlerCodec { - type Protocol = ProtocolId; - type Request = Request; - type Response = Response; - async fn read_request( - &mut self, - protocol: &Self::Protocol, - io: &mut T, - ) -> io::Result - where - T: AsyncRead + Unpin + Send, - { - let data = read_length_prefixed(io, 1_000_000).await?; - - if data.is_empty() { - return Err(std::io::ErrorKind::UnexpectedEof.into()); - } - let decompressed_data = snap::raw::Decoder::new().decompress_vec(&data)?; - Request::from_ssz_bytes(&decompressed_data, &protocol.message_name).map_err(|_| { - io::Error::new( - io::ErrorKind::InvalidInput, - "Could not read request data {decompressed_data:?}", - ) - }) - } - - async fn read_response( - &mut self, - protocol: &Self::Protocol, - io: &mut T, - ) -> io::Result - where - T: AsyncRead + Unpin + Send, - { - let data = read_length_prefixed(io, 1_000_000).await?; - - if data.is_empty() { - return Err(std::io::ErrorKind::UnexpectedEof.into()); - } - - let decompressed_data = snap::raw::Decoder::new().decompress_vec(&data)?; - - Response::from_ssz_bytes(&decompressed_data, &protocol.message_name).map_err(|_| { - io::Error::new( - io::ErrorKind::InvalidInput, - "Could not read response data {decompressed_data:?}", - ) - }) - } - - async fn write_request( - &mut self, - protocol: &Self::Protocol, - io: &mut T, - req: Self::Request, - ) -> io::Result<()> - where - T: AsyncWrite + Unpin + Send, - { - let mut buffer = Vec::new(); - match (protocol.message_name, req) { - (Protocol::Goodbye, Request::Goodbye(data)) => { - Into::::into(data).serialize(&mut buffer) - } - (Protocol::MetaData, Request::GetMetaData) => Ok(0usize), - (Protocol::Ping, Request::Ping(data)) => data.serialize(&mut buffer), - (Protocol::Status, Request::Status(data)) => data.serialize(&mut buffer), - (Protocol::PooledUserOpHashes, Request::PooledUserOpHashesReq(data)) => { - data.serialize(&mut buffer) - } - (Protocol::PooledUserOpsByHash, Request::PooledUserOpsByHashReq(data)) => { - data.serialize(&mut buffer) - } - _ => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Request {req:} is not correspond to the protocol {protocol:}", - )) - } - } - .map_err(|_| { - io::Error::new( - io::ErrorKind::InvalidInput, - "Could not write request data {req:?}", - ) - })?; - Ok(()) - } - - async fn write_response( - &mut self, - protocol: &Self::Protocol, - io: &mut T, - res: Self::Response, - ) -> io::Result<()> - where - T: AsyncWrite + Unpin + Send, - { - let mut buffer = Vec::new(); - match (protocol.message_name, res) { - (Protocol::Goodbye, Response::Goodbye(data)) => { - Into::::into(data).serialize(&mut buffer) - } - (Protocol::MetaData, Response::MetaData(data)) => data.serialize(&mut buffer), - (Protocol::Ping, Response::Pong(data)) => data.serialize(&mut buffer), - (Protocol::Status, Response::Status(data)) => data.serialize(&mut buffer), - (Protocol::PooledUserOpHashes, Response::PooledUserOpHashes(data)) => { - data.serialize(&mut buffer) - } - (Protocol::PooledUserOpsByHash, Response::PooledUserOpsByHash(data)) => { - data.serialize(&mut buffer) - } - _ => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Response {req:} is not correspond to the protocol {protocol:}", - )) - } - } - .map_err(|_| { - io::Error::new( - io::ErrorKind::InvalidInput, - "Could not write response data {req:?}", - ) - })?; - Ok(()) - } -} - -#[derive(Debug)] -pub enum Request { - Status(Status), - Goodbye(GoodbyeReason), - Ping(Ping), - GetMetaData, - PooledUserOpHashesReq(PooledUserOpHashesReq), - PooledUserOpsByHashReq(PooledUserOpsByHashReq), -} - -impl Request { - fn from_ssz_bytes(encoding: &[u8], protocol: &Protocol) -> Result { - let req = match protocol { - Protocol::Status => Request::Status(Status::deserialize(&encoding)?), - Protocol::Goodbye => { - Request::Goodbye(::deserialize(&encoding)?.into()) - } - Protocol::MetaData => Request::GetMetaData, - Protocol::Ping => Request::Ping(Ping::deserialize(&encoding)?), - Protocol::PooledUserOpHashes => { - Request::PooledUserOpHashesReq(PooledUserOpHashesReq::deserialize(&encoding)?) - } - Protocol::PooledUserOpsByHash => { - Request::PooledUserOpsByHashReq(PooledUserOpsByHashReq::deserialize(&encoding)?) - } - }; - Ok(req) - } -} - -#[derive(SimpleSerialize, Clone, Debug, PartialEq, Default)] -pub struct Status { - supported_mempool: List<[u8; 32], 1024>, -} - -#[derive(Clone, Debug, PartialEq)] -pub enum GoodbyeReason { - ClientShutdown, - IrrelevantNetwork, - Error, - Unknown(u64), -} - -impl From for GoodbyeReason { - fn from(value: u64) -> Self { - match value { - 1 => GoodbyeReason::ClientShutdown, - 2 => GoodbyeReason::IrrelevantNetwork, - 3 => GoodbyeReason::Error, - _ => GoodbyeReason::Unknown(value), - } - } -} - -impl Into for GoodbyeReason { - fn into(self) -> u64 { - match self { - GoodbyeReason::ClientShutdown => 1, - GoodbyeReason::IrrelevantNetwork => 2, - GoodbyeReason::Error => 3, - GoodbyeReason::Unknown(v) => v, - } - } -} - -#[derive(SimpleSerialize, Clone, Debug, PartialEq, Default)] -pub struct Ping { - data: u64, -} - -#[derive(SimpleSerialize, Clone, Debug, PartialEq, Default)] -pub struct Pong { - data: u64, -} - -#[derive(SimpleSerialize, Clone, Debug, PartialEq, Default)] -pub struct PooledUserOpHashesReq { - mempool: [u8; 32], - offset: u64, -} - -#[derive(SimpleSerialize, Clone, Debug, PartialEq, Default)] -pub struct PooledUserOpsByHashReq { - hashes: List, 1024>, -} - -#[derive(SimpleSerialize, Clone, Debug, PartialEq, Default)] -pub struct MetaData { - seq_number: u64, - mempool_nets: Bitvector<32>, -} - -#[derive(Debug)] -pub enum Response { - Status(Status), - Goodbye(GoodbyeReason), - Pong(Pong), - MetaData(MetaData), - PooledUserOpHashes(PooledUserOpHashes), - PooledUserOpsByHash(PooledUserOpsByHash), -} - -impl Response { - fn from_ssz_bytes(encoding: &[u8], protocol: &Protocol) -> Result { - let resp = match protocol { - Protocol::Status => Response::Status(Status::deserialize(encoding)?), - Protocol::Goodbye => { - Response::Goodbye(::deserialize(encoding)?.into()) - } - Protocol::Ping => Response::Pong(Pong::deserialize(encoding)?), - Protocol::MetaData => Response::MetaData(MetaData::deserialize(encoding)?), - Protocol::PooledUserOpHashes => { - Response::PooledUserOpHashes(PooledUserOpHashes::deserialize(encoding)?) - } - Protocol::PooledUserOpsByHash => { - Response::PooledUserOpsByHash(PooledUserOpsByHash::deserialize(encoding)?) - } - }; - Ok(resp) - } -} - -#[derive(SimpleSerialize, Clone, Debug, PartialEq, Default)] - -pub struct PooledUserOpHashes { - more_flag: u64, - hashes: List<[u8; 32], 1024>, -} - -#[derive(SimpleSerialize, Clone, Debug, PartialEq, Default)] -pub struct PooledUserOpsByHash { - hashes: List, -} diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index cf8bfb00..0a5671a8 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -19,8 +19,8 @@ lazy_static = "1.4.0" rustc-hex = "^2.0.1" serde = "1" serde_json = "1" -ssz_rs = "0.8.0" -ssz_rs_derive = "0.8.0" +ssz_rs = "0.9.0" +ssz_rs_derive = "0.9.0" strum = "0.24" strum_macros = "0.24" tokio = { workspace = true } diff --git a/crates/primitives/src/user_operation.rs b/crates/primitives/src/user_operation.rs index 3f4910fd..31056daf 100644 --- a/crates/primitives/src/user_operation.rs +++ b/crates/primitives/src/user_operation.rs @@ -7,13 +7,11 @@ use ethers::{ }; use rustc_hex::FromHexError; use serde::{Deserialize, Serialize}; -use ssz_rs::{Merkleized, SimpleSerialize, Sized}; -use std::{ - ops::{AddAssign, Deref}, - slice::Windows, - str::FromStr, -}; - +use ssz_rs::{List, Sized}; +use std::{ops::Deref, slice::Windows, str::FromStr}; +const BYTES_PER_LENGTH_OFFSET: usize = 4; +/// This could be increased if we found bigger bytes, the propper value is not sure right now. +const MAXIMUM_SSZ_BYTES_LENGTH: usize = 1024; /// Transaction type for ERC-4337 account abstraction #[derive( Clone, @@ -409,34 +407,12 @@ pub struct UserOperationGasEstimation { pub call_gas_limit: U256, } -fn ssz_pack_u256( - fixed: &mut Vec>>, - fixed_lengths_sum: &mut usize, - variable_lengths: &mut Vec, - value: U256, -) -> Result<(), ssz_rs::SerializeError> { - let mut element_buffer = Vec::with_capacity(32); - <[u64; 4] as ssz_rs::Serialize>::serialize(&value.0, &mut element_buffer)?; - fixed_lengths_sum.add_assign(32); - fixed.push(Some(element_buffer)); - variable_lengths.push(0); - Ok(()) -} - -fn ssz_pack_bytes( - fixed: &mut Vec>>, - fixed_lengths_sum: &mut usize, - variable: &mut Vec>, - variable_lengths: &mut Vec, - value: Bytes, -) { - let size = value.len(); - let mut element: Vec = Vec::with_capacity(size); - element.extend(value.iter()); - fixed.push(None); - fixed_lengths_sum.add_assign(4); - variable_lengths.push(size); - variable.push(element); +fn btyes_to_list( + value: &Bytes, +) -> Result, ssz_rs::SerializeError> { + let data = value.to_vec(); + List::::try_from(data) + .map_err(|(data, _)| ssz_rs::SerializeError::MaximumEncodedLengthReached(data.len())) } impl ssz_rs::Sized for UserOperation { @@ -450,90 +426,19 @@ impl ssz_rs::Sized for UserOperation { impl ssz_rs::Serialize for UserOperation { fn serialize(&self, buffer: &mut Vec) -> Result { - let mut fixed = Vec::new(); - let mut variable = Vec::new(); - let mut variable_lengths = Vec::new(); - let mut fixed_lengths_sum = 0usize; - - // sender - let mut element_buffer = Vec::with_capacity(20); - <[u8; 20] as ssz_rs::Serialize>::serialize(&self.sender.0, &mut element_buffer)?; - fixed_lengths_sum += element_buffer.len(); - fixed.push(Some(element_buffer)); - variable_lengths.push(0); - - ssz_pack_u256( - &mut fixed, - &mut fixed_lengths_sum, - &mut variable_lengths, - self.nonce, - )?; - ssz_pack_bytes( - &mut fixed, - &mut fixed_lengths_sum, - &mut variable, - &mut variable_lengths, - self.init_code.clone(), - ); - ssz_pack_bytes( - &mut fixed, - &mut fixed_lengths_sum, - &mut variable, - &mut variable_lengths, - self.call_data.clone(), - ); - ssz_pack_u256( - &mut fixed, - &mut fixed_lengths_sum, - &mut variable_lengths, - self.call_gas_limit, - )?; - ssz_pack_u256( - &mut fixed, - &mut fixed_lengths_sum, - &mut variable_lengths, - self.verification_gas_limit, - )?; - ssz_pack_u256( - &mut fixed, - &mut fixed_lengths_sum, - &mut variable_lengths, - self.pre_verification_gas, - )?; - ssz_pack_u256( - &mut fixed, - &mut fixed_lengths_sum, - &mut variable_lengths, - self.max_fee_per_gas, - )?; - ssz_pack_u256( - &mut fixed, - &mut fixed_lengths_sum, - &mut variable_lengths, - self.max_priority_fee_per_gas, - )?; - ssz_pack_bytes( - &mut fixed, - &mut fixed_lengths_sum, - &mut variable, - &mut variable_lengths, - self.paymaster_and_data.clone(), - ); - ssz_pack_bytes( - &mut fixed, - &mut fixed_lengths_sum, - &mut variable, - &mut variable_lengths, - self.signature.clone(), - ); - - ssz_rs::__internal::serialize_composite_from_components( - fixed, - variable, - variable_lengths, - fixed_lengths_sum, - buffer, - ) + let mut serializer = ssz_rs::__internal::Serializer::default(); + serializer.with_element(&self.sender.0)?; + serializer.with_element(&self.nonce.0)?; + serializer.with_element(&btyes_to_list(&self.init_code)?)?; + serializer.with_element(&btyes_to_list(&self.call_data)?)?; + serializer.with_element(&self.call_gas_limit.0)?; + serializer.with_element(&self.verification_gas_limit.0)?; + serializer.with_element(&self.pre_verification_gas.0)?; + serializer.with_element(&self.max_fee_per_gas.0)?; + serializer.with_element(&self.max_priority_fee_per_gas.0)?; + serializer.with_element(&btyes_to_list(&self.paymaster_and_data)?)?; + serializer.with_element(&btyes_to_list(&self.signature)?)?; + serializer.serialize(buffer) } } @@ -678,17 +583,13 @@ impl ssz_rs::Deserialize for UserOperation { } } -impl SimpleSerialize for UserOperation { - fn is_composite_type() -> bool { - true - } -} - -impl Merkleized for UserOperation { +impl ssz_rs::Merkleized for UserOperation { fn hash_tree_root(&mut self) -> Result { - unimplemented!("Merkeized is not needed right now") + unimplemented!() } } + +impl ssz_rs::SimpleSerialize for UserOperation {} #[cfg(test)] mod tests {