espresso_types/v0/impls/
header.rs

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