espresso_types/v0/impls/
header.rs

1use std::fmt;
2
3use alloy::primitives::{B256, Keccak256};
4use anyhow::{Context, ensure};
5use ark_serialize::CanonicalSerialize;
6use base64::{Engine, prelude::BASE64_STANDARD};
7use committable::{Commitment, Committable, RawCommitmentBuilder};
8use either::Either;
9use hotshot_query_service::{availability::QueryableHeader, explorer::ExplorerHeader};
10use hotshot_types::{
11    data::{EpochNumber, VidCommitment, ViewNumber, vid_commitment},
12    light_client::LightClientState,
13    traits::{
14        BlockPayload, EncodeBytes, ValidatedState as _,
15        block_contents::{BlockHeader, BuilderFee, GENESIS_VID_NUM_STORAGE_NODES},
16        node_implementation::NodeType,
17        signature_key::BuilderSignatureKey,
18    },
19    utils::{BuilderCommitment, epoch_from_block_number, is_ge_epoch_root},
20};
21use jf_merkle_tree_compat::{AppendableMerkleTreeScheme, MerkleCommitment, MerkleTreeScheme};
22use serde::{
23    Deserialize, Deserializer, Serialize, Serializer,
24    de::{self, MapAccess, SeqAccess, Visitor},
25};
26use serde_json::{Map, Value};
27use thiserror::Error;
28use time::OffsetDateTime;
29use vbs::version::Version;
30use versions::{DRB_AND_HEADER_UPGRADE_VERSION, EPOCH_VERSION};
31
32use super::{
33    instance_state::NodeState, state::ValidatedState, v0_1::IterableFeeInfo, v0_3::ChainConfig,
34};
35use crate::{
36    BlockMerkleCommitment, FeeAccount, FeeAmount, FeeInfo, FeeMerkleCommitment, Header,
37    L1BlockInfo, L1Snapshot, Leaf2, NamespaceId, NsIndex, NsTable, PayloadByteLen, SeqTypes,
38    TimestampMillis, UpgradeType,
39    eth_signature_key::BuilderSignature,
40    v0::{
41        header::{EitherOrVersion, VersionedHeader},
42        impls::{StakeTableHash, distribute_block_reward, reward::RewardDistributor},
43    },
44    v0_1::{self},
45    v0_2,
46    v0_3::{
47        self, REWARD_MERKLE_TREE_V1_HEIGHT, RewardAmount, RewardMerkleCommitmentV1,
48        RewardMerkleTreeV1,
49    },
50    v0_4::{self, RewardMerkleCommitmentV2},
51    v0_5,
52};
53
54impl v0_1::Header {
55    pub(crate) fn commit(&self) -> Commitment<Header> {
56        let mut bmt_bytes = vec![];
57        self.block_merkle_tree_root
58            .serialize_with_mode(&mut bmt_bytes, ark_serialize::Compress::Yes)
59            .unwrap();
60        let mut fmt_bytes = vec![];
61        self.fee_merkle_tree_root
62            .serialize_with_mode(&mut fmt_bytes, ark_serialize::Compress::Yes)
63            .unwrap();
64
65        RawCommitmentBuilder::new(&Self::tag())
66            .field("chain_config", self.chain_config.commit())
67            .u64_field("height", self.height)
68            .u64_field("timestamp", self.timestamp)
69            .u64_field("l1_head", self.l1_head)
70            .optional("l1_finalized", &self.l1_finalized)
71            .constant_str("payload_commitment")
72            .fixed_size_bytes(self.payload_commitment.as_ref())
73            .constant_str("builder_commitment")
74            .fixed_size_bytes(self.builder_commitment.as_ref())
75            .field("ns_table", self.ns_table.commit())
76            .var_size_field("block_merkle_tree_root", &bmt_bytes)
77            .var_size_field("fee_merkle_tree_root", &fmt_bytes)
78            .field("fee_info", self.fee_info.commit())
79            .finalize()
80    }
81}
82
83impl Committable for Header {
84    fn commit(&self) -> Commitment<Self> {
85        match self {
86            Self::V1(header) => header.commit(),
87            Self::V2(fields) => RawCommitmentBuilder::new(&Self::tag())
88                .u64_field("version_major", 0)
89                .u64_field("version_minor", 2)
90                .field("fields", fields.commit())
91                .finalize(),
92            Self::V3(fields) => RawCommitmentBuilder::new(&Self::tag())
93                .u64_field("version_major", 0)
94                .u64_field("version_minor", 3)
95                .field("fields", fields.commit())
96                .finalize(),
97            Self::V4(fields) => RawCommitmentBuilder::new(&Self::tag())
98                .u64_field("version_major", 0)
99                .u64_field("version_minor", 4)
100                .field("fields", fields.commit())
101                .finalize(),
102            Self::V5(fields) => RawCommitmentBuilder::new(&Self::tag())
103                .u64_field("version_major", 0)
104                .u64_field("version_minor", 5)
105                .field("fields", fields.commit())
106                .finalize(),
107        }
108    }
109
110    fn tag() -> String {
111        // We use the tag "BLOCK" since blocks are identified by the hash of their header. This will
112        // thus be more intuitive to users than "HEADER".
113        "BLOCK".into()
114    }
115}
116
117impl Serialize for Header {
118    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
119    where
120        S: Serializer,
121    {
122        match self {
123            Self::V1(header) => header.serialize(serializer),
124            Self::V2(fields) => VersionedHeader {
125                version: EitherOrVersion::Version(Version { major: 0, minor: 2 }),
126                fields: fields.clone(),
127            }
128            .serialize(serializer),
129            Self::V3(fields) => VersionedHeader {
130                version: EitherOrVersion::Version(Version { major: 0, minor: 3 }),
131                fields: fields.clone(),
132            }
133            .serialize(serializer),
134            Self::V4(fields) => VersionedHeader {
135                version: EitherOrVersion::Version(Version { major: 0, minor: 4 }),
136                fields: fields.clone(),
137            }
138            .serialize(serializer),
139            Self::V5(fields) => VersionedHeader {
140                version: EitherOrVersion::Version(Version { major: 0, minor: 5 }),
141                fields: fields.clone(),
142            }
143            .serialize(serializer),
144        }
145    }
146}
147
148impl<'de> Deserialize<'de> for Header {
149    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
150    where
151        D: Deserializer<'de>,
152    {
153        struct HeaderVisitor;
154
155        impl<'de> Visitor<'de> for HeaderVisitor {
156            type Value = Header;
157
158            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
159                formatter.write_str("Header")
160            }
161
162            fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
163            where
164                V: SeqAccess<'de>,
165            {
166                let chain_config_or_version: EitherOrVersion = seq
167                    .next_element()?
168                    .ok_or_else(|| de::Error::missing_field("chain_config"))?;
169
170                match chain_config_or_version {
171                    // For v0.1, the first field in the sequence of fields is the first field of the struct, so we call a function to get the rest of
172                    // the fields from the sequence and pack them into the struct.
173                    EitherOrVersion::Left(cfg) => Ok(Header::V1(
174                        v0_1::Header::deserialize_with_chain_config(cfg.into(), seq)?,
175                    )),
176                    EitherOrVersion::Right(commit) => Ok(Header::V1(
177                        v0_1::Header::deserialize_with_chain_config(commit.into(), seq)?,
178                    )),
179                    // For all versions > 0.1, the first "field" is not actually part of the `Header` struct.
180                    // We just delegate directly to the derived deserialization impl for the appropriate version.
181                    EitherOrVersion::Version(Version { major: 0, minor: 2 }) => Ok(Header::V2(
182                        seq.next_element()?
183                            .ok_or_else(|| de::Error::missing_field("fields"))?,
184                    )),
185                    EitherOrVersion::Version(Version { major: 0, minor: 3 }) => Ok(Header::V3(
186                        seq.next_element()?
187                            .ok_or_else(|| de::Error::missing_field("fields"))?,
188                    )),
189                    EitherOrVersion::Version(Version { major: 0, minor: 4 }) => Ok(Header::V4(
190                        seq.next_element()?
191                            .ok_or_else(|| de::Error::missing_field("fields"))?,
192                    )),
193                    EitherOrVersion::Version(Version { major: 0, minor: 5 }) => Ok(Header::V5(
194                        seq.next_element()?
195                            .ok_or_else(|| de::Error::missing_field("fields"))?,
196                    )),
197                    EitherOrVersion::Version(v) => {
198                        Err(serde::de::Error::custom(format!("invalid version {v:?}")))
199                    },
200                }
201            }
202
203            fn visit_map<V>(self, mut map: V) -> Result<Header, V::Error>
204            where
205                V: MapAccess<'de>,
206            {
207                // insert all the fields in the serde_map as the map may have out of order fields.
208                let mut serde_map: Map<String, Value> = Map::new();
209
210                while let Some(key) = map.next_key::<String>()? {
211                    serde_map.insert(key.trim().to_owned(), map.next_value()?);
212                }
213
214                if let Some(v) = serde_map.get("version") {
215                    let fields = serde_map
216                        .get("fields")
217                        .ok_or_else(|| de::Error::missing_field("fields"))?;
218
219                    let version = serde_json::from_value::<EitherOrVersion>(v.clone())
220                        .map_err(de::Error::custom)?;
221                    let result = match version {
222                        EitherOrVersion::Version(Version { major: 0, minor: 2 }) => Ok(Header::V2(
223                            serde_json::from_value(fields.clone()).map_err(de::Error::custom)?,
224                        )),
225                        EitherOrVersion::Version(Version { major: 0, minor: 3 }) => Ok(Header::V3(
226                            serde_json::from_value(fields.clone()).map_err(de::Error::custom)?,
227                        )),
228                        EitherOrVersion::Version(Version { major: 0, minor: 4 }) => Ok(Header::V4(
229                            serde_json::from_value(fields.clone()).map_err(de::Error::custom)?,
230                        )),
231                        EitherOrVersion::Version(Version { major: 0, minor: 5 }) => Ok(Header::V5(
232                            serde_json::from_value(fields.clone()).map_err(de::Error::custom)?,
233                        )),
234                        EitherOrVersion::Version(v) => {
235                            Err(de::Error::custom(format!("invalid version {v:?}")))
236                        },
237                        chain_config => Err(de::Error::custom(format!(
238                            "expected version, found chain_config {chain_config:?}"
239                        ))),
240                    };
241                    return result;
242                }
243
244                Ok(Header::V1(
245                    serde_json::from_value(serde_map.into()).map_err(de::Error::custom)?,
246                ))
247            }
248        }
249
250        // List of all possible fields of all versions of the `Header`.
251        // serde's `deserialize_struct` works by deserializing to a struct with a specific list of fields.
252        // The length of the fields list we provide is always going to be greater than the length of the target struct.
253        // In our case, we are deserializing to either a V1 Header or a VersionedHeader for versions > 0.1.
254        // We use serde_json and bincode serialization in the sequencer.
255        // Fortunately, serde_json ignores fields parameter and only cares about our Visitor implementation.
256        // -  https://docs.rs/serde_json/1.0.120/serde_json/struct.Deserializer.html#method.deserialize_struct
257        // Bincode uses the length of the fields list, but the bincode deserialization only cares that the length of the fields
258        // is an upper bound of the target struct's fields length.
259        // -  https://docs.rs/bincode/1.3.3/src/bincode/de/mod.rs.html#313
260        // This works because the bincode deserializer only consumes the next field when `next_element` is called,
261        // and our visitor calls it the correct number of times.
262        // This would, however, break if the bincode deserializer implementation required an exact match of the field's length,
263        // consuming one element for each field.
264        let fields: &[&str] = &[
265            "fields",
266            "chain_config",
267            "version",
268            "height",
269            "timestamp",
270            "l1_head",
271            "l1_finalized",
272            "payload_commitment",
273            "builder_commitment",
274            "ns_table",
275            "block_merkle_tree_root",
276            "fee_merkle_tree_root",
277            "fee_info",
278            "builder_signature",
279        ];
280
281        deserializer.deserialize_struct("Header", fields, HeaderVisitor)
282    }
283}
284
285impl Header {
286    pub fn version(&self) -> Version {
287        match self {
288            Self::V1(_) => Version { major: 0, minor: 1 },
289            Self::V2(_) => Version { major: 0, minor: 2 },
290            Self::V3(_) => Version { major: 0, minor: 3 },
291            Self::V4(_) => Version { major: 0, minor: 4 },
292            Self::V5(_) => Version { major: 0, minor: 5 },
293        }
294    }
295    #[allow(clippy::too_many_arguments)]
296    pub(crate) fn create(
297        chain_config: ChainConfig,
298        height: u64,
299        timestamp: u64,
300        timestamp_millis: u64,
301        l1_head: u64,
302        l1_finalized: Option<L1BlockInfo>,
303        payload_commitment: VidCommitment,
304        builder_commitment: BuilderCommitment,
305        ns_table: NsTable,
306        fee_merkle_tree_root: FeeMerkleCommitment,
307        block_merkle_tree_root: BlockMerkleCommitment,
308        reward_merkle_tree_root_v1: RewardMerkleCommitmentV1,
309        reward_merkle_tree_root_v2: RewardMerkleCommitmentV2,
310        fee_info: Vec<FeeInfo>,
311        builder_signature: Vec<BuilderSignature>,
312        total_reward_distributed: Option<RewardAmount>,
313        version: Version,
314        next_stake_table_hash: Option<StakeTableHash>,
315    ) -> Self {
316        // Ensure FeeInfo contains at least 1 element
317        assert!(!fee_info.is_empty(), "Invalid fee_info length: 0");
318
319        match (version.major, version.minor) {
320            (0, 1) => Self::V1(v0_1::Header {
321                chain_config: v0_1::ResolvableChainConfig::from(v0_1::ChainConfig::from(
322                    chain_config,
323                )),
324                height,
325                timestamp,
326                l1_head,
327                l1_finalized,
328                payload_commitment,
329                builder_commitment,
330                ns_table,
331                block_merkle_tree_root,
332                fee_merkle_tree_root,
333                fee_info: fee_info[0], // NOTE this is asserted to exist above
334                builder_signature: builder_signature.first().copied(),
335            }),
336            (0, 2) => Self::V2(v0_2::Header {
337                chain_config: v0_1::ResolvableChainConfig::from(v0_1::ChainConfig::from(
338                    chain_config,
339                )),
340                height,
341                timestamp,
342                l1_head,
343                l1_finalized,
344                payload_commitment,
345                builder_commitment,
346                ns_table,
347                block_merkle_tree_root,
348                fee_merkle_tree_root,
349                fee_info: fee_info[0], // NOTE this is asserted to exist above
350                builder_signature: builder_signature.first().copied(),
351            }),
352            (0, 3) => Self::V3(v0_3::Header {
353                chain_config: chain_config.into(),
354                height,
355                timestamp,
356                l1_head,
357                l1_finalized,
358                payload_commitment,
359                builder_commitment,
360                ns_table,
361                block_merkle_tree_root,
362                fee_merkle_tree_root,
363                fee_info: fee_info[0], // NOTE this is asserted to exist above
364                builder_signature: builder_signature.first().copied(),
365                reward_merkle_tree_root: reward_merkle_tree_root_v1,
366            }),
367            (0, 4) => Self::V4(v0_4::Header {
368                chain_config: chain_config.into(),
369                height,
370                timestamp,
371                timestamp_millis: TimestampMillis::from_millis(timestamp_millis),
372                l1_head,
373                l1_finalized,
374                payload_commitment,
375                builder_commitment,
376                ns_table,
377                block_merkle_tree_root,
378                fee_merkle_tree_root,
379                fee_info: fee_info[0], // NOTE this is asserted to exist above
380                builder_signature: builder_signature.first().copied(),
381                reward_merkle_tree_root: reward_merkle_tree_root_v2,
382                total_reward_distributed: total_reward_distributed.unwrap_or_default(),
383                next_stake_table_hash,
384            }),
385            (0, 5) => Self::V5(v0_5::Header {
386                chain_config: chain_config.into(),
387                height,
388                timestamp,
389                timestamp_millis: TimestampMillis::from_millis(timestamp_millis),
390                l1_head,
391                l1_finalized,
392                payload_commitment,
393                builder_commitment,
394                ns_table,
395                block_merkle_tree_root,
396                fee_merkle_tree_root,
397                fee_info: fee_info[0], // NOTE this is asserted to exist above
398                builder_signature: builder_signature.first().copied(),
399                reward_merkle_tree_root: reward_merkle_tree_root_v2,
400                total_reward_distributed: total_reward_distributed.unwrap_or_default(),
401                next_stake_table_hash,
402            }),
403            // This case should never occur
404            // but if it does, we must panic
405            // because we don't have the versioned types for this version
406            _ => panic!("invalid version: {version}"),
407        }
408    }
409
410    pub fn next_stake_table_hash(&self) -> Option<StakeTableHash> {
411        match self {
412            Self::V4(fields) | Self::V5(fields) => fields.next_stake_table_hash,
413            _ => None,
414        }
415    }
416
417    pub fn set_next_stake_table_hash(&mut self, hash: StakeTableHash) -> bool {
418        match self {
419            Self::V4(fields) | Self::V5(fields) => {
420                fields.next_stake_table_hash = Some(hash);
421                true
422            },
423            _ => false,
424        }
425    }
426}
427
428// Getter for a field which is the same across all versions.
429macro_rules! field {
430    ($obj:ident.$name:ident) => {
431        match $obj {
432            Self::V1(data) => &data.$name,
433            Self::V2(data) => &data.$name,
434            Self::V3(data) => &data.$name,
435            Self::V4(data) => &data.$name,
436            Self::V5(data) => &data.$name,
437        }
438    };
439}
440
441macro_rules! field_mut {
442    ($obj:ident.$name:ident) => {
443        match $obj {
444            Self::V1(data) => &mut data.$name,
445            Self::V2(data) => &mut data.$name,
446            Self::V3(data) => &mut data.$name,
447            Self::V4(data) => &mut data.$name,
448            Self::V5(data) => &mut data.$name,
449        }
450    };
451}
452
453impl Header {
454    #[allow(clippy::too_many_arguments)]
455    fn from_info(
456        payload_commitment: VidCommitment,
457        builder_commitment: BuilderCommitment,
458        ns_table: NsTable,
459        parent_leaf: &Leaf2,
460        mut l1: L1Snapshot,
461        l1_deposits: &[FeeInfo],
462        builder_fee: Vec<BuilderFee<SeqTypes>>,
463        mut timestamp: u64,
464        mut timestamp_millis: u64,
465        mut state: ValidatedState,
466        chain_config: ChainConfig,
467        version: Version,
468        reward_distributor: Option<RewardDistributor>,
469        next_stake_table_hash: Option<StakeTableHash>,
470    ) -> anyhow::Result<Self> {
471        ensure!(
472            version.major == 0,
473            "Invalid major version {}",
474            version.major
475        );
476
477        // Increment height.
478        let parent_header = parent_leaf.block_header();
479        let height = parent_header.height() + 1;
480
481        // Ensure the timestamp does not decrease. We can trust `parent.timestamp` because `parent`
482        // has already been voted on by consensus. If our timestamp is behind, either f + 1 nodes
483        // are lying about the current time, or our clock is just lagging.
484        if timestamp < parent_header.timestamp() {
485            tracing::warn!(
486                "Espresso timestamp {timestamp} behind parent {}, local clock may be out of sync",
487                parent_header.timestamp()
488            );
489            timestamp = parent_header.timestamp();
490        }
491
492        if timestamp_millis < parent_header.timestamp_millis() {
493            tracing::warn!(
494                "Espresso timestamp {timestamp} behind parent {}, local clock may be out of sync",
495                parent_header.timestamp_millis()
496            );
497            timestamp_millis = parent_header.timestamp_millis();
498        }
499
500        // Ensure the L1 block references don't decrease. Again, we can trust `parent.l1_*` are
501        // accurate.
502        if l1.head < parent_header.l1_head() {
503            tracing::warn!(
504                "L1 head {} behind parent {}, L1 client may be lagging",
505                l1.head,
506                parent_header.l1_head()
507            );
508            l1.head = parent_header.l1_head();
509        }
510        if l1.finalized < parent_header.l1_finalized() {
511            tracing::warn!(
512                "L1 finalized {:?} behind parent {:?}, L1 client may be lagging",
513                l1.finalized,
514                parent_header.l1_finalized()
515            );
516            l1.finalized = parent_header.l1_finalized();
517        }
518
519        // Enforce that the sequencer block timestamp is not behind the L1 block timestamp. This can
520        // only happen if our clock is badly out of sync with L1.
521        if let Some(l1_block) = &l1.finalized {
522            let l1_timestamp = l1_block.timestamp.to::<u64>();
523            if timestamp < l1_timestamp {
524                tracing::warn!(
525                    "Espresso timestamp {timestamp} behind L1 timestamp {l1_timestamp}, local \
526                     clock may be out of sync"
527                );
528                timestamp = l1_timestamp;
529            }
530
531            let l1_timestamp_millis = l1_timestamp * 1_000;
532
533            if timestamp_millis < l1_timestamp_millis {
534                tracing::warn!(
535                    "Espresso timestamp_millis {timestamp_millis} behind L1 timestamp \
536                     {l1_timestamp_millis}, local clock may be out of sync"
537                );
538                timestamp_millis = l1_timestamp_millis;
539            }
540        }
541
542        state
543            .block_merkle_tree
544            .push(parent_header.commit())
545            .context("missing blocks frontier")?;
546        let block_merkle_tree_root = state.block_merkle_tree.commitment();
547
548        // Insert the new L1 deposits
549        for fee_info in l1_deposits {
550            state
551                .insert_fee_deposit(*fee_info)
552                .context(format!("missing fee account {}", fee_info.account()))?;
553        }
554
555        // Validate and charge the builder fee.
556        for BuilderFee {
557            fee_account,
558            fee_signature,
559            fee_amount,
560        } in &builder_fee
561        {
562            ensure!(
563                fee_account.validate_fee_signature(fee_signature, *fee_amount, &ns_table)
564                    || fee_account.validate_fee_signature_with_vid_commitment(
565                        fee_signature,
566                        *fee_amount,
567                        &ns_table,
568                        &payload_commitment
569                    ),
570                "invalid builder signature"
571            );
572
573            let fee_info = FeeInfo::new(*fee_account, *fee_amount);
574            state
575                .charge_fee(fee_info, chain_config.fee_recipient)
576                .context(format!("invalid builder fee {fee_info:?}"))?;
577        }
578
579        let fee_info = FeeInfo::from_builder_fees(builder_fee.clone());
580
581        let builder_signature: Vec<BuilderSignature> =
582            builder_fee.iter().map(|e| e.fee_signature).collect();
583
584        let fee_merkle_tree_root = state.fee_merkle_tree.commitment();
585
586        let header = match (version.major, version.minor) {
587            (0, 1) => Self::V1(v0_1::Header {
588                chain_config: v0_1::ResolvableChainConfig::from(v0_1::ChainConfig::from(
589                    chain_config,
590                )),
591                height,
592                timestamp,
593                l1_head: l1.head,
594                l1_finalized: l1.finalized,
595                payload_commitment,
596                builder_commitment,
597                ns_table,
598                block_merkle_tree_root,
599                fee_merkle_tree_root,
600                fee_info: fee_info[0],
601                builder_signature: builder_signature.first().copied(),
602            }),
603            (0, 2) => Self::V2(v0_2::Header {
604                chain_config: v0_1::ResolvableChainConfig::from(v0_1::ChainConfig::from(
605                    chain_config,
606                )),
607                height,
608                timestamp,
609                l1_head: l1.head,
610                l1_finalized: l1.finalized,
611                payload_commitment,
612                builder_commitment,
613                ns_table,
614                block_merkle_tree_root,
615                fee_merkle_tree_root,
616                fee_info: fee_info[0],
617                builder_signature: builder_signature.first().copied(),
618            }),
619            (0, 3) => Self::V3(v0_3::Header {
620                chain_config: chain_config.into(),
621                height,
622                timestamp,
623                l1_head: l1.head,
624                l1_finalized: l1.finalized,
625                payload_commitment,
626                builder_commitment,
627                ns_table,
628                block_merkle_tree_root,
629                fee_merkle_tree_root,
630                reward_merkle_tree_root: state.reward_merkle_tree_v1.commitment(),
631                fee_info: fee_info[0],
632                builder_signature: builder_signature.first().copied(),
633            }),
634            (0, 4) => Self::V4(v0_4::Header {
635                chain_config: chain_config.into(),
636                height,
637                timestamp,
638                timestamp_millis: TimestampMillis::from_millis(timestamp_millis),
639                l1_head: l1.head,
640                l1_finalized: l1.finalized,
641                payload_commitment,
642                builder_commitment,
643                ns_table,
644                block_merkle_tree_root,
645                fee_merkle_tree_root,
646                reward_merkle_tree_root: state.reward_merkle_tree_v2.commitment(),
647                fee_info: fee_info[0],
648                builder_signature: builder_signature.first().copied(),
649                total_reward_distributed: reward_distributor
650                    .map(|r| r.total_distributed())
651                    .unwrap_or_default(),
652                next_stake_table_hash,
653            }),
654            (0, 5) => Self::V5(v0_5::Header {
655                chain_config: chain_config.into(),
656                height,
657                timestamp,
658                timestamp_millis: TimestampMillis::from_millis(timestamp_millis),
659                l1_head: l1.head,
660                l1_finalized: l1.finalized,
661                payload_commitment,
662                builder_commitment,
663                ns_table,
664                block_merkle_tree_root,
665                fee_merkle_tree_root,
666                reward_merkle_tree_root: state.reward_merkle_tree_v2.commitment(),
667                fee_info: fee_info[0],
668                builder_signature: builder_signature.first().copied(),
669                total_reward_distributed: reward_distributor
670                    .map(|r| r.total_distributed())
671                    .unwrap_or_default(),
672                next_stake_table_hash,
673            }),
674            // This case should never occur
675            // but if it does, we must panic
676            // because we don't have the versioned types for this version
677            _ => panic!("invalid version: {version}"),
678        };
679        Ok(header)
680    }
681
682    async fn get_chain_config(
683        validated_state: &ValidatedState,
684        instance_state: &NodeState,
685    ) -> anyhow::Result<ChainConfig> {
686        let validated_cf = validated_state.chain_config;
687        let instance_cf = instance_state.chain_config;
688
689        if validated_cf.commit() == instance_cf.commit() {
690            return Ok(instance_cf);
691        }
692
693        match validated_cf.resolve() {
694            Some(cf) => Ok(cf),
695            None => {
696                tracing::info!("fetching chain config {} from peers", validated_cf.commit());
697
698                instance_state
699                    .state_catchup
700                    .as_ref()
701                    .fetch_chain_config(validated_cf.commit())
702                    .await
703            },
704        }
705    }
706}
707
708impl Header {
709    /// A commitment to a ChainConfig or a full ChainConfig.
710    pub fn chain_config(&self) -> v0_3::ResolvableChainConfig {
711        match self {
712            Self::V1(fields) => v0_3::ResolvableChainConfig::from(&fields.chain_config),
713            Self::V2(fields) => v0_3::ResolvableChainConfig::from(&fields.chain_config),
714            Self::V3(fields) => fields.chain_config,
715            Self::V4(fields) => fields.chain_config,
716            Self::V5(fields) => fields.chain_config,
717        }
718    }
719
720    pub fn height(&self) -> u64 {
721        *field!(self.height)
722    }
723
724    pub fn height_mut(&mut self) -> &mut u64 {
725        &mut *field_mut!(self.height)
726    }
727
728    pub fn timestamp_internal(&self) -> u64 {
729        match self {
730            Self::V1(fields) => fields.timestamp,
731            Self::V2(fields) => fields.timestamp,
732            Self::V3(fields) => fields.timestamp,
733            Self::V4(fields) => fields.timestamp,
734            Self::V5(fields) => fields.timestamp,
735        }
736    }
737
738    pub fn timestamp_millis_internal(&self) -> u64 {
739        match self {
740            Self::V1(fields) => fields.timestamp * 1_000,
741            Self::V2(fields) => fields.timestamp * 1_000,
742            Self::V3(fields) => fields.timestamp * 1_000,
743            Self::V4(fields) => fields.timestamp_millis.u64(),
744            Self::V5(fields) => fields.timestamp_millis.u64(),
745        }
746    }
747
748    pub fn set_timestamp(&mut self, timestamp: u64, timestamp_millis: u64) {
749        match self {
750            Self::V1(fields) => {
751                fields.timestamp = timestamp;
752            },
753            Self::V2(fields) => {
754                fields.timestamp = timestamp;
755            },
756            Self::V3(fields) => {
757                fields.timestamp = timestamp;
758            },
759            Self::V4(fields) => {
760                fields.timestamp = timestamp;
761                fields.timestamp_millis = TimestampMillis::from_millis(timestamp_millis);
762            },
763            Self::V5(fields) => {
764                fields.timestamp = timestamp;
765                fields.timestamp_millis = TimestampMillis::from_millis(timestamp_millis);
766            },
767        };
768    }
769
770    /// The Espresso block header includes a reference to the current head of the L1 chain.
771    ///
772    /// Rollups can use this to facilitate bridging between the L1 and L2 in a deterministic way.
773    /// This field deterministically associates an L2 block with a recent L1 block the instant the
774    /// L2 block is sequenced. Rollups can then define the L2 state after this block as the state
775    /// obtained by executing all the transactions in this block _plus_ all the L1 deposits up to
776    /// the given L1 block number. Since there is no need to wait for the L2 block to be reflected
777    /// on the L1, this bridge design retains the low confirmation latency of HotShot.
778    ///
779    /// This block number indicates the unsafe head of the L1 chain, so it is subject to reorgs. For
780    /// this reason, the Espresso header does not include any information that might change in a
781    /// reorg, such as the L1 block timestamp or hash. It includes only the L1 block number, which
782    /// will always refer to _some_ block after a reorg: if the L1 head at the time this block was
783    /// sequenced gets reorged out, the L1 chain will eventually (and probably quickly) grow to the
784    /// same height once again, and a different block will exist with the same height. In this way,
785    /// Espresso does not have to handle L1 reorgs, and the Espresso blockchain will always be
786    /// reflective of the current state of the L1 blockchain. Rollups that use this block number
787    /// _do_ have to handle L1 reorgs, but each rollup and each rollup client can decide how many
788    /// confirmations they want to wait for on top of this `l1_head` before they consider an L2
789    /// block finalized. This offers a tradeoff between low-latency L1-L2 bridges and finality.
790    ///
791    /// Rollups that want a stronger guarantee of finality, or that want Espresso to attest to data
792    /// from the L1 block that might change in reorgs, can instead use the latest L1 _finalized_
793    /// block at the time this L2 block was sequenced: [`Self::l1_finalized`].
794    pub fn l1_head(&self) -> u64 {
795        *field!(self.l1_head)
796    }
797
798    pub fn l1_head_mut(&mut self) -> &mut u64 {
799        &mut *field_mut!(self.l1_head)
800    }
801
802    /// The Espresso block header includes information about the latest finalized L1 block.
803    ///
804    /// Similar to [`l1_head`](Self::l1_head), rollups can use this information to implement a
805    /// bridge between the L1 and L2 while retaining the finality of low-latency block confirmations
806    /// from HotShot. Since this information describes the finalized L1 block, a bridge using this
807    /// L1 block will have much higher latency than a bridge using [`l1_head`](Self::l1_head). In
808    /// exchange, rollups that use the finalized block do not have to worry about L1 reorgs, and can
809    /// inject verifiable attestations to the L1 block metadata (such as its timestamp or hash) into
810    /// their execution layers, since Espresso replicas will sign this information for the finalized
811    /// L1 block.
812    ///
813    /// This block may be `None` in the rare case where Espresso has started shortly after the
814    /// genesis of the L1, and the L1 has yet to finalize a block. In all other cases it will be
815    /// `Some`.
816    pub fn l1_finalized(&self) -> Option<L1BlockInfo> {
817        *field!(self.l1_finalized)
818    }
819
820    pub fn l1_finalized_mut(&mut self) -> &mut Option<L1BlockInfo> {
821        &mut *field_mut!(self.l1_finalized)
822    }
823
824    pub fn payload_commitment(&self) -> VidCommitment {
825        *field!(self.payload_commitment)
826    }
827
828    pub fn payload_commitment_mut(&mut self) -> &mut VidCommitment {
829        &mut *field_mut!(self.payload_commitment)
830    }
831
832    pub fn builder_commitment(&self) -> &BuilderCommitment {
833        field!(self.builder_commitment)
834    }
835
836    pub fn builder_commitment_mut(&mut self) -> &mut BuilderCommitment {
837        &mut *field_mut!(self.builder_commitment)
838    }
839
840    pub fn ns_table(&self) -> &NsTable {
841        field!(self.ns_table)
842    }
843
844    pub fn ns_table_mut(&mut self) -> &mut NsTable {
845        &mut *field_mut!(self.ns_table)
846    }
847
848    /// Root Commitment of Block Merkle Tree
849    pub fn block_merkle_tree_root(&self) -> BlockMerkleCommitment {
850        *field!(self.block_merkle_tree_root)
851    }
852
853    pub fn block_merkle_tree_root_mut(&mut self) -> &mut BlockMerkleCommitment {
854        &mut *field_mut!(self.block_merkle_tree_root)
855    }
856
857    /// Root Commitment of `FeeMerkleTree`
858    pub fn fee_merkle_tree_root(&self) -> FeeMerkleCommitment {
859        *field!(self.fee_merkle_tree_root)
860    }
861
862    pub fn fee_merkle_tree_root_mut(&mut self) -> &mut FeeMerkleCommitment {
863        &mut *field_mut!(self.fee_merkle_tree_root)
864    }
865
866    /// Fee paid by the block builder
867    pub fn fee_info(&self) -> Vec<FeeInfo> {
868        match self {
869            Self::V1(fields) => vec![fields.fee_info],
870            Self::V2(fields) => vec![fields.fee_info],
871            Self::V3(fields) => vec![fields.fee_info],
872            Self::V4(fields) => vec![fields.fee_info],
873            Self::V5(fields) => vec![fields.fee_info],
874        }
875    }
876
877    pub fn reward_merkle_tree_root(
878        &self,
879    ) -> Either<RewardMerkleCommitmentV1, RewardMerkleCommitmentV2> {
880        let empty_reward_merkle_tree = RewardMerkleTreeV1::new(REWARD_MERKLE_TREE_V1_HEIGHT);
881        match self {
882            Self::V1(_) => Either::Left(empty_reward_merkle_tree.commitment()),
883            Self::V2(_) => Either::Left(empty_reward_merkle_tree.commitment()),
884            Self::V3(fields) => Either::Left(fields.reward_merkle_tree_root),
885            Self::V4(fields) => Either::Right(fields.reward_merkle_tree_root),
886            Self::V5(fields) => Either::Right(fields.reward_merkle_tree_root),
887        }
888    }
889
890    /// Account (etheruem address) of builder
891    ///
892    /// This signature is not considered formally part of the header; it is just evidence proving
893    /// that other parts of the header ([`fee_info`](Self::fee_info)) are correct. It exists in the
894    /// header so that it is available to all nodes to be used during validation. But since it is
895    /// checked during consensus, any downstream client who has a proof of consensus finality of a
896    /// header can trust that [`fee_info`](Self::fee_info) is correct without relying on the
897    /// signature. Thus, this signature is not included in the header commitment.
898    pub fn builder_signature(&self) -> Vec<BuilderSignature> {
899        match self {
900            // Previously we used `Option<BuilderSignature>` to
901            // represent presence/absence of signature.  The simplest
902            // way to represent the same now that we have a `Vec` is
903            // empty/non-empty
904            Self::V1(fields) => fields.builder_signature.as_slice().to_vec(),
905            Self::V2(fields) => fields.builder_signature.as_slice().to_vec(),
906            Self::V3(fields) => fields.builder_signature.as_slice().to_vec(),
907            Self::V4(fields) => fields.builder_signature.as_slice().to_vec(),
908            Self::V5(fields) => fields.builder_signature.as_slice().to_vec(),
909        }
910    }
911
912    pub fn total_reward_distributed(&self) -> Option<RewardAmount> {
913        match self {
914            Self::V1(_) | Self::V2(_) | Self::V3(_) => None,
915            Self::V4(fields) | Self::V5(fields) => Some(fields.total_reward_distributed),
916        }
917    }
918}
919
920#[derive(Debug, Error)]
921#[error("Invalid Block Header {msg}")]
922pub struct InvalidBlockHeader {
923    msg: String,
924}
925impl InvalidBlockHeader {
926    fn new(msg: String) -> Self {
927        Self { msg }
928    }
929}
930
931impl From<anyhow::Error> for InvalidBlockHeader {
932    fn from(err: anyhow::Error) -> Self {
933        Self::new(format!("{err:#}"))
934    }
935}
936
937impl BlockHeader<SeqTypes> for Header {
938    type Error = InvalidBlockHeader;
939
940    #[tracing::instrument(
941        skip_all,
942        fields(
943            node_id = instance_state.node_id,
944            view = ?parent_leaf.view_number(),
945            height = parent_leaf.block_header().height(),
946        ),
947    )]
948    #[tracing::instrument(
949        skip_all,
950        fields(
951            height = parent_leaf.block_header().block_number() + 1,
952            parent_view = ?parent_leaf.view_number(),
953            payload_commitment,
954            version,
955        )
956    )]
957    async fn new(
958        parent_state: &ValidatedState,
959        instance_state: &NodeState,
960        parent_leaf: &Leaf2,
961        payload_commitment: VidCommitment,
962        builder_commitment: BuilderCommitment,
963        metadata: <<SeqTypes as NodeType>::BlockPayload as BlockPayload<SeqTypes>>::Metadata,
964        builder_fee: BuilderFee<SeqTypes>,
965        version: Version,
966        view_number: u64,
967    ) -> Result<Self, Self::Error> {
968        tracing::info!("preparing to propose legacy header");
969
970        let height = parent_leaf.height();
971        let view = parent_leaf.view_number();
972
973        let mut validated_state = parent_state.clone();
974
975        let chain_config = if version > instance_state.current_version {
976            match instance_state.upgrades.get(&version) {
977                Some(upgrade) => match upgrade.upgrade_type {
978                    UpgradeType::Fee { chain_config } => chain_config,
979                    UpgradeType::Epoch { chain_config } => chain_config,
980                    UpgradeType::DrbAndHeader { chain_config } => chain_config,
981                    UpgradeType::Da { chain_config } => chain_config,
982                },
983                None => Header::get_chain_config(&validated_state, instance_state).await?,
984            }
985        } else {
986            Header::get_chain_config(&validated_state, instance_state).await?
987        };
988
989        validated_state.chain_config = chain_config.into();
990
991        // Fetch the latest L1 snapshot.
992        let l1_snapshot = instance_state.l1_client.snapshot().await;
993        // Fetch the new L1 deposits between parent and current finalized L1 block.
994        let l1_deposits = if let (Some(addr), Some(block_info)) =
995            (chain_config.fee_contract, l1_snapshot.finalized)
996        {
997            instance_state
998                .l1_client
999                .get_finalized_deposits(
1000                    addr,
1001                    parent_leaf
1002                        .block_header()
1003                        .l1_finalized()
1004                        .map(|block_info| block_info.number),
1005                    block_info.number,
1006                )
1007                .await
1008        } else {
1009            vec![]
1010        };
1011        // Find missing fee state entries. We will need to use the builder account which is paying a
1012        // fee and the recipient account which is receiving it, plus any counts receiving deposits
1013        // in this block.
1014        let missing_accounts = parent_state.forgotten_accounts(
1015            [builder_fee.fee_account, chain_config.fee_recipient]
1016                .into_iter()
1017                .chain(l1_deposits.iter().map(|info| info.account())),
1018        );
1019        if !missing_accounts.is_empty() {
1020            tracing::warn!(
1021                height,
1022                ?view,
1023                ?missing_accounts,
1024                "fetching missing accounts from peers"
1025            );
1026
1027            // Fetch missing fee state entries
1028            let missing_account_proofs = instance_state
1029                .state_catchup
1030                .as_ref()
1031                .fetch_accounts(
1032                    instance_state,
1033                    height,
1034                    view,
1035                    parent_state.fee_merkle_tree.commitment(),
1036                    missing_accounts,
1037                )
1038                .await?;
1039
1040            // Insert missing fee state entries
1041            for proof in missing_account_proofs.iter() {
1042                proof
1043                    .remember(&mut validated_state.fee_merkle_tree)
1044                    .context("remembering fee account")?;
1045            }
1046        }
1047
1048        // Ensure merkle tree has frontier
1049        if validated_state.need_to_fetch_blocks_mt_frontier() {
1050            tracing::warn!(height, ?view, "fetching block frontier from peers");
1051            instance_state
1052                .state_catchup
1053                .as_ref()
1054                .remember_blocks_merkle_tree(
1055                    instance_state,
1056                    height,
1057                    view,
1058                    &mut validated_state.block_merkle_tree,
1059                )
1060                .await
1061                .context("remembering block proof")?;
1062        }
1063
1064        let mut rewards = None;
1065        if version >= EPOCH_VERSION {
1066            rewards = distribute_block_reward(
1067                instance_state,
1068                &mut validated_state,
1069                parent_leaf,
1070                ViewNumber::new(view_number),
1071                version,
1072            )
1073            .await?;
1074        };
1075
1076        let mut next_stake_table_hash = None;
1077
1078        if version >= DRB_AND_HEADER_UPGRADE_VERSION {
1079            let epoch_height = instance_state
1080                .epoch_height
1081                .context("epoch height not in instance state")?;
1082            if is_ge_epoch_root(height + 1, epoch_height) {
1083                let coordinator = instance_state.coordinator.clone();
1084                let first_epoch = {
1085                    coordinator
1086                        .membership()
1087                        .read()
1088                        .await
1089                        .first_epoch()
1090                        .context("The first epoch was not set.")?
1091                };
1092
1093                let epoch = EpochNumber::new(epoch_from_block_number(height + 1, epoch_height));
1094
1095                // first 2 epochs don't have a stake table hash because they are configured.
1096                if epoch > first_epoch {
1097                    let epoch_membership = coordinator
1098                        .stake_table_for_epoch(Some(epoch + 1))
1099                        .await
1100                        .map_err(|e| anyhow::anyhow!("failed to get epoch membership: {e}"))?;
1101                    next_stake_table_hash = Some(
1102                        epoch_membership
1103                            .stake_table_hash()
1104                            .await
1105                            .context("failed to get next stake table hash")?,
1106                    );
1107                }
1108            }
1109        }
1110
1111        let now = OffsetDateTime::now_utc();
1112
1113        let timestamp = now.unix_timestamp() as u64;
1114        let timestamp_millis = TimestampMillis::from_time(&now).u64();
1115
1116        Ok(Self::from_info(
1117            payload_commitment,
1118            builder_commitment,
1119            metadata,
1120            parent_leaf,
1121            l1_snapshot,
1122            &l1_deposits,
1123            vec![builder_fee],
1124            timestamp,
1125            timestamp_millis,
1126            validated_state,
1127            chain_config,
1128            version,
1129            rewards,
1130            next_stake_table_hash,
1131        )?)
1132    }
1133
1134    fn genesis(
1135        instance_state: &NodeState,
1136        payload: <SeqTypes as NodeType>::BlockPayload,
1137        metadata: &<<SeqTypes as NodeType>::BlockPayload as BlockPayload<SeqTypes>>::Metadata,
1138        _: Version,
1139    ) -> Self {
1140        let payload_bytes = payload.encode();
1141        let builder_commitment = payload.builder_commitment(metadata);
1142
1143        let vid_commitment_version = instance_state.genesis_version;
1144
1145        let payload_commitment = vid_commitment(
1146            &payload_bytes,
1147            &metadata.encode(),
1148            GENESIS_VID_NUM_STORAGE_NODES,
1149            vid_commitment_version,
1150        );
1151
1152        let ValidatedState {
1153            fee_merkle_tree,
1154            block_merkle_tree,
1155            reward_merkle_tree_v1,
1156            reward_merkle_tree_v2,
1157            ..
1158        } = ValidatedState::genesis(instance_state).0;
1159        let block_merkle_tree_root = block_merkle_tree.commitment();
1160        let fee_merkle_tree_root = fee_merkle_tree.commitment();
1161        let reward_merkle_tree_root = reward_merkle_tree_v2.commitment();
1162
1163        let time = instance_state.genesis_header.timestamp;
1164
1165        let timestamp = time.unix_timestamp();
1166        let timestamp_millis = time.unix_timestamp_millis();
1167
1168        //  The Header is versioned,
1169        //  so we create the genesis header for the current version of the sequencer.
1170        Self::create(
1171            instance_state.genesis_header.chain_config,
1172            0,
1173            timestamp,
1174            timestamp_millis,
1175            instance_state
1176                .l1_genesis
1177                .map(|block| block.number)
1178                .unwrap_or_default(),
1179            instance_state.l1_genesis,
1180            payload_commitment,
1181            builder_commitment.clone(),
1182            metadata.clone(),
1183            fee_merkle_tree_root,
1184            block_merkle_tree_root,
1185            reward_merkle_tree_v1.commitment(),
1186            reward_merkle_tree_root,
1187            vec![FeeInfo::genesis()],
1188            vec![],
1189            None,
1190            instance_state.genesis_version,
1191            None,
1192        )
1193    }
1194
1195    fn timestamp(&self) -> u64 {
1196        self.timestamp_internal()
1197    }
1198
1199    fn timestamp_millis(&self) -> u64 {
1200        self.timestamp_millis_internal()
1201    }
1202
1203    fn block_number(&self) -> u64 {
1204        self.height()
1205    }
1206
1207    fn version(&self) -> Version {
1208        self.version()
1209    }
1210
1211    fn payload_commitment(&self) -> VidCommitment {
1212        self.payload_commitment()
1213    }
1214
1215    fn metadata(
1216        &self,
1217    ) -> &<<SeqTypes as NodeType>::BlockPayload as BlockPayload<SeqTypes>>::Metadata {
1218        self.ns_table()
1219    }
1220
1221    /// Commit over fee_amount, payload_commitment and metadata
1222    fn builder_commitment(&self) -> BuilderCommitment {
1223        self.builder_commitment().clone()
1224    }
1225
1226    fn get_light_client_state(&self, view: ViewNumber) -> anyhow::Result<LightClientState> {
1227        let mut block_comm_root_bytes = vec![];
1228        self.block_merkle_tree_root()
1229            .serialize_compressed(&mut block_comm_root_bytes)?;
1230
1231        Ok(LightClientState {
1232            view_number: view.u64(),
1233            block_height: self.height(),
1234            block_comm_root: hotshot_types::light_client::hash_bytes_to_field(
1235                &block_comm_root_bytes,
1236            )?,
1237        })
1238    }
1239
1240    fn auth_root(&self) -> anyhow::Result<B256> {
1241        match self {
1242            Header::V1(_) | Header::V2(_) | Header::V3(_) => Ok(B256::ZERO),
1243            Header::V4(header) | Header::V5(header) => {
1244                // Temporary placeholder values for future fields
1245                let placeholder_1 = B256::ZERO;
1246                let placeholder_2 = B256::ZERO;
1247                let placeholder_3 = B256::ZERO;
1248                let placeholder_4 = B256::ZERO;
1249                let placeholder_5 = B256::ZERO;
1250                let placeholder_6 = B256::ZERO;
1251                let placeholder_7 = B256::ZERO;
1252
1253                let mut hasher = Keccak256::new();
1254
1255                // Start with the reward Merkle tree root digest as the base input
1256                let digest = header.reward_merkle_tree_root.digest();
1257                hasher.update(digest.0);
1258                hasher.update(placeholder_1);
1259                hasher.update(placeholder_2);
1260                hasher.update(placeholder_3);
1261                hasher.update(placeholder_4);
1262                hasher.update(placeholder_5);
1263                hasher.update(placeholder_6);
1264                hasher.update(placeholder_7);
1265
1266                Ok(hasher.finalize())
1267            },
1268        }
1269    }
1270}
1271
1272impl QueryableHeader<SeqTypes> for Header {
1273    type NamespaceId = NamespaceId;
1274    type NamespaceIndex = NsIndex;
1275
1276    fn namespace_id(&self, i: &NsIndex) -> Option<NamespaceId> {
1277        self.ns_table().read_ns_id(i)
1278    }
1279
1280    fn namespace_size(&self, i: &NsIndex, payload_size: usize) -> u64 {
1281        self.ns_table()
1282            .ns_range(i, &PayloadByteLen(payload_size))
1283            .byte_len()
1284            .0 as u64
1285    }
1286
1287    fn ns_table(&self) -> String {
1288        BASE64_STANDARD.encode(&self.ns_table().bytes)
1289    }
1290}
1291
1292impl ExplorerHeader<SeqTypes> for Header {
1293    type BalanceAmount = FeeAmount;
1294    type WalletAddress = Vec<FeeAccount>;
1295    type ProposerId = Vec<FeeAccount>;
1296
1297    // TODO what are these expected values w/ multiple Fees
1298    fn proposer_id(&self) -> Self::ProposerId {
1299        self.fee_info().accounts()
1300    }
1301
1302    fn fee_info_account(&self) -> Self::WalletAddress {
1303        self.fee_info().accounts()
1304    }
1305
1306    fn fee_info_balance(&self) -> Self::BalanceAmount {
1307        // TODO this will panic if some amount or total does not fit in a u64
1308        self.fee_info().amount().unwrap()
1309    }
1310
1311    /// reward_balance at the moment is only implemented as a stub, as block
1312    /// rewards have not yet been implemented.
1313    ///
1314    /// TODO: update implementation when rewards have been created / supported.
1315    ///       Issue: https://github.com/EspressoSystems/espresso-sequencer/issues/1453
1316    fn reward_balance(&self) -> Self::BalanceAmount {
1317        FeeAmount::from(0)
1318    }
1319
1320    fn namespace_ids(&self) -> Vec<NamespaceId> {
1321        self.ns_table()
1322            .iter()
1323            .map(|i| self.ns_table().read_ns_id_unchecked(&i))
1324            .collect()
1325    }
1326}
1327
1328#[cfg(test)]
1329mod test_headers {
1330    use std::sync::Arc;
1331
1332    use alloy::{
1333        node_bindings::Anvil,
1334        primitives::{Address, U256},
1335    };
1336    use hotshot_query_service::testing::mocks::MOCK_UPGRADE;
1337    use hotshot_types::traits::signature_key::BuilderSignatureKey;
1338    use v0_1::{BlockMerkleTree, FeeMerkleTree, L1Client};
1339    use vbs::{BinarySerializer, bincode_serializer::BincodeSerializer, version::StaticVersion};
1340    use versions::version;
1341
1342    use super::*;
1343    use crate::{
1344        Leaf,
1345        eth_signature_key::EthKeyPair,
1346        mock::MockStateCatchup,
1347        v0_3::{REWARD_MERKLE_TREE_V1_HEIGHT, RewardAccountV1, RewardAmount},
1348        v0_4::{REWARD_MERKLE_TREE_V2_HEIGHT, RewardAccountV2, RewardMerkleTreeV2},
1349    };
1350
1351    #[derive(Debug, Default)]
1352    #[must_use]
1353    struct TestCase {
1354        // Parent header info.
1355        parent_timestamp: u64,
1356        parent_timestamp_millis: u64,
1357        parent_l1_head: u64,
1358        parent_l1_finalized: Option<L1BlockInfo>,
1359
1360        // Environment at the time the new header is created.
1361        l1_head: u64,
1362        l1_finalized: Option<L1BlockInfo>,
1363        timestamp: u64,
1364        timestamp_millis: u64,
1365        l1_deposits: Vec<FeeInfo>,
1366
1367        // Expected new header info.
1368        expected_timestamp: u64,
1369        expected_timestamp_millis: u64,
1370        expected_l1_head: u64,
1371        expected_l1_finalized: Option<L1BlockInfo>,
1372    }
1373
1374    impl TestCase {
1375        async fn run(self) {
1376            // Check test case validity.
1377            assert!(self.expected_timestamp >= self.parent_timestamp);
1378            assert!(self.expected_timestamp_millis >= self.parent_timestamp_millis);
1379            assert!(self.expected_l1_head >= self.parent_l1_head);
1380            assert!(self.expected_l1_finalized >= self.parent_l1_finalized);
1381
1382            let genesis = GenesisForTest::default().await;
1383            let mut parent = genesis.header.clone();
1384            parent.set_timestamp(self.parent_timestamp, self.parent_timestamp_millis);
1385            *parent.l1_head_mut() = self.parent_l1_head;
1386            *parent.l1_finalized_mut() = self.parent_l1_finalized;
1387
1388            let mut parent_leaf = genesis.leaf.clone();
1389            *parent_leaf.block_header_mut() = parent.clone();
1390
1391            let block_merkle_tree =
1392                BlockMerkleTree::from_elems(Some(32), Vec::<Commitment<Header>>::new()).unwrap();
1393
1394            let fee_info = FeeInfo::genesis();
1395            let fee_merkle_tree = FeeMerkleTree::from_kv_set(
1396                20,
1397                Vec::from([(fee_info.account(), fee_info.amount())]),
1398            )
1399            .unwrap();
1400
1401            let reward_account_v1 = RewardAccountV1::default();
1402            let reward_account = RewardAccountV2::default();
1403            let reward_amount = RewardAmount::default();
1404            let reward_merkle_tree_v2 =
1405                RewardMerkleTreeV2::from_kv_set(20, Vec::from([(reward_account, reward_amount)]))
1406                    .unwrap();
1407
1408            let reward_merkle_tree_v1 = RewardMerkleTreeV1::from_kv_set(
1409                20,
1410                Vec::from([(reward_account_v1, reward_amount)]),
1411            )
1412            .unwrap();
1413
1414            let mut validated_state = ValidatedState {
1415                block_merkle_tree: block_merkle_tree.clone(),
1416                fee_merkle_tree,
1417                reward_merkle_tree_v2,
1418                reward_merkle_tree_v1,
1419                chain_config: genesis.instance_state.chain_config.into(),
1420            };
1421
1422            let (fee_account, fee_key) = FeeAccount::generated_from_seed_indexed([0; 32], 0);
1423            let fee_amount = 0;
1424            let fee_signature =
1425                FeeAccount::sign_fee(&fee_key, fee_amount, &genesis.ns_table).unwrap();
1426
1427            let header = Header::from_info(
1428                genesis.header.payload_commitment(),
1429                genesis.header.builder_commitment().clone(),
1430                genesis.ns_table,
1431                &parent_leaf,
1432                L1Snapshot {
1433                    head: self.l1_head,
1434                    finalized: self.l1_finalized,
1435                },
1436                &self.l1_deposits,
1437                vec![BuilderFee {
1438                    fee_account,
1439                    fee_amount,
1440                    fee_signature,
1441                }],
1442                self.timestamp,
1443                self.timestamp_millis,
1444                validated_state.clone(),
1445                genesis.instance_state.chain_config,
1446                version(0, 1),
1447                None,
1448                None,
1449            )
1450            .unwrap();
1451            assert_eq!(header.height(), parent.height() + 1);
1452            assert_eq!(header.timestamp(), self.expected_timestamp);
1453            assert_eq!(header.timestamp_millis(), self.expected_timestamp_millis);
1454            assert_eq!(header.l1_head(), self.expected_l1_head);
1455            assert_eq!(header.l1_finalized(), self.expected_l1_finalized);
1456
1457            // Check deposits were inserted before computing the fee merkle tree root.
1458            for fee_info in self.l1_deposits {
1459                validated_state.insert_fee_deposit(fee_info).unwrap();
1460            }
1461            assert_eq!(
1462                validated_state.fee_merkle_tree.commitment(),
1463                header.fee_merkle_tree_root(),
1464            );
1465
1466            assert_eq!(
1467                block_merkle_tree,
1468                BlockMerkleTree::from_elems(Some(32), Vec::<Commitment<Header>>::new()).unwrap()
1469            );
1470        }
1471    }
1472
1473    fn l1_block(number: u64) -> L1BlockInfo {
1474        L1BlockInfo {
1475            number,
1476            ..Default::default()
1477        }
1478    }
1479
1480    #[test_log::test(tokio::test(flavor = "multi_thread"))]
1481    async fn test_new_header() {
1482        // Simplest case: building on genesis, L1 info and timestamp unchanged.
1483        TestCase::default().run().await
1484    }
1485
1486    #[test_log::test(tokio::test(flavor = "multi_thread"))]
1487    async fn test_new_header_advance_timestamp() {
1488        TestCase {
1489            timestamp: 1,
1490            timestamp_millis: 1_000,
1491            expected_timestamp: 1,
1492            expected_timestamp_millis: 1_000,
1493            ..Default::default()
1494        }
1495        .run()
1496        .await
1497    }
1498
1499    #[test_log::test(tokio::test(flavor = "multi_thread"))]
1500    async fn test_new_header_advance_l1_block() {
1501        TestCase {
1502            parent_l1_head: 0,
1503            parent_l1_finalized: Some(l1_block(0)),
1504
1505            l1_head: 1,
1506            l1_finalized: Some(l1_block(1)),
1507
1508            expected_l1_head: 1,
1509            expected_l1_finalized: Some(l1_block(1)),
1510
1511            ..Default::default()
1512        }
1513        .run()
1514        .await
1515    }
1516
1517    #[test_log::test(tokio::test(flavor = "multi_thread"))]
1518    async fn test_new_header_advance_l1_finalized_from_none() {
1519        TestCase {
1520            l1_finalized: Some(l1_block(1)),
1521            expected_l1_finalized: Some(l1_block(1)),
1522            ..Default::default()
1523        }
1524        .run()
1525        .await
1526    }
1527
1528    #[test_log::test(tokio::test(flavor = "multi_thread"))]
1529    async fn test_new_header_timestamp_behind_finalized_l1_block() {
1530        let l1_finalized = Some(L1BlockInfo {
1531            number: 1,
1532            timestamp: U256::from(1),
1533            ..Default::default()
1534        });
1535        TestCase {
1536            l1_head: 1,
1537            l1_finalized,
1538            timestamp: 0,
1539            timestamp_millis: 0,
1540
1541            expected_l1_head: 1,
1542            expected_l1_finalized: l1_finalized,
1543            expected_timestamp: 1,
1544            expected_timestamp_millis: 1_000,
1545
1546            ..Default::default()
1547        }
1548        .run()
1549        .await
1550    }
1551
1552    #[test_log::test(tokio::test(flavor = "multi_thread"))]
1553    async fn test_new_header_timestamp_behind() {
1554        TestCase {
1555            parent_timestamp: 1,
1556            parent_timestamp_millis: 1_000,
1557            timestamp: 0,
1558            timestamp_millis: 0,
1559            expected_timestamp: 1,
1560            expected_timestamp_millis: 1_000,
1561
1562            ..Default::default()
1563        }
1564        .run()
1565        .await
1566    }
1567
1568    #[test_log::test(tokio::test(flavor = "multi_thread"))]
1569    async fn test_new_header_l1_head_behind() {
1570        TestCase {
1571            parent_l1_head: 1,
1572            l1_head: 0,
1573            expected_l1_head: 1,
1574
1575            ..Default::default()
1576        }
1577        .run()
1578        .await
1579    }
1580
1581    #[test_log::test(tokio::test(flavor = "multi_thread"))]
1582    async fn test_new_header_l1_finalized_behind_some() {
1583        TestCase {
1584            parent_l1_finalized: Some(l1_block(1)),
1585            l1_finalized: Some(l1_block(0)),
1586            expected_l1_finalized: Some(l1_block(1)),
1587
1588            ..Default::default()
1589        }
1590        .run()
1591        .await
1592    }
1593
1594    #[test_log::test(tokio::test(flavor = "multi_thread"))]
1595    async fn test_new_header_l1_finalized_behind_none() {
1596        TestCase {
1597            parent_l1_finalized: Some(l1_block(0)),
1598            l1_finalized: None,
1599            expected_l1_finalized: Some(l1_block(0)),
1600
1601            ..Default::default()
1602        }
1603        .run()
1604        .await
1605    }
1606
1607    #[test_log::test(tokio::test(flavor = "multi_thread"))]
1608    async fn test_new_header_deposits_one() {
1609        TestCase {
1610            l1_deposits: vec![FeeInfo::new(Address::default(), 1)],
1611            ..Default::default()
1612        }
1613        .run()
1614        .await
1615    }
1616
1617    #[test_log::test(tokio::test(flavor = "multi_thread"))]
1618    async fn test_new_header_deposits_many() {
1619        TestCase {
1620            l1_deposits: [
1621                (Address::default(), 1),
1622                (Address::default(), 2),
1623                (Address::random(), 3),
1624            ]
1625            .iter()
1626            .map(|(address, amount)| FeeInfo::new(*address, *amount))
1627            .collect(),
1628            ..Default::default()
1629        }
1630        .run()
1631        .await
1632    }
1633
1634    struct GenesisForTest {
1635        pub instance_state: NodeState,
1636        pub validated_state: ValidatedState,
1637        pub leaf: Leaf2,
1638        pub header: Header,
1639        pub ns_table: NsTable,
1640    }
1641
1642    impl GenesisForTest {
1643        async fn default() -> Self {
1644            let instance_state = NodeState::mock();
1645            let validated_state = ValidatedState::genesis(&instance_state).0;
1646            let leaf: Leaf2 = Leaf::genesis(&validated_state, &instance_state, MOCK_UPGRADE.base)
1647                .await
1648                .into();
1649            let header = leaf.block_header().clone();
1650            let ns_table = leaf.block_payload().unwrap().ns_table().clone();
1651            Self {
1652                instance_state,
1653                validated_state,
1654                leaf,
1655                header,
1656                ns_table,
1657            }
1658        }
1659    }
1660
1661    #[test_log::test(tokio::test(flavor = "multi_thread"))]
1662    async fn test_proposal_validation_success() {
1663        let anvil = Anvil::new().block_time(1u64).spawn();
1664        let mut genesis_state = NodeState::mock()
1665            .with_l1(L1Client::new(vec![anvil.endpoint_url()]).expect("Failed to create L1 client"))
1666            .with_current_version(version(0, 1));
1667
1668        let genesis = GenesisForTest::default().await;
1669
1670        let mut parent_state = genesis.validated_state.clone();
1671
1672        let mut block_merkle_tree = parent_state.block_merkle_tree.clone();
1673        let fee_merkle_tree = parent_state.fee_merkle_tree.clone();
1674
1675        // Populate the tree with an initial `push`.
1676        block_merkle_tree.push(genesis.header.commit()).unwrap();
1677        let block_merkle_tree_root = block_merkle_tree.commitment();
1678        let fee_merkle_tree_root = fee_merkle_tree.commitment();
1679        parent_state.block_merkle_tree = block_merkle_tree.clone();
1680        parent_state.fee_merkle_tree = fee_merkle_tree.clone();
1681
1682        let mut parent_header = genesis.header.clone();
1683        *parent_header.block_merkle_tree_root_mut() = block_merkle_tree_root;
1684        *parent_header.fee_merkle_tree_root_mut() = fee_merkle_tree_root;
1685
1686        let mut parent_leaf = genesis.leaf.clone();
1687        *parent_leaf.block_header_mut() = parent_header.clone();
1688
1689        // Forget the state to trigger lookups in Header::new
1690        let forgotten_state = parent_state.forget();
1691        genesis_state.state_catchup = Arc::new(MockStateCatchup::from_iter([(
1692            parent_leaf.view_number(),
1693            Arc::new(parent_state.clone()),
1694        )]));
1695        // Get a proposal from a parent
1696
1697        // TODO this currently fails because after fetching the blocks frontier
1698        // the element (header commitment) does not match the one in the proof.
1699        let key_pair = EthKeyPair::for_test();
1700        let fee_amount = 0u64;
1701        let payload_commitment = parent_header.payload_commitment();
1702        let builder_commitment = parent_header.builder_commitment();
1703        let ns_table = genesis.ns_table;
1704        let fee_signature = FeeAccount::sign_fee(&key_pair, fee_amount, &ns_table).unwrap();
1705        let builder_fee = BuilderFee {
1706            fee_amount,
1707            fee_account: key_pair.fee_account(),
1708            fee_signature,
1709        };
1710        let proposal = Header::new(
1711            &forgotten_state,
1712            &genesis_state,
1713            &parent_leaf,
1714            payload_commitment,
1715            builder_commitment.clone(),
1716            ns_table,
1717            builder_fee,
1718            version(0, 1),
1719            *parent_leaf.view_number() + 1,
1720        )
1721        .await
1722        .unwrap();
1723
1724        let mut proposal_state = parent_state.clone();
1725        for fee_info in genesis_state
1726            .l1_client
1727            .get_finalized_deposits(Address::default(), None, 0)
1728            .await
1729        {
1730            proposal_state.insert_fee_deposit(fee_info).unwrap();
1731        }
1732
1733        let mut block_merkle_tree = proposal_state.block_merkle_tree.clone();
1734        block_merkle_tree.push(proposal.commit()).unwrap();
1735
1736        let _proposal_state = proposal_state
1737            .apply_header(
1738                &genesis_state,
1739                &genesis_state.state_catchup,
1740                &parent_leaf,
1741                &proposal,
1742                version(0, 1),
1743                parent_leaf.view_number() + 1,
1744            )
1745            .await
1746            .unwrap()
1747            .0;
1748
1749        // ValidatedTransition::new(
1750        //     proposal_state.clone(),
1751        //     &parent_leaf.block_header(),
1752        //     Proposal::new(&proposal, ADVZScheme::get_payload_byte_len(&vid_common)),
1753        // )
1754        // .validate()
1755        // .unwrap();
1756
1757        // assert_eq!(
1758        //     proposal_state.block_merkle_tree.commitment(),
1759        //     proposal.block_merkle_tree_root()
1760        // );
1761    }
1762
1763    #[test_log::test]
1764    fn verify_builder_signature() {
1765        // simulate a fixed size hash by padding our message
1766        let message = ";)";
1767        let mut commitment = [0u8; 32];
1768        commitment[..message.len()].copy_from_slice(message.as_bytes());
1769
1770        let key = FeeAccount::generated_from_seed_indexed([0; 32], 0).1;
1771        let signature = FeeAccount::sign_builder_message(&key, &commitment).unwrap();
1772        assert!(
1773            key.fee_account()
1774                .validate_builder_signature(&signature, &commitment)
1775        );
1776    }
1777
1778    #[test_log::test(tokio::test(flavor = "multi_thread"))]
1779    async fn test_versioned_header_serialization() {
1780        let genesis = GenesisForTest::default().await;
1781        let header = genesis.header.clone();
1782        let ns_table = genesis.ns_table;
1783
1784        let (fee_account, _) = FeeAccount::generated_from_seed_indexed([0; 32], 0);
1785
1786        let v1_header = Header::create(
1787            genesis.instance_state.chain_config,
1788            1,
1789            2,
1790            2_000_000_000,
1791            3,
1792            Default::default(),
1793            header.payload_commitment(),
1794            header.builder_commitment().clone(),
1795            ns_table.clone(),
1796            header.fee_merkle_tree_root(),
1797            header.block_merkle_tree_root(),
1798            header.reward_merkle_tree_root().left().unwrap_or_else(|| {
1799                RewardMerkleTreeV1::new(REWARD_MERKLE_TREE_V1_HEIGHT).commitment()
1800            }),
1801            header.reward_merkle_tree_root().right().unwrap_or_else(|| {
1802                RewardMerkleTreeV2::new(REWARD_MERKLE_TREE_V2_HEIGHT).commitment()
1803            }),
1804            vec![FeeInfo {
1805                amount: 0.into(),
1806                account: fee_account,
1807            }],
1808            Default::default(),
1809            None,
1810            version(0, 1),
1811            None,
1812        );
1813
1814        let serialized = serde_json::to_string(&v1_header).unwrap();
1815        let deserialized: Header = serde_json::from_str(&serialized).unwrap();
1816        assert_eq!(v1_header, deserialized);
1817
1818        let v2_header = Header::create(
1819            genesis.instance_state.chain_config,
1820            1,
1821            2,
1822            2_000_000_000,
1823            3,
1824            Default::default(),
1825            header.payload_commitment(),
1826            header.builder_commitment().clone(),
1827            ns_table.clone(),
1828            header.fee_merkle_tree_root(),
1829            header.block_merkle_tree_root(),
1830            header.reward_merkle_tree_root().left().unwrap_or_else(|| {
1831                RewardMerkleTreeV1::new(REWARD_MERKLE_TREE_V1_HEIGHT).commitment()
1832            }),
1833            header.reward_merkle_tree_root().right().unwrap_or_else(|| {
1834                RewardMerkleTreeV2::new(REWARD_MERKLE_TREE_V2_HEIGHT).commitment()
1835            }),
1836            vec![FeeInfo {
1837                amount: 0.into(),
1838                account: fee_account,
1839            }],
1840            Default::default(),
1841            None,
1842            version(0, 2),
1843            None,
1844        );
1845
1846        let serialized = serde_json::to_string(&v2_header).unwrap();
1847        let deserialized: Header = serde_json::from_str(&serialized).unwrap();
1848        assert_eq!(v2_header, deserialized);
1849
1850        let v3_header = Header::create(
1851            genesis.instance_state.chain_config,
1852            1,
1853            2,
1854            2_000_000_000,
1855            3,
1856            Default::default(),
1857            header.payload_commitment(),
1858            header.builder_commitment().clone(),
1859            ns_table.clone(),
1860            header.fee_merkle_tree_root(),
1861            header.block_merkle_tree_root(),
1862            header.reward_merkle_tree_root().left().unwrap_or_else(|| {
1863                RewardMerkleTreeV1::new(REWARD_MERKLE_TREE_V1_HEIGHT).commitment()
1864            }),
1865            header.reward_merkle_tree_root().right().unwrap_or_else(|| {
1866                RewardMerkleTreeV2::new(REWARD_MERKLE_TREE_V2_HEIGHT).commitment()
1867            }),
1868            vec![FeeInfo {
1869                amount: 0.into(),
1870                account: fee_account,
1871            }],
1872            Default::default(),
1873            None,
1874            version(0, 3),
1875            None,
1876        );
1877
1878        let serialized = serde_json::to_string(&v3_header).unwrap();
1879        let deserialized: Header = serde_json::from_str(&serialized).unwrap();
1880        assert_eq!(v3_header, deserialized);
1881
1882        let v1_bytes = BincodeSerializer::<StaticVersion<0, 1>>::serialize(&v1_header).unwrap();
1883        let deserialized: Header =
1884            BincodeSerializer::<StaticVersion<0, 1>>::deserialize(&v1_bytes).unwrap();
1885        assert_eq!(v1_header, deserialized);
1886
1887        let v2_bytes = BincodeSerializer::<StaticVersion<0, 2>>::serialize(&v2_header).unwrap();
1888        let deserialized: Header =
1889            BincodeSerializer::<StaticVersion<0, 2>>::deserialize(&v2_bytes).unwrap();
1890        assert_eq!(v2_header, deserialized);
1891
1892        let v3_bytes = BincodeSerializer::<StaticVersion<0, 3>>::serialize(&v3_header).unwrap();
1893        let deserialized: Header =
1894            BincodeSerializer::<StaticVersion<0, 3>>::deserialize(&v3_bytes).unwrap();
1895        assert_eq!(v3_header, deserialized);
1896    }
1897}