mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: add Payload build abstraction (#2143)
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -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"
|
||||
|
||||
@ -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
19
crates/miner/Cargo.toml
Normal 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"
|
||||
6
crates/miner/src/error.rs
Normal file
6
crates/miner/src/error.rs
Normal 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
74
crates/miner/src/lib.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
79
crates/miner/src/payload.rs
Normal file
79
crates/miner/src/payload.rs
Normal 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"))
|
||||
}
|
||||
}
|
||||
@ -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")]
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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>
|
||||
|
||||
Reference in New Issue
Block a user