diff --git a/crates/supervisor/core/src/rpc/metrics.rs b/crates/supervisor/core/src/rpc/metrics.rs index 5a4fd8c6e7..c9f26ac2b8 100644 --- a/crates/supervisor/core/src/rpc/metrics.rs +++ b/crates/supervisor/core/src/rpc/metrics.rs @@ -20,6 +20,7 @@ impl Metrics { "cross_derived_to_source"; pub(crate) const SUPERVISOR_RPC_METHOD_DEPENDENCY_SET: &'static str = "dependency_set"; pub(crate) const SUPERVISOR_RPC_METHOD_LOCAL_UNSAFE: &'static str = "local_unsafe"; + pub(crate) const SUPERVISOR_RPC_METHOD_LOCAL_SAFE: &'static str = "local_safe"; pub(crate) const SUPERVISOR_RPC_METHOD_CROSS_SAFE: &'static str = "cross_safe"; pub(crate) const SUPERVISOR_RPC_METHOD_FINALIZED: &'static str = "finalized"; pub(crate) const SUPERVISOR_RPC_METHOD_FINALIZED_L1: &'static str = "finalized_l1"; @@ -83,6 +84,7 @@ impl Metrics { fn zero() { Self::zero_rpc_method(Self::SUPERVISOR_RPC_METHOD_CROSS_DERIVED_TO_SOURCE); Self::zero_rpc_method(Self::SUPERVISOR_RPC_METHOD_LOCAL_UNSAFE); + Self::zero_rpc_method(Self::SUPERVISOR_RPC_METHOD_LOCAL_SAFE); Self::zero_rpc_method(Self::SUPERVISOR_RPC_METHOD_CROSS_SAFE); Self::zero_rpc_method(Self::SUPERVISOR_RPC_METHOD_FINALIZED); Self::zero_rpc_method(Self::SUPERVISOR_RPC_METHOD_FINALIZED_L1); diff --git a/crates/supervisor/core/src/rpc/server.rs b/crates/supervisor/core/src/rpc/server.rs index 0b561264ca..0abafd77a3 100644 --- a/crates/supervisor/core/src/rpc/server.rs +++ b/crates/supervisor/core/src/rpc/server.rs @@ -89,6 +89,25 @@ where ) } + async fn local_safe(&self, chain_id_hex: HexStringU64) -> RpcResult { + let chain_id = ChainId::from(chain_id_hex); + crate::observe_rpc_call!( + Metrics::SUPERVISOR_RPC_METHOD_LOCAL_SAFE, + async { + trace!(target: "supervisor::rpc", + %chain_id, + "Received local_safe request" + ); + + let derived = self.supervisor.local_safe(chain_id)?.id(); + let source = self.supervisor.derived_to_source_block(chain_id, derived)?.id(); + + Ok(DerivedIdPair { source, derived }) + } + .await + ) + } + async fn dependency_set_v1(&self) -> RpcResult { crate::observe_rpc_call!( Metrics::SUPERVISOR_RPC_METHOD_DEPENDENCY_SET, @@ -333,6 +352,7 @@ mod tests { fn latest_block_from(&self, l1_block: BlockNumHash, chain: ChainId) -> Result; fn derived_to_source_block(&self, chain: ChainId, derived: BlockNumHash) -> Result; fn local_unsafe(&self, chain: ChainId) -> Result; + fn local_safe(&self, chain: ChainId) -> Result; fn cross_safe(&self, chain: ChainId) -> Result; fn finalized(&self, chain: ChainId) -> Result; fn finalized_l1(&self) -> Result; diff --git a/crates/supervisor/core/src/supervisor.rs b/crates/supervisor/core/src/supervisor.rs index 1407ed03c0..3a5e18c0a1 100644 --- a/crates/supervisor/core/src/supervisor.rs +++ b/crates/supervisor/core/src/supervisor.rs @@ -58,6 +58,11 @@ pub trait SupervisorService: Debug + Send + Sync { /// [`LocalUnsafe`]: SafetyLevel::LocalUnsafe fn local_unsafe(&self, chain: ChainId) -> Result; + /// Returns [`LocalSafe`] block for the given chain. + /// + /// [`LocalSafe`]: SafetyLevel::LocalSafe + fn local_safe(&self, chain: ChainId) -> Result; + /// Returns [`CrossSafe`] block for the given chain. /// /// [`CrossSafe`]: SafetyLevel::CrossSafe @@ -190,6 +195,13 @@ where })?) } + fn local_safe(&self, chain: ChainId) -> Result { + Ok(self.get_db(chain)?.get_safety_head_ref(SafetyLevel::LocalSafe).map_err(|err| { + error!(target: "supervisor::service", %chain, %err, "Failed to get local safe head ref for chain"); + SpecError::from(err) + })?) + } + fn cross_safe(&self, chain: ChainId) -> Result { Ok(self.get_db(chain)?.get_safety_head_ref(SafetyLevel::CrossSafe).map_err(|err| { error!(target: "supervisor::service", %chain, %err, "Failed to get cross safe head ref for chain"); diff --git a/crates/supervisor/rpc/src/jsonrpsee.rs b/crates/supervisor/rpc/src/jsonrpsee.rs index 7221066001..084552012c 100644 --- a/crates/supervisor/rpc/src/jsonrpsee.rs +++ b/crates/supervisor/rpc/src/jsonrpsee.rs @@ -39,6 +39,13 @@ pub trait SupervisorApi { #[method(name = "localUnsafe")] async fn local_unsafe(&self, chain_id: HexStringU64) -> RpcResult; + /// Returns the [`LocalSafe`] block for given chain. + /// + /// [`LocalSafe`]: SafetyLevel::LocalSafe + // todo: link to spec after PR(https://github.com/ethereum-optimism/specs/pull/753) is merged + #[method(name = "localSafe")] + async fn local_safe(&self, chain_id: HexStringU64) -> RpcResult; + /// Returns the [`CrossSafe`] block for given chain. /// /// Spec: diff --git a/crates/supervisor/service/src/actors/rpc.rs b/crates/supervisor/service/src/actors/rpc.rs index c89dec92d3..70f3e673b6 100644 --- a/crates/supervisor/service/src/actors/rpc.rs +++ b/crates/supervisor/service/src/actors/rpc.rs @@ -114,6 +114,7 @@ mod tests { fn latest_block_from(&self, l1_block: BlockNumHash, chain: ChainId) -> Result; fn derived_to_source_block(&self, chain: ChainId, derived: BlockNumHash) -> Result; fn local_unsafe(&self, chain: ChainId) -> Result; + fn local_safe(&self, chain: ChainId) -> Result; fn cross_safe(&self, chain: ChainId) -> Result; fn finalized(&self, chain: ChainId) -> Result; fn finalized_l1(&self) -> Result;