mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-09 19:51:47 +00:00
Prevent port re-use in HTTP API tests (#4745)
## Issue Addressed
CI is plagued by `AddrAlreadyInUse` failures, which are caused by race conditions in allocating free ports.
This PR removes all usages of the `unused_port` crate for Lighthouse's HTTP API, in favour of passing `:0` as the listen address. As a result, the listen address isn't known ahead of time and must be read from the listening socket after it binds. This requires tying some self-referential knots, which is a little disruptive, but hopefully doesn't clash too much with Deneb 🤞
There are still a few usages of `unused_tcp4_port` left in cases where we start external processes, like the `watch` Postgres DB, Anvil, Geth, Nethermind, etc. Removing these usages is non-trivial because it's hard to read the port back from an external process after starting it with `--port 0`. We might be able to do something on Linux where we read from `/proc/`, but I'll leave that for future work.
This commit is contained in:
@@ -40,6 +40,11 @@ use types::{
|
||||
Uint256,
|
||||
};
|
||||
|
||||
pub type MockBuilderServer = axum::Server<
|
||||
hyper::server::conn::AddrIncoming,
|
||||
axum::routing::IntoMakeService<axum::routing::Router>,
|
||||
>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Operation {
|
||||
FeeRecipient(Address),
|
||||
@@ -170,19 +175,25 @@ impl BidStuff for BuilderBid {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestingBuilder<E: EthSpec> {
|
||||
server: BlindedBlockProviderServer<MockBuilder<E>>,
|
||||
pub builder: MockBuilder<E>,
|
||||
#[derive(Clone)]
|
||||
pub struct MockBuilder<E: EthSpec> {
|
||||
el: ExecutionLayer<E>,
|
||||
beacon_client: BeaconNodeHttpClient,
|
||||
spec: ChainSpec,
|
||||
context: Arc<Context>,
|
||||
val_registration_cache: Arc<RwLock<HashMap<BlsPublicKey, SignedValidatorRegistration>>>,
|
||||
builder_sk: SecretKey,
|
||||
operations: Arc<RwLock<Vec<Operation>>>,
|
||||
invalidate_signatures: Arc<RwLock<bool>>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TestingBuilder<E> {
|
||||
pub fn new(
|
||||
impl<E: EthSpec> MockBuilder<E> {
|
||||
pub fn new_for_testing(
|
||||
mock_el_url: SensitiveUrl,
|
||||
builder_url: SensitiveUrl,
|
||||
beacon_url: SensitiveUrl,
|
||||
spec: ChainSpec,
|
||||
executor: TaskExecutor,
|
||||
) -> Self {
|
||||
) -> (Self, MockBuilderServer) {
|
||||
let file = NamedTempFile::new().unwrap();
|
||||
let path = file.path().into();
|
||||
std::fs::write(&path, hex::encode(DEFAULT_JWT_SECRET)).unwrap();
|
||||
@@ -211,39 +222,13 @@ impl<E: EthSpec> TestingBuilder<E> {
|
||||
spec,
|
||||
context,
|
||||
);
|
||||
let port = builder_url.full.port().unwrap();
|
||||
let host: Ipv4Addr = builder_url
|
||||
.full
|
||||
.host_str()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.parse()
|
||||
.unwrap();
|
||||
let server = BlindedBlockProviderServer::new(host, port, builder.clone());
|
||||
Self { server, builder }
|
||||
let host: Ipv4Addr = Ipv4Addr::LOCALHOST;
|
||||
let port = 0;
|
||||
let provider = BlindedBlockProviderServer::new(host, port, builder.clone());
|
||||
let server = provider.serve();
|
||||
(builder, server)
|
||||
}
|
||||
|
||||
pub async fn run(&self) {
|
||||
let server = self.server.serve();
|
||||
if let Err(err) = server.await {
|
||||
println!("error while listening for incoming: {err}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MockBuilder<E: EthSpec> {
|
||||
el: ExecutionLayer<E>,
|
||||
beacon_client: BeaconNodeHttpClient,
|
||||
spec: ChainSpec,
|
||||
context: Arc<Context>,
|
||||
val_registration_cache: Arc<RwLock<HashMap<BlsPublicKey, SignedValidatorRegistration>>>,
|
||||
builder_sk: SecretKey,
|
||||
operations: Arc<RwLock<Vec<Operation>>>,
|
||||
invalidate_signatures: Arc<RwLock<bool>>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> MockBuilder<E> {
|
||||
pub fn new(
|
||||
el: ExecutionLayer<E>,
|
||||
beacon_client: BeaconNodeHttpClient,
|
||||
|
||||
@@ -31,7 +31,6 @@ impl<T: EthSpec> MockExecutionLayer<T> {
|
||||
None,
|
||||
Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()),
|
||||
spec,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -43,7 +42,6 @@ impl<T: EthSpec> MockExecutionLayer<T> {
|
||||
builder_threshold: Option<u128>,
|
||||
jwt_key: Option<JwtKey>,
|
||||
spec: ChainSpec,
|
||||
builder_url: Option<SensitiveUrl>,
|
||||
) -> Self {
|
||||
let handle = executor.handle().unwrap();
|
||||
|
||||
@@ -65,7 +63,6 @@ impl<T: EthSpec> MockExecutionLayer<T> {
|
||||
|
||||
let config = Config {
|
||||
execution_endpoints: vec![url],
|
||||
builder_url,
|
||||
secret_files: vec![path],
|
||||
suggested_fee_recipient: Some(Address::repeat_byte(42)),
|
||||
builder_profit_threshold: builder_threshold.unwrap_or(DEFAULT_BUILDER_THRESHOLD_WEI),
|
||||
|
||||
@@ -25,7 +25,7 @@ use warp::{http::StatusCode, Filter, Rejection};
|
||||
use crate::EngineCapabilities;
|
||||
pub use execution_block_generator::{generate_pow_block, Block, ExecutionBlockGenerator};
|
||||
pub use hook::Hook;
|
||||
pub use mock_builder::{Context as MockBuilderContext, MockBuilder, Operation, TestingBuilder};
|
||||
pub use mock_builder::{Context as MockBuilderContext, MockBuilder, MockBuilderServer, Operation};
|
||||
pub use mock_execution_layer::MockExecutionLayer;
|
||||
|
||||
pub const DEFAULT_TERMINAL_DIFFICULTY: u64 = 6400;
|
||||
|
||||
Reference in New Issue
Block a user