From 412e2255a84c1276b4dfa31a7974be15e5a0f418 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Fri, 20 Dec 2024 17:48:17 +0100 Subject: [PATCH 01/11] Enable random port on --port 0 --- Cargo.lock | 339 +++++++++++++----- Cargo.toml | 1 + crates/starknet-devnet/Cargo.toml | 2 +- crates/starknet-devnet/src/cli.rs | 2 +- crates/starknet-devnet/src/main.rs | 30 +- .../tests/common/background_devnet.rs | 72 ++-- .../starknet-devnet/tests/common/constants.rs | 4 +- crates/starknet-devnet/tests/common/errors.rs | 10 +- 8 files changed, 318 insertions(+), 142 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f299a5cb..67621a3b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -329,7 +329,7 @@ checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -368,7 +368,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -505,6 +505,26 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.71.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 2.1.0", + "shlex", + "syn 2.0.90", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -592,7 +612,7 @@ dependencies = [ "starknet_api", "strum 0.25.0", "strum_macros 0.25.3", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -656,9 +676,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -697,7 +717,7 @@ dependencies = [ "hashbrown 0.13.2", "instant", "once_cell", - "thiserror", + "thiserror 1.0.63", "tokio", ] @@ -744,7 +764,7 @@ dependencies = [ "num-bigint", "num-traits 0.2.19", "serde", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -784,7 +804,7 @@ dependencies = [ "log", "salsa", "smol_str", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -808,7 +828,7 @@ dependencies = [ "indoc", "salsa", "smol_str", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -953,7 +973,7 @@ dependencies = [ "salsa", "serde", "smol_str", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1104,7 +1124,7 @@ checksum = "3d55dcf98a6e1a03e0b36129fad4253f9e6666a1746ab9c075d212ba68a4e9c1" dependencies = [ "cairo-lang-debug 2.7.0", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -1116,7 +1136,7 @@ dependencies = [ "cairo-lang-filesystem 1.0.0-rc0", "serde", "smol_str", - "thiserror", + "thiserror 1.0.63", "toml 0.4.10", ] @@ -1130,7 +1150,7 @@ dependencies = [ "cairo-lang-utils 2.7.0", "serde", "smol_str", - "thiserror", + "thiserror 1.0.63", "toml 0.8.19", ] @@ -1162,7 +1182,7 @@ dependencies = [ "sha2", "smol_str", "starknet-types-core", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1235,7 +1255,7 @@ dependencies = [ "serde", "sha3", "smol_str", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1263,7 +1283,7 @@ dependencies = [ "sha3", "smol_str", "starknet-types-core", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1276,7 +1296,7 @@ dependencies = [ "cairo-lang-sierra 1.0.0-rc0", "cairo-lang-utils 1.0.0-rc0", "itertools 0.10.5", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1292,7 +1312,7 @@ dependencies = [ "itertools 0.12.1", "num-bigint", "num-traits 0.2.19", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1305,7 +1325,7 @@ dependencies = [ "cairo-lang-sierra 1.0.0-rc0", "cairo-lang-utils 1.0.0-rc0", "itertools 0.10.5", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1321,7 +1341,7 @@ dependencies = [ "itertools 0.12.1", "num-bigint", "num-traits 0.2.19", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1395,7 +1415,7 @@ dependencies = [ "log", "num-bigint", "num-traits 0.2.19", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1416,7 +1436,7 @@ dependencies = [ "num-bigint", "num-traits 0.2.19", "starknet-types-core", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1467,7 +1487,7 @@ dependencies = [ "serde_json", "sha3", "smol_str", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1498,7 +1518,7 @@ dependencies = [ "serde_json", "smol_str", "starknet-types-core", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1522,7 +1542,7 @@ dependencies = [ "sha3", "smol_str", "starknet-types-core", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1538,7 +1558,7 @@ dependencies = [ "num-traits 0.2.19", "salsa", "smol_str", - "thiserror", + "thiserror 1.0.63", "unescaper", ] @@ -1686,7 +1706,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1706,6 +1726,15 @@ dependencies = [ "shlex", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -1735,6 +1764,17 @@ dependencies = [ "inout", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "2.34.0" @@ -1777,7 +1817,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -1799,7 +1839,7 @@ dependencies = [ "k256", "serde", "sha2", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1815,7 +1855,7 @@ dependencies = [ "pbkdf2 0.12.2", "rand", "sha2", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -1835,7 +1875,7 @@ dependencies = [ "serde_derive", "sha2", "sha3", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -2133,7 +2173,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -2155,7 +2195,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -2205,7 +2245,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -2438,7 +2478,7 @@ dependencies = [ "serde_json", "sha2", "sha3", - "thiserror", + "thiserror 1.0.63", "uuid 0.8.2", ] @@ -2455,7 +2495,7 @@ dependencies = [ "serde", "serde_json", "sha3", - "thiserror", + "thiserror 1.0.63", "uint", ] @@ -2534,7 +2574,7 @@ dependencies = [ "pin-project", "serde", "serde_json", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -2556,7 +2596,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "syn 2.0.77", + "syn 2.0.90", "toml 0.8.19", "walkdir", ] @@ -2574,7 +2614,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -2600,9 +2640,9 @@ dependencies = [ "serde", "serde_json", "strum 0.26.3", - "syn 2.0.77", + "syn 2.0.90", "tempfile", - "thiserror", + "thiserror 1.0.63", "tiny-keccak", "unicode-xid", ] @@ -2619,7 +2659,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror", + "thiserror 1.0.63", "tracing", ] @@ -2643,7 +2683,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "thiserror", + "thiserror 1.0.63", "tokio", "tracing", "tracing-futures", @@ -2675,7 +2715,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "thiserror", + "thiserror 1.0.63", "tokio", "tokio-tungstenite", "tracing", @@ -2702,7 +2742,7 @@ dependencies = [ "ethers-core", "rand", "sha2", - "thiserror", + "thiserror 1.0.63", "tracing", ] @@ -2730,7 +2770,7 @@ dependencies = [ "serde_json", "solang-parser", "svm-rs", - "thiserror", + "thiserror 1.0.63", "tiny-keccak", "tokio", "tracing", @@ -2904,7 +2944,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -2975,7 +3015,7 @@ checksum = "553630feadf7b76442b0849fd25fdf89b860d933623aec9693fed19af0400c78" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -3770,9 +3810,19 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "libloading" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] [[package]] name = "libm" @@ -3953,6 +4003,73 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "netlink-packet-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" +dependencies = [ + "anyhow", + "byteorder", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-sock-diag" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a495cb1de50560a7cd12fdcf023db70eec00e340df81be31cedbbfd4aadd6b76" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "byteorder", + "libc", + "netlink-packet-core", + "netlink-packet-utils", + "smallvec", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror 1.0.63", +] + +[[package]] +name = "netlink-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16c903aa70590cb93691bf97a767c8d1d6122d2cc9070433deb3bbf36ce8bd23" +dependencies = [ + "bytes", + "libc", + "log", +] + +[[package]] +name = "netstat2" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6422b6a8c7635e8a82323e4cdf07a90e91901e07f4c1f0f3a245d54b4637e55c" +dependencies = [ + "bindgen", + "bitflags 2.6.0", + "byteorder", + "netlink-packet-core", + "netlink-packet-sock-diag", + "netlink-packet-utils", + "netlink-sys", + "num-derive", + "num-traits 0.2.19", + "thiserror 2.0.8", +] + [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -4013,6 +4130,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -4108,7 +4236,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -4189,7 +4317,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -4428,7 +4556,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -4472,7 +4600,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -4569,7 +4697,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -4597,9 +4725,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -4735,7 +4863,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -5003,6 +5131,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -5126,7 +5260,7 @@ dependencies = [ "log", "oorandom", "parking_lot 0.11.2", - "rustc-hash", + "rustc-hash 1.1.0", "salsa-macros", "smallvec", ] @@ -5225,7 +5359,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -5347,7 +5481,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -5358,7 +5492,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -5443,7 +5577,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -5481,7 +5615,7 @@ checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -5558,7 +5692,7 @@ checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" dependencies = [ "num-bigint", "num-traits 0.2.19", - "thiserror", + "thiserror 1.0.63", "time", ] @@ -5612,7 +5746,7 @@ dependencies = [ "lalrpop 0.20.2", "lalrpop-util 0.20.2", "phf", - "thiserror", + "thiserror 1.0.63", "unicode-xid", ] @@ -5661,7 +5795,7 @@ dependencies = [ "starknet-crypto 0.7.2", "starknet-providers", "starknet-signers", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -5676,7 +5810,7 @@ dependencies = [ "starknet-accounts", "starknet-core", "starknet-providers", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -5765,7 +5899,7 @@ checksum = "bbc159a1934c7be9761c237333a57febe060ace2bc9e3b337a59a37af206d19f" dependencies = [ "starknet-curve 0.4.2", "starknet-ff", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -5807,6 +5941,7 @@ dependencies = [ "ethers", "futures", "lazy_static", + "netstat2", "reqwest 0.12.7", "serde", "serde_json", @@ -5819,7 +5954,7 @@ dependencies = [ "starknet-devnet-types", "starknet-providers", "starknet-signers", - "thiserror", + "thiserror 1.0.63", "tokio", "tracing", "tracing-subscriber", @@ -5850,7 +5985,7 @@ dependencies = [ "starknet-signers", "starknet-types-core", "starknet_api", - "thiserror", + "thiserror 1.0.63", "tracing", "universal-sierra-compiler", "url", @@ -5877,7 +6012,7 @@ dependencies = [ "starknet-core", "starknet-devnet-core", "starknet-devnet-types", - "thiserror", + "thiserror 1.0.63", "tokio", "tower-http", "tracing", @@ -5914,7 +6049,7 @@ dependencies = [ "starknet-crypto 0.7.2", "starknet-types-core", "starknet_api", - "thiserror", + "thiserror 1.0.63", "universal-sierra-compiler", ] @@ -5947,7 +6082,7 @@ dependencies = [ "serde_json", "serde_with", "starknet-core", - "thiserror", + "thiserror 1.0.63", "url", ] @@ -5965,7 +6100,7 @@ dependencies = [ "rand", "starknet-core", "starknet-crypto 0.7.2", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -6004,7 +6139,7 @@ dependencies = [ "starknet-types-core", "strum 0.24.1", "strum_macros 0.24.3", - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -6082,7 +6217,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -6095,7 +6230,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -6119,7 +6254,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "thiserror", + "thiserror 1.0.63", "url", "zip", ] @@ -6137,9 +6272,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -6257,7 +6392,16 @@ version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.63", +] + +[[package]] +name = "thiserror" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f5383f3e0071702bf93ab5ee99b52d26936be9dedd9413067cbdcddcb6141a" +dependencies = [ + "thiserror-impl 2.0.8", ] [[package]] @@ -6268,7 +6412,18 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f357fcec90b3caef6623a099691be676d033b40a058ac95d2a6ade6fa0c943" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -6394,7 +6549,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -6578,7 +6733,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -6651,7 +6806,7 @@ dependencies = [ "rand", "rustls 0.21.12", "sha1", - "thiserror", + "thiserror 1.0.63", "url", "utf-8", ] @@ -6686,7 +6841,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c878a167baa8afd137494101a688ef8c67125089ff2249284bd2b5f9bfedb815" dependencies = [ - "thiserror", + "thiserror 1.0.63", ] [[package]] @@ -6898,7 +7053,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", "wasm-bindgen-shared", ] @@ -6932,7 +7087,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7209,7 +7364,7 @@ dependencies = [ "pharos", "rustc_version", "send_wrapper 0.6.0", - "thiserror", + "thiserror 1.0.63", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -7263,7 +7418,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] @@ -7283,7 +7438,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.90", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e7295bbfa..546cad7ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -115,6 +115,7 @@ parking_lot = "0.12.3" serial_test = "3.1.1" hex = "0.4.3" lazy_static = { version = "1.4.0" } +netstat2 = "0.11.1" # Benchmarking criterion = { version = "0.3.4", features = ["async_tokio"] } diff --git a/crates/starknet-devnet/Cargo.toml b/crates/starknet-devnet/Cargo.toml index db12f8807..e61885c81 100644 --- a/crates/starknet-devnet/Cargo.toml +++ b/crates/starknet-devnet/Cargo.toml @@ -53,7 +53,7 @@ usc = { workspace = true } reqwest = { workspace = true } criterion = { workspace = true } serial_test = { workspace = true } - +netstat2 = { workspace = true } [[bench]] name = "mint_bench" diff --git a/crates/starknet-devnet/src/cli.rs b/crates/starknet-devnet/src/cli.rs index 6d5dd7e51..89cb827f9 100644 --- a/crates/starknet-devnet/src/cli.rs +++ b/crates/starknet-devnet/src/cli.rs @@ -85,7 +85,7 @@ pub(crate) struct Args { #[arg(env = "PORT")] #[arg(value_name = "PORT")] #[arg(default_value_t = DEVNET_DEFAULT_PORT)] - #[arg(help = "Specify the port to listen at;")] + #[arg(help = "Specify the port to listen at; If 0, looks for a free random port;")] port: u16, // Set start time in seconds diff --git a/crates/starknet-devnet/src/main.rs b/crates/starknet-devnet/src/main.rs index 6c69d22d0..41673e1cb 100644 --- a/crates/starknet-devnet/src/main.rs +++ b/crates/starknet-devnet/src/main.rs @@ -1,4 +1,5 @@ use std::future::IntoFuture; +use std::net::IpAddr; use std::result::Result::Ok; use std::time::Duration; @@ -240,6 +241,32 @@ pub async fn set_and_log_fork_config( Ok(()) } +/// Finds a free port if `specified_port` is 0. The returned listener reference must not be dropped +/// in order to keep the port reserved by the current process. +async fn get_listener( + host: IpAddr, + specified_port: u16, +) -> Result<(String, TcpListener), anyhow::Error> { + if specified_port == 0 { + // if specified port == 0, find a free one + for candidate_port in 1025..=65_535 { + if let Ok(listener) = TcpListener::bind((host, candidate_port)).await { + let address = format!("{host}:{candidate_port}"); + return Ok((address, listener)); + } + // otherwise port is occupied + } + Err(anyhow::Error::msg( + "No free ports! Try using `--port` to specify a port you expect to be free.", + )) + } else { + let listener = + TcpListener::bind((host, specified_port)).await.map_err(anyhow::Error::from)?; + let address = format!("{host}:{specified_port}"); + Ok((address, listener)) + } +} + #[tokio::main] async fn main() -> Result<(), anyhow::Error> { configure_tracing(); @@ -261,8 +288,7 @@ async fn main() -> Result<(), anyhow::Error> { starknet_config.chain_id = json_rpc_client.chain_id().await?.into(); } - let address = format!("{}:{}", server_config.host, server_config.port); - let listener = TcpListener::bind(address.clone()).await?; + let (address, listener) = get_listener(server_config.host, server_config.port).await?; let starknet = Starknet::new(&starknet_config)?; let api = Api::new(starknet); diff --git a/crates/starknet-devnet/tests/common/background_devnet.rs b/crates/starknet-devnet/tests/common/background_devnet.rs index de90fadfe..ac153e57a 100644 --- a/crates/starknet-devnet/tests/common/background_devnet.rs +++ b/crates/starknet-devnet/tests/common/background_devnet.rs @@ -1,10 +1,10 @@ use std::collections::HashMap; use std::fmt::LowerHex; -use std::net::TcpListener; use std::process::{Child, Command, Stdio}; use std::time; use lazy_static::lazy_static; +use netstat2::{get_sockets_info, AddressFamilyFlags, ProtocolFlags}; use reqwest::{Client, StatusCode}; use serde_json::json; use server::rpc_core::error::{ErrorCode, RpcError}; @@ -20,26 +20,15 @@ use starknet_rs_providers::{JsonRpcClient, Provider}; use starknet_rs_signers::{LocalWallet, SigningKey}; use starknet_types::felt::felt_from_prefixed_hex; use starknet_types::rpc::transaction_receipt::FeeUnit; -use tokio::sync::Mutex; use url::Url; use super::constants::{ - ACCOUNTS, HEALTHCHECK_PATH, HOST, MAX_PORT, MIN_PORT, PREDEPLOYED_ACCOUNT_INITIAL_BALANCE, - RPC_PATH, SEED, + ACCOUNTS, HEALTHCHECK_PATH, HOST, PREDEPLOYED_ACCOUNT_INITIAL_BALANCE, RPC_PATH, SEED, }; use super::errors::TestError; use super::reqwest_client::{PostReqwestSender, ReqwestClient}; use super::utils::{to_hex_felt, ImpersonationAction}; -lazy_static! { - /// This is to prevent TOCTOU errors; i.e. one background devnet might find one - /// port to be free, and while it's trying to start listening to it, another instance - /// finds that it's free and tries occupying it - /// Using the mutex in `get_free_port_listener` might be safer than using no mutex at all, - /// but not sufficiently safe - static ref BACKGROUND_DEVNET_MUTEX: Mutex<()> = Mutex::new(()); -} - #[derive(Debug)] pub struct BackgroundDevnet { reqwest_client: ReqwestClient, @@ -50,14 +39,16 @@ pub struct BackgroundDevnet { rpc_url: Url, } -fn get_free_port() -> Result { - for port in MIN_PORT..=MAX_PORT { - if let Ok(listener) = TcpListener::bind(("127.0.0.1", port)) { - return Ok(listener.local_addr().expect("No local addr").port()); - } - // otherwise port is occupied - } - Err(TestError::NoFreePorts) +/// Returns the ports used by process identified by `pid`. +fn get_ports_by_pid(pid: u32) -> Result, anyhow::Error> { + let af_flags = AddressFamilyFlags::IPV4 | AddressFamilyFlags::IPV6; + let sockets = get_sockets_info(af_flags, ProtocolFlags::TCP)?; + + let ports = sockets + .into_iter() + .filter_map(|socket| socket.associated_pids.contains(&pid).then_some(socket.local_port())) + .collect(); + Ok(ports) } lazy_static! { @@ -114,39 +105,42 @@ impl BackgroundDevnet { } pub(crate) async fn spawn_with_additional_args(args: &[&str]) -> Result { - // we keep the reference, otherwise the mutex unlocks immediately - let _mutex_guard = BACKGROUND_DEVNET_MUTEX.lock().await; - - let free_port = get_free_port().expect("No free ports"); - - let devnet_url = format!("http://{HOST}:{free_port}"); - let devnet_rpc_url = Url::parse(format!("{}{RPC_PATH}", devnet_url.as_str()).as_str())?; - let json_rpc_client = JsonRpcClient::new(HttpTransport::new(devnet_rpc_url.clone())); - let process = Command::new("cargo") .arg("run") .arg("--release") .arg("--") - .arg("--port") - .arg(free_port.to_string()) .args(Self::add_default_args(args)) .stdout(Stdio::piped()) // comment this out for complete devnet stdout .spawn() .expect("Could not start background devnet"); - let healthcheck_uri = format!("{}{HEALTHCHECK_PATH}", devnet_url.as_str()).to_string(); let reqwest_client = Client::new(); - let max_retries = 30; for _ in 0..max_retries { + // attempt to get ports used by PID of the spawned subprocess + let port = match get_ports_by_pid(process.id()) { + Ok(ports) => match ports.len() { + 0 => continue, // if no ports, wait a bit more + 1 => ports[0], + _ => return Err(TestError::TooManyPorts(ports)), + }, + Err(e) => return Err(TestError::DevnetNotStartable(e.to_string())), + }; + + // now we know the port; check if it can be used to poll Devnet's endpoint + let devnet_url = format!("http://{HOST}:{port}"); + let devnet_rpc_url = Url::parse(format!("{devnet_url}{RPC_PATH}").as_str())?; + + let healthcheck_uri = format!("{devnet_url}{HEALTHCHECK_PATH}").to_string(); + if let Ok(alive_resp) = reqwest_client.get(&healthcheck_uri).send().await { assert_eq!(alive_resp.status(), StatusCode::OK); - println!("Spawned background devnet at port {free_port}"); + println!("Spawned background devnet at port {port}"); return Ok(BackgroundDevnet { reqwest_client: ReqwestClient::new(devnet_url.clone(), reqwest_client), - json_rpc_client, + json_rpc_client: JsonRpcClient::new(HttpTransport::new(devnet_rpc_url.clone())), process, - port: free_port, + port, url: devnet_url, rpc_url: devnet_rpc_url, }); @@ -157,7 +151,9 @@ impl BackgroundDevnet { tokio::time::sleep(time::Duration::from_millis(500)).await; } - Err(TestError::DevnetNotStartable) + Err(TestError::DevnetNotStartable( + "Before testing, make sure you build Devnet with: `cargo build --release`".into(), + )) } pub async fn send_custom_rpc( diff --git a/crates/starknet-devnet/tests/common/constants.rs b/crates/starknet-devnet/tests/common/constants.rs index 7c657cf97..2ec846c44 100644 --- a/crates/starknet-devnet/tests/common/constants.rs +++ b/crates/starknet-devnet/tests/common/constants.rs @@ -1,9 +1,7 @@ use starknet_core::constants::DEVNET_DEFAULT_INITIAL_BALANCE; use starknet_rs_core::types::Felt; -pub const HOST: &str = "localhost"; -pub const MIN_PORT: u16 = 1025; -pub const MAX_PORT: u16 = 65_535; +pub const HOST: &str = "localhost"; // TODO replace pub const SEED: usize = 42; pub const ACCOUNTS: usize = 3; pub const CHAIN_ID: Felt = starknet_rs_core::chain_id::SEPOLIA; diff --git a/crates/starknet-devnet/tests/common/errors.rs b/crates/starknet-devnet/tests/common/errors.rs index afe8111de..9c1e73e88 100644 --- a/crates/starknet-devnet/tests/common/errors.rs +++ b/crates/starknet-devnet/tests/common/errors.rs @@ -1,17 +1,17 @@ use thiserror::Error; #[derive(Error, Debug)] pub enum TestError { - #[error("No free ports")] - NoFreePorts, - #[error("Could not parse URL")] UrlParseError(#[from] url::ParseError), #[error("Invalid URI")] InvalidUri(#[from] axum::http::uri::InvalidUri), - #[error("Could not start Devnet. Make sure you've built it with: `cargo build --release`")] - DevnetNotStartable, + #[error("Could not start Devnet: {0}")] + DevnetNotStartable(String), + + #[error("Too many ports occupied: {0:?}")] + TooManyPorts(Vec), #[error("Could not start Anvil")] AnvilNotStartable, From bc3614ba5a2f88ed06f3fce9233ec91f5f659f3c Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 23 Dec 2024 10:17:10 +0100 Subject: [PATCH 02/11] Restore mutex in BackgroundDevnet --- .../tests/common/background_devnet.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/starknet-devnet/tests/common/background_devnet.rs b/crates/starknet-devnet/tests/common/background_devnet.rs index ac153e57a..6abeb157f 100644 --- a/crates/starknet-devnet/tests/common/background_devnet.rs +++ b/crates/starknet-devnet/tests/common/background_devnet.rs @@ -20,6 +20,7 @@ use starknet_rs_providers::{JsonRpcClient, Provider}; use starknet_rs_signers::{LocalWallet, SigningKey}; use starknet_types::felt::felt_from_prefixed_hex; use starknet_types::rpc::transaction_receipt::FeeUnit; +use tokio::sync::Mutex; use url::Url; use super::constants::{ @@ -29,6 +30,15 @@ use super::errors::TestError; use super::reqwest_client::{PostReqwestSender, ReqwestClient}; use super::utils::{to_hex_felt, ImpersonationAction}; +lazy_static! { + /// This is to prevent TOCTOU errors; i.e. one background devnet might find one + /// port to be free, and while it's trying to start listening to it, another instance + /// finds that it's free and tries occupying it + /// Using the mutex in `get_free_port_listener` might be safer than using no mutex at all, + /// but not sufficiently safe + static ref BACKGROUND_DEVNET_MUTEX: Mutex<()> = Mutex::new(()); +} + #[derive(Debug)] pub struct BackgroundDevnet { reqwest_client: ReqwestClient, @@ -105,6 +115,10 @@ impl BackgroundDevnet { } pub(crate) async fn spawn_with_additional_args(args: &[&str]) -> Result { + // Necessary to synchronize, otherwise multiple Devnet instances acquire the same port. + // We keep the reference, otherwise the mutex unlocks immediately + let _mutex_guard = BACKGROUND_DEVNET_MUTEX.lock().await; + let process = Command::new("cargo") .arg("run") .arg("--release") From de6662865660c146e4cf4326893f972242a2f519 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 23 Dec 2024 10:24:33 +0100 Subject: [PATCH 03/11] More widespread use of HOST constant (change to 127.0.0.1) --- crates/starknet-devnet/tests/common/background_anvil.rs | 7 +++---- crates/starknet-devnet/tests/common/constants.rs | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/starknet-devnet/tests/common/background_anvil.rs b/crates/starknet-devnet/tests/common/background_anvil.rs index 0a1e777c4..59a576953 100644 --- a/crates/starknet-devnet/tests/common/background_anvil.rs +++ b/crates/starknet-devnet/tests/common/background_anvil.rs @@ -10,6 +10,7 @@ use rand::Rng; use reqwest::StatusCode; use starknet_core::messaging::ethereum::ETH_ACCOUNT_DEFAULT; +use super::constants::HOST; use super::errors::TestError; pub struct BackgroundAnvil { @@ -50,15 +51,13 @@ impl BackgroundAnvil { .spawn() .expect("Could not start background Anvil"); - let address = "127.0.0.1"; - let anvil_url = format!("http://{address}:{port}"); - + let anvil_url = format!("http://{HOST}:{port}"); let client = reqwest::Client::new(); let max_retries = 30; for _ in 0..max_retries { if let Ok(anvil_block_rsp) = send_dummy_request(&client, &anvil_url).await { assert_eq!(anvil_block_rsp.status(), StatusCode::OK); - println!("Spawned background anvil at port {port} ({address})"); + println!("Spawned background anvil at {anvil_url}"); let (provider, provider_signer) = setup_ethereum_provider(&anvil_url).await?; diff --git a/crates/starknet-devnet/tests/common/constants.rs b/crates/starknet-devnet/tests/common/constants.rs index 2ec846c44..88b72e549 100644 --- a/crates/starknet-devnet/tests/common/constants.rs +++ b/crates/starknet-devnet/tests/common/constants.rs @@ -1,7 +1,7 @@ use starknet_core::constants::DEVNET_DEFAULT_INITIAL_BALANCE; use starknet_rs_core::types::Felt; -pub const HOST: &str = "localhost"; // TODO replace +pub const HOST: &str = "127.0.0.1"; pub const SEED: usize = 42; pub const ACCOUNTS: usize = 3; pub const CHAIN_ID: Felt = starknet_rs_core::chain_id::SEPOLIA; From 90a361549086c9a254e84d925119ae7c9fa5b9f2 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 23 Dec 2024 10:32:26 +0100 Subject: [PATCH 04/11] Add random port test --- .../tests/general_integration_tests.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/starknet-devnet/tests/general_integration_tests.rs b/crates/starknet-devnet/tests/general_integration_tests.rs index 77ae16174..7e95678c8 100644 --- a/crates/starknet-devnet/tests/general_integration_tests.rs +++ b/crates/starknet-devnet/tests/general_integration_tests.rs @@ -18,11 +18,19 @@ mod general_integration_tests { use crate::common::utils::{to_hex_felt, UniqueAutoDeletableFile}; #[tokio::test] - /// Asserts that a background instance can be spawned - async fn spawnable() { + async fn background_devnet_can_be_spawned() { BackgroundDevnet::spawn().await.expect("Could not start Devnet"); } + #[tokio::test] + async fn background_devnets_at_different_ports_with_random_acquisition() { + let devnet_args = ["--port", "0"]; + let devnet1 = BackgroundDevnet::spawn_with_additional_args(&devnet_args).await.unwrap(); + let devnet2 = BackgroundDevnet::spawn_with_additional_args(&devnet_args).await.unwrap(); + + assert_ne!(devnet1.url, devnet2.url); + } + #[tokio::test] async fn too_big_request_rejected_via_non_rpc() { let limit = 1_000; From 687908fe6e31a6d853a40a01e395ba3bcfde890f Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 23 Dec 2024 11:38:13 +0100 Subject: [PATCH 05/11] Rely on system to handle port 0; apply port=0 in BackgroundDevnet --- crates/starknet-devnet/src/main.rs | 29 +++++-------------- .../tests/common/background_devnet.rs | 1 + 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/crates/starknet-devnet/src/main.rs b/crates/starknet-devnet/src/main.rs index 41673e1cb..9ac1c48c4 100644 --- a/crates/starknet-devnet/src/main.rs +++ b/crates/starknet-devnet/src/main.rs @@ -241,30 +241,15 @@ pub async fn set_and_log_fork_config( Ok(()) } -/// Finds a free port if `specified_port` is 0. The returned listener reference must not be dropped -/// in order to keep the port reserved by the current process. -async fn get_listener( +async fn bind_port( host: IpAddr, specified_port: u16, ) -> Result<(String, TcpListener), anyhow::Error> { - if specified_port == 0 { - // if specified port == 0, find a free one - for candidate_port in 1025..=65_535 { - if let Ok(listener) = TcpListener::bind((host, candidate_port)).await { - let address = format!("{host}:{candidate_port}"); - return Ok((address, listener)); - } - // otherwise port is occupied - } - Err(anyhow::Error::msg( - "No free ports! Try using `--port` to specify a port you expect to be free.", - )) - } else { - let listener = - TcpListener::bind((host, specified_port)).await.map_err(anyhow::Error::from)?; - let address = format!("{host}:{specified_port}"); - Ok((address, listener)) - } + let binding_address = format!("{host}:{specified_port}"); + let listener = TcpListener::bind(binding_address.clone()).await?; + + let acquired_port = listener.local_addr()?.port(); + Ok((format!("{host}:{acquired_port}"), listener)) } #[tokio::main] @@ -288,7 +273,7 @@ async fn main() -> Result<(), anyhow::Error> { starknet_config.chain_id = json_rpc_client.chain_id().await?.into(); } - let (address, listener) = get_listener(server_config.host, server_config.port).await?; + let (address, listener) = bind_port(server_config.host, server_config.port).await?; let starknet = Starknet::new(&starknet_config)?; let api = Api::new(starknet); diff --git a/crates/starknet-devnet/tests/common/background_devnet.rs b/crates/starknet-devnet/tests/common/background_devnet.rs index 6abeb157f..8ded2de29 100644 --- a/crates/starknet-devnet/tests/common/background_devnet.rs +++ b/crates/starknet-devnet/tests/common/background_devnet.rs @@ -66,6 +66,7 @@ lazy_static! { ("--seed", SEED.to_string()), ("--accounts", ACCOUNTS.to_string()), ("--initial-balance", PREDEPLOYED_ACCOUNT_INITIAL_BALANCE.to_string()), + ("--port", 0.to_string()) ]); } From 7a90c303504831701b65cea5ff414efc2e2245d6 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 23 Dec 2024 11:49:28 +0100 Subject: [PATCH 06/11] Remove mutex in BackgroundDevnet --- .../tests/common/background_devnet.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/crates/starknet-devnet/tests/common/background_devnet.rs b/crates/starknet-devnet/tests/common/background_devnet.rs index 8ded2de29..7e7f63a89 100644 --- a/crates/starknet-devnet/tests/common/background_devnet.rs +++ b/crates/starknet-devnet/tests/common/background_devnet.rs @@ -20,7 +20,6 @@ use starknet_rs_providers::{JsonRpcClient, Provider}; use starknet_rs_signers::{LocalWallet, SigningKey}; use starknet_types::felt::felt_from_prefixed_hex; use starknet_types::rpc::transaction_receipt::FeeUnit; -use tokio::sync::Mutex; use url::Url; use super::constants::{ @@ -30,15 +29,6 @@ use super::errors::TestError; use super::reqwest_client::{PostReqwestSender, ReqwestClient}; use super::utils::{to_hex_felt, ImpersonationAction}; -lazy_static! { - /// This is to prevent TOCTOU errors; i.e. one background devnet might find one - /// port to be free, and while it's trying to start listening to it, another instance - /// finds that it's free and tries occupying it - /// Using the mutex in `get_free_port_listener` might be safer than using no mutex at all, - /// but not sufficiently safe - static ref BACKGROUND_DEVNET_MUTEX: Mutex<()> = Mutex::new(()); -} - #[derive(Debug)] pub struct BackgroundDevnet { reqwest_client: ReqwestClient, @@ -116,10 +106,6 @@ impl BackgroundDevnet { } pub(crate) async fn spawn_with_additional_args(args: &[&str]) -> Result { - // Necessary to synchronize, otherwise multiple Devnet instances acquire the same port. - // We keep the reference, otherwise the mutex unlocks immediately - let _mutex_guard = BACKGROUND_DEVNET_MUTEX.lock().await; - let process = Command::new("cargo") .arg("run") .arg("--release") From 843acbae2b0e70a846d56d43d3a3af3411f9a4ca Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 23 Dec 2024 11:52:00 +0100 Subject: [PATCH 07/11] Refactor send_custom_rpc --- .../tests/common/background_devnet.rs | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/crates/starknet-devnet/tests/common/background_devnet.rs b/crates/starknet-devnet/tests/common/background_devnet.rs index 7e7f63a89..f597a9934 100644 --- a/crates/starknet-devnet/tests/common/background_devnet.rs +++ b/crates/starknet-devnet/tests/common/background_devnet.rs @@ -162,20 +162,15 @@ impl BackgroundDevnet { method: &str, params: serde_json::Value, ) -> Result { - let body_json = if params.is_null() { - json!({ - "jsonrpc": "2.0", - "id": 0, - "method": method - }) - } else { - json!({ - "jsonrpc": "2.0", - "id": 0, - "method": method, - "params": params - }) - }; + let mut body_json = json!({ + "jsonrpc": "2.0", + "id": 0, + "method": method, + }); + + if !params.is_null() { + body_json["params"] = params; + } let json_rpc_result: serde_json::Value = self.reqwest_client().post_json_async(RPC_PATH, body_json).await.map_err(|err| { From 0667916b149b0ac646351d60f39d7372cf2d1ac8 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 23 Dec 2024 12:16:18 +0100 Subject: [PATCH 08/11] Fix test_config --- crates/starknet-devnet/tests/general_integration_tests.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/starknet-devnet/tests/general_integration_tests.rs b/crates/starknet-devnet/tests/general_integration_tests.rs index 7e95678c8..5adc7cf55 100644 --- a/crates/starknet-devnet/tests/general_integration_tests.rs +++ b/crates/starknet-devnet/tests/general_integration_tests.rs @@ -100,7 +100,7 @@ mod general_integration_tests { async fn test_config() { // random values let dump_file = UniqueAutoDeletableFile::new("dummy"); - let mut expected_config = json!({ + let expected_config = json!({ "seed": 1, "total_accounts": 2, "account_contract_class_hash": "0x61dac032f228abef9c6626f995015233097ae253a7f72d68552db02f2971b8f", @@ -120,7 +120,7 @@ mod general_integration_tests { }, "server_config": { "host": "0.0.0.0", - // expected port added after spawning; determined by port-acquiring logic + "port": 0, // default value in tests, config not modified upon finding a free port "timeout": 121, "request_body_size_limit": 1000, "restricted_methods": null, @@ -169,8 +169,6 @@ mod general_integration_tests { .await .unwrap(); - expected_config["server_config"]["port"] = devnet.port.into(); - let fetched_config = devnet.get_config().await; assert_eq!(fetched_config, expected_config); } From e216eb3abb79ec89b3d5c4a23e8dd91a2453c46a Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 23 Dec 2024 13:08:40 +0100 Subject: [PATCH 09/11] Do not early exit on multiple ports in BackgroudDevnet; restore mutex --- .../tests/common/background_devnet.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/starknet-devnet/tests/common/background_devnet.rs b/crates/starknet-devnet/tests/common/background_devnet.rs index f597a9934..42c7f2abe 100644 --- a/crates/starknet-devnet/tests/common/background_devnet.rs +++ b/crates/starknet-devnet/tests/common/background_devnet.rs @@ -20,6 +20,7 @@ use starknet_rs_providers::{JsonRpcClient, Provider}; use starknet_rs_signers::{LocalWallet, SigningKey}; use starknet_types::felt::felt_from_prefixed_hex; use starknet_types::rpc::transaction_receipt::FeeUnit; +use tokio::sync::Mutex; use url::Url; use super::constants::{ @@ -29,6 +30,15 @@ use super::errors::TestError; use super::reqwest_client::{PostReqwestSender, ReqwestClient}; use super::utils::{to_hex_felt, ImpersonationAction}; +lazy_static! { + /// This is to prevent TOCTOU errors; i.e. one background devnet might find one + /// port to be free, and while it's trying to start listening to it, another instance + /// finds that it's free and tries occupying it + /// Using the mutex in `get_free_port_listener` might be safer than using no mutex at all, + /// but not sufficiently safe + static ref BACKGROUND_DEVNET_MUTEX: Mutex<()> = Mutex::new(()); +} + #[derive(Debug)] pub struct BackgroundDevnet { reqwest_client: ReqwestClient, @@ -106,6 +116,8 @@ impl BackgroundDevnet { } pub(crate) async fn spawn_with_additional_args(args: &[&str]) -> Result { + let _mutex_guard = BACKGROUND_DEVNET_MUTEX.lock().await; + let process = Command::new("cargo") .arg("run") .arg("--release") @@ -123,7 +135,7 @@ impl BackgroundDevnet { Ok(ports) => match ports.len() { 0 => continue, // if no ports, wait a bit more 1 => ports[0], - _ => return Err(TestError::TooManyPorts(ports)), + _ => continue, // multiple ports associated with pid when forking }, Err(e) => return Err(TestError::DevnetNotStartable(e.to_string())), }; @@ -136,7 +148,7 @@ impl BackgroundDevnet { if let Ok(alive_resp) = reqwest_client.get(&healthcheck_uri).send().await { assert_eq!(alive_resp.status(), StatusCode::OK); - println!("Spawned background devnet at port {port}"); + println!("Spawned background devnet at {devnet_url}"); return Ok(BackgroundDevnet { reqwest_client: ReqwestClient::new(devnet_url.clone(), reqwest_client), json_rpc_client: JsonRpcClient::new(HttpTransport::new(devnet_rpc_url.clone())), From 56183a25873007e8a04640aed32678810568ae2c Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 23 Dec 2024 13:17:17 +0100 Subject: [PATCH 10/11] Improve CLI docs message [skip ci] --- crates/starknet-devnet/src/cli.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/starknet-devnet/src/cli.rs b/crates/starknet-devnet/src/cli.rs index 89cb827f9..a354d7aa4 100644 --- a/crates/starknet-devnet/src/cli.rs +++ b/crates/starknet-devnet/src/cli.rs @@ -85,7 +85,7 @@ pub(crate) struct Args { #[arg(env = "PORT")] #[arg(value_name = "PORT")] #[arg(default_value_t = DEVNET_DEFAULT_PORT)] - #[arg(help = "Specify the port to listen at; If 0, looks for a free random port;")] + #[arg(help = "Specify the port to listen at; If 0, acquires a random free port and prints it;")] port: u16, // Set start time in seconds From 694181bbbfd73c45bdb59017062a4adb5d8627e5 Mon Sep 17 00:00:00 2001 From: FabijanC Date: Mon, 23 Dec 2024 16:19:24 +0100 Subject: [PATCH 11/11] Extract only listening ports; extend BackgroundDevnet retry time to 30s --- .../tests/common/background_devnet.rs | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/crates/starknet-devnet/tests/common/background_devnet.rs b/crates/starknet-devnet/tests/common/background_devnet.rs index 42c7f2abe..808827719 100644 --- a/crates/starknet-devnet/tests/common/background_devnet.rs +++ b/crates/starknet-devnet/tests/common/background_devnet.rs @@ -4,7 +4,10 @@ use std::process::{Child, Command, Stdio}; use std::time; use lazy_static::lazy_static; -use netstat2::{get_sockets_info, AddressFamilyFlags, ProtocolFlags}; +use netstat2::{ + get_sockets_info, AddressFamilyFlags, ProtocolFlags, ProtocolSocketInfo, TcpSocketInfo, + TcpState, +}; use reqwest::{Client, StatusCode}; use serde_json::json; use server::rpc_core::error::{ErrorCode, RpcError}; @@ -49,6 +52,10 @@ pub struct BackgroundDevnet { rpc_url: Url, } +fn is_socket_tcp_listener(info: &ProtocolSocketInfo) -> bool { + matches!(info, ProtocolSocketInfo::Tcp(TcpSocketInfo { state: TcpState::Listen, .. })) +} + /// Returns the ports used by process identified by `pid`. fn get_ports_by_pid(pid: u32) -> Result, anyhow::Error> { let af_flags = AddressFamilyFlags::IPV4 | AddressFamilyFlags::IPV6; @@ -56,7 +63,9 @@ fn get_ports_by_pid(pid: u32) -> Result, anyhow::Error> { let ports = sockets .into_iter() - .filter_map(|socket| socket.associated_pids.contains(&pid).then_some(socket.local_port())) + .filter(|socket| socket.associated_pids.contains(&pid)) + .filter(|socket| is_socket_tcp_listener(&socket.protocol_socket_info)) + .map(|socket| socket.local_port()) .collect(); Ok(ports) } @@ -66,7 +75,7 @@ lazy_static! { ("--seed", SEED.to_string()), ("--accounts", ACCOUNTS.to_string()), ("--initial-balance", PREDEPLOYED_ACCOUNT_INITIAL_BALANCE.to_string()), - ("--port", 0.to_string()) + ("--port", 0.to_string()) // random port by default ]); } @@ -125,17 +134,17 @@ impl BackgroundDevnet { .args(Self::add_default_args(args)) .stdout(Stdio::piped()) // comment this out for complete devnet stdout .spawn() - .expect("Could not start background devnet"); + .expect("Devnet subprocess should be startable"); let reqwest_client = Client::new(); - let max_retries = 30; + let max_retries = 60; for _ in 0..max_retries { // attempt to get ports used by PID of the spawned subprocess let port = match get_ports_by_pid(process.id()) { Ok(ports) => match ports.len() { 0 => continue, // if no ports, wait a bit more 1 => ports[0], - _ => continue, // multiple ports associated with pid when forking + _ => return Err(TestError::TooManyPorts(ports)), }, Err(e) => return Err(TestError::DevnetNotStartable(e.to_string())), };