Skip to content

Commit

Permalink
Build valid execution payloads (#18)
Browse files Browse the repository at this point in the history
* Build valid execution payloads

* Fix clippy and revert temp hacks
  • Loading branch information
michaelsproul authored May 24, 2023
1 parent 49be387 commit dcfb666
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 54 deletions.
91 changes: 50 additions & 41 deletions Cargo.lock

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ version = "0.1.0"
edition = "2021"

[dependencies]
execution_layer = { git = "https://github.com/sigp/lighthouse", rev = "60d13c3fea558e0f1935466375d976defa175114" }
execution_layer = { git = "https://github.com/michaelsproul/lighthouse", rev = "c144ae391edc938dbc5e185a99df78b8c8cb1c76" }
tree_hash = "0.5.1"
tree_hash_derive = "0.5.1"
task_executor = { git = "https://github.com/sigp/lighthouse", rev = "60d13c3fea558e0f1935466375d976defa175114" }
eth2_network_config = { git = "https://github.com/sigp/lighthouse", rev = "60d13c3fea558e0f1935466375d976defa175114" }
eth2 = { git = "https://github.com/sigp/lighthouse", rev = "60d13c3fea558e0f1935466375d976defa175114" }
task_executor = { git = "https://github.com/michaelsproul/lighthouse", rev = "c144ae391edc938dbc5e185a99df78b8c8cb1c76" }
eth2_network_config = { git = "https://github.com/michaelsproul/lighthouse", rev = "c144ae391edc938dbc5e185a99df78b8c8cb1c76" }
eth2 = { git = "https://github.com/michaelsproul/lighthouse", rev = "c144ae391edc938dbc5e185a99df78b8c8cb1c76" }
ethereum_serde_utils = "0.5.1"
tokio = { version = "1.0.0", features = ["rt-multi-thread"] }
axum = "0.6.10"
Expand All @@ -26,6 +26,7 @@ tracing-slog = "0.2.0"
slog = "2.7.0"
clap = { version = "4.0.0", features = ["derive"] }
strum = { version = "0.24.1", features = ["derive", "strum_macros"] }
keccak-hash = "0.10.0"

[patch]
[patch.crates-io]
Expand Down
36 changes: 36 additions & 0 deletions src/base_fee.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//! EIP-1559 base fee per gas calculations.
//!
//! Translation of Python spec from: https://eips.ethereum.org/EIPS/eip-1559
use eth2::types::Uint256;
use std::cmp::max;

const ELASTICITY_MULTIPLIER: u64 = 2;
const BASE_FEE_MAX_CHANGE_DENOMINATOR: u64 = 8;

#[allow(clippy::comparison_chain)]
pub fn expected_base_fee_per_gas(
parent_base_fee_per_gas: Uint256,
parent_gas_used: u64,
parent_gas_limit: u64,
) -> Uint256 {
let parent_gas_target = parent_gas_limit / ELASTICITY_MULTIPLIER;

if parent_gas_used == parent_gas_target {
parent_base_fee_per_gas
} else if parent_gas_used > parent_gas_target {
let gas_used_delta = parent_gas_used.saturating_sub(parent_gas_target);
let base_fee_per_gas_delta = max(
parent_base_fee_per_gas * gas_used_delta
/ parent_gas_target
/ BASE_FEE_MAX_CHANGE_DENOMINATOR,
Uint256::one(),
);
parent_base_fee_per_gas + base_fee_per_gas_delta
} else {
let gas_used_delta = parent_gas_target.saturating_sub(parent_gas_used);
let base_fee_per_gas_delta = parent_base_fee_per_gas * gas_used_delta
/ parent_gas_target
/ BASE_FEE_MAX_CHANGE_DENOMINATOR;
parent_base_fee_per_gas.saturating_sub(base_fee_per_gas_delta)
}
}
3 changes: 3 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ pub struct Config {
/// Number of payload attributes and past payloads to cache in memory.
#[arg(long, value_name = "N", default_value = "8")]
pub payload_builder_cache_size: usize,
/// Extra data to include in produced blocks.
#[arg(long, value_name = "STRING", default_value = "Eleel")]
pub payload_builder_extra_data: String,
/// Number of justified block hashes to cache in memory.
#[arg(long, value_name = "N", default_value = "4")]
pub justified_block_cache_size: usize,
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use std::net::SocketAddr;
use std::sync::Arc;
use tokio::runtime::Handle;

mod base_fee;
mod config;
mod fcu;
mod logging;
Expand Down
1 change: 1 addition & 0 deletions src/multiplexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ impl<E: EthSpec> Multiplexer<E> {
));
let payload_builder = Mutex::new(PayloadBuilder::new(
NonZeroUsize::new(config.payload_builder_cache_size).ok_or("invalid cache size")?,
&config.payload_builder_extra_data,
));

// Derived values.
Expand Down
65 changes: 56 additions & 9 deletions src/payload_builder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{
base_fee::expected_base_fee_per_gas,
types::{
JsonExecutionPayload, JsonGetPayloadResponseV1, JsonGetPayloadResponseV2,
JsonPayloadStatusV1Status, PayloadId, TransparentJsonPayloadId,
Expand All @@ -7,17 +8,27 @@ use crate::{
};
use eth2::types::{
EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadMerge,
ForkName, Uint256, VariableList,
FixedVector, ForkName, Hash256, Uint256, Unsigned, VariableList,
};
use execution_layer::PayloadAttributes;
use execution_layer::{ExecutionLayer, PayloadAttributes};
use lru::LruCache;
use std::marker::PhantomData;
use std::num::NonZeroUsize;

/// Information about previously seen canonical payloads which is used for building descendant payloads.
#[derive(Debug, Clone, Copy)]
pub struct PayloadInfo {
/// Execution block number.
pub block_number: u64,
/// Execution state root.
///
/// We use this as the state root of the block built upon this block. With 0 transactions, the
/// state root does not change!
pub state_root: Hash256,
/// For EIP-1559 calculations.
pub base_fee_per_gas: Uint256,
pub gas_used: u64,
pub gas_limit: u64,
}

pub struct PayloadBuilder<E: EthSpec> {
Expand All @@ -27,16 +38,22 @@ pub struct PayloadBuilder<E: EthSpec> {
payload_info: LruCache<ExecutionBlockHash, PayloadInfo>,
/// Map from payload ID to dummy execution payload.
payloads: LruCache<PayloadId, ExecutionPayload<E>>,
extra_data: VariableList<u8, E::MaxExtraDataBytes>,
_phantom: PhantomData<E>,
}

impl<E: EthSpec> PayloadBuilder<E> {
pub fn new(cache_size: NonZeroUsize) -> Self {
pub fn new(cache_size: NonZeroUsize, extra_data_str: &str) -> Self {
let extra_data_bytes = extra_data_str.as_bytes();
let len = std::cmp::min(extra_data_bytes.len(), E::MaxExtraDataBytes::to_usize());
let extra_data = VariableList::new(extra_data_bytes[..len].to_vec()).unwrap();

Self {
next_payload_id: 0,
payload_attributes: LruCache::new(cache_size),
payload_info: LruCache::new(cache_size),
payloads: LruCache::new(cache_size),
extra_data,
_phantom: PhantomData,
}
}
Expand Down Expand Up @@ -77,17 +94,34 @@ impl<E: EthSpec> Multiplexer<E> {
let gas_limit = 30_000_000;
let fork_name = self.spec.fork_name_at_slot::<E>(slot);
let transactions = VariableList::new(vec![]).unwrap();

let payload = match fork_name {
let state_root = parent_info.state_root;
let receipts_root = keccak_hash::KECCAK_EMPTY_LIST_RLP.as_fixed_bytes().into();
let logs_bloom = FixedVector::default();
let gas_used = 0;
let extra_data = builder.extra_data.clone();
let base_fee_per_gas = expected_base_fee_per_gas(
parent_info.base_fee_per_gas,
parent_info.gas_used,
parent_info.gas_limit,
);
let block_hash = ExecutionBlockHash::zero();

let mut payload = match fork_name {
ForkName::Merge => ExecutionPayload::Merge(ExecutionPayloadMerge {
parent_hash,
timestamp,
fee_recipient,
state_root,
receipts_root,
logs_bloom,
prev_randao,
block_number,
gas_limit,
gas_used,
timestamp,
extra_data,
base_fee_per_gas,
block_hash,
transactions,
..Default::default()
}),
ForkName::Capella => {
let withdrawals = payload_attributes
Expand All @@ -97,19 +131,28 @@ impl<E: EthSpec> Multiplexer<E> {
.into();
ExecutionPayload::Capella(ExecutionPayloadCapella {
parent_hash,
timestamp,
fee_recipient,
state_root,
receipts_root,
logs_bloom,
prev_randao,
block_number,
gas_limit,
gas_used,
timestamp,
extra_data,
base_fee_per_gas,
block_hash,
transactions,
withdrawals,
..Default::default()
})
}
ForkName::Base | ForkName::Altair => return Err(format!("invalid fork: {fork_name}")),
};

let (block_hash, _) = ExecutionLayer::<E>::calculate_execution_block_hash(payload.to_ref());
*payload.block_hash_mut() = block_hash;

builder.payload_attributes.put(attributes_key, id);
builder.payloads.put(id, payload);
builder.next_payload_id += 1;
Expand Down Expand Up @@ -149,6 +192,10 @@ impl<E: EthSpec> Multiplexer<E> {
.payload_info
.get_or_insert(payload.block_hash(), || PayloadInfo {
block_number: payload.block_number(),
state_root: payload.state_root(),
base_fee_per_gas: payload.base_fee_per_gas(),
gas_used: payload.gas_used(),
gas_limit: payload.gas_limit(),
});
}

Expand Down

0 comments on commit dcfb666

Please sign in to comment.