mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(payload): introduce payload freezing for predetermined blocks (#11790)
This commit is contained in:
@ -178,7 +178,7 @@ where
|
||||
deadline,
|
||||
// ticks immediately
|
||||
interval: tokio::time::interval(self.config.interval),
|
||||
best_payload: None,
|
||||
best_payload: PayloadState::Missing,
|
||||
pending_block: None,
|
||||
cached_reads,
|
||||
payload_task_guard: self.payload_task_guard.clone(),
|
||||
@ -324,8 +324,8 @@ where
|
||||
deadline: Pin<Box<Sleep>>,
|
||||
/// The interval at which the job should build a new payload after the last.
|
||||
interval: Interval,
|
||||
/// The best payload so far.
|
||||
best_payload: Option<Builder::BuiltPayload>,
|
||||
/// The best payload so far and its state.
|
||||
best_payload: PayloadState<Builder::BuiltPayload>,
|
||||
/// Receiver for the block that is currently being built.
|
||||
pending_block: Option<PendingPayload<Builder::BuiltPayload>>,
|
||||
/// Restricts how many generator tasks can be executed at once.
|
||||
@ -362,7 +362,7 @@ where
|
||||
let _cancel = cancel.clone();
|
||||
let guard = self.payload_task_guard.clone();
|
||||
let payload_config = self.config.clone();
|
||||
let best_payload = self.best_payload.clone();
|
||||
let best_payload = self.best_payload.payload().cloned();
|
||||
self.metrics.inc_initiated_payload_builds();
|
||||
let cached_reads = self.cached_reads.take().unwrap_or_default();
|
||||
let builder = self.builder.clone();
|
||||
@ -407,8 +407,9 @@ where
|
||||
|
||||
// check if the interval is reached
|
||||
while this.interval.poll_tick(cx).is_ready() {
|
||||
// start a new job if there is no pending block and we haven't reached the deadline
|
||||
if this.pending_block.is_none() {
|
||||
// start a new job if there is no pending block, we haven't reached the deadline,
|
||||
// and the payload isn't frozen
|
||||
if this.pending_block.is_none() && !this.best_payload.is_frozen() {
|
||||
this.spawn_build_job();
|
||||
}
|
||||
}
|
||||
@ -420,7 +421,11 @@ where
|
||||
BuildOutcome::Better { payload, cached_reads } => {
|
||||
this.cached_reads = Some(cached_reads);
|
||||
debug!(target: "payload_builder", value = %payload.fees(), "built better payload");
|
||||
this.best_payload = Some(payload);
|
||||
this.best_payload = PayloadState::Best(payload);
|
||||
}
|
||||
BuildOutcome::Freeze(payload) => {
|
||||
debug!(target: "payload_builder", "payload frozen, no further building will occur");
|
||||
this.best_payload = PayloadState::Frozen(payload);
|
||||
}
|
||||
BuildOutcome::Aborted { fees, cached_reads } => {
|
||||
this.cached_reads = Some(cached_reads);
|
||||
@ -459,17 +464,18 @@ where
|
||||
type BuiltPayload = Builder::BuiltPayload;
|
||||
|
||||
fn best_payload(&self) -> Result<Self::BuiltPayload, PayloadBuilderError> {
|
||||
if let Some(ref payload) = self.best_payload {
|
||||
return Ok(payload.clone())
|
||||
if let Some(payload) = self.best_payload.payload() {
|
||||
Ok(payload.clone())
|
||||
} else {
|
||||
// No payload has been built yet, but we need to return something that the CL then
|
||||
// can deliver, so we need to return an empty payload.
|
||||
//
|
||||
// Note: it is assumed that this is unlikely to happen, as the payload job is
|
||||
// started right away and the first full block should have been
|
||||
// built by the time CL is requesting the payload.
|
||||
self.metrics.inc_requested_empty_payload();
|
||||
self.builder.build_empty_payload(&self.client, self.config.clone())
|
||||
}
|
||||
// No payload has been built yet, but we need to return something that the CL then can
|
||||
// deliver, so we need to return an empty payload.
|
||||
//
|
||||
// Note: it is assumed that this is unlikely to happen, as the payload job is started right
|
||||
// away and the first full block should have been built by the time CL is requesting the
|
||||
// payload.
|
||||
self.metrics.inc_requested_empty_payload();
|
||||
self.builder.build_empty_payload(&self.client, self.config.clone())
|
||||
}
|
||||
|
||||
fn payload_attributes(&self) -> Result<Self::PayloadAttributes, PayloadBuilderError> {
|
||||
@ -480,8 +486,7 @@ where
|
||||
&mut self,
|
||||
kind: PayloadKind,
|
||||
) -> (Self::ResolvePayloadFuture, KeepPayloadJobAlive) {
|
||||
let best_payload = self.best_payload.take();
|
||||
|
||||
let best_payload = self.best_payload.payload().cloned();
|
||||
if best_payload.is_none() && self.pending_block.is_none() {
|
||||
// ensure we have a job scheduled if we don't have a best payload yet and none is active
|
||||
self.spawn_build_job();
|
||||
@ -545,6 +550,34 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the current state of a payload being built.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PayloadState<P> {
|
||||
/// No payload has been built yet.
|
||||
Missing,
|
||||
/// The best payload built so far, which may still be improved upon.
|
||||
Best(P),
|
||||
/// The payload is frozen and no further building should occur.
|
||||
///
|
||||
/// Contains the final payload `P` that should be used.
|
||||
Frozen(P),
|
||||
}
|
||||
|
||||
impl<P> PayloadState<P> {
|
||||
/// Checks if the payload is frozen.
|
||||
pub const fn is_frozen(&self) -> bool {
|
||||
matches!(self, Self::Frozen(_))
|
||||
}
|
||||
|
||||
/// Returns the payload if it exists (either Best or Frozen).
|
||||
pub const fn payload(&self) -> Option<&P> {
|
||||
match self {
|
||||
Self::Missing => None,
|
||||
Self::Best(p) | Self::Frozen(p) => Some(p),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The future that returns the best payload to be served to the consensus layer.
|
||||
///
|
||||
/// This returns the payload that's supposed to be sent to the CL.
|
||||
@ -725,6 +758,9 @@ pub enum BuildOutcome<Payload> {
|
||||
},
|
||||
/// Build job was cancelled
|
||||
Cancelled,
|
||||
|
||||
/// The payload is final and no further building should occur
|
||||
Freeze(Payload),
|
||||
}
|
||||
|
||||
impl<Payload> BuildOutcome<Payload> {
|
||||
|
||||
Reference in New Issue
Block a user