From b6909b824d16f75231c39a3ad7a59fcf8a7126c1 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 27 Sep 2021 17:03:47 +1000 Subject: [PATCH] Allow producing block with execution payload --- beacon_node/beacon_chain/src/beacon_chain.rs | 49 +++++++++++++++++--- beacon_node/beacon_chain/src/errors.rs | 3 ++ beacon_node/client/src/builder.rs | 1 + beacon_node/client/src/config.rs | 4 +- beacon_node/execution_layer/src/lib.rs | 37 ++++++++++++++- beacon_node/src/cli.rs | 11 +++++ beacon_node/src/config.rs | 2 + 7 files changed, 97 insertions(+), 10 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 38602ffb76..793fe29789 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -60,7 +60,9 @@ use slot_clock::SlotClock; use state_processing::{ common::get_indexed_attestation, per_block_processing, - per_block_processing::errors::AttestationValidationError, + per_block_processing::{ + compute_timestamp_at_slot, errors::AttestationValidationError, is_merge_complete, + }, per_slot_processing, state_advance::{complete_state_advance, partial_state_advance}, BlockSignatureStrategy, SigVerifiedOp, @@ -2790,12 +2792,44 @@ impl BeaconChain { })) }; // Closure to fetch a sync aggregate in cases where it is required. - let get_execution_payload = || -> Result, BlockProductionError> { - // TODO: actually get the payload from eth1 node.. - Ok(ExecutionPayload::default()) + let get_execution_payload = |latest_execution_payload_header: &ExecutionPayloadHeader< + T::EthSpec, + >| + -> Result, BlockProductionError> { + let execution_layer = self + .execution_layer + .as_ref() + .ok_or(BlockProductionError::ExecutionLayerMissing)?; + + let parent_hash; + if !is_merge_complete(&state) { + let terminal_pow_block_hash = execution_layer + .block_on(|execution_layer| { + execution_layer.get_pow_block_hash_at_total_difficulty() + }) + .map_err(BlockProductionError::TerminalPoWBlockLookupFailed)?; + + if let Some(terminal_pow_block_hash) = terminal_pow_block_hash { + parent_hash = terminal_pow_block_hash; + } else { + return Ok(<_>::default()); + } + } else { + parent_hash = latest_execution_payload_header.block_hash; + } + + let timestamp = + compute_timestamp_at_slot(&state, &self.spec).map_err(BeaconStateError::from)?; + let random = *state.get_randao_mix(state.current_epoch())?; + + execution_layer + .block_on(|execution_layer| { + execution_layer.get_payload(parent_hash, timestamp, random) + }) + .map_err(BlockProductionError::GetPayloadFailed) }; - let inner_block = match state { + let inner_block = match &state { BeaconState::Base(_) => BeaconBlock::Base(BeaconBlockBase { slot, proposer_index, @@ -2832,9 +2866,10 @@ impl BeaconChain { }, }) } - BeaconState::Merge(_) => { + BeaconState::Merge(state) => { let sync_aggregate = get_sync_aggregate()?; - let execution_payload = get_execution_payload()?; + let execution_payload = + get_execution_payload(&state.latest_execution_payload_header)?; BeaconBlock::Merge(BeaconBlockMerge { slot, proposer_index, diff --git a/beacon_node/beacon_chain/src/errors.rs b/beacon_node/beacon_chain/src/errors.rs index 799ce86f28..6bb06e8896 100644 --- a/beacon_node/beacon_chain/src/errors.rs +++ b/beacon_node/beacon_chain/src/errors.rs @@ -177,6 +177,9 @@ pub enum BlockProductionError { produce_at_slot: Slot, state_slot: Slot, }, + ExecutionLayerMissing, + TerminalPoWBlockLookupFailed(execution_layer::Error), + GetPayloadFailed(execution_layer::Error), } easy_from_to!(BlockProcessingError, BlockProductionError); diff --git a/beacon_node/client/src/builder.rs b/beacon_node/client/src/builder.rs index 4acee035fd..0079d3ec59 100644 --- a/beacon_node/client/src/builder.rs +++ b/beacon_node/client/src/builder.rs @@ -156,6 +156,7 @@ where let execution_layer = ExecutionLayer::from_urls( execution_endpoints, terminal_total_difficulty, + config.fee_recipient, context.executor.clone(), context.log().clone(), ) diff --git a/beacon_node/client/src/config.rs b/beacon_node/client/src/config.rs index f21becb276..f950d3922d 100644 --- a/beacon_node/client/src/config.rs +++ b/beacon_node/client/src/config.rs @@ -4,7 +4,7 @@ use sensitive_url::SensitiveUrl; use serde_derive::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf; -use types::{Graffiti, PublicKeyBytes, Uint256}; +use types::{Address, Graffiti, PublicKeyBytes, Uint256}; /// Default directory name for the freezer database under the top-level data dir. const DEFAULT_FREEZER_DB_DIR: &str = "freezer_db"; @@ -76,6 +76,7 @@ pub struct Config { pub eth1: eth1::Config, pub execution_endpoints: Option>, pub terminal_total_difficulty_override: Option, + pub fee_recipient: Option
, pub http_api: http_api::Config, pub http_metrics: http_metrics::Config, pub monitoring_api: Option, @@ -98,6 +99,7 @@ impl Default for Config { eth1: <_>::default(), execution_endpoints: None, terminal_total_difficulty_override: None, + fee_recipient: None, disabled_forks: Vec::new(), graffiti: Graffiti::default(), http_api: <_>::default(), diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 525b8fae36..7b34a31b2e 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -20,6 +20,7 @@ pub enum Error { EngineErrors(Vec), NotSynced, ShuttingDown, + FeeRecipientUnspecified, } impl From for Error { @@ -31,6 +32,7 @@ impl From for Error { struct Inner { engines: Engines, terminal_total_difficulty: Uint256, + fee_recipient: Option
, executor: TaskExecutor, log: Logger, } @@ -44,6 +46,7 @@ impl ExecutionLayer { pub fn from_urls( urls: Vec, terminal_total_difficulty: Uint256, + fee_recipient: Option
, executor: TaskExecutor, log: Logger, ) -> Result { @@ -62,6 +65,7 @@ impl ExecutionLayer { log: log.clone(), }, terminal_total_difficulty, + fee_recipient, executor, log, }; @@ -85,6 +89,12 @@ impl ExecutionLayer { self.inner.terminal_total_difficulty } + fn fee_recipient(&self) -> Result { + self.inner + .fee_recipient + .ok_or(Error::FeeRecipientUnspecified) + } + fn log(&self) -> &Logger { &self.inner.log } @@ -118,10 +128,11 @@ impl ExecutionLayer { parent_hash: Hash256, timestamp: u64, random: Hash256, - fee_recipient: Address, ) -> Result { + let fee_recipient = self.fee_recipient()?; self.engines() .first_success(|engine| { + // TODO(paul): put these in a cache. engine .api .prepare_payload(parent_hash, timestamp, random, fee_recipient) @@ -130,6 +141,27 @@ impl ExecutionLayer { .map_err(Error::EngineErrors) } + pub async fn get_payload( + &self, + parent_hash: Hash256, + timestamp: u64, + random: Hash256, + ) -> Result, Error> { + let fee_recipient = self.fee_recipient()?; + self.engines() + .first_success(|engine| async move { + // TODO(paul): make a cache for these IDs. + let payload_id = engine + .api + .prepare_payload(parent_hash, timestamp, random, fee_recipient) + .await?; + + engine.api.get_payload(payload_id).await + }) + .await + .map_err(Error::EngineErrors) + } + pub async fn execute_payload( &self, execution_payload: &ExecutionPayload, @@ -226,7 +258,7 @@ impl ExecutionLayer { } } - pub async fn get_pow_block_at_total_difficulty(&self) -> Result, Error> { + pub async fn get_pow_block_hash_at_total_difficulty(&self) -> Result, Error> { self.engines() .first_success(|engine| async move { let mut ttd_exceeding_block = None; @@ -239,6 +271,7 @@ impl ExecutionLayer { if block.total_difficulty >= self.terminal_total_difficulty() { ttd_exceeding_block = Some(block.block_hash); + // TODO(paul): add a LRU cache for these lookups. block = engine.api.get_block_by_hash(block.parent_hash).await?; } else { return Ok::<_, ApiError>(ttd_exceeding_block); diff --git a/beacon_node/src/cli.rs b/beacon_node/src/cli.rs index 2188a463ed..e130518106 100644 --- a/beacon_node/src/cli.rs +++ b/beacon_node/src/cli.rs @@ -380,6 +380,17 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { Be extremely careful with the use of this flag.") .takes_value(true) ) + .arg( + Arg::with_name("fee-recipient") + .long("fee-recipient") + .help("Once the merge has happened, this address will receive transaction fees \ + collected from any blocks produced by this node. Defaults to a junk \ + address whilst the merge is in development stages. THE DEFAULT VALUE \ + WILL BE REMOVED BEFORE THE MERGE ENTERS PRODUCTION") + // TODO: remove this default value. It's just there to make life easy during merge + // testnets. + .default_value("0x000000000000000000000000000000000000000000000001"), + ) /* * Database purging and compaction. diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index b984d50477..ea0a0ba148 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -237,6 +237,8 @@ pub fn get_config( client_config.terminal_total_difficulty_override = Some(terminal_total_difficulty); } + client_config.fee_recipient = clap_utils::parse_optional(cli_args, "fee-recipient")?; + if let Some(freezer_dir) = cli_args.value_of("freezer-dir") { client_config.freezer_db_path = Some(PathBuf::from(freezer_dir)); }