mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-07 16:55:46 +00:00
Merge remote-tracking branch 'origin/release-v7.0.0' into unstable
This commit is contained in:
@@ -779,6 +779,7 @@ where
|
|||||||
SensitiveUrl::parse(format!("http://127.0.0.1:{port}").as_str()).unwrap(),
|
SensitiveUrl::parse(format!("http://127.0.0.1:{port}").as_str()).unwrap(),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ pub const DEFAULT_GET_HEADER_TIMEOUT_MILLIS: u64 = 1000;
|
|||||||
/// Default user agent for HTTP requests.
|
/// Default user agent for HTTP requests.
|
||||||
pub const DEFAULT_USER_AGENT: &str = lighthouse_version::VERSION;
|
pub const DEFAULT_USER_AGENT: &str = lighthouse_version::VERSION;
|
||||||
|
|
||||||
|
/// The value we set on the `ACCEPT` http header to indicate a preference for ssz response.
|
||||||
|
pub const PREFERENCE_ACCEPT_VALUE: &str = "application/octet-stream;q=1.0,application/json;q=0.9";
|
||||||
|
/// Only accept json responses.
|
||||||
|
pub const JSON_ACCEPT_VALUE: &str = "application/json";
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Timeouts {
|
pub struct Timeouts {
|
||||||
get_header: Duration,
|
get_header: Duration,
|
||||||
@@ -57,7 +62,12 @@ pub struct BuilderHttpClient {
|
|||||||
server: SensitiveUrl,
|
server: SensitiveUrl,
|
||||||
timeouts: Timeouts,
|
timeouts: Timeouts,
|
||||||
user_agent: String,
|
user_agent: String,
|
||||||
ssz_enabled: Arc<AtomicBool>,
|
/// Only use json for all requests/responses types.
|
||||||
|
disable_ssz: bool,
|
||||||
|
/// Indicates that the `get_header` response had content-type ssz
|
||||||
|
/// so we can set content-type header to ssz to make the `submit_blinded_blocks`
|
||||||
|
/// request.
|
||||||
|
ssz_available: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuilderHttpClient {
|
impl BuilderHttpClient {
|
||||||
@@ -65,6 +75,7 @@ impl BuilderHttpClient {
|
|||||||
server: SensitiveUrl,
|
server: SensitiveUrl,
|
||||||
user_agent: Option<String>,
|
user_agent: Option<String>,
|
||||||
builder_header_timeout: Option<Duration>,
|
builder_header_timeout: Option<Duration>,
|
||||||
|
disable_ssz: bool,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let user_agent = user_agent.unwrap_or(DEFAULT_USER_AGENT.to_string());
|
let user_agent = user_agent.unwrap_or(DEFAULT_USER_AGENT.to_string());
|
||||||
let client = reqwest::Client::builder().user_agent(&user_agent).build()?;
|
let client = reqwest::Client::builder().user_agent(&user_agent).build()?;
|
||||||
@@ -73,7 +84,8 @@ impl BuilderHttpClient {
|
|||||||
server,
|
server,
|
||||||
timeouts: Timeouts::new(builder_header_timeout),
|
timeouts: Timeouts::new(builder_header_timeout),
|
||||||
user_agent,
|
user_agent,
|
||||||
ssz_enabled: Arc::new(false.into()),
|
disable_ssz,
|
||||||
|
ssz_available: Arc::new(false.into()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +136,7 @@ impl BuilderHttpClient {
|
|||||||
|
|
||||||
let Ok(Some(fork_name)) = self.fork_name_from_header(&headers) else {
|
let Ok(Some(fork_name)) = self.fork_name_from_header(&headers) else {
|
||||||
// if no fork version specified, attempt to fallback to JSON
|
// if no fork version specified, attempt to fallback to JSON
|
||||||
self.ssz_enabled.store(false, Ordering::SeqCst);
|
self.ssz_available.store(false, Ordering::SeqCst);
|
||||||
return serde_json::from_slice(&response_bytes).map_err(Error::InvalidJson);
|
return serde_json::from_slice(&response_bytes).map_err(Error::InvalidJson);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -132,7 +144,7 @@ impl BuilderHttpClient {
|
|||||||
|
|
||||||
match content_type {
|
match content_type {
|
||||||
ContentType::Ssz => {
|
ContentType::Ssz => {
|
||||||
self.ssz_enabled.store(true, Ordering::SeqCst);
|
self.ssz_available.store(true, Ordering::SeqCst);
|
||||||
T::from_ssz_bytes_by_fork(&response_bytes, fork_name)
|
T::from_ssz_bytes_by_fork(&response_bytes, fork_name)
|
||||||
.map(|data| ForkVersionedResponse {
|
.map(|data| ForkVersionedResponse {
|
||||||
version: Some(fork_name),
|
version: Some(fork_name),
|
||||||
@@ -142,15 +154,17 @@ impl BuilderHttpClient {
|
|||||||
.map_err(Error::InvalidSsz)
|
.map_err(Error::InvalidSsz)
|
||||||
}
|
}
|
||||||
ContentType::Json => {
|
ContentType::Json => {
|
||||||
self.ssz_enabled.store(false, Ordering::SeqCst);
|
self.ssz_available.store(false, Ordering::SeqCst);
|
||||||
serde_json::from_slice(&response_bytes).map_err(Error::InvalidJson)
|
serde_json::from_slice(&response_bytes).map_err(Error::InvalidJson)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if the most recently received response from the builder had SSZ Content-Type.
|
/// Return `true` if the most recently received response from the builder had SSZ Content-Type.
|
||||||
pub fn is_ssz_enabled(&self) -> bool {
|
/// Return `false` otherwise.
|
||||||
self.ssz_enabled.load(Ordering::SeqCst)
|
/// Also returns `false` if we have explicitly disabled ssz.
|
||||||
|
pub fn is_ssz_available(&self) -> bool {
|
||||||
|
!self.disable_ssz && self.ssz_available.load(Ordering::SeqCst)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_with_timeout<T: DeserializeOwned, U: IntoUrl>(
|
async fn get_with_timeout<T: DeserializeOwned, U: IntoUrl>(
|
||||||
@@ -213,7 +227,7 @@ impl BuilderHttpClient {
|
|||||||
&self,
|
&self,
|
||||||
url: U,
|
url: U,
|
||||||
ssz_body: Vec<u8>,
|
ssz_body: Vec<u8>,
|
||||||
mut headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
) -> Result<Response, Error> {
|
) -> Result<Response, Error> {
|
||||||
let mut builder = self.client.post(url);
|
let mut builder = self.client.post(url);
|
||||||
@@ -221,11 +235,6 @@ impl BuilderHttpClient {
|
|||||||
builder = builder.timeout(timeout);
|
builder = builder.timeout(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
headers.insert(
|
|
||||||
CONTENT_TYPE_HEADER,
|
|
||||||
HeaderValue::from_static(SSZ_CONTENT_TYPE_HEADER),
|
|
||||||
);
|
|
||||||
|
|
||||||
let response = builder
|
let response = builder
|
||||||
.headers(headers)
|
.headers(headers)
|
||||||
.body(ssz_body)
|
.body(ssz_body)
|
||||||
@@ -292,9 +301,21 @@ impl BuilderHttpClient {
|
|||||||
.push("blinded_blocks");
|
.push("blinded_blocks");
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
if let Ok(value) = HeaderValue::from_str(&blinded_block.fork_name_unchecked().to_string()) {
|
headers.insert(
|
||||||
headers.insert(CONSENSUS_VERSION_HEADER, value);
|
CONSENSUS_VERSION_HEADER,
|
||||||
}
|
HeaderValue::from_str(&blinded_block.fork_name_unchecked().to_string())
|
||||||
|
.map_err(|e| Error::InvalidHeaders(format!("{}", e)))?,
|
||||||
|
);
|
||||||
|
headers.insert(
|
||||||
|
CONTENT_TYPE_HEADER,
|
||||||
|
HeaderValue::from_str(SSZ_CONTENT_TYPE_HEADER)
|
||||||
|
.map_err(|e| Error::InvalidHeaders(format!("{}", e)))?,
|
||||||
|
);
|
||||||
|
headers.insert(
|
||||||
|
ACCEPT,
|
||||||
|
HeaderValue::from_str(PREFERENCE_ACCEPT_VALUE)
|
||||||
|
.map_err(|e| Error::InvalidHeaders(format!("{}", e)))?,
|
||||||
|
);
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
.post_ssz_with_raw_response(
|
.post_ssz_with_raw_response(
|
||||||
@@ -326,9 +347,21 @@ impl BuilderHttpClient {
|
|||||||
.push("blinded_blocks");
|
.push("blinded_blocks");
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
if let Ok(value) = HeaderValue::from_str(&blinded_block.fork_name_unchecked().to_string()) {
|
headers.insert(
|
||||||
headers.insert(CONSENSUS_VERSION_HEADER, value);
|
CONSENSUS_VERSION_HEADER,
|
||||||
}
|
HeaderValue::from_str(&blinded_block.fork_name_unchecked().to_string())
|
||||||
|
.map_err(|e| Error::InvalidHeaders(format!("{}", e)))?,
|
||||||
|
);
|
||||||
|
headers.insert(
|
||||||
|
CONTENT_TYPE_HEADER,
|
||||||
|
HeaderValue::from_str(JSON_CONTENT_TYPE_HEADER)
|
||||||
|
.map_err(|e| Error::InvalidHeaders(format!("{}", e)))?,
|
||||||
|
);
|
||||||
|
headers.insert(
|
||||||
|
ACCEPT,
|
||||||
|
HeaderValue::from_str(JSON_ACCEPT_VALUE)
|
||||||
|
.map_err(|e| Error::InvalidHeaders(format!("{}", e)))?,
|
||||||
|
);
|
||||||
|
|
||||||
Ok(self
|
Ok(self
|
||||||
.post_with_raw_response(
|
.post_with_raw_response(
|
||||||
@@ -362,12 +395,20 @@ impl BuilderHttpClient {
|
|||||||
.push(pubkey.as_hex_string().as_str());
|
.push(pubkey.as_hex_string().as_str());
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
if let Ok(ssz_content_type_header) = HeaderValue::from_str(&format!(
|
if self.disable_ssz {
|
||||||
"{}; q=1.0,{}; q=0.9",
|
headers.insert(
|
||||||
SSZ_CONTENT_TYPE_HEADER, JSON_CONTENT_TYPE_HEADER
|
ACCEPT,
|
||||||
)) {
|
HeaderValue::from_str(JSON_CONTENT_TYPE_HEADER)
|
||||||
headers.insert(ACCEPT, ssz_content_type_header);
|
.map_err(|e| Error::InvalidHeaders(format!("{}", e)))?,
|
||||||
};
|
);
|
||||||
|
} else {
|
||||||
|
// Indicate preference for ssz response in the accept header
|
||||||
|
headers.insert(
|
||||||
|
ACCEPT,
|
||||||
|
HeaderValue::from_str(PREFERENCE_ACCEPT_VALUE)
|
||||||
|
.map_err(|e| Error::InvalidHeaders(format!("{}", e)))?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let resp = self
|
let resp = self
|
||||||
.get_with_header(path, self.timeouts.get_header, headers)
|
.get_with_header(path, self.timeouts.get_header, headers)
|
||||||
@@ -395,3 +436,18 @@ impl BuilderHttpClient {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_headers_no_panic() {
|
||||||
|
for fork in ForkName::list_all() {
|
||||||
|
assert!(HeaderValue::from_str(&fork.to_string()).is_ok());
|
||||||
|
}
|
||||||
|
assert!(HeaderValue::from_str(PREFERENCE_ACCEPT_VALUE).is_ok());
|
||||||
|
assert!(HeaderValue::from_str(JSON_ACCEPT_VALUE).is_ok());
|
||||||
|
assert!(HeaderValue::from_str(JSON_CONTENT_TYPE_HEADER).is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -441,6 +441,8 @@ pub struct Config {
|
|||||||
pub builder_header_timeout: Option<Duration>,
|
pub builder_header_timeout: Option<Duration>,
|
||||||
/// User agent to send with requests to the builder API.
|
/// User agent to send with requests to the builder API.
|
||||||
pub builder_user_agent: Option<String>,
|
pub builder_user_agent: Option<String>,
|
||||||
|
/// Disable ssz requests on builder. Only use json.
|
||||||
|
pub disable_builder_ssz_requests: bool,
|
||||||
/// JWT secret for the above endpoint running the engine api.
|
/// JWT secret for the above endpoint running the engine api.
|
||||||
pub secret_file: Option<PathBuf>,
|
pub secret_file: Option<PathBuf>,
|
||||||
/// The default fee recipient to use on the beacon node if none if provided from
|
/// The default fee recipient to use on the beacon node if none if provided from
|
||||||
@@ -470,6 +472,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
|||||||
builder_url,
|
builder_url,
|
||||||
builder_user_agent,
|
builder_user_agent,
|
||||||
builder_header_timeout,
|
builder_header_timeout,
|
||||||
|
disable_builder_ssz_requests,
|
||||||
secret_file,
|
secret_file,
|
||||||
suggested_fee_recipient,
|
suggested_fee_recipient,
|
||||||
jwt_id,
|
jwt_id,
|
||||||
@@ -539,7 +542,12 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(builder_url) = builder_url {
|
if let Some(builder_url) = builder_url {
|
||||||
el.set_builder_url(builder_url, builder_user_agent, builder_header_timeout)?;
|
el.set_builder_url(
|
||||||
|
builder_url,
|
||||||
|
builder_user_agent,
|
||||||
|
builder_header_timeout,
|
||||||
|
disable_builder_ssz_requests,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(el)
|
Ok(el)
|
||||||
@@ -562,11 +570,13 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
|||||||
builder_url: SensitiveUrl,
|
builder_url: SensitiveUrl,
|
||||||
builder_user_agent: Option<String>,
|
builder_user_agent: Option<String>,
|
||||||
builder_header_timeout: Option<Duration>,
|
builder_header_timeout: Option<Duration>,
|
||||||
|
disable_ssz: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let builder_client = BuilderHttpClient::new(
|
let builder_client = BuilderHttpClient::new(
|
||||||
builder_url.clone(),
|
builder_url.clone(),
|
||||||
builder_user_agent,
|
builder_user_agent,
|
||||||
builder_header_timeout,
|
builder_header_timeout,
|
||||||
|
disable_ssz,
|
||||||
)
|
)
|
||||||
.map_err(Error::Builder)?;
|
.map_err(Error::Builder)?;
|
||||||
info!(
|
info!(
|
||||||
@@ -574,6 +584,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
|||||||
"Using external block builder";
|
"Using external block builder";
|
||||||
"builder_url" => ?builder_url,
|
"builder_url" => ?builder_url,
|
||||||
"local_user_agent" => builder_client.get_user_agent(),
|
"local_user_agent" => builder_client.get_user_agent(),
|
||||||
|
"ssz_disabled" => disable_ssz
|
||||||
);
|
);
|
||||||
self.inner.builder.swap(Some(Arc::new(builder_client)));
|
self.inner.builder.swap(Some(Arc::new(builder_client)));
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1901,7 +1912,14 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
|||||||
if let Some(builder) = self.builder() {
|
if let Some(builder) = self.builder() {
|
||||||
let (payload_result, duration) =
|
let (payload_result, duration) =
|
||||||
timed_future(metrics::POST_BLINDED_PAYLOAD_BUILDER, async {
|
timed_future(metrics::POST_BLINDED_PAYLOAD_BUILDER, async {
|
||||||
if builder.is_ssz_enabled() {
|
let ssz_enabled = builder.is_ssz_available();
|
||||||
|
debug!(
|
||||||
|
self.log(),
|
||||||
|
"Calling submit_blinded_block on builder";
|
||||||
|
"block_root" => ?block_root,
|
||||||
|
"ssz" => ssz_enabled
|
||||||
|
);
|
||||||
|
if ssz_enabled {
|
||||||
builder
|
builder
|
||||||
.post_builder_blinded_blocks_ssz(block)
|
.post_builder_blinded_blocks_ssz(block)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -1460,6 +1460,15 @@ pub fn cli_app() -> Command {
|
|||||||
.action(ArgAction::Set)
|
.action(ArgAction::Set)
|
||||||
.display_order(0)
|
.display_order(0)
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("builder-disable-ssz")
|
||||||
|
.long("builder-disable-ssz")
|
||||||
|
.value_name("BOOLEAN")
|
||||||
|
.help("Disables sending requests using SSZ over the builder API.")
|
||||||
|
.requires("builder")
|
||||||
|
.action(ArgAction::SetTrue)
|
||||||
|
.display_order(0)
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("reset-payload-statuses")
|
Arg::new("reset-payload-statuses")
|
||||||
.long("reset-payload-statuses")
|
.long("reset-payload-statuses")
|
||||||
|
|||||||
@@ -346,6 +346,8 @@ pub fn get_config<E: EthSpec>(
|
|||||||
el_config.builder_header_timeout =
|
el_config.builder_header_timeout =
|
||||||
clap_utils::parse_optional(cli_args, "builder-header-timeout")?
|
clap_utils::parse_optional(cli_args, "builder-header-timeout")?
|
||||||
.map(Duration::from_millis);
|
.map(Duration::from_millis);
|
||||||
|
|
||||||
|
el_config.disable_builder_ssz_requests = cli_args.get_flag("builder-disable-ssz");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set config values from parse values.
|
// Set config values from parse values.
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ Options:
|
|||||||
network. Multiaddr is also supported.
|
network. Multiaddr is also supported.
|
||||||
--builder <builder>
|
--builder <builder>
|
||||||
The URL of a service compatible with the MEV-boost API.
|
The URL of a service compatible with the MEV-boost API.
|
||||||
|
--builder-disable-ssz
|
||||||
|
Disables sending requests using SSZ over the builder API.
|
||||||
--builder-fallback-epochs-since-finalization <builder-fallback-epochs-since-finalization>
|
--builder-fallback-epochs-since-finalization <builder-fallback-epochs-since-finalization>
|
||||||
If this node is proposing a block and the chain has not finalized
|
If this node is proposing a block and the chain has not finalized
|
||||||
within this number of epochs, it will NOT query any connected
|
within this number of epochs, it will NOT query any connected
|
||||||
|
|||||||
@@ -720,6 +720,40 @@ fn builder_user_agent() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_builder_disable_ssz_flag() {
|
||||||
|
run_payload_builder_flag_test_with_config(
|
||||||
|
"builder",
|
||||||
|
"http://meow.cats",
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
|config| {
|
||||||
|
assert!(
|
||||||
|
!config
|
||||||
|
.execution_layer
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.disable_builder_ssz_requests,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
run_payload_builder_flag_test_with_config(
|
||||||
|
"builder",
|
||||||
|
"http://meow.cats",
|
||||||
|
Some("builder-disable-ssz"),
|
||||||
|
None,
|
||||||
|
|config| {
|
||||||
|
assert!(
|
||||||
|
config
|
||||||
|
.execution_layer
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.disable_builder_ssz_requests,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn run_jwt_optional_flags_test(jwt_flag: &str, jwt_id_flag: &str, jwt_version_flag: &str) {
|
fn run_jwt_optional_flags_test(jwt_flag: &str, jwt_id_flag: &str, jwt_version_flag: &str) {
|
||||||
use sensitive_url::SensitiveUrl;
|
use sensitive_url::SensitiveUrl;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user