From 193e29b25e2b84e79eef5e2edaed5b7fbdade3e2 Mon Sep 17 00:00:00 2001 From: Ognyan Genev <39865181+ogenev@users.noreply.github.com> Date: Fri, 9 Aug 2024 10:19:05 +0300 Subject: [PATCH] feat(beacon-network): add json-rpc method to get the latest finalized root (#1364) --- ethportal-api/src/beacon.rs | 4 ++++ ethportal-api/src/types/jsonrpc/endpoints.rs | 2 ++ light-client/src/client.rs | 4 ++++ light-client/src/node.rs | 4 ++++ rpc/src/beacon_rpc.rs | 9 +++++++++ trin-beacon/src/jsonrpc.rs | 13 +++++++++++++ 6 files changed, 36 insertions(+) diff --git a/ethportal-api/src/beacon.rs b/ethportal-api/src/beacon.rs index ee66031bc..dda88748b 100644 --- a/ethportal-api/src/beacon.rs +++ b/ethportal-api/src/beacon.rs @@ -42,6 +42,10 @@ pub trait BeaconNetworkApi { #[method(name = "beaconPing")] async fn ping(&self, enr: Enr) -> RpcResult; + /// Get the finalized state root of the finalized beacon header. + #[method(name = "beaconFinalizedStateRoot")] + async fn finalized_state_root(&self) -> RpcResult; + /// Send a FINDNODES request for nodes that fall within the given set of distances, to the /// designated peer and wait for a response #[method(name = "beaconFindNodes")] diff --git a/ethportal-api/src/types/jsonrpc/endpoints.rs b/ethportal-api/src/types/jsonrpc/endpoints.rs index abab2629f..b3afe4050 100644 --- a/ethportal-api/src/types/jsonrpc/endpoints.rs +++ b/ethportal-api/src/types/jsonrpc/endpoints.rs @@ -113,6 +113,8 @@ pub enum BeaconEndpoint { FindContent(Enr, BeaconContentKey), /// params: [enr, distances] FindNodes(Enr, Vec), + /// params: None + FinalizedStateRoot, /// params: node_id GetEnr(NodeId), /// params: content_key diff --git a/light-client/src/client.rs b/light-client/src/client.rs index bce470f5b..993c24d91 100644 --- a/light-client/src/client.rs +++ b/light-client/src/client.rs @@ -459,4 +459,8 @@ impl Client { pub async fn get_header(&self) -> Result { self.node.read().await.get_header() } + + pub async fn get_finalized_header(&self) -> Result { + self.node.read().await.get_finalized_header() + } } diff --git a/light-client/src/node.rs b/light-client/src/node.rs index 8ec5c95ef..e047e384d 100644 --- a/light-client/src/node.rs +++ b/light-client/src/node.rs @@ -77,6 +77,10 @@ impl Node { self.config.chain.chain_id } + pub fn get_finalized_header(&self) -> Result { + Ok(self.consensus.get_finalized_header().clone()) + } + pub fn get_header(&self) -> Result { self.check_head_age()?; Ok(self.consensus.get_header().clone()) diff --git a/rpc/src/beacon_rpc.rs b/rpc/src/beacon_rpc.rs index 54dedd7d7..a465edbd4 100644 --- a/rpc/src/beacon_rpc.rs +++ b/rpc/src/beacon_rpc.rs @@ -151,6 +151,7 @@ impl BeaconNetworkApiServer for BeaconNetworkApi { Ok(result) } + /// Get the optimistic state root of the optimistic beacon header. async fn optimistic_state_root(&self) -> RpcResult { let endpoint = BeaconEndpoint::OptimisticStateRoot; let result = self.proxy_query_to_beacon_subnet(endpoint).await?; @@ -170,6 +171,14 @@ impl BeaconNetworkApiServer for BeaconNetworkApi { Ok(result) } + /// Get the finalized state root of the finalized beacon header. + async fn finalized_state_root(&self) -> RpcResult { + let endpoint = BeaconEndpoint::FinalizedStateRoot; + let result = self.proxy_query_to_beacon_subnet(endpoint).await?; + let result: B256 = from_value(result)?; + Ok(result) + } + /// Lookup a target content key in the network async fn recursive_find_content( &self, diff --git a/trin-beacon/src/jsonrpc.rs b/trin-beacon/src/jsonrpc.rs index 500274a89..48c5a2734 100644 --- a/trin-beacon/src/jsonrpc.rs +++ b/trin-beacon/src/jsonrpc.rs @@ -97,6 +97,19 @@ async fn complete_request(network: Arc, request: BeaconJsonRpcReq None => Err("Beacon client not initialized".to_string()), } } + BeaconEndpoint::FinalizedStateRoot => { + let beacon_client = network.beacon_client.lock().await; + match beacon_client.as_ref() { + Some(client) => { + let header = client.get_finalized_header().await; + match header { + Ok(header) => Ok(json!((header.state_root))), + Err(err) => Err(err.to_string()), + } + } + None => Err("Beacon client not initialized".to_string()), + } + } }; let _ = request.resp.send(response); }