Set user agent on requests to builder (#4199)

## Issue Addressed

Closes #4185

## Proposed Changes

- Set user agent to `Lighthouse/vX.Y.Z-<commit hash>` by default
- Allow tweaking user agent via `--builder-user-agent "agent"`
This commit is contained in:
Michael Sproul 2023-04-18 02:47:36 +00:00
parent 1d92e3f77c
commit e9a7316f1d
7 changed files with 71 additions and 12 deletions

1
Cargo.lock generated
View File

@ -863,6 +863,7 @@ name = "builder_client"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"eth2", "eth2",
"lighthouse_version",
"reqwest", "reqwest",
"sensitive_url", "sensitive_url",
"serde", "serde",

View File

@ -10,3 +10,4 @@ sensitive_url = { path = "../../common/sensitive_url" }
eth2 = { path = "../../common/eth2" } eth2 = { path = "../../common/eth2" }
serde = { version = "1.0.116", features = ["derive"] } serde = { version = "1.0.116", features = ["derive"] }
serde_json = "1.0.58" serde_json = "1.0.58"
lighthouse_version = { path = "../../common/lighthouse_version" }

View File

@ -17,6 +17,9 @@ pub const DEFAULT_TIMEOUT_MILLIS: u64 = 15000;
/// This timeout is in accordance with v0.2.0 of the [builder specs](https://github.com/flashbots/mev-boost/pull/20). /// This timeout is in accordance with v0.2.0 of the [builder specs](https://github.com/flashbots/mev-boost/pull/20).
pub const DEFAULT_GET_HEADER_TIMEOUT_MILLIS: u64 = 1000; pub const DEFAULT_GET_HEADER_TIMEOUT_MILLIS: u64 = 1000;
/// Default user agent for HTTP requests.
pub const DEFAULT_USER_AGENT: &str = lighthouse_version::VERSION;
#[derive(Clone)] #[derive(Clone)]
pub struct Timeouts { pub struct Timeouts {
get_header: Duration, get_header: Duration,
@ -41,23 +44,23 @@ pub struct BuilderHttpClient {
client: reqwest::Client, client: reqwest::Client,
server: SensitiveUrl, server: SensitiveUrl,
timeouts: Timeouts, timeouts: Timeouts,
user_agent: String,
} }
impl BuilderHttpClient { impl BuilderHttpClient {
pub fn new(server: SensitiveUrl) -> Result<Self, Error> { pub fn new(server: SensitiveUrl, user_agent: Option<String>) -> Result<Self, Error> {
let user_agent = user_agent.unwrap_or(DEFAULT_USER_AGENT.to_string());
let client = reqwest::Client::builder().user_agent(&user_agent).build()?;
Ok(Self { Ok(Self {
client: reqwest::Client::new(), client,
server, server,
timeouts: Timeouts::default(), timeouts: Timeouts::default(),
user_agent,
}) })
} }
pub fn new_with_timeouts(server: SensitiveUrl, timeouts: Timeouts) -> Result<Self, Error> { pub fn get_user_agent(&self) -> &str {
Ok(Self { &self.user_agent
client: reqwest::Client::new(),
server,
timeouts,
})
} }
async fn get_with_timeout<T: DeserializeOwned, U: IntoUrl>( async fn get_with_timeout<T: DeserializeOwned, U: IntoUrl>(

View File

@ -230,6 +230,8 @@ pub struct Config {
pub execution_endpoints: Vec<SensitiveUrl>, pub execution_endpoints: Vec<SensitiveUrl>,
/// Endpoint urls for services providing the builder api. /// Endpoint urls for services providing the builder api.
pub builder_url: Option<SensitiveUrl>, pub builder_url: Option<SensitiveUrl>,
/// User agent to send with requests to the builder API.
pub builder_user_agent: Option<String>,
/// JWT secrets for the above endpoints running the engine api. /// JWT secrets for the above endpoints running the engine api.
pub secret_files: Vec<PathBuf>, pub secret_files: Vec<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
@ -260,6 +262,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
let Config { let Config {
execution_endpoints: urls, execution_endpoints: urls,
builder_url, builder_url,
builder_user_agent,
secret_files, secret_files,
suggested_fee_recipient, suggested_fee_recipient,
jwt_id, jwt_id,
@ -320,12 +323,17 @@ impl<T: EthSpec> ExecutionLayer<T> {
let builder = builder_url let builder = builder_url
.map(|url| { .map(|url| {
let builder_client = BuilderHttpClient::new(url.clone()).map_err(Error::Builder); let builder_client = BuilderHttpClient::new(url.clone(), builder_user_agent)
info!(log, .map_err(Error::Builder)?;
info!(
log,
"Connected to external block builder"; "Connected to external block builder";
"builder_url" => ?url, "builder_url" => ?url,
"builder_profit_threshold" => builder_profit_threshold); "builder_profit_threshold" => builder_profit_threshold,
builder_client "local_user_agent" => builder_client.get_user_agent(),
);
Ok::<_, Error>(builder_client)
}) })
.transpose()?; .transpose()?;

View File

@ -1000,6 +1000,15 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
.default_value("0") .default_value("0")
.takes_value(true) .takes_value(true)
) )
.arg(
Arg::with_name("builder-user-agent")
.long("builder-user-agent")
.value_name("STRING")
.help("The HTTP user agent to send alongside requests to the builder URL. The \
default is Lighthouse's version string.")
.requires("builder")
.takes_value(true)
)
.arg( .arg(
Arg::with_name("count-unrealized") Arg::with_name("count-unrealized")
.long("count-unrealized") .long("count-unrealized")

View File

@ -329,6 +329,9 @@ pub fn get_config<E: EthSpec>(
let payload_builder = let payload_builder =
parse_only_one_value(endpoint, SensitiveUrl::parse, "--builder", log)?; parse_only_one_value(endpoint, SensitiveUrl::parse, "--builder", log)?;
el_config.builder_url = Some(payload_builder); el_config.builder_url = Some(payload_builder);
el_config.builder_user_agent =
clap_utils::parse_optional(cli_args, "builder-user-agent")?;
} }
// Set config values from parse values. // Set config values from parse values.

View File

@ -716,6 +716,40 @@ fn builder_fallback_flags() {
); );
} }
#[test]
fn builder_user_agent() {
run_payload_builder_flag_test_with_config(
"builder",
"http://meow.cats",
None,
None,
|config| {
assert_eq!(
config.execution_layer.as_ref().unwrap().builder_user_agent,
None
);
},
);
run_payload_builder_flag_test_with_config(
"builder",
"http://meow.cats",
Some("builder-user-agent"),
Some("anon"),
|config| {
assert_eq!(
config
.execution_layer
.as_ref()
.unwrap()
.builder_user_agent
.as_ref()
.unwrap(),
"anon"
);
},
);
}
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;