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 "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 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 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 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 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 assert!(major == 0, "Invalid major version {major}");
304 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], 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], 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], 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 _ => panic!("invalid version: {version}"),
377 }
378 }
379}
380
381macro_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 let parent_header = parent_leaf.block_header();
430 let height = parent_header.height() + 1;
431
432 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 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 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 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 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 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 _ => 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 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 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 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 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 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 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 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 Self::V99(_) => empty_reward_merkle_tree.commitment(),
778 }
779 }
780
781 pub fn builder_signature(&self) -> Vec<BuilderSignature> {
790 match self {
791 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 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 #[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 let l1_snapshot = instance_state.l1_client.snapshot().await;
890 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 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 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 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 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 let l1_snapshot = instance_state.l1_client.snapshot().await;
1026 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 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 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 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 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 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 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 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 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 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 self.fee_info().amount().unwrap()
1234 }
1235
1236 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_timestamp: u64,
1280 parent_l1_head: u64,
1281 parent_l1_finalized: Option<L1BlockInfo>,
1282
1283 l1_head: u64,
1285 l1_finalized: Option<L1BlockInfo>,
1286 timestamp: u64,
1287 l1_deposits: Vec<FeeInfo>,
1288
1289 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 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 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 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 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 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 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 }
1673
1674 #[test]
1675 fn verify_builder_signature() {
1676 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}