espresso_types/v0/impls/
header.rs

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