From 2c5c318529181a8d5dad1eb3184d898c4ee500a3 Mon Sep 17 00:00:00 2001 From: Noah Citron Date: Mon, 23 Jan 2023 10:07:11 -0500 Subject: [PATCH] feat: check consensus rpc network (#177) * feat: check consensus rpc network * cleanup --- client/src/errors.rs | 6 +++--- client/src/node.rs | 5 +++++ consensus/src/consensus.rs | 10 ++++++++++ consensus/src/errors.rs | 2 ++ consensus/src/rpc/mock_rpc.rs | 10 ++++++---- consensus/src/rpc/mod.rs | 1 + consensus/src/rpc/nimbus_rpc.rs | 28 +++++++++++++++++++++++++++- consensus/src/types.rs | 2 +- execution/src/errors.rs | 2 -- execution/src/execution.rs | 12 +++--------- execution/src/rpc/http_rpc.rs | 2 +- 11 files changed, 59 insertions(+), 21 deletions(-) diff --git a/client/src/errors.rs b/client/src/errors.rs index 84959fd..39a6679 100644 --- a/client/src/errors.rs +++ b/client/src/errors.rs @@ -1,5 +1,5 @@ use common::errors::BlockNotFoundError; -use execution::errors::{EvmError, ExecutionError}; +use execution::errors::EvmError; use eyre::Report; use thiserror::Error; @@ -9,8 +9,8 @@ pub enum NodeError { #[error(transparent)] ExecutionEvmError(#[from] EvmError), - #[error(transparent)] - ExecutionError(#[from] ExecutionError), + #[error("execution error: {0}")] + ExecutionError(Report), #[error("out of sync: {0} slots behind")] OutOfSync(u64), diff --git a/client/src/node.rs b/client/src/node.rs index 48bc0dc..5b1dd3b 100644 --- a/client/src/node.rs +++ b/client/src/node.rs @@ -60,6 +60,11 @@ impl Node { .await .map_err(NodeError::ExecutionError)?; + self.consensus + .check_rpc() + .await + .map_err(NodeError::ConsensusSyncError)?; + self.consensus .sync() .await diff --git a/consensus/src/consensus.rs b/consensus/src/consensus.rs index dc1ea65..b29905b 100644 --- a/consensus/src/consensus.rs +++ b/consensus/src/consensus.rs @@ -59,6 +59,16 @@ impl ConsensusClient { }) } + pub async fn check_rpc(&self) -> Result<()> { + let chain_id = self.rpc.chain_id().await?; + + if chain_id != self.config.chain.chain_id { + Err(ConsensusError::IncorrectRpcNetwork.into()) + } else { + Ok(()) + } + } + pub async fn get_execution_payload(&self, slot: &Option) -> Result { let slot = slot.unwrap_or(self.store.optimistic_header.slot); let mut block = self.rpc.get_block(slot).await?; diff --git a/consensus/src/errors.rs b/consensus/src/errors.rs index 41c5558..98a5424 100644 --- a/consensus/src/errors.rs +++ b/consensus/src/errors.rs @@ -24,4 +24,6 @@ pub enum ConsensusError { PayloadNotFound(u64), #[error("checkpoint is too old")] CheckpointTooOld, + #[error("consensus rpc is for the incorrect network")] + IncorrectRpcNetwork, } diff --git a/consensus/src/rpc/mock_rpc.rs b/consensus/src/rpc/mock_rpc.rs index 97a4b90..f4ac130 100644 --- a/consensus/src/rpc/mock_rpc.rs +++ b/consensus/src/rpc/mock_rpc.rs @@ -1,11 +1,9 @@ use std::{fs::read_to_string, path::PathBuf}; -use async_trait::async_trait; -use eyre::Result; - use super::ConsensusRpc; use crate::types::{BeaconBlock, Bootstrap, FinalityUpdate, OptimisticUpdate, Update}; - +use async_trait::async_trait; +use eyre::Result; pub struct MockRpc { testdata: PathBuf, } @@ -42,4 +40,8 @@ impl ConsensusRpc for MockRpc { let block = read_to_string(self.testdata.join("blocks.json"))?; Ok(serde_json::from_str(&block)?) } + + async fn chain_id(&self) -> Result { + eyre::bail!("not implemented") + } } diff --git a/consensus/src/rpc/mod.rs b/consensus/src/rpc/mod.rs index cba8bf1..9dc8874 100644 --- a/consensus/src/rpc/mod.rs +++ b/consensus/src/rpc/mod.rs @@ -15,4 +15,5 @@ pub trait ConsensusRpc { async fn get_finality_update(&self) -> Result; async fn get_optimistic_update(&self) -> Result; async fn get_block(&self, slot: u64) -> Result; + async fn chain_id(&self) -> Result; } diff --git a/consensus/src/rpc/nimbus_rpc.rs b/consensus/src/rpc/nimbus_rpc.rs index ca6c478..e4006fa 100644 --- a/consensus/src/rpc/nimbus_rpc.rs +++ b/consensus/src/rpc/nimbus_rpc.rs @@ -1,5 +1,4 @@ use async_trait::async_trait; -use common::errors::RpcError; use eyre::Result; use reqwest_middleware::{ClientBuilder, ClientWithMiddleware}; use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware}; @@ -8,6 +7,7 @@ use std::cmp; use super::ConsensusRpc; use crate::constants::MAX_REQUEST_LIGHT_CLIENT_UPDATES; use crate::types::*; +use common::errors::RpcError; pub struct NimbusRpc { rpc: String, @@ -115,6 +115,21 @@ impl ConsensusRpc for NimbusRpc { Ok(res.data.message) } + + async fn chain_id(&self) -> Result { + let req = format!("{}/eth/v1/config/spec", self.rpc); + let res = self + .client + .get(req) + .send() + .await + .map_err(|e| RpcError::new("spec", e))? + .json::() + .await + .map_err(|e| RpcError::new("spec", e))?; + + Ok(res.data.chain_id) + } } #[derive(serde::Deserialize, Debug)] @@ -148,3 +163,14 @@ struct OptimisticUpdateResponse { struct BootstrapResponse { data: Bootstrap, } + +#[derive(serde::Deserialize, Debug)] +struct SpecResponse { + data: Spec, +} + +#[derive(serde::Deserialize, Debug)] +struct Spec { + #[serde(rename = "DEPOSIT_NETWORK_ID", deserialize_with = "u64_deserialize")] + chain_id: u64, +} diff --git a/consensus/src/types.rs b/consensus/src/types.rs index 44c7056..b341ef2 100644 --- a/consensus/src/types.rs +++ b/consensus/src/types.rs @@ -376,7 +376,7 @@ where .map_err(D::Error::custom) } -fn u64_deserialize<'de, D>(deserializer: D) -> Result +pub fn u64_deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, { diff --git a/execution/src/errors.rs b/execution/src/errors.rs index 0512d10..12b52b1 100644 --- a/execution/src/errors.rs +++ b/execution/src/errors.rs @@ -24,8 +24,6 @@ pub enum ExecutionError { MissingLog(String, U256), #[error("too many logs to prove: {0}, current limit is: {1}")] TooManyLogsToProve(usize, usize), - #[error("rpc error: {0:?}")] - RpcError(Report), #[error("execution rpc is for the incorect network")] IncorrectRpcNetwork(), } diff --git a/execution/src/execution.rs b/execution/src/execution.rs index 0f310f8..3a16028 100644 --- a/execution/src/execution.rs +++ b/execution/src/execution.rs @@ -36,15 +36,9 @@ impl ExecutionClient { Ok(ExecutionClient { rpc }) } - pub async fn check_rpc(&self, chain_id: u64) -> Result<(), ExecutionError> { - if self - .rpc - .chain_id() - .await - .map_err(ExecutionError::RpcError)? - != chain_id - { - Err(ExecutionError::IncorrectRpcNetwork()) + pub async fn check_rpc(&self, chain_id: u64) -> Result<()> { + if self.rpc.chain_id().await? != chain_id { + Err(ExecutionError::IncorrectRpcNetwork().into()) } else { Ok(()) } diff --git a/execution/src/rpc/http_rpc.rs b/execution/src/rpc/http_rpc.rs index d395b4b..05e4342 100644 --- a/execution/src/rpc/http_rpc.rs +++ b/execution/src/rpc/http_rpc.rs @@ -1,7 +1,6 @@ use std::str::FromStr; use async_trait::async_trait; -use common::errors::RpcError; use ethers::prelude::{Address, Http}; use ethers::providers::{HttpRateLimitRetryPolicy, Middleware, Provider, RetryClient}; use ethers::types::transaction::eip2718::TypedTransaction; @@ -13,6 +12,7 @@ use ethers::types::{ use eyre::Result; use crate::types::CallOpts; +use common::errors::RpcError; use super::ExecutionRpc;