diff --git a/consensus/src/consensus.rs b/consensus/src/consensus.rs index 86c60a1..dd08b85 100644 --- a/consensus/src/consensus.rs +++ b/consensus/src/consensus.rs @@ -92,7 +92,7 @@ impl ConsensusClient { } else if slot == finalized_slot { self.store.finalized_header.clone().hash_tree_root()? } else { - return Err(ConsensusError::PayloadNotFound(slot).into()); + self.rpc.get_header(slot).await?.message.hash_tree_root()? }; if verified_block_hash != block_hash { diff --git a/consensus/src/rpc/mock_rpc.rs b/consensus/src/rpc/mock_rpc.rs index a887410..d41f8d3 100644 --- a/consensus/src/rpc/mock_rpc.rs +++ b/consensus/src/rpc/mock_rpc.rs @@ -1,7 +1,7 @@ use std::{fs::read_to_string, path::PathBuf}; use super::ConsensusRpc; -use crate::types::{BeaconBlock, Bootstrap, FinalityUpdate, OptimisticUpdate, Update}; +use crate::types::{BeaconBlock, BeaconHeader, Bootstrap, FinalityUpdate, OptimisticUpdate, Update}; use async_trait::async_trait; use eyre::Result; pub struct MockRpc { @@ -42,6 +42,11 @@ impl ConsensusRpc for MockRpc { Ok(serde_json::from_str(&block)?) } + async fn get_header(&self, _slot: u64) -> Result { + let header = read_to_string(self.testdata.join("headers.json"))?; + Ok(serde_json::from_str(&header)?) + } + 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 03f46dd..537aac7 100644 --- a/consensus/src/rpc/mod.rs +++ b/consensus/src/rpc/mod.rs @@ -4,7 +4,7 @@ pub mod nimbus_rpc; use async_trait::async_trait; use eyre::Result; -use crate::types::{BeaconBlock, Bootstrap, FinalityUpdate, OptimisticUpdate, Update}; +use crate::types::{BeaconBlock, BeaconHeader, Bootstrap, FinalityUpdate, Header, OptimisticUpdate, Update}; // implements https://github.com/ethereum/beacon-APIs/tree/master/apis/beacon/light_client #[cfg_attr(not(target_arch = "wasm32"), async_trait)] @@ -16,5 +16,6 @@ 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 get_header(&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 e0548fb..f64c6fd 100644 --- a/consensus/src/rpc/nimbus_rpc.rs +++ b/consensus/src/rpc/nimbus_rpc.rs @@ -6,6 +6,7 @@ use super::ConsensusRpc; use crate::constants::MAX_REQUEST_LIGHT_CLIENT_UPDATES; use crate::types::*; use common::errors::RpcError; +use common::types::Bytes32; #[derive(Debug)] pub struct NimbusRpc { @@ -97,6 +98,19 @@ impl ConsensusRpc for NimbusRpc { Ok(res.data.message) } + async fn get_header(&self, slot: u64) -> Result { + let req = format!("{}/eth/v1/beacon/headers/{}", self.rpc, slot); + let res = reqwest::get(req) + .await + .map_err(|e| RpcError::new("headers", e))? + .json::() + .await + .map_err(|e| RpcError::new("headers", e))?; + + Ok(res.data.header) + } + + async fn chain_id(&self) -> Result { let req = format!("{}/eth/v1/config/spec", self.rpc); let res = reqwest::get(req) @@ -110,6 +124,12 @@ impl ConsensusRpc for NimbusRpc { } } +#[derive(serde::Deserialize, Debug)] +struct BeaconHeaderResponse { + data: BeaconHeaderData, + execution_optimistic: bool, +} + #[derive(serde::Deserialize, Debug)] struct BeaconBlockResponse { data: BeaconBlockData, @@ -120,6 +140,14 @@ struct BeaconBlockData { message: BeaconBlock, } +#[derive(serde::Deserialize, Debug)] +struct BeaconHeaderData { + #[serde(deserialize_with = "bytes32_deserialize")] + root: Bytes32, + header: BeaconHeader, + canonical: bool, +} + type UpdateResponse = Vec; #[derive(serde::Deserialize, Debug)] diff --git a/consensus/src/types.rs b/consensus/src/types.rs index b341ef2..cdfad5f 100644 --- a/consensus/src/types.rs +++ b/consensus/src/types.rs @@ -24,6 +24,13 @@ pub struct BeaconBlock { pub body: BeaconBlockBody, } +#[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)] +pub struct BeaconHeader { + pub message: Header, + #[serde(deserialize_with = "signature_deserialize")] + signature: SignatureBytes, +} + #[derive(serde::Deserialize, Debug, Default, SimpleSerialize, Clone)] pub struct BeaconBlockBody { #[serde(deserialize_with = "signature_deserialize")] @@ -395,7 +402,7 @@ where Ok(U256::from_bytes_le(x_bytes)) } -fn bytes32_deserialize<'de, D>(deserializer: D) -> Result +pub fn bytes32_deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de>, {