kona_engine/task_queue/tasks/insert/
task.rs1use crate::{
4 EngineClient, EngineState, EngineTaskExt, InsertTaskError, SynchronizeTask,
5 state::EngineSyncStateUpdate,
6};
7use alloy_eips::eip7685::EMPTY_REQUESTS_HASH;
8use alloy_provider::ext::EngineApi;
9use alloy_rpc_types_engine::{
10 CancunPayloadFields, ExecutionPayloadInputV2, PayloadStatusEnum, PraguePayloadFields,
11};
12use async_trait::async_trait;
13use kona_genesis::RollupConfig;
14use kona_protocol::L2BlockInfo;
15use op_alloy_consensus::OpBlock;
16use op_alloy_provider::ext::engine::OpEngineApi;
17use op_alloy_rpc_types_engine::{
18 OpExecutionPayload, OpExecutionPayloadEnvelope, OpExecutionPayloadSidecar,
19};
20use std::{sync::Arc, time::Instant};
21
22#[derive(Debug, Clone)]
24pub struct InsertTask {
25 client: Arc<EngineClient>,
27 rollup_config: Arc<RollupConfig>,
29 envelope: OpExecutionPayloadEnvelope,
31 is_payload_safe: bool,
34}
35
36impl InsertTask {
37 pub const fn new(
39 client: Arc<EngineClient>,
40 rollup_config: Arc<RollupConfig>,
41 envelope: OpExecutionPayloadEnvelope,
42 is_attributes_derived: bool,
43 ) -> Self {
44 Self { client, rollup_config, envelope, is_payload_safe: is_attributes_derived }
45 }
46
47 const fn check_new_payload_status(&self, status: &PayloadStatusEnum) -> bool {
49 matches!(status, PayloadStatusEnum::Valid | PayloadStatusEnum::Syncing)
50 }
51}
52
53#[async_trait]
54impl EngineTaskExt for InsertTask {
55 type Output = ();
56
57 type Error = InsertTaskError;
58
59 async fn execute(&self, state: &mut EngineState) -> Result<(), InsertTaskError> {
60 let time_start = Instant::now();
61
62 let parent_beacon_block_root = self.envelope.parent_beacon_block_root.unwrap_or_default();
65 let insert_time_start = Instant::now();
66 let (response, block): (_, OpBlock) = match self.envelope.execution_payload.clone() {
67 OpExecutionPayload::V1(payload) => (
68 self.client.new_payload_v1(payload).await,
69 self.envelope
70 .execution_payload
71 .clone()
72 .try_into_block()
73 .map_err(InsertTaskError::FromBlockError)?,
74 ),
75 OpExecutionPayload::V2(payload) => {
76 let payload_input = ExecutionPayloadInputV2 {
77 execution_payload: payload.payload_inner,
78 withdrawals: Some(payload.withdrawals),
79 };
80 (
81 self.client.new_payload_v2(payload_input).await,
82 self.envelope
83 .execution_payload
84 .clone()
85 .try_into_block()
86 .map_err(InsertTaskError::FromBlockError)?,
87 )
88 }
89 OpExecutionPayload::V3(payload) => (
90 self.client.new_payload_v3(payload, parent_beacon_block_root).await,
91 self.envelope
92 .execution_payload
93 .clone()
94 .try_into_block_with_sidecar(&OpExecutionPayloadSidecar::v3(
95 CancunPayloadFields::new(parent_beacon_block_root, vec![]),
96 ))
97 .map_err(InsertTaskError::FromBlockError)?,
98 ),
99 OpExecutionPayload::V4(payload) => (
100 self.client.new_payload_v4(payload, parent_beacon_block_root).await,
101 self.envelope
102 .execution_payload
103 .clone()
104 .try_into_block_with_sidecar(&OpExecutionPayloadSidecar::v4(
105 CancunPayloadFields::new(parent_beacon_block_root, vec![]),
106 PraguePayloadFields::new(EMPTY_REQUESTS_HASH),
107 ))
108 .map_err(InsertTaskError::FromBlockError)?,
109 ),
110 };
111
112 let response = match response {
114 Ok(resp) => resp,
115 Err(e) => return Err(InsertTaskError::InsertFailed(e)),
116 };
117 if !self.check_new_payload_status(&response.status) {
118 return Err(InsertTaskError::UnexpectedPayloadStatus(response.status));
119 }
120 let insert_duration = insert_time_start.elapsed();
121
122 let new_unsafe_ref =
123 L2BlockInfo::from_block_and_genesis(&block, &self.rollup_config.genesis)
124 .map_err(InsertTaskError::L2BlockInfoConstruction)?;
125
126 SynchronizeTask::new(
128 Arc::clone(&self.client),
129 self.rollup_config.clone(),
130 EngineSyncStateUpdate {
131 cross_unsafe_head: Some(new_unsafe_ref),
132 unsafe_head: Some(new_unsafe_ref),
133 local_safe_head: self.is_payload_safe.then_some(new_unsafe_ref),
134 safe_head: self.is_payload_safe.then_some(new_unsafe_ref),
135 ..Default::default()
136 },
137 )
138 .execute(state)
139 .await?;
140
141 let total_duration = time_start.elapsed();
142
143 info!(
144 target: "engine",
145 hash = %new_unsafe_ref.block_info.hash,
146 number = new_unsafe_ref.block_info.number,
147 total_duration = ?total_duration,
148 insert_duration = ?insert_duration,
149 "Inserted new unsafe block"
150 );
151
152 Ok(())
153 }
154}