kona_protocol/
attributes.rs

1//! Optimism Payload attributes that reference the parent L2 block.
2
3use crate::{BlockInfo, L2BlockInfo};
4use alloc::vec;
5use op_alloy_consensus::OpTxType;
6use op_alloy_rpc_types_engine::OpPayloadAttributes;
7
8/// Optimism Payload Attributes with parent block reference and the L1 origin block.
9#[derive(Debug, Clone, PartialEq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct OpAttributesWithParent {
12    /// The payload attributes.
13    pub inner: OpPayloadAttributes,
14    /// The parent block reference.
15    pub parent: L2BlockInfo,
16    /// The L1 block that the attributes were derived from.
17    pub derived_from: Option<BlockInfo>,
18    /// Whether the current batch is the last in its span.
19    pub is_last_in_span: bool,
20}
21
22impl OpAttributesWithParent {
23    /// Create a new [`OpAttributesWithParent`] instance.
24    pub const fn new(
25        inner: OpPayloadAttributes,
26        parent: L2BlockInfo,
27        derived_from: Option<BlockInfo>,
28        is_last_in_span: bool,
29    ) -> Self {
30        Self { inner, parent, derived_from, is_last_in_span }
31    }
32
33    /// Returns the L2 block number for the payload attributes if made canonical.
34    /// Derived as the parent block height plus one.
35    pub const fn block_number(&self) -> u64 {
36        self.parent.block_info.number.saturating_add(1)
37    }
38
39    /// Consumes `self` and returns the inner [`OpPayloadAttributes`].
40    pub fn take_inner(self) -> OpPayloadAttributes {
41        self.inner
42    }
43
44    /// Returns the payload attributes.
45    pub const fn inner(&self) -> &OpPayloadAttributes {
46        &self.inner
47    }
48
49    /// Returns the parent block reference.
50    pub const fn parent(&self) -> &L2BlockInfo {
51        &self.parent
52    }
53
54    /// Returns the L1 origin block reference.
55    pub const fn derived_from(&self) -> Option<&BlockInfo> {
56        self.derived_from.as_ref()
57    }
58
59    /// Returns whether the current batch is the last in its span.
60    pub const fn is_last_in_span(&self) -> bool {
61        self.is_last_in_span
62    }
63
64    /// Returns `true` if all transactions in the payload are deposits.
65    pub fn is_deposits_only(&self) -> bool {
66        self.inner
67            .transactions
68            .iter()
69            .all(|tx| tx.first().is_some_and(|tx| tx[0] == OpTxType::Deposit as u8))
70    }
71
72    /// Converts the [`OpAttributesWithParent`] into a deposits-only payload.
73    pub fn as_deposits_only(&self) -> Self {
74        Self {
75            inner: OpPayloadAttributes {
76                transactions: self.inner.transactions.as_ref().map(|txs| {
77                    txs.iter()
78                        .map(|_| alloy_primitives::Bytes::from(vec![OpTxType::Deposit as u8]))
79                        .collect()
80                }),
81                ..self.inner.clone()
82            },
83            parent: self.parent,
84            derived_from: self.derived_from,
85            is_last_in_span: self.is_last_in_span,
86        }
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_op_attributes_with_parent() {
96        let attributes = OpPayloadAttributes::default();
97        let parent = L2BlockInfo::default();
98        let is_last_in_span = true;
99        let op_attributes_with_parent =
100            OpAttributesWithParent::new(attributes.clone(), parent, None, is_last_in_span);
101
102        assert_eq!(op_attributes_with_parent.inner(), &attributes);
103        assert_eq!(op_attributes_with_parent.parent(), &parent);
104        assert_eq!(op_attributes_with_parent.is_last_in_span(), is_last_in_span);
105        assert_eq!(op_attributes_with_parent.derived_from(), None);
106    }
107}