feat: add Payload build abstraction (#2143)

This commit is contained in:
Matthias Seitz
2023-04-06 20:48:31 +02:00
committed by GitHub
parent f90f734a76
commit 2fd2825e24
9 changed files with 210 additions and 5 deletions

12
Cargo.lock generated
View File

@ -4843,6 +4843,18 @@ dependencies = [
"trybuild",
]
[[package]]
name = "reth-miner"
version = "0.1.0"
dependencies = [
"parking_lot 0.12.1",
"reth-primitives",
"reth-rlp",
"reth-rpc-types",
"sha2 0.10.6",
"thiserror",
]
[[package]]
name = "reth-net-common"
version = "0.1.0"

View File

@ -6,6 +6,7 @@ members = [
"crates/consensus/common",
"crates/executor",
"crates/interfaces",
"crates/miner",
"crates/metrics/metrics-derive",
"crates/metrics/common",
"crates/net/common",

19
crates/miner/Cargo.toml Normal file
View File

@ -0,0 +1,19 @@
[package]
name = "reth-miner"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://github.com/paradigmxyz/reth"
readme = "README.md"
description = "Block production"
[dependencies]
## reth
reth-primitives = { path = "../primitives" }
reth-rpc-types = { path = "../rpc/rpc-types" }
reth-rlp = { path = "../rlp" }
## misc
thiserror = "1.0"
sha2 = { version = "0.10.6", default-features = false }
parking_lot = "0.12.1"

View File

@ -0,0 +1,6 @@
//! Error types emitted by types or implementations of this crate.
/// Possible error variants during payload building.
#[derive(Debug, thiserror::Error)]
#[error("Payload error")]
pub struct PayloadError;

74
crates/miner/src/lib.rs Normal file
View File

@ -0,0 +1,74 @@
#![warn(missing_docs)]
#![deny(
unused_must_use,
rust_2018_idioms,
rustdoc::broken_intra_doc_links,
unused_crate_dependencies
)]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]
//! reth miner implementation
mod payload;
use crate::error::PayloadError;
use parking_lot::Mutex;
pub use payload::{BuiltPayload, PayloadBuilderAttributes};
use reth_primitives::H256;
use reth_rpc_types::engine::{ExecutionPayload, PayloadAttributes, PayloadId};
use std::{collections::HashMap, sync::Arc};
pub mod error;
/// A type that has access to all locally built payloads and can create new ones.
/// This type is intended to by used by the engine API.
pub trait PayloadStore: Send + Sync {
/// Returns true if the payload store contains the given payload.
fn contains(&self, payload_id: PayloadId) -> bool;
/// Returns the current [ExecutionPayload] associated with the [PayloadId].
///
/// Returns `None` if the payload is not yet built, See [PayloadStore::new_payload].
fn get_execution_payload(&self, payload_id: PayloadId) -> Option<ExecutionPayload>;
/// Builds and stores a new payload using the given attributes.
///
/// Returns an error if the payload could not be built.
// TODO: does this require async?
fn new_payload(
&self,
parent: H256,
attributes: PayloadAttributes,
) -> Result<PayloadId, PayloadError>;
}
/// A simple in-memory payload store.
#[derive(Debug, Default)]
pub struct TestPayloadStore {
payloads: Arc<Mutex<HashMap<PayloadId, BuiltPayload>>>,
}
impl PayloadStore for TestPayloadStore {
fn contains(&self, payload_id: PayloadId) -> bool {
self.payloads.lock().contains_key(&payload_id)
}
fn get_execution_payload(&self, _payload_id: PayloadId) -> Option<ExecutionPayload> {
// TODO requires conversion
None
}
fn new_payload(
&self,
parent: H256,
attributes: PayloadAttributes,
) -> Result<PayloadId, PayloadError> {
let attr = PayloadBuilderAttributes::new(parent, attributes);
let payload_id = attr.payload_id();
self.payloads.lock().insert(payload_id, BuiltPayload::new(payload_id, Default::default()));
Ok(payload_id)
}
}

View File

@ -0,0 +1,79 @@
//! Contains types required for building a payload.
use reth_primitives::{Address, Block, SealedBlock, Withdrawal, H256};
use reth_rlp::Encodable;
use reth_rpc_types::engine::{PayloadAttributes, PayloadId};
/// Contains the built payload.
///
/// According to the [engine API specification](https://github.com/ethereum/execution-apis/blob/main/src/engine/README.md) the execution layer should build the initial version of the payload with an empty transaction set and then keep update it in order to maximize the revenue.
/// Therefore, the empty-block here is always available and full-block will be set/updated
/// afterwards.
#[derive(Debug)]
pub struct BuiltPayload {
/// Identifier of the payload
pub(crate) id: PayloadId,
/// The initially empty block.
_initial_empty_block: SealedBlock,
}
// === impl BuiltPayload ===
impl BuiltPayload {
/// Initializes the payload with the given initial block.
pub(crate) fn new(id: PayloadId, initial: Block) -> Self {
Self { id, _initial_empty_block: initial.seal_slow() }
}
/// Returns the identifier of the payload.
pub fn id(&self) -> PayloadId {
self.id
}
}
/// Container type for all components required to build a payload.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PayloadBuilderAttributes {
/// Parent block to build the payload on top
pub(crate) parent: H256,
/// Timestamp for the generated payload
pub(crate) timestamp: u64,
/// Address of the recipient for collecting transaction fee
pub(crate) suggested_fee_recipient: Address,
/// Randomness value for the generated payload
pub(crate) prev_randao: H256,
/// Withdrawals for the generated payload
pub(crate) withdrawals: Vec<Withdrawal>,
}
// === impl PayloadBuilderAttributes ===
impl PayloadBuilderAttributes {
/// Creates a new payload builder for the given parent block and the attributes
pub fn new(parent: H256, attributes: PayloadAttributes) -> Self {
Self {
parent,
timestamp: attributes.timestamp.as_u64(),
suggested_fee_recipient: attributes.suggested_fee_recipient,
prev_randao: attributes.prev_randao,
withdrawals: attributes.withdrawals.unwrap_or_default(),
}
}
/// Generates the payload id for the configured payload
///
/// Returns an 8-byte identifier by hashing the payload components.
pub fn payload_id(&self) -> PayloadId {
use sha2::Digest;
let mut hasher = sha2::Sha256::new();
hasher.update(self.parent.as_bytes());
hasher.update(&self.timestamp.to_be_bytes()[..]);
hasher.update(self.prev_randao.as_bytes());
hasher.update(self.suggested_fee_recipient.as_bytes());
let mut buf = Vec::new();
self.withdrawals.encode(&mut buf);
hasher.update(buf);
let out = hasher.finalize();
PayloadId::new(out.as_slice()[..8].try_into().expect("sufficient length"))
}
}

View File

@ -4,7 +4,7 @@ use reth_rlp::{RlpDecodable, RlpEncodable};
/// Withdrawal represents a validator withdrawal from the consensus layer.
#[main_codec]
#[derive(Debug, Clone, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)]
#[derive(Debug, Clone, PartialEq, Eq, Default, Hash, RlpEncodable, RlpDecodable)]
pub struct Withdrawal {
/// Monotonically increasing identifier issued by consensus layer.
#[serde(with = "u64_hex")]

View File

@ -1,5 +1,6 @@
use super::{PayloadStatus, PayloadStatusEnum};
use reth_primitives::{H256, H64};
use crate::engine::PayloadId;
use reth_primitives::H256;
use serde::{Deserialize, Serialize};
/// This structure encapsulates the fork choice state
@ -15,7 +16,7 @@ pub struct ForkchoiceState {
#[serde(rename_all = "camelCase")]
pub struct ForkchoiceUpdated {
pub payload_status: PayloadStatus,
pub payload_id: Option<H64>,
pub payload_id: Option<PayloadId>,
}
impl ForkchoiceUpdated {
@ -32,7 +33,7 @@ impl ForkchoiceUpdated {
self
}
pub fn with_payload_id(mut self, id: H64) -> Self {
pub fn with_payload_id(mut self, id: PayloadId) -> Self {
self.payload_id = Some(id);
self
}

View File

@ -2,11 +2,24 @@ use reth_primitives::{
constants::MIN_PROTOCOL_BASE_FEE_U256,
proofs::{self, EMPTY_LIST_HASH},
Address, Block, Bloom, Bytes, Header, SealedBlock, TransactionSigned, UintTryTo, Withdrawal,
H256, U256, U64,
H256, H64, U256, U64,
};
use reth_rlp::{Decodable, Encodable};
use serde::{ser::SerializeMap, Deserialize, Serialize, Serializer};
/// And 8-byte identifier for an execution payload.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct PayloadId(H64);
// === impl PayloadId ===
impl PayloadId {
/// Creates a new payload id from the given identifier.
pub fn new(id: [u8; 8]) -> Self {
Self(H64::from(id))
}
}
/// This structure maps on the ExecutionPayload structure of the beacon chain spec.
///
/// See also: <https://github.com/ethereum/execution-apis/blob/6709c2a795b707202e93c4f2867fa0bf2640a84f/src/engine/paris.md#executionpayloadv1>