From f9fd6ac39272053f7b1334486aa113d3f7560033 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 27 Sep 2021 16:05:19 +1000 Subject: [PATCH] Add search for TTD block --- beacon_node/execution_layer/src/engine_api.rs | 26 +++++++++++++++- .../execution_layer/src/engine_api/http.rs | 27 +++++++++++++++++ beacon_node/execution_layer/src/lib.rs | 30 +++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index 7362c52eee..e03a9e6dae 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -2,7 +2,9 @@ use async_trait::async_trait; use eth1::http::RpcError; use serde::{Deserialize, Serialize}; -pub use types::{Address, EthSpec, ExecutionPayload, Hash256}; +pub const LATEST_TAG: &str = "latest"; + +pub use types::{Address, EthSpec, ExecutionPayload, Hash256, Uint256}; pub mod http; @@ -37,6 +39,13 @@ impl From for Error { pub trait EngineApi { async fn upcheck(&self) -> Result<(), Error>; + async fn get_block_by_number<'a>( + &self, + block_by_number: BlockByNumberQuery<'a>, + ) -> Result; + + async fn get_block_by_hash<'a>(&self, block_hash: Hash256) -> Result; + async fn prepare_payload( &self, parent_hash: Hash256, @@ -82,3 +91,18 @@ pub enum ConsensusStatus { Valid, Invalid, } + +#[derive(Clone, Copy, Debug, PartialEq, Serialize)] +#[serde(untagged)] +pub enum BlockByNumberQuery<'a> { + Tag(&'a str), +} + +#[derive(Clone, Copy, Debug, PartialEq, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ExecutionBlock { + pub block_hash: Hash256, + pub block_number: u64, + pub parent_hash: Hash256, + pub total_difficulty: Uint256, +} diff --git a/beacon_node/execution_layer/src/engine_api/http.rs b/beacon_node/execution_layer/src/engine_api/http.rs index 976cca2102..5dce3500b0 100644 --- a/beacon_node/execution_layer/src/engine_api/http.rs +++ b/beacon_node/execution_layer/src/engine_api/http.rs @@ -13,6 +13,12 @@ pub use reqwest::Client; const STATIC_ID: u32 = 1; const JSONRPC_VERSION: &str = "2.0"; +const ETH_GET_BLOCK_BY_NUMBER: &str = "eth_getBlockByNumber"; +const ETH_GET_BLOCK_BY_NUMBER_TIMEOUT: Duration = Duration::from_secs(1); + +const ETH_GET_BLOCK_BY_HASH: &str = "eth_getBlockByHash"; +const ETH_GET_BLOCK_BY_HASH_TIMEOUT: Duration = Duration::from_secs(1); + const ETH_SYNCING: &str = "eth_syncing"; const ETH_SYNCING_TIMEOUT: Duration = Duration::from_millis(250); @@ -103,6 +109,27 @@ impl EngineApi for HttpJsonRpc { } } + async fn get_block_by_number<'a>( + &self, + query: BlockByNumberQuery<'a>, + ) -> Result { + let params = json!([query]); + + self.rpc_request( + ETH_GET_BLOCK_BY_NUMBER, + params, + ETH_GET_BLOCK_BY_NUMBER_TIMEOUT, + ) + .await + } + + async fn get_block_by_hash<'a>(&self, block_hash: Hash256) -> Result { + let params = json!([block_hash]); + + self.rpc_request(ETH_GET_BLOCK_BY_HASH, params, ETH_GET_BLOCK_BY_HASH_TIMEOUT) + .await + } + async fn prepare_payload( &self, parent_hash: Hash256, diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 5862a5cb12..da58853a78 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -30,6 +30,7 @@ impl From for Error { struct Inner { engines: Engines, + total_terminal_difficulty: Uint256, executor: TaskExecutor, log: Logger, } @@ -42,6 +43,7 @@ pub struct ExecutionLayer { impl ExecutionLayer { pub fn from_urls( urls: Vec, + total_terminal_difficulty: Uint256, executor: TaskExecutor, log: Logger, ) -> Result { @@ -59,6 +61,7 @@ impl ExecutionLayer { engines, log: log.clone(), }, + total_terminal_difficulty, executor, log, }; @@ -78,6 +81,10 @@ impl ExecutionLayer { &self.inner.executor } + fn total_terminal_difficulty(&self) -> Uint256 { + self.inner.total_terminal_difficulty + } + fn log(&self) -> &Logger { &self.inner.log } @@ -218,4 +225,27 @@ impl ExecutionLayer { )) } } + + pub async fn find_ttd_block_hash(&self) -> Result, Error> { + self.engines() + .first_success(|engine| async move { + let mut ttd_exceeding_block = None; + let mut block = engine + .api + .get_block_by_number(BlockByNumberQuery::Tag(LATEST_TAG)) + .await?; + + loop { + if block.total_difficulty >= self.total_terminal_difficulty() { + ttd_exceeding_block = Some(block.block_hash); + + block = engine.api.get_block_by_hash(block.parent_hash).await?; + } else { + return Ok::<_, ApiError>(ttd_exceeding_block); + } + } + }) + .await + .map_err(Error::EngineErrors) + } }