Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Remove builder redundancy #3294

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
merge unstable, add builder client, add types required by builder cli…
…ent, fix compile errors
  • Loading branch information
realbigsean committed Jun 29, 2022
commit e944326a42129c4992dc7f00a5631120a0a7dd0b
35 changes: 35 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions beacon_node/builder_client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "builder_client"
version = "0.1.0"
edition = "2021"
authors = ["Sean Anderson <sean@sigmaprime.io>"]

[dependencies]
reqwest = { version = "0.11.0", features = ["json","stream"] }
sensitive_url = { path = "../../common/sensitive_url" }
eth2 = { path = "../../common/eth2" }
serde = { version = "1.0.116", features = ["derive"] }
serde_json = "1.0.58"
192 changes: 192 additions & 0 deletions beacon_node/builder_client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
use eth2::ok_or_error;
use eth2::types::builder_bid::SignedBuilderBid;
use eth2::types::{
BlindedPayload, EthSpec, ExecPayload, ExecutionBlockHash, ExecutionPayload,
ForkVersionedResponse, PublicKeyBytes, SignedBeaconBlock, SignedValidatorRegistrationData,
Slot,
};
pub use eth2::Error;
use reqwest::{IntoUrl, Response};
use sensitive_url::SensitiveUrl;
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::time::Duration;

pub const DEFAULT_GET_HEADER_TIMEOUT_MILLIS: u64 = 500;

#[derive(Clone)]
pub struct Timeouts {
get_header: Duration,
}

impl Default for Timeouts {
fn default() -> Self {
Self {
get_header: Duration::from_millis(DEFAULT_GET_HEADER_TIMEOUT_MILLIS),
}
}
}

#[derive(Clone)]
pub struct BuilderHttpClient {
client: reqwest::Client,
server: SensitiveUrl,
timeouts: Timeouts,
}

impl BuilderHttpClient {
pub fn new(server: SensitiveUrl) -> Result<Self, Error> {
Ok(Self {
client: reqwest::Client::new(),
server,
timeouts: Timeouts::default(),
})
}

pub fn new_with_timeouts(server: SensitiveUrl, timeouts: Timeouts) -> Result<Self, Error> {
Ok(Self {
client: reqwest::Client::new(),
server,
timeouts,
})
}

async fn get<T: DeserializeOwned, U: IntoUrl>(&self, url: U) -> Result<T, Error> {
self.get_response_with_timeout(url, None)
.await?
.json()
.await
.map_err(Error::Reqwest)
}

async fn get_with_timeout<T: DeserializeOwned, U: IntoUrl>(
&self,
url: U,
timeout: Duration,
) -> Result<T, Error> {
self.get_response_with_timeout(url, Some(timeout))
.await?
.json()
.await
.map_err(Error::Reqwest)
}

/// Perform a HTTP GET request, returning the `Response` for further processing.
async fn get_response_with_timeout<U: IntoUrl>(
&self,
url: U,
timeout: Option<Duration>,
) -> Result<Response, Error> {
let mut builder = self.client.get(url);
if let Some(timeout) = timeout {
builder = builder.timeout(timeout);
}
let response = builder.send().await.map_err(Error::Reqwest)?;
ok_or_error(response).await
}

/// Generic POST function supporting arbitrary responses and timeouts.
async fn post_generic<T: Serialize, U: IntoUrl>(
&self,
url: U,
body: &T,
timeout: Option<Duration>,
) -> Result<Response, Error> {
let mut builder = self.client.post(url);
if let Some(timeout) = timeout {
builder = builder.timeout(timeout);
}
let response = builder.json(body).send().await?;
ok_or_error(response).await
}

async fn post_with_raw_response<T: Serialize, U: IntoUrl>(
&self,
url: U,
body: &T,
) -> Result<Response, Error> {
let response = self
.client
.post(url)
.json(body)
.send()
.await
.map_err(Error::Reqwest)?;
ok_or_error(response).await
}

/// `POST /eth/v1/builder/validators`
pub async fn post_builder_validators(
&self,
validator: &[SignedValidatorRegistrationData],
) -> Result<(), Error> {
let mut path = self.server.full.clone();

path.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("eth")
.push("v1")
.push("builder")
.push("validators");

self.post_generic(path, &validator, None).await?;
Ok(())
}

/// `POST /eth/v1/builder/blinded_blocks`
pub async fn post_builder_blinded_blocks<E: EthSpec>(
&self,
blinded_block: &SignedBeaconBlock<E, BlindedPayload<E>>,
) -> Result<ForkVersionedResponse<ExecutionPayload<E>>, Error> {
let mut path = self.server.full.clone();

path.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("eth")
.push("v1")
.push("builder")
.push("blinded_blocks");

Ok(self
.post_with_raw_response(path, &blinded_block)
.await?
.json()
.await?)
}

/// `GET /eth/v1/builder/header`
pub async fn get_builder_header<E: EthSpec, Payload: ExecPayload<E>>(
&self,
slot: Slot,
parent_hash: ExecutionBlockHash,
pubkey: &PublicKeyBytes,
) -> Result<ForkVersionedResponse<SignedBuilderBid<E, Payload>>, Error> {
let mut path = self.server.full.clone();

path.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("eth")
.push("v1")
.push("builder")
.push("header")
.push(slot.to_string().as_str())
.push(format!("{parent_hash:?}").as_str())
.push(pubkey.as_hex_string().as_str());

self.get_with_timeout(path, self.timeouts.get_header).await
}

/// `GET /eth/v1/builder/status`
pub async fn get_builder_status<E: EthSpec>(&self) -> Result<(), Error> {
let mut path = self.server.full.clone();

path.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("eth")
.push("v1")
.push("builder")
.push("status");

self.get(path).await
}
}
2 changes: 0 additions & 2 deletions beacon_node/execution_layer/src/engine_api.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use crate::engines::ForkChoiceState;
use async_trait::async_trait;
use eth1::http::RpcError;
pub use ethers_core::types::Transaction;
use http::deposit_methods::RpcError;
pub use json_structures::TransitionConfigurationV1;
Expand Down
1 change: 0 additions & 1 deletion beacon_node/execution_layer/src/engine_api/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ pub const ENGINE_EXCHANGE_TRANSITION_CONFIGURATION_V1: &str =
pub const ENGINE_EXCHANGE_TRANSITION_CONFIGURATION_V1_TIMEOUT: Duration =
Duration::from_millis(500);


/// This error is returned during a `chainId` call by Geth.
pub const EIP155_ERROR_STR: &str = "chain not synced beyond EIP-155 replay-protection fork block";

Expand Down
1 change: 0 additions & 1 deletion beacon_node/execution_layer/src/engines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::engine_api::{
EngineApi, Error as EngineApiError, ForkchoiceUpdatedResponse, PayloadAttributes, PayloadId,
};
use crate::HttpJsonRpc;
use futures::future::join_all;
use lru::LruCache;
use slog::{crit, debug, info, warn, Logger};
use std::future::Future;
Expand Down
40 changes: 28 additions & 12 deletions beacon_node/execution_layer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
//! This crate only provides useful functionality for "The Merge", it does not provide any of the
//! deposit-contract functionality that the `beacon_node/eth1` crate already provides.

use crate::engine_api::Builder;
use crate::engines::Builders;
use auth::{strip_prefix, Auth, JwtKey};
use builder_client::BuilderHttpClient;
use engine_api::Error as ApiError;
Expand Down Expand Up @@ -611,7 +609,34 @@ impl<T: EthSpec> ExecutionLayer<T> {
pubkey_opt: Option<PublicKeyBytes>,
slot: Slot,
) -> Result<Payload, Error> {
todo!("sean")
//FIXME(sean) fallback logic included in PR #3134

// Don't attempt to outsource payload construction until after the merge transition has been
// finalized. We want to be conservative with payload construction until then.
if let (Some(builder), Some(pubkey)) = (self.builder(), pubkey_opt) {
if finalized_block_hash != ExecutionBlockHash::zero() {
info!(
self.log(),
"Requesting blinded header from connected builder";
"slot" => ?slot,
"pubkey" => ?pubkey,
"parent_hash" => ?parent_hash,
);
return builder
.get_builder_header::<T, Payload>(slot, parent_hash, &pubkey)
.await
.map(|d| d.data.message.header)
.map_err(Error::Builder);
}
}
self.get_full_payload::<Payload>(
parent_hash,
timestamp,
prev_randao,
finalized_block_hash,
suggested_fee_recipient,
)
.await
}

/// Get a full payload without caching its result in the execution layer's payload cache.
Expand Down Expand Up @@ -1337,15 +1362,6 @@ mod test {
})
.await;
}

// test fallback

// test normal flow used when
// - merge hasn't finalized
// - bad chain health (finalization not advancing?)
// - gas_limit not what you sent builder
// - fee recipient not what you sent builder
// - timeout?
}

fn noop<T: EthSpec>(_: &ExecutionLayer<T>, _: &ExecutionPayload<T>) -> Option<ExecutionPayload<T>> {
Expand Down
4 changes: 2 additions & 2 deletions beacon_node/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,8 @@ pub fn get_config<E: EthSpec>(
// Parse and set the payload builder, if any.
if let Some(endpoint) = cli_args.value_of("builder") {
let payload_builder =
parse_only_one_value(endpoints, SensitiveUrl::parse, "--builder", log)?;
el_config.builder_url = payload_builder;
parse_only_one_value(endpoint, SensitiveUrl::parse, "--builder", log)?;
el_config.builder_url = Some(payload_builder);
}

// Set config values from parse values.
Expand Down
Loading