diff --git a/crates/rbuilder-primitives/src/mev_boost/mod.rs b/crates/rbuilder-primitives/src/mev_boost/mod.rs index c0751edc2..158412b8c 100644 --- a/crates/rbuilder-primitives/src/mev_boost/mod.rs +++ b/crates/rbuilder-primitives/src/mev_boost/mod.rs @@ -183,7 +183,7 @@ pub struct ValidatorSlotData { pub regional_endpoints: Vec, /// (Titan) Validator preferences. #[serde(default)] - pub preferences: Option, + pub preferences: Option, } /// Bloxroute validator RProxy details. @@ -201,6 +201,36 @@ pub struct BloxrouteRegionalEndpoint { pub websocket_endpoint: String, } +/// Relay validator preferences. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Hash)] +#[serde(untagged)] +pub enum ValidatorPreferences { + Ultrasound(UltrasoundValidatorPreferences), + Titan(TitanValidatorPreferences), +} + +impl ValidatorPreferences { + /// Returns [`TitanValidatorPreferences`] if the variant matches. + pub fn as_titan(&self) -> Option<&TitanValidatorPreferences> { + if let Self::Titan(preferences) = self { + Some(preferences) + } else { + None + } + } +} + +/// Ultrasound validator preferences. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Hash)] +pub struct UltrasoundValidatorPreferences { + /// Indicator whether the validator is filtering. Values: "none", "ofac". + filtering: String, + /// Flag indicating whether the validator is integrated with MEV Protect. + is_mev_protect: bool, + /// Flag indicating whether the validator is integrated with Primev. + is_primev: bool, +} + /// Titan validator preferences. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] pub struct TitanValidatorPreferences { @@ -292,6 +322,26 @@ mod tests { } } "#, + r#" + { + "slot": "123", + "validator_index": "123", + "entry": { + "message": { + "fee_recipient": "0x0000000000000000000000000000000000000000", + "gas_limit": "60000000", + "timestamp": "123", + "pubkey": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + "signature": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + "preferences": { + "filtering": "none", + "is_mev_protect": false, + "is_primev": false + } + } + "#, ]; for raw in registrations { assert!(serde_json::from_str::(raw).is_ok()); diff --git a/crates/rbuilder/src/mev_boost/mod.rs b/crates/rbuilder/src/mev_boost/mod.rs index 38fbd0e5d..f0926b48e 100644 --- a/crates/rbuilder/src/mev_boost/mod.rs +++ b/crates/rbuilder/src/mev_boost/mod.rs @@ -7,8 +7,8 @@ use flate2::{write::GzEncoder, Compression}; use governor::{DefaultDirectRateLimiter, Quota, RateLimiter}; use rbuilder_primitives::mev_boost::{ KnownRelay, MevBoostRelayID, RelayMode, SubmitBlockRequestNoBlobs, - SubmitBlockRequestWithMetadata, SubmitHeaderRequestWithMetadata, ValidatorRegistration, - ValidatorSlotData, MEV_BOOST_SLOT_INFO_REQUEST_TIMEOUT, + SubmitBlockRequestWithMetadata, SubmitHeaderRequestWithMetadata, ValidatorPreferences, + ValidatorRegistration, ValidatorSlotData, MEV_BOOST_SLOT_INFO_REQUEST_TIMEOUT, }; use reqwest::{ header::{HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_ENCODING, CONTENT_TYPE}, @@ -691,6 +691,7 @@ impl RelayClient { .filter(|r| { r.preferences .as_ref() + .and_then(ValidatorPreferences::as_titan) .is_none_or(|p| !p.censoring || self.ask_for_filtering_validators) }) .collect();