1use std::{collections::HashSet, fmt};
2
3use alloy::primitives::{B256, Keccak256};
4use anyhow::{Context, bail, ensure};
5use ark_serialize::CanonicalSerialize;
6use base64::{Engine, prelude::BASE64_STANDARD};
7use committable::{Commitment, Committable, RawCommitmentBuilder};
8use either::Either;
9use hotshot_query_service_types::{
10 HeightIndexed, availability::QueryableHeader, explorer::traits::ExplorerHeader,
11};
12use hotshot_types::{
13 data::{EpochNumber, VidCommitment, ViewNumber, vid_commitment},
14 light_client::LightClientState,
15 stake_table::HSStakeTable,
16 traits::{
17 BlockPayload, EncodeBytes, ValidatedState as _,
18 block_contents::{BlockHeader, BuilderFee, GENESIS_VID_NUM_STORAGE_NODES},
19 election::{Membership, MembershipSnapshot},
20 node_implementation::NodeType,
21 signature_key::BuilderSignatureKey,
22 },
23 utils::{BuilderCommitment, epoch_from_block_number, is_ge_epoch_root, is_last_block},
24};
25use jf_merkle_tree_compat::{AppendableMerkleTreeScheme, MerkleCommitment, MerkleTreeScheme};
26use serde::{
27 Deserialize, Deserializer, Serialize, Serializer,
28 de::{self, MapAccess, SeqAccess, Visitor},
29};
30use serde_json::{Map, Value};
31use thiserror::Error;
32use time::OffsetDateTime;
33use vbs::version::Version;
34use versions::{DRB_AND_HEADER_UPGRADE_VERSION, EPOCH_REWARD_VERSION, EPOCH_VERSION};
35
36use super::{
37 instance_state::NodeState, state::ValidatedState, v0_1::IterableFeeInfo, v0_3::ChainConfig,
38};
39use crate::{
40 BlockMerkleCommitment, FeeAccount, FeeAmount, FeeInfo, FeeMerkleCommitment, Header,
41 L1BlockInfo, L1Snapshot, Leaf2, NamespaceId, NsIndex, NsTable, PayloadByteLen, SeqTypes,
42 TimestampMillis, UpgradeType,
43 eth_signature_key::BuilderSignature,
44 v0::{
45 header::{EitherOrVersion, VersionedHeader},
46 impls::{StakeTableHash, distribute_block_reward},
47 },
48 v0_1::{self},
49 v0_2,
50 v0_3::{
51 self, REWARD_MERKLE_TREE_V1_HEIGHT, RewardAmount, RewardMerkleCommitmentV1,
52 RewardMerkleTreeV1,
53 },
54 v0_4::{self, RewardAccountV2, RewardMerkleCommitmentV2},
55 v0_5::{self, LeaderCounts, MAX_VALIDATORS},
56 v0_6::{self, REWARD_MERKLE_TREE_V2_HEIGHT, RewardMerkleTreeV2},
57};
58
59impl v0_1::Header {
60 pub(crate) fn commit(&self) -> Commitment<Header> {
61 let mut bmt_bytes = vec![];
62 self.block_merkle_tree_root
63 .serialize_with_mode(&mut bmt_bytes, ark_serialize::Compress::Yes)
64 .unwrap();
65 let mut fmt_bytes = vec![];
66 self.fee_merkle_tree_root
67 .serialize_with_mode(&mut fmt_bytes, ark_serialize::Compress::Yes)
68 .unwrap();
69
70 RawCommitmentBuilder::new(&Self::tag())
71 .field("chain_config", self.chain_config.commit())
72 .u64_field("height", self.height)
73 .u64_field("timestamp", self.timestamp)
74 .u64_field("l1_head", self.l1_head)
75 .optional("l1_finalized", &self.l1_finalized)
76 .constant_str("payload_commitment")
77 .fixed_size_bytes(self.payload_commitment.as_ref())
78 .constant_str("builder_commitment")
79 .fixed_size_bytes(self.builder_commitment.as_ref())
80 .field("ns_table", self.ns_table.commit())
81 .var_size_field("block_merkle_tree_root", &bmt_bytes)
82 .var_size_field("fee_merkle_tree_root", &fmt_bytes)
83 .field("fee_info", self.fee_info.commit())
84 .finalize()
85 }
86}
87
88impl Committable for Header {
89 fn commit(&self) -> Commitment<Self> {
90 match self {
91 Self::V1(header) => header.commit(),
92 Self::V2(fields) => RawCommitmentBuilder::new(&Self::tag())
93 .u64_field("version_major", 0)
94 .u64_field("version_minor", 2)
95 .field("fields", fields.commit())
96 .finalize(),
97 Self::V3(fields) => RawCommitmentBuilder::new(&Self::tag())
98 .u64_field("version_major", 0)
99 .u64_field("version_minor", 3)
100 .field("fields", fields.commit())
101 .finalize(),
102 Self::V4(fields) => RawCommitmentBuilder::new(&Self::tag())
103 .u64_field("version_major", 0)
104 .u64_field("version_minor", 4)
105 .field("fields", fields.commit())
106 .finalize(),
107 Self::V5(fields) => RawCommitmentBuilder::new(&Self::tag())
108 .u64_field("version_major", 0)
109 .u64_field("version_minor", 5)
110 .field("fields", fields.commit())
111 .finalize(),
112 Self::V6(fields) => RawCommitmentBuilder::new(&Self::tag())
113 .u64_field("version_major", 0)
114 .u64_field("version_minor", 6)
115 .field("fields", fields.commit())
116 .finalize(),
117 }
118 }
119
120 fn tag() -> String {
121 "BLOCK".into()
124 }
125}
126
127impl Serialize for Header {
128 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
129 where
130 S: Serializer,
131 {
132 match self {
133 Self::V1(header) => header.serialize(serializer),
134 Self::V2(fields) => VersionedHeader {
135 version: EitherOrVersion::Version(Version { major: 0, minor: 2 }),
136 fields: fields.clone(),
137 }
138 .serialize(serializer),
139 Self::V3(fields) => VersionedHeader {
140 version: EitherOrVersion::Version(Version { major: 0, minor: 3 }),
141 fields: fields.clone(),
142 }
143 .serialize(serializer),
144 Self::V4(fields) => VersionedHeader {
145 version: EitherOrVersion::Version(Version { major: 0, minor: 4 }),
146 fields: fields.clone(),
147 }
148 .serialize(serializer),
149 Self::V5(fields) => VersionedHeader {
150 version: EitherOrVersion::Version(Version { major: 0, minor: 5 }),
151 fields: fields.clone(),
152 }
153 .serialize(serializer),
154 Self::V6(fields) => VersionedHeader {
155 version: EitherOrVersion::Version(Version { major: 0, minor: 6 }),
156 fields: fields.clone(),
157 }
158 .serialize(serializer),
159 }
160 }
161}
162
163impl<'de> Deserialize<'de> for Header {
164 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
165 where
166 D: Deserializer<'de>,
167 {
168 struct HeaderVisitor;
169
170 impl<'de> Visitor<'de> for HeaderVisitor {
171 type Value = Header;
172
173 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
174 formatter.write_str("Header")
175 }
176
177 fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
178 where
179 V: SeqAccess<'de>,
180 {
181 let chain_config_or_version: EitherOrVersion = seq
182 .next_element()?
183 .ok_or_else(|| de::Error::missing_field("chain_config"))?;
184
185 match chain_config_or_version {
186 EitherOrVersion::Left(cfg) => Ok(Header::V1(
189 v0_1::Header::deserialize_with_chain_config(cfg.into(), seq)?,
190 )),
191 EitherOrVersion::Right(commit) => Ok(Header::V1(
192 v0_1::Header::deserialize_with_chain_config(commit.into(), seq)?,
193 )),
194 EitherOrVersion::Version(Version { major: 0, minor: 2 }) => Ok(Header::V2(
197 seq.next_element()?
198 .ok_or_else(|| de::Error::missing_field("fields"))?,
199 )),
200 EitherOrVersion::Version(Version { major: 0, minor: 3 }) => Ok(Header::V3(
201 seq.next_element()?
202 .ok_or_else(|| de::Error::missing_field("fields"))?,
203 )),
204 EitherOrVersion::Version(Version { major: 0, minor: 4 }) => Ok(Header::V4(
205 seq.next_element()?
206 .ok_or_else(|| de::Error::missing_field("fields"))?,
207 )),
208 EitherOrVersion::Version(Version { major: 0, minor: 5 }) => Ok(Header::V5(
209 seq.next_element()?
210 .ok_or_else(|| de::Error::missing_field("fields"))?,
211 )),
212 EitherOrVersion::Version(Version { major: 0, minor: 6 }) => Ok(Header::V6(
213 seq.next_element()?
214 .ok_or_else(|| de::Error::missing_field("fields"))?,
215 )),
216 EitherOrVersion::Version(v) => {
217 Err(serde::de::Error::custom(format!("invalid version {v:?}")))
218 },
219 }
220 }
221
222 fn visit_map<V>(self, mut map: V) -> Result<Header, V::Error>
223 where
224 V: MapAccess<'de>,
225 {
226 let mut serde_map: Map<String, Value> = Map::new();
228
229 while let Some(key) = map.next_key::<String>()? {
230 serde_map.insert(key.trim().to_owned(), map.next_value()?);
231 }
232
233 if let Some(v) = serde_map.get("version") {
234 let fields = serde_map
235 .get("fields")
236 .ok_or_else(|| de::Error::missing_field("fields"))?;
237
238 let version = serde_json::from_value::<EitherOrVersion>(v.clone())
239 .map_err(de::Error::custom)?;
240 let result = match version {
241 EitherOrVersion::Version(Version { major: 0, minor: 2 }) => Ok(Header::V2(
242 serde_json::from_value(fields.clone()).map_err(de::Error::custom)?,
243 )),
244 EitherOrVersion::Version(Version { major: 0, minor: 3 }) => Ok(Header::V3(
245 serde_json::from_value(fields.clone()).map_err(de::Error::custom)?,
246 )),
247 EitherOrVersion::Version(Version { major: 0, minor: 4 }) => Ok(Header::V4(
248 serde_json::from_value(fields.clone()).map_err(de::Error::custom)?,
249 )),
250 EitherOrVersion::Version(Version { major: 0, minor: 5 }) => Ok(Header::V5(
251 serde_json::from_value(fields.clone()).map_err(de::Error::custom)?,
252 )),
253 EitherOrVersion::Version(Version { major: 0, minor: 6 }) => Ok(Header::V6(
254 serde_json::from_value(fields.clone()).map_err(de::Error::custom)?,
255 )),
256 EitherOrVersion::Version(v) => {
257 Err(de::Error::custom(format!("invalid version {v:?}")))
258 },
259 chain_config => Err(de::Error::custom(format!(
260 "expected version, found chain_config {chain_config:?}"
261 ))),
262 };
263 return result;
264 }
265
266 Ok(Header::V1(
267 serde_json::from_value(serde_map.into()).map_err(de::Error::custom)?,
268 ))
269 }
270 }
271
272 let fields: &[&str] = &[
287 "fields",
288 "chain_config",
289 "version",
290 "height",
291 "timestamp",
292 "l1_head",
293 "l1_finalized",
294 "payload_commitment",
295 "builder_commitment",
296 "ns_table",
297 "block_merkle_tree_root",
298 "fee_merkle_tree_root",
299 "fee_info",
300 "builder_signature",
301 ];
302
303 deserializer.deserialize_struct("Header", fields, HeaderVisitor)
304 }
305}
306
307impl Header {
308 pub fn version(&self) -> Version {
309 match self {
310 Self::V1(_) => Version { major: 0, minor: 1 },
311 Self::V2(_) => Version { major: 0, minor: 2 },
312 Self::V3(_) => Version { major: 0, minor: 3 },
313 Self::V4(_) => Version { major: 0, minor: 4 },
314 Self::V5(_) => Version { major: 0, minor: 5 },
315 Self::V6(_) => Version { major: 0, minor: 6 },
316 }
317 }
318 #[allow(clippy::too_many_arguments)]
319 pub(crate) fn create(
320 chain_config: ChainConfig,
321 height: u64,
322 timestamp: u64,
323 timestamp_millis: u64,
324 l1_head: u64,
325 l1_finalized: Option<L1BlockInfo>,
326 payload_commitment: VidCommitment,
327 builder_commitment: BuilderCommitment,
328 ns_table: NsTable,
329 fee_merkle_tree_root: FeeMerkleCommitment,
330 block_merkle_tree_root: BlockMerkleCommitment,
331 reward_merkle_tree_root_v1: RewardMerkleCommitmentV1,
332 reward_merkle_tree_root_v2: RewardMerkleCommitmentV2,
333 fee_info: Vec<FeeInfo>,
334 builder_signature: Vec<BuilderSignature>,
335 total_reward_distributed: Option<RewardAmount>,
336 version: Version,
337 next_stake_table_hash: Option<StakeTableHash>,
338 leader_counts: Option<LeaderCounts>,
339 ) -> Self {
340 assert!(!fee_info.is_empty(), "Invalid fee_info length: 0");
342
343 match (version.major, version.minor) {
344 (0, 1) => Self::V1(v0_1::Header {
345 chain_config: v0_1::ResolvableChainConfig::from(v0_1::ChainConfig::from(
346 chain_config,
347 )),
348 height,
349 timestamp,
350 l1_head,
351 l1_finalized,
352 payload_commitment,
353 builder_commitment,
354 ns_table,
355 block_merkle_tree_root,
356 fee_merkle_tree_root,
357 fee_info: fee_info[0], builder_signature: builder_signature.first().copied(),
359 }),
360 (0, 2) => Self::V2(v0_2::Header {
361 chain_config: v0_1::ResolvableChainConfig::from(v0_1::ChainConfig::from(
362 chain_config,
363 )),
364 height,
365 timestamp,
366 l1_head,
367 l1_finalized,
368 payload_commitment,
369 builder_commitment,
370 ns_table,
371 block_merkle_tree_root,
372 fee_merkle_tree_root,
373 fee_info: fee_info[0], builder_signature: builder_signature.first().copied(),
375 }),
376 (0, 3) => Self::V3(v0_3::Header {
377 chain_config: chain_config.into(),
378 height,
379 timestamp,
380 l1_head,
381 l1_finalized,
382 payload_commitment,
383 builder_commitment,
384 ns_table,
385 block_merkle_tree_root,
386 fee_merkle_tree_root,
387 fee_info: fee_info[0], builder_signature: builder_signature.first().copied(),
389 reward_merkle_tree_root: reward_merkle_tree_root_v1,
390 }),
391 (0, 4) => Self::V4(v0_4::Header {
392 chain_config: chain_config.into(),
393 height,
394 timestamp,
395 timestamp_millis: TimestampMillis::from_millis(timestamp_millis),
396 l1_head,
397 l1_finalized,
398 payload_commitment,
399 builder_commitment,
400 ns_table,
401 block_merkle_tree_root,
402 fee_merkle_tree_root,
403 fee_info: fee_info[0], builder_signature: builder_signature.first().copied(),
405 reward_merkle_tree_root: reward_merkle_tree_root_v2,
406 total_reward_distributed: total_reward_distributed.unwrap_or_default(),
407 next_stake_table_hash,
408 }),
409 (0, 5) => Self::V5(v0_5::Header {
410 chain_config: chain_config.into(),
411 height,
412 timestamp,
413 timestamp_millis: TimestampMillis::from_millis(timestamp_millis),
414 l1_head,
415 l1_finalized,
416 payload_commitment,
417 builder_commitment,
418 ns_table,
419 block_merkle_tree_root,
420 fee_merkle_tree_root,
421 fee_info: fee_info[0], builder_signature: builder_signature.first().copied(),
423 reward_merkle_tree_root: reward_merkle_tree_root_v2,
424 total_reward_distributed: total_reward_distributed.unwrap_or_default(),
425 next_stake_table_hash,
426 leader_counts: leader_counts.expect("leader_counts required for V5 header"),
427 }),
428 (0, 6) => {
430 let fields = v0_6::Header {
431 chain_config: chain_config.into(),
432 height,
433 timestamp,
434 timestamp_millis: TimestampMillis::from_millis(timestamp_millis),
435 l1_head,
436 l1_finalized,
437 payload_commitment,
438 builder_commitment,
439 ns_table,
440 block_merkle_tree_root,
441 fee_merkle_tree_root,
442 fee_info: fee_info[0],
443 builder_signature: builder_signature.first().copied(),
444 reward_merkle_tree_root: reward_merkle_tree_root_v2,
445 total_reward_distributed: total_reward_distributed.unwrap_or_default(),
446 next_stake_table_hash,
447 leader_counts: leader_counts.expect("leader_counts required for V6 header"),
448 };
449 Self::V6(fields)
450 },
451 _ => panic!("invalid version: {version}"),
455 }
456 }
457
458 pub fn next_stake_table_hash(&self) -> Option<StakeTableHash> {
459 match self {
460 Self::V4(fields) => fields.next_stake_table_hash,
461 Self::V5(fields) | Self::V6(fields) => fields.next_stake_table_hash,
462 _ => None,
463 }
464 }
465
466 pub fn leader_counts(&self) -> Option<&LeaderCounts> {
469 match self {
470 Self::V5(fields) | Self::V6(fields) => Some(&fields.leader_counts),
471 _ => None,
472 }
473 }
474
475 pub fn set_next_stake_table_hash(&mut self, hash: StakeTableHash) -> bool {
476 match self {
477 Self::V4(fields) => {
478 fields.next_stake_table_hash = Some(hash);
479 true
480 },
481 Self::V5(fields) | Self::V6(fields) => {
482 fields.next_stake_table_hash = Some(hash);
483 true
484 },
485 _ => false,
486 }
487 }
488}
489
490macro_rules! field {
492 ($obj:ident.$name:ident) => {
493 match $obj {
494 Self::V1(data) => &data.$name,
495 Self::V2(data) => &data.$name,
496 Self::V3(data) => &data.$name,
497 Self::V4(data) => &data.$name,
498 Self::V5(data) => &data.$name,
499 Self::V6(data) => &data.$name,
500 }
501 };
502}
503
504macro_rules! field_mut {
505 ($obj:ident.$name:ident) => {
506 match $obj {
507 Self::V1(data) => &mut data.$name,
508 Self::V2(data) => &mut data.$name,
509 Self::V3(data) => &mut data.$name,
510 Self::V4(data) => &mut data.$name,
511 Self::V5(data) => &mut data.$name,
512 Self::V6(data) => &mut data.$name,
513 }
514 };
515}
516
517impl Header {
518 #[allow(clippy::too_many_arguments)]
519 fn from_info(
520 payload_commitment: VidCommitment,
521 builder_commitment: BuilderCommitment,
522 ns_table: NsTable,
523 parent_leaf: &Leaf2,
524 mut l1: L1Snapshot,
525 l1_deposits: &[FeeInfo],
526 builder_fee: Vec<BuilderFee<SeqTypes>>,
527 mut timestamp: u64,
528 mut timestamp_millis: u64,
529 mut state: ValidatedState,
530 chain_config: ChainConfig,
531 version: Version,
532 total_reward_distributed: Option<RewardAmount>,
533 next_stake_table_hash: Option<StakeTableHash>,
534 leader_counts: Option<LeaderCounts>,
535 ) -> anyhow::Result<Self> {
536 ensure!(
537 version.major == 0,
538 "Invalid major version {}",
539 version.major
540 );
541
542 let parent_header = parent_leaf.block_header();
544 let height = parent_header.height() + 1;
545
546 if timestamp < parent_header.timestamp() {
550 tracing::warn!(
551 "Espresso timestamp {timestamp} behind parent {}, local clock may be out of sync",
552 parent_header.timestamp()
553 );
554 timestamp = parent_header.timestamp();
555 }
556
557 if timestamp_millis < parent_header.timestamp_millis() {
558 tracing::warn!(
559 "Espresso timestamp {timestamp} behind parent {}, local clock may be out of sync",
560 parent_header.timestamp_millis()
561 );
562 timestamp_millis = parent_header.timestamp_millis();
563 }
564
565 if l1.head < parent_header.l1_head() {
568 tracing::warn!(
569 "L1 head {} behind parent {}, L1 client may be lagging",
570 l1.head,
571 parent_header.l1_head()
572 );
573 l1.head = parent_header.l1_head();
574 }
575 if l1.finalized < parent_header.l1_finalized() {
576 tracing::warn!(
577 "L1 finalized {:?} behind parent {:?}, L1 client may be lagging",
578 l1.finalized,
579 parent_header.l1_finalized()
580 );
581 l1.finalized = parent_header.l1_finalized();
582 }
583
584 if let Some(l1_block) = &l1.finalized {
587 let l1_timestamp = l1_block.timestamp.to::<u64>();
588 if timestamp < l1_timestamp {
589 tracing::warn!(
590 "Espresso timestamp {timestamp} behind L1 timestamp {l1_timestamp}, local \
591 clock may be out of sync"
592 );
593 timestamp = l1_timestamp;
594 }
595
596 let l1_timestamp_millis = l1_timestamp * 1_000;
597
598 if timestamp_millis < l1_timestamp_millis {
599 tracing::warn!(
600 "Espresso timestamp_millis {timestamp_millis} behind L1 timestamp \
601 {l1_timestamp_millis}, local clock may be out of sync"
602 );
603 timestamp_millis = l1_timestamp_millis;
604 }
605 }
606
607 state
608 .block_merkle_tree
609 .push(parent_header.commit())
610 .context("missing blocks frontier")?;
611 let block_merkle_tree_root = state.block_merkle_tree.commitment();
612
613 for fee_info in l1_deposits {
615 state
616 .insert_fee_deposit(*fee_info)
617 .context(format!("missing fee account {}", fee_info.account()))?;
618 }
619
620 if version < versions::NEW_PROTOCOL_VERSION {
622 for BuilderFee {
623 fee_account,
624 fee_signature,
625 fee_amount,
626 } in &builder_fee
627 {
628 ensure!(
629 fee_account.validate_fee_signature(fee_signature, *fee_amount, &ns_table)
630 || fee_account.validate_fee_signature_with_vid_commitment(
631 fee_signature,
632 *fee_amount,
633 &ns_table,
634 &payload_commitment
635 ),
636 "invalid builder signature"
637 );
638
639 let fee_info = FeeInfo::new(*fee_account, *fee_amount);
640 state
641 .charge_fee(fee_info, chain_config.fee_recipient)
642 .context(format!("invalid builder fee {fee_info:?}"))?;
643 }
644 }
645
646 let fee_info = FeeInfo::from_builder_fees(builder_fee.clone());
647
648 let builder_signature: Vec<BuilderSignature> =
649 builder_fee.iter().map(|e| e.fee_signature).collect();
650
651 let fee_merkle_tree_root = state.fee_merkle_tree.commitment();
652
653 let header = match (version.major, version.minor) {
654 (0, 1) => Self::V1(v0_1::Header {
655 chain_config: v0_1::ResolvableChainConfig::from(v0_1::ChainConfig::from(
656 chain_config,
657 )),
658 height,
659 timestamp,
660 l1_head: l1.head,
661 l1_finalized: l1.finalized,
662 payload_commitment,
663 builder_commitment,
664 ns_table,
665 block_merkle_tree_root,
666 fee_merkle_tree_root,
667 fee_info: fee_info[0],
668 builder_signature: builder_signature.first().copied(),
669 }),
670 (0, 2) => Self::V2(v0_2::Header {
671 chain_config: v0_1::ResolvableChainConfig::from(v0_1::ChainConfig::from(
672 chain_config,
673 )),
674 height,
675 timestamp,
676 l1_head: l1.head,
677 l1_finalized: l1.finalized,
678 payload_commitment,
679 builder_commitment,
680 ns_table,
681 block_merkle_tree_root,
682 fee_merkle_tree_root,
683 fee_info: fee_info[0],
684 builder_signature: builder_signature.first().copied(),
685 }),
686 (0, 3) => Self::V3(v0_3::Header {
687 chain_config: chain_config.into(),
688 height,
689 timestamp,
690 l1_head: l1.head,
691 l1_finalized: l1.finalized,
692 payload_commitment,
693 builder_commitment,
694 ns_table,
695 block_merkle_tree_root,
696 fee_merkle_tree_root,
697 reward_merkle_tree_root: state.reward_merkle_tree_v1.commitment(),
698 fee_info: fee_info[0],
699 builder_signature: builder_signature.first().copied(),
700 }),
701 (0, 4) => Self::V4(v0_4::Header {
702 chain_config: chain_config.into(),
703 height,
704 timestamp,
705 timestamp_millis: TimestampMillis::from_millis(timestamp_millis),
706 l1_head: l1.head,
707 l1_finalized: l1.finalized,
708 payload_commitment,
709 builder_commitment,
710 ns_table,
711 block_merkle_tree_root,
712 fee_merkle_tree_root,
713 reward_merkle_tree_root: state.reward_merkle_tree_v2.commitment(),
714 fee_info: fee_info[0],
715 builder_signature: builder_signature.first().copied(),
716 total_reward_distributed: total_reward_distributed.unwrap_or_default(),
717 next_stake_table_hash,
718 }),
719 (0, 5) => Self::V5(v0_5::Header {
720 chain_config: chain_config.into(),
721 height,
722 timestamp,
723 timestamp_millis: TimestampMillis::from_millis(timestamp_millis),
724 l1_head: l1.head,
725 l1_finalized: l1.finalized,
726 payload_commitment,
727 builder_commitment,
728 ns_table,
729 block_merkle_tree_root,
730 fee_merkle_tree_root,
731 reward_merkle_tree_root: state.reward_merkle_tree_v2.commitment(),
732 fee_info: fee_info[0],
733 builder_signature: builder_signature.first().copied(),
734 total_reward_distributed: total_reward_distributed.unwrap_or_default(),
735 next_stake_table_hash,
736 leader_counts: leader_counts.expect("leader_counts is required for V5 headers"),
737 }),
738 (0, 6) => {
740 let fields = v0_6::Header {
741 chain_config: chain_config.into(),
742 height,
743 timestamp,
744 timestamp_millis: TimestampMillis::from_millis(timestamp_millis),
745 l1_head: l1.head,
746 l1_finalized: l1.finalized,
747 payload_commitment,
748 builder_commitment,
749 ns_table,
750 block_merkle_tree_root,
751 fee_merkle_tree_root,
752 reward_merkle_tree_root: state.reward_merkle_tree_v2.commitment(),
753 fee_info: fee_info[0],
754 builder_signature: builder_signature.first().copied(),
755 total_reward_distributed: total_reward_distributed.unwrap_or_default(),
756 next_stake_table_hash,
757 leader_counts: leader_counts.expect("leader_counts is required for V6 headers"),
758 };
759 Self::V6(fields)
760 },
761 _ => panic!("invalid version: {version}"),
765 };
766 Ok(header)
767 }
768
769 pub fn calculate_leader_counts(
776 parent_header: &Header,
777 height: u64,
778 leader_index: usize,
779 epoch_height: u64,
780 ) -> LeaderCounts {
781 let mut leader_counts = [0u16; MAX_VALIDATORS];
782
783 let parent_counts = parent_header.leader_counts();
785
786 let is_epoch_start = is_last_block(height.saturating_sub(1), epoch_height);
788
789 if is_epoch_start || parent_counts.is_none() {
790 leader_counts[leader_index] = 1;
791 } else if let Some(parent_counts) = parent_counts {
792 leader_counts = *parent_counts;
793 leader_counts[leader_index] += 1;
794 }
795
796 leader_counts
797 }
798
799 pub async fn get_leader_index(
807 version: Version,
808 height: u64,
809 view_number: u64,
810 instance_state: &NodeState,
811 ) -> anyhow::Result<Option<usize>> {
812 if version < EPOCH_REWARD_VERSION {
814 return Ok(None);
815 }
816
817 let epoch_height = instance_state
818 .epoch_height
819 .context("epoch height not in instance state for V6")?;
820 let epoch = EpochNumber::new(epoch_from_block_number(height, epoch_height));
821
822 let coordinator = instance_state.coordinator.clone();
823 coordinator
824 .membership_for_epoch(Some(epoch))
825 .map_err(|e| anyhow::anyhow!("failed to get epoch membership: {e}"))?;
826
827 let snapshot = coordinator
829 .membership()
830 .snapshot(epoch)
831 .with_context(|| format!("no committee for epoch {epoch:?}"))?;
832
833 let leader = snapshot
834 .leader(ViewNumber::new(view_number))
835 .with_context(|| format!("leader for epoch {epoch:?} not found"))?;
836
837 let index = snapshot.validator_index(&leader).with_context(|| {
838 format!("Leader {leader} not found in stake table for epoch {epoch}")
839 })?;
840
841 Ok(Some(index))
842 }
843
844 pub async fn handle_epoch_rewards(
870 height: u64,
871 leader_counts: &LeaderCounts,
872 instance_state: &NodeState,
873 validated_state: &mut ValidatedState,
874 header_root: Option<RewardMerkleCommitmentV2>,
875 ) -> anyhow::Result<(RewardAmount, HashSet<RewardAccountV2>)> {
876 let epoch_height = instance_state
877 .epoch_height
878 .context("epoch_height not configured")?;
879 ensure!(epoch_height > 0, "epoch_height must be > 0");
880 let epoch = EpochNumber::new(epoch_from_block_number(height, epoch_height));
881 let prev_epoch = EpochNumber::new(*epoch - 1);
882 let coordinator = instance_state.coordinator.clone();
883 let first_epoch = coordinator
884 .membership()
885 .first_epoch()
886 .context("first_epoch not available")?;
887
888 if epoch <= first_epoch + 1 {
890 return Ok((RewardAmount::default(), HashSet::new()));
891 }
892
893 let mut reward_calculator = instance_state.epoch_rewards_calculator.lock().await;
894
895 if epoch > first_epoch + 2 && !reward_calculator.is_calculating(prev_epoch) {
898 tracing::info!(%epoch, %prev_epoch, "triggering catchup reward calculation");
899 reward_calculator.spawn_background_task(
900 prev_epoch,
901 epoch_height,
902 validated_state.reward_merkle_tree_v2.clone(),
903 instance_state.clone(),
904 coordinator.clone(),
905 None,
906 );
907 }
908
909 if !is_last_block(height, epoch_height) {
910 return Ok((RewardAmount::default(), HashSet::new()));
911 }
912
913 tracing::info!(%height, %epoch, %prev_epoch, "epoch boundary: applying rewards");
914
915 let (epoch_rewards_applied, changed_accounts) = if let Some(result) =
916 reward_calculator.get_result(prev_epoch).await
917 {
918 tracing::info!(
919 %epoch,
920 prev_epoch = %result.epoch,
921 total = %result.total_distributed.0,
922 "applying epoch rewards"
923 );
924 validated_state.reward_merkle_tree_v2 = result.reward_tree.clone();
925 (result.total_distributed, result.changed_accounts)
926 } else if prev_epoch <= first_epoch + 1 {
927 (RewardAmount::default(), HashSet::new())
929 } else {
930 let prev_epoch_last_block = *prev_epoch * epoch_height;
933 if let Err(err) = coordinator.membership_for_epoch(Some(prev_epoch)) {
934 tracing::info!(%prev_epoch, "stake table missing for prev_epoch, triggering catchup: {err:#}");
935 coordinator
936 .wait_for_catchup(prev_epoch)
937 .await
938 .context(format!("failed to catch up for prev_epoch={prev_epoch}"))?;
939 }
940
941 let prev_snapshot = coordinator
942 .membership()
943 .snapshot(prev_epoch)
944 .with_context(|| format!("no committee for prev_epoch={prev_epoch}"))?;
945
946 let stake_table = HSStakeTable::from_iter(prev_snapshot.stake_table());
947 let success_threshold = prev_snapshot.success_threshold();
948
949 let prev_epoch_leaf = instance_state
950 .state_catchup
951 .as_ref()
952 .fetch_leaf(prev_epoch_last_block, stake_table, success_threshold)
953 .await
954 .with_context(|| {
955 format!(
956 "failed to fetch leaf at height {prev_epoch_last_block} for prev_epoch \
957 {prev_epoch}"
958 )
959 })?;
960 let prev_epoch_header = prev_epoch_leaf.block_header();
961
962 if prev_epoch_header.version() >= EPOCH_REWARD_VERSION {
963 tracing::warn!(
964 %epoch,
965 %prev_epoch,
966 "missing epoch rewards at boundary, spawning calculation now"
967 );
968
969 if !reward_calculator.is_calculating(prev_epoch) {
970 let expected_root = prev_epoch_header.reward_merkle_tree_root().right();
975 let actual_root = validated_state.reward_merkle_tree_v2.commitment();
976 let reward_tree = if expected_root == Some(actual_root) {
977 validated_state.reward_merkle_tree_v2.clone()
978 } else {
979 tracing::warn!(
980 %epoch,
981 %prev_epoch,
982 ?expected_root,
983 ?actual_root,
984 "reward merkle tree root mismatch, using empty tree for catchup"
985 );
986 RewardMerkleTreeV2::new(REWARD_MERKLE_TREE_V2_HEIGHT)
987 };
988
989 reward_calculator.spawn_background_task(
990 prev_epoch,
991 epoch_height,
992 reward_tree,
993 instance_state.clone(),
994 coordinator.clone(),
995 prev_epoch_header.leader_counts().copied(),
996 );
997 }
998
999 let result = reward_calculator
1000 .get_result(prev_epoch)
1001 .await
1002 .context(format!(
1003 "failed to calculate missing rewards for epoch {prev_epoch}"
1004 ))?;
1005
1006 tracing::info!(
1007 %epoch,
1008 %prev_epoch,
1009 total = %result.total_distributed.0,
1010 "applied delayed epoch rewards"
1011 );
1012
1013 validated_state.reward_merkle_tree_v2 = result.reward_tree.clone();
1014 (result.total_distributed, result.changed_accounts)
1015 } else {
1016 tracing::info!(%epoch, %prev_epoch, "no rewards for pre-V5 epoch");
1017 (RewardAmount::default(), HashSet::new())
1018 }
1019 };
1020
1021 let calculated_root = validated_state.reward_merkle_tree_v2.commitment();
1023 if let Some(header_root) = header_root
1024 && calculated_root != header_root
1025 {
1026 bail!(
1027 "reward merkle tree root mismatch, using new merkle tree. Header root: \
1028 {header_root}, Calculated root: {calculated_root}"
1029 );
1030 }
1031
1032 reward_calculator.spawn_background_task(
1035 epoch,
1036 epoch_height,
1037 validated_state.reward_merkle_tree_v2.clone(),
1038 instance_state.clone(),
1039 coordinator,
1040 Some(*leader_counts),
1041 );
1042
1043 Ok((epoch_rewards_applied, changed_accounts))
1044 }
1045
1046 async fn get_chain_config(
1047 validated_state: &ValidatedState,
1048 instance_state: &NodeState,
1049 ) -> anyhow::Result<ChainConfig> {
1050 let validated_cf = validated_state.chain_config;
1051 let instance_cf = instance_state.chain_config;
1052
1053 if validated_cf.commit() == instance_cf.commit() {
1054 return Ok(instance_cf);
1055 }
1056
1057 match validated_cf.resolve() {
1058 Some(cf) => Ok(cf),
1059 None => {
1060 tracing::info!("fetching chain config {} from peers", validated_cf.commit());
1061
1062 instance_state
1063 .state_catchup
1064 .as_ref()
1065 .fetch_chain_config(validated_cf.commit())
1066 .await
1067 },
1068 }
1069 }
1070}
1071
1072impl Header {
1073 pub fn chain_config(&self) -> v0_3::ResolvableChainConfig {
1075 match self {
1076 Self::V1(fields) => v0_3::ResolvableChainConfig::from(&fields.chain_config),
1077 Self::V2(fields) => v0_3::ResolvableChainConfig::from(&fields.chain_config),
1078 Self::V3(fields) => fields.chain_config,
1079 Self::V4(fields) => fields.chain_config,
1080 Self::V5(fields) => fields.chain_config,
1081 Self::V6(fields) => fields.chain_config,
1082 }
1083 }
1084
1085 pub fn height(&self) -> u64 {
1086 *field!(self.height)
1087 }
1088
1089 pub fn height_mut(&mut self) -> &mut u64 {
1090 &mut *field_mut!(self.height)
1091 }
1092
1093 pub fn timestamp_internal(&self) -> u64 {
1094 match self {
1095 Self::V1(fields) => fields.timestamp,
1096 Self::V2(fields) => fields.timestamp,
1097 Self::V3(fields) => fields.timestamp,
1098 Self::V4(fields) => fields.timestamp,
1099 Self::V5(fields) => fields.timestamp,
1100 Self::V6(fields) => fields.timestamp,
1101 }
1102 }
1103
1104 pub fn timestamp_millis_internal(&self) -> u64 {
1105 match self {
1106 Self::V1(fields) => fields.timestamp * 1_000,
1107 Self::V2(fields) => fields.timestamp * 1_000,
1108 Self::V3(fields) => fields.timestamp * 1_000,
1109 Self::V4(fields) => fields.timestamp_millis.u64(),
1110 Self::V5(fields) => fields.timestamp_millis.u64(),
1111 Self::V6(fields) => fields.timestamp_millis.u64(),
1112 }
1113 }
1114
1115 pub fn set_timestamp(&mut self, timestamp: u64, timestamp_millis: u64) {
1116 match self {
1117 Self::V1(fields) => {
1118 fields.timestamp = timestamp;
1119 },
1120 Self::V2(fields) => {
1121 fields.timestamp = timestamp;
1122 },
1123 Self::V3(fields) => {
1124 fields.timestamp = timestamp;
1125 },
1126 Self::V4(fields) => {
1127 fields.timestamp = timestamp;
1128 fields.timestamp_millis = TimestampMillis::from_millis(timestamp_millis);
1129 },
1130 Self::V5(fields) => {
1131 fields.timestamp = timestamp;
1132 fields.timestamp_millis = TimestampMillis::from_millis(timestamp_millis);
1133 },
1134 Self::V6(fields) => {
1135 fields.timestamp = timestamp;
1136 fields.timestamp_millis = TimestampMillis::from_millis(timestamp_millis);
1137 },
1138 };
1139 }
1140
1141 pub fn l1_head(&self) -> u64 {
1166 *field!(self.l1_head)
1167 }
1168
1169 pub fn l1_head_mut(&mut self) -> &mut u64 {
1170 &mut *field_mut!(self.l1_head)
1171 }
1172
1173 pub fn l1_finalized(&self) -> Option<L1BlockInfo> {
1188 *field!(self.l1_finalized)
1189 }
1190
1191 pub fn l1_finalized_mut(&mut self) -> &mut Option<L1BlockInfo> {
1192 &mut *field_mut!(self.l1_finalized)
1193 }
1194
1195 pub fn payload_commitment(&self) -> VidCommitment {
1196 *field!(self.payload_commitment)
1197 }
1198
1199 pub fn payload_commitment_mut(&mut self) -> &mut VidCommitment {
1200 &mut *field_mut!(self.payload_commitment)
1201 }
1202
1203 pub fn builder_commitment(&self) -> &BuilderCommitment {
1204 field!(self.builder_commitment)
1205 }
1206
1207 pub fn builder_commitment_mut(&mut self) -> &mut BuilderCommitment {
1208 &mut *field_mut!(self.builder_commitment)
1209 }
1210
1211 pub fn ns_table(&self) -> &NsTable {
1212 field!(self.ns_table)
1213 }
1214
1215 pub fn ns_table_mut(&mut self) -> &mut NsTable {
1216 &mut *field_mut!(self.ns_table)
1217 }
1218
1219 pub fn block_merkle_tree_root(&self) -> BlockMerkleCommitment {
1221 *field!(self.block_merkle_tree_root)
1222 }
1223
1224 pub fn block_merkle_tree_root_mut(&mut self) -> &mut BlockMerkleCommitment {
1225 &mut *field_mut!(self.block_merkle_tree_root)
1226 }
1227
1228 pub fn fee_merkle_tree_root(&self) -> FeeMerkleCommitment {
1230 *field!(self.fee_merkle_tree_root)
1231 }
1232
1233 pub fn fee_merkle_tree_root_mut(&mut self) -> &mut FeeMerkleCommitment {
1234 &mut *field_mut!(self.fee_merkle_tree_root)
1235 }
1236
1237 pub fn fee_info(&self) -> Vec<FeeInfo> {
1239 match self {
1240 Self::V1(fields) => vec![fields.fee_info],
1241 Self::V2(fields) => vec![fields.fee_info],
1242 Self::V3(fields) => vec![fields.fee_info],
1243 Self::V4(fields) => vec![fields.fee_info],
1244 Self::V5(fields) => vec![fields.fee_info],
1245 Self::V6(fields) => vec![fields.fee_info],
1246 }
1247 }
1248
1249 pub fn reward_merkle_tree_root(
1250 &self,
1251 ) -> Either<RewardMerkleCommitmentV1, RewardMerkleCommitmentV2> {
1252 let empty_reward_merkle_tree = RewardMerkleTreeV1::new(REWARD_MERKLE_TREE_V1_HEIGHT);
1253 match self {
1254 Self::V1(_) => Either::Left(empty_reward_merkle_tree.commitment()),
1255 Self::V2(_) => Either::Left(empty_reward_merkle_tree.commitment()),
1256 Self::V3(fields) => Either::Left(fields.reward_merkle_tree_root),
1257 Self::V4(fields) => Either::Right(fields.reward_merkle_tree_root),
1258 Self::V5(fields) => Either::Right(fields.reward_merkle_tree_root),
1259 Self::V6(fields) => Either::Right(fields.reward_merkle_tree_root),
1260 }
1261 }
1262
1263 pub fn builder_signature(&self) -> Vec<BuilderSignature> {
1272 match self {
1273 Self::V1(fields) => fields.builder_signature.as_slice().to_vec(),
1278 Self::V2(fields) => fields.builder_signature.as_slice().to_vec(),
1279 Self::V3(fields) => fields.builder_signature.as_slice().to_vec(),
1280 Self::V4(fields) => fields.builder_signature.as_slice().to_vec(),
1281 Self::V5(fields) => fields.builder_signature.as_slice().to_vec(),
1282 Self::V6(fields) => fields.builder_signature.as_slice().to_vec(),
1283 }
1284 }
1285
1286 pub fn total_reward_distributed(&self) -> Option<RewardAmount> {
1287 match self {
1288 Self::V1(_) | Self::V2(_) | Self::V3(_) => None,
1289 Self::V4(fields) => Some(fields.total_reward_distributed),
1290 Self::V5(fields) => Some(fields.total_reward_distributed),
1291 Self::V6(fields) => Some(fields.total_reward_distributed),
1292 }
1293 }
1294}
1295
1296#[derive(Debug, Error)]
1297#[error("Invalid Block Header {msg}")]
1298pub struct InvalidBlockHeader {
1299 msg: String,
1300}
1301impl InvalidBlockHeader {
1302 fn new(msg: String) -> Self {
1303 Self { msg }
1304 }
1305}
1306
1307impl From<anyhow::Error> for InvalidBlockHeader {
1308 fn from(err: anyhow::Error) -> Self {
1309 Self::new(format!("{err:#}"))
1310 }
1311}
1312
1313impl BlockHeader<SeqTypes> for Header {
1314 type Error = InvalidBlockHeader;
1315
1316 #[tracing::instrument(
1317 skip_all,
1318 fields(
1319 node_id = instance_state.node_id,
1320 view = ?parent_leaf.view_number(),
1321 height = parent_leaf.block_header().height(),
1322 ),
1323 )]
1324 #[tracing::instrument(
1325 skip_all,
1326 fields(
1327 height = parent_leaf.block_header().block_number() + 1,
1328 parent_view = ?parent_leaf.view_number(),
1329 payload_commitment,
1330 version,
1331 )
1332 )]
1333 async fn new(
1334 parent_state: &ValidatedState,
1335 instance_state: &NodeState,
1336 parent_leaf: &Leaf2,
1337 payload_commitment: VidCommitment,
1338 builder_commitment: BuilderCommitment,
1339 metadata: <<SeqTypes as NodeType>::BlockPayload as BlockPayload<SeqTypes>>::Metadata,
1340 builder_fee: BuilderFee<SeqTypes>,
1341 version: Version,
1342 view_number: u64,
1343 ) -> Result<Self, Self::Error> {
1344 tracing::info!("preparing to propose header");
1345
1346 let height = parent_leaf.height();
1347 let view = parent_leaf.view_number();
1348
1349 let mut validated_state = parent_state.clone();
1350
1351 let chain_config = if version > instance_state.current_version {
1352 match instance_state.upgrades.get(&version) {
1353 Some(upgrade) => match upgrade.upgrade_type {
1354 UpgradeType::Fee { chain_config } => chain_config,
1355 UpgradeType::Epoch { chain_config } => chain_config,
1356 UpgradeType::DrbAndHeader { chain_config } => chain_config,
1357 UpgradeType::Da { chain_config } => chain_config,
1358 UpgradeType::EpochReward { chain_config } => chain_config,
1359 },
1360 None => Header::get_chain_config(&validated_state, instance_state).await?,
1361 }
1362 } else {
1363 Header::get_chain_config(&validated_state, instance_state).await?
1364 };
1365
1366 validated_state.chain_config = chain_config.into();
1367
1368 let l1_snapshot = instance_state.l1_client.snapshot().await;
1370 let l1_deposits = if let (Some(addr), Some(block_info)) =
1372 (chain_config.fee_contract, l1_snapshot.finalized)
1373 {
1374 instance_state
1375 .l1_client
1376 .get_finalized_deposits(
1377 addr,
1378 parent_leaf
1379 .block_header()
1380 .l1_finalized()
1381 .map(|block_info| block_info.number),
1382 block_info.number,
1383 )
1384 .await
1385 } else {
1386 vec![]
1387 };
1388 let missing_accounts = parent_state.forgotten_accounts(
1392 [builder_fee.fee_account, chain_config.fee_recipient]
1393 .into_iter()
1394 .chain(l1_deposits.iter().map(|info| info.account())),
1395 );
1396 if !missing_accounts.is_empty() {
1397 tracing::warn!(
1398 height,
1399 ?view,
1400 ?missing_accounts,
1401 "fetching missing accounts from peers"
1402 );
1403
1404 let missing_account_proofs = instance_state
1406 .state_catchup
1407 .as_ref()
1408 .fetch_accounts(
1409 instance_state,
1410 height,
1411 view,
1412 parent_state.fee_merkle_tree.commitment(),
1413 missing_accounts,
1414 )
1415 .await?;
1416
1417 for proof in missing_account_proofs.iter() {
1419 proof
1420 .remember(&mut validated_state.fee_merkle_tree)
1421 .context("remembering fee account")?;
1422 }
1423 }
1424
1425 if validated_state.need_to_fetch_blocks_mt_frontier() {
1427 tracing::warn!(height, ?view, "fetching block frontier from peers");
1428 instance_state
1429 .state_catchup
1430 .as_ref()
1431 .remember_blocks_merkle_tree(
1432 instance_state,
1433 height,
1434 view,
1435 &mut validated_state.block_merkle_tree,
1436 )
1437 .await
1438 .context("remembering block proof")?;
1439 }
1440
1441 let (leader_counts, total_reward_distributed) = if version >= EPOCH_REWARD_VERSION {
1443 let epoch_height = instance_state
1444 .epoch_height
1445 .context("epoch_height not configured for V6")?;
1446 let new_height = height + 1;
1448 let leader_index =
1449 Header::get_leader_index(version, new_height, view_number, instance_state)
1450 .await?
1451 .context("leader_index must be present for V6")?;
1452
1453 let leader_counts = Header::calculate_leader_counts(
1454 parent_leaf.block_header(),
1455 new_height,
1456 leader_index,
1457 epoch_height,
1458 );
1459
1460 let (epoch_rewards_applied, _changed_accounts) = Header::handle_epoch_rewards(
1461 new_height,
1462 &leader_counts,
1463 instance_state,
1464 &mut validated_state,
1465 None,
1466 )
1467 .await?;
1468
1469 let parent_total = parent_leaf
1473 .block_header()
1474 .total_reward_distributed()
1475 .unwrap_or_default();
1476
1477 (
1478 Some(leader_counts),
1479 Some(RewardAmount(parent_total.0 + epoch_rewards_applied.0)),
1480 )
1481 } else if version >= EPOCH_VERSION {
1482 let total = distribute_block_reward(
1484 instance_state,
1485 &mut validated_state,
1486 parent_leaf,
1487 ViewNumber::new(view_number),
1488 version,
1489 )
1490 .await?
1491 .map(|r| r.total_distributed());
1492
1493 (None, total)
1494 } else {
1495 (None, None)
1496 };
1497
1498 let mut next_stake_table_hash = None;
1499
1500 if version >= DRB_AND_HEADER_UPGRADE_VERSION {
1501 let epoch_height = instance_state
1502 .epoch_height
1503 .context("epoch height not in instance state")?;
1504 if is_ge_epoch_root(height + 1, epoch_height) {
1505 let coordinator = instance_state.coordinator.clone();
1506 let first_epoch = {
1507 coordinator
1508 .membership()
1509 .first_epoch()
1510 .context("The first epoch was not set.")?
1511 };
1512
1513 let epoch = EpochNumber::new(epoch_from_block_number(height + 1, epoch_height));
1514
1515 if epoch > first_epoch {
1517 let epoch_membership = coordinator
1518 .stake_table_for_epoch(Some(epoch + 1))
1519 .map_err(|e| anyhow::anyhow!("failed to get epoch membership: {e}"))?;
1520 next_stake_table_hash = Some(
1521 epoch_membership
1522 .stake_table_hash()
1523 .context("failed to get next stake table hash")?,
1524 );
1525 }
1526 }
1527 }
1528
1529 let now = OffsetDateTime::now_utc();
1530
1531 let timestamp = now.unix_timestamp() as u64;
1532 let timestamp_millis = TimestampMillis::from_time(&now).u64();
1533
1534 Ok(Self::from_info(
1535 payload_commitment,
1536 builder_commitment,
1537 metadata,
1538 parent_leaf,
1539 l1_snapshot,
1540 &l1_deposits,
1541 vec![builder_fee],
1542 timestamp,
1543 timestamp_millis,
1544 validated_state,
1545 chain_config,
1546 version,
1547 total_reward_distributed,
1548 next_stake_table_hash,
1549 leader_counts,
1550 )?)
1551 }
1552
1553 fn genesis(
1554 instance_state: &NodeState,
1555 payload: <SeqTypes as NodeType>::BlockPayload,
1556 metadata: &<<SeqTypes as NodeType>::BlockPayload as BlockPayload<SeqTypes>>::Metadata,
1557 _: Version,
1558 ) -> Self {
1559 let payload_bytes = payload.encode();
1560 let builder_commitment = payload.builder_commitment(metadata);
1561
1562 let vid_commitment_version = instance_state.genesis_version;
1563
1564 let payload_commitment = vid_commitment(
1565 &payload_bytes,
1566 &metadata.encode(),
1567 GENESIS_VID_NUM_STORAGE_NODES,
1568 vid_commitment_version,
1569 );
1570
1571 let ValidatedState {
1572 fee_merkle_tree,
1573 block_merkle_tree,
1574 reward_merkle_tree_v1,
1575 reward_merkle_tree_v2,
1576 ..
1577 } = ValidatedState::genesis(instance_state).0;
1578 let block_merkle_tree_root = block_merkle_tree.commitment();
1579 let fee_merkle_tree_root = fee_merkle_tree.commitment();
1580 let reward_merkle_tree_root = reward_merkle_tree_v2.commitment();
1581
1582 let time = instance_state.genesis_header.timestamp;
1583
1584 let timestamp = time.unix_timestamp();
1585 let timestamp_millis = time.unix_timestamp_millis();
1586
1587 Self::create(
1590 instance_state.genesis_header.chain_config,
1591 0,
1592 timestamp,
1593 timestamp_millis,
1594 instance_state
1595 .l1_genesis
1596 .map(|block| block.number)
1597 .unwrap_or_default(),
1598 instance_state.l1_genesis,
1599 payload_commitment,
1600 builder_commitment.clone(),
1601 metadata.clone(),
1602 fee_merkle_tree_root,
1603 block_merkle_tree_root,
1604 reward_merkle_tree_v1.commitment(),
1605 reward_merkle_tree_root,
1606 vec![FeeInfo::genesis()],
1607 vec![],
1608 None,
1609 instance_state.genesis_version,
1610 None,
1611 Some([0; 100]),
1612 )
1613 }
1614
1615 fn timestamp(&self) -> u64 {
1616 self.timestamp_internal()
1617 }
1618
1619 fn timestamp_millis(&self) -> u64 {
1620 self.timestamp_millis_internal()
1621 }
1622
1623 fn block_number(&self) -> u64 {
1624 self.height()
1625 }
1626
1627 fn version(&self) -> Version {
1628 self.version()
1629 }
1630
1631 fn payload_commitment(&self) -> VidCommitment {
1632 self.payload_commitment()
1633 }
1634
1635 fn metadata(
1636 &self,
1637 ) -> &<<SeqTypes as NodeType>::BlockPayload as BlockPayload<SeqTypes>>::Metadata {
1638 self.ns_table()
1639 }
1640
1641 fn builder_commitment(&self) -> BuilderCommitment {
1643 self.builder_commitment().clone()
1644 }
1645
1646 fn get_light_client_state(&self, view: ViewNumber) -> anyhow::Result<LightClientState> {
1647 let mut block_comm_root_bytes = vec![];
1648 self.block_merkle_tree_root()
1649 .serialize_compressed(&mut block_comm_root_bytes)?;
1650
1651 Ok(LightClientState {
1652 view_number: view.u64(),
1653 block_height: self.height(),
1654 block_comm_root: hotshot_types::light_client::hash_bytes_to_field(
1655 &block_comm_root_bytes,
1656 )?,
1657 })
1658 }
1659
1660 fn auth_root(&self) -> anyhow::Result<B256> {
1661 match self {
1662 Header::V1(_) | Header::V2(_) | Header::V3(_) => Ok(B256::ZERO),
1663 Header::V4(header) => {
1664 let placeholder_1 = B256::ZERO;
1666 let placeholder_2 = B256::ZERO;
1667 let placeholder_3 = B256::ZERO;
1668 let placeholder_4 = B256::ZERO;
1669 let placeholder_5 = B256::ZERO;
1670 let placeholder_6 = B256::ZERO;
1671 let placeholder_7 = B256::ZERO;
1672
1673 let mut hasher = Keccak256::new();
1674
1675 let digest = header.reward_merkle_tree_root.digest();
1676 hasher.update(digest.0);
1677 hasher.update(placeholder_1);
1678 hasher.update(placeholder_2);
1679 hasher.update(placeholder_3);
1680 hasher.update(placeholder_4);
1681 hasher.update(placeholder_5);
1682 hasher.update(placeholder_6);
1683 hasher.update(placeholder_7);
1684
1685 Ok(hasher.finalize())
1686 },
1687 Header::V5(header) | Header::V6(header) => {
1688 let placeholder_1 = B256::ZERO;
1690 let placeholder_2 = B256::ZERO;
1691 let placeholder_3 = B256::ZERO;
1692 let placeholder_4 = B256::ZERO;
1693 let placeholder_5 = B256::ZERO;
1694 let placeholder_6 = B256::ZERO;
1695 let placeholder_7 = B256::ZERO;
1696
1697 let mut hasher = Keccak256::new();
1698
1699 let digest = header.reward_merkle_tree_root.digest();
1701 hasher.update(digest.0);
1702 hasher.update(placeholder_1);
1703 hasher.update(placeholder_2);
1704 hasher.update(placeholder_3);
1705 hasher.update(placeholder_4);
1706 hasher.update(placeholder_5);
1707 hasher.update(placeholder_6);
1708 hasher.update(placeholder_7);
1709
1710 Ok(hasher.finalize())
1711 },
1712 }
1713 }
1714}
1715
1716impl HeightIndexed for Header {
1717 fn height(&self) -> u64 {
1718 self.height()
1719 }
1720}
1721
1722impl QueryableHeader<SeqTypes> for Header {
1723 type NamespaceId = NamespaceId;
1724 type NamespaceIndex = NsIndex;
1725
1726 fn namespace_id(&self, i: &NsIndex) -> Option<NamespaceId> {
1727 self.ns_table().read_ns_id(i)
1728 }
1729
1730 fn namespace_size(&self, i: &NsIndex, payload_size: usize) -> u64 {
1731 self.ns_table()
1732 .ns_range(i, &PayloadByteLen(payload_size))
1733 .byte_len()
1734 .0 as u64
1735 }
1736
1737 fn ns_table(&self) -> String {
1738 BASE64_STANDARD.encode(&self.ns_table().bytes)
1739 }
1740}
1741
1742impl ExplorerHeader<SeqTypes> for Header {
1743 type BalanceAmount = FeeAmount;
1744 type WalletAddress = Vec<FeeAccount>;
1745 type ProposerId = Vec<FeeAccount>;
1746
1747 fn proposer_id(&self) -> Self::ProposerId {
1749 self.fee_info().accounts()
1750 }
1751
1752 fn fee_info_account(&self) -> Self::WalletAddress {
1753 self.fee_info().accounts()
1754 }
1755
1756 fn fee_info_balance(&self) -> Self::BalanceAmount {
1757 self.fee_info().amount().unwrap()
1759 }
1760
1761 fn reward_balance(&self) -> Self::BalanceAmount {
1767 FeeAmount::from(0)
1768 }
1769
1770 fn namespace_ids(&self) -> Vec<NamespaceId> {
1771 self.ns_table()
1772 .iter()
1773 .map(|i| self.ns_table().read_ns_id_unchecked(&i))
1774 .collect()
1775 }
1776}
1777
1778#[cfg(test)]
1779mod test_headers {
1780 use std::sync::Arc;
1781
1782 use alloy::{
1783 node_bindings::Anvil,
1784 primitives::{Address, U256},
1785 };
1786 use hotshot_query_service::testing::mocks::MOCK_UPGRADE;
1787 use hotshot_types::traits::signature_key::BuilderSignatureKey;
1788 use v0_1::{BlockMerkleTree, FeeMerkleTree, L1Client};
1789 use vbs::{BinarySerializer, bincode_serializer::BincodeSerializer, version::StaticVersion};
1790 use versions::version;
1791
1792 use super::*;
1793 use crate::{
1794 Leaf,
1795 eth_signature_key::EthKeyPair,
1796 mock::MockStateCatchup,
1797 v0_3::{REWARD_MERKLE_TREE_V1_HEIGHT, RewardAccountV1, RewardAmount},
1798 v0_4::{REWARD_MERKLE_TREE_V2_HEIGHT, RewardAccountV2, RewardMerkleTreeV2},
1799 };
1800
1801 #[derive(Debug, Default)]
1802 #[must_use]
1803 struct TestCase {
1804 parent_timestamp: u64,
1806 parent_timestamp_millis: u64,
1807 parent_l1_head: u64,
1808 parent_l1_finalized: Option<L1BlockInfo>,
1809
1810 l1_head: u64,
1812 l1_finalized: Option<L1BlockInfo>,
1813 timestamp: u64,
1814 timestamp_millis: u64,
1815 l1_deposits: Vec<FeeInfo>,
1816
1817 expected_timestamp: u64,
1819 expected_timestamp_millis: u64,
1820 expected_l1_head: u64,
1821 expected_l1_finalized: Option<L1BlockInfo>,
1822 }
1823
1824 impl TestCase {
1825 async fn run(self) {
1826 assert!(self.expected_timestamp >= self.parent_timestamp);
1828 assert!(self.expected_timestamp_millis >= self.parent_timestamp_millis);
1829 assert!(self.expected_l1_head >= self.parent_l1_head);
1830 assert!(self.expected_l1_finalized >= self.parent_l1_finalized);
1831
1832 let genesis = GenesisForTest::default().await;
1833 let mut parent = genesis.header.clone();
1834 parent.set_timestamp(self.parent_timestamp, self.parent_timestamp_millis);
1835 *parent.l1_head_mut() = self.parent_l1_head;
1836 *parent.l1_finalized_mut() = self.parent_l1_finalized;
1837
1838 let mut parent_leaf = genesis.leaf.clone();
1839 *parent_leaf.block_header_mut() = parent.clone();
1840
1841 let block_merkle_tree =
1842 BlockMerkleTree::from_elems(Some(32), Vec::<Commitment<Header>>::new()).unwrap();
1843
1844 let fee_info = FeeInfo::genesis();
1845 let fee_merkle_tree = FeeMerkleTree::from_kv_set(
1846 20,
1847 Vec::from([(fee_info.account(), fee_info.amount())]),
1848 )
1849 .unwrap();
1850
1851 let reward_account_v1 = RewardAccountV1::default();
1852 let reward_account = RewardAccountV2::default();
1853 let reward_amount = RewardAmount::default();
1854 let reward_merkle_tree_v2 =
1855 RewardMerkleTreeV2::from_kv_set(20, Vec::from([(reward_account, reward_amount)]))
1856 .unwrap();
1857
1858 let reward_merkle_tree_v1 = RewardMerkleTreeV1::from_kv_set(
1859 20,
1860 Vec::from([(reward_account_v1, reward_amount)]),
1861 )
1862 .unwrap();
1863
1864 let mut validated_state = ValidatedState {
1865 block_merkle_tree: block_merkle_tree.clone(),
1866 fee_merkle_tree,
1867 reward_merkle_tree_v2,
1868 reward_merkle_tree_v1,
1869 chain_config: genesis.instance_state.chain_config.into(),
1870 };
1871
1872 let (fee_account, fee_key) = FeeAccount::generated_from_seed_indexed([0; 32], 0);
1873 let fee_amount = 0;
1874 let fee_signature =
1875 FeeAccount::sign_fee(&fee_key, fee_amount, &genesis.ns_table).unwrap();
1876
1877 let header = Header::from_info(
1878 genesis.header.payload_commitment(),
1879 genesis.header.builder_commitment().clone(),
1880 genesis.ns_table,
1881 &parent_leaf,
1882 L1Snapshot {
1883 head: self.l1_head,
1884 finalized: self.l1_finalized,
1885 },
1886 &self.l1_deposits,
1887 vec![BuilderFee {
1888 fee_account,
1889 fee_amount,
1890 fee_signature,
1891 }],
1892 self.timestamp,
1893 self.timestamp_millis,
1894 validated_state.clone(),
1895 genesis.instance_state.chain_config,
1896 version(0, 1),
1897 None, None, None, )
1901 .unwrap();
1902 assert_eq!(header.height(), parent.height() + 1);
1903 assert_eq!(header.timestamp(), self.expected_timestamp);
1904 assert_eq!(header.timestamp_millis(), self.expected_timestamp_millis);
1905 assert_eq!(header.l1_head(), self.expected_l1_head);
1906 assert_eq!(header.l1_finalized(), self.expected_l1_finalized);
1907
1908 for fee_info in self.l1_deposits {
1910 validated_state.insert_fee_deposit(fee_info).unwrap();
1911 }
1912 assert_eq!(
1913 validated_state.fee_merkle_tree.commitment(),
1914 header.fee_merkle_tree_root(),
1915 );
1916
1917 assert_eq!(
1918 block_merkle_tree,
1919 BlockMerkleTree::from_elems(Some(32), Vec::<Commitment<Header>>::new()).unwrap()
1920 );
1921 }
1922 }
1923
1924 fn l1_block(number: u64) -> L1BlockInfo {
1925 L1BlockInfo {
1926 number,
1927 ..Default::default()
1928 }
1929 }
1930
1931 #[test_log::test(tokio::test(flavor = "multi_thread"))]
1932 async fn test_new_header() {
1933 TestCase::default().run().await
1935 }
1936
1937 #[test_log::test(tokio::test(flavor = "multi_thread"))]
1938 async fn test_new_header_advance_timestamp() {
1939 TestCase {
1940 timestamp: 1,
1941 timestamp_millis: 1_000,
1942 expected_timestamp: 1,
1943 expected_timestamp_millis: 1_000,
1944 ..Default::default()
1945 }
1946 .run()
1947 .await
1948 }
1949
1950 #[test_log::test(tokio::test(flavor = "multi_thread"))]
1951 async fn test_new_header_advance_l1_block() {
1952 TestCase {
1953 parent_l1_head: 0,
1954 parent_l1_finalized: Some(l1_block(0)),
1955
1956 l1_head: 1,
1957 l1_finalized: Some(l1_block(1)),
1958
1959 expected_l1_head: 1,
1960 expected_l1_finalized: Some(l1_block(1)),
1961
1962 ..Default::default()
1963 }
1964 .run()
1965 .await
1966 }
1967
1968 #[test_log::test(tokio::test(flavor = "multi_thread"))]
1969 async fn test_new_header_advance_l1_finalized_from_none() {
1970 TestCase {
1971 l1_finalized: Some(l1_block(1)),
1972 expected_l1_finalized: Some(l1_block(1)),
1973 ..Default::default()
1974 }
1975 .run()
1976 .await
1977 }
1978
1979 #[test_log::test(tokio::test(flavor = "multi_thread"))]
1980 async fn test_new_header_timestamp_behind_finalized_l1_block() {
1981 let l1_finalized = Some(L1BlockInfo {
1982 number: 1,
1983 timestamp: U256::from(1),
1984 ..Default::default()
1985 });
1986 TestCase {
1987 l1_head: 1,
1988 l1_finalized,
1989 timestamp: 0,
1990 timestamp_millis: 0,
1991
1992 expected_l1_head: 1,
1993 expected_l1_finalized: l1_finalized,
1994 expected_timestamp: 1,
1995 expected_timestamp_millis: 1_000,
1996
1997 ..Default::default()
1998 }
1999 .run()
2000 .await
2001 }
2002
2003 #[test_log::test(tokio::test(flavor = "multi_thread"))]
2004 async fn test_new_header_timestamp_behind() {
2005 TestCase {
2006 parent_timestamp: 1,
2007 parent_timestamp_millis: 1_000,
2008 timestamp: 0,
2009 timestamp_millis: 0,
2010 expected_timestamp: 1,
2011 expected_timestamp_millis: 1_000,
2012
2013 ..Default::default()
2014 }
2015 .run()
2016 .await
2017 }
2018
2019 #[test_log::test(tokio::test(flavor = "multi_thread"))]
2020 async fn test_new_header_l1_head_behind() {
2021 TestCase {
2022 parent_l1_head: 1,
2023 l1_head: 0,
2024 expected_l1_head: 1,
2025
2026 ..Default::default()
2027 }
2028 .run()
2029 .await
2030 }
2031
2032 #[test_log::test(tokio::test(flavor = "multi_thread"))]
2033 async fn test_new_header_l1_finalized_behind_some() {
2034 TestCase {
2035 parent_l1_finalized: Some(l1_block(1)),
2036 l1_finalized: Some(l1_block(0)),
2037 expected_l1_finalized: Some(l1_block(1)),
2038
2039 ..Default::default()
2040 }
2041 .run()
2042 .await
2043 }
2044
2045 #[test_log::test(tokio::test(flavor = "multi_thread"))]
2046 async fn test_new_header_l1_finalized_behind_none() {
2047 TestCase {
2048 parent_l1_finalized: Some(l1_block(0)),
2049 l1_finalized: None,
2050 expected_l1_finalized: Some(l1_block(0)),
2051
2052 ..Default::default()
2053 }
2054 .run()
2055 .await
2056 }
2057
2058 #[test_log::test(tokio::test(flavor = "multi_thread"))]
2059 async fn test_new_header_deposits_one() {
2060 TestCase {
2061 l1_deposits: vec![FeeInfo::new(Address::default(), 1)],
2062 ..Default::default()
2063 }
2064 .run()
2065 .await
2066 }
2067
2068 #[test_log::test(tokio::test(flavor = "multi_thread"))]
2069 async fn test_new_header_deposits_many() {
2070 TestCase {
2071 l1_deposits: [
2072 (Address::default(), 1),
2073 (Address::default(), 2),
2074 (Address::random(), 3),
2075 ]
2076 .iter()
2077 .map(|(address, amount)| FeeInfo::new(*address, *amount))
2078 .collect(),
2079 ..Default::default()
2080 }
2081 .run()
2082 .await
2083 }
2084
2085 struct GenesisForTest {
2086 pub instance_state: NodeState,
2087 pub validated_state: ValidatedState,
2088 pub leaf: Leaf2,
2089 pub header: Header,
2090 pub ns_table: NsTable,
2091 }
2092
2093 impl GenesisForTest {
2094 async fn default() -> Self {
2095 let instance_state = NodeState::mock();
2096 let validated_state = ValidatedState::genesis(&instance_state).0;
2097 let leaf: Leaf2 = Leaf::genesis(&validated_state, &instance_state, MOCK_UPGRADE.base)
2098 .await
2099 .into();
2100 let header = leaf.block_header().clone();
2101 let ns_table = leaf.block_payload().unwrap().ns_table().clone();
2102 Self {
2103 instance_state,
2104 validated_state,
2105 leaf,
2106 header,
2107 ns_table,
2108 }
2109 }
2110 }
2111
2112 #[test_log::test(tokio::test(flavor = "multi_thread"))]
2113 async fn test_proposal_validation_success() {
2114 let anvil = Anvil::new().block_time(1u64).spawn();
2115 let mut genesis_state = NodeState::mock()
2116 .with_l1(L1Client::new(vec![anvil.endpoint_url()]).expect("Failed to create L1 client"))
2117 .with_current_version(version(0, 1));
2118
2119 let genesis = GenesisForTest::default().await;
2120
2121 let mut parent_state = genesis.validated_state.clone();
2122
2123 let mut block_merkle_tree = parent_state.block_merkle_tree.clone();
2124 let fee_merkle_tree = parent_state.fee_merkle_tree.clone();
2125
2126 block_merkle_tree.push(genesis.header.commit()).unwrap();
2128 let block_merkle_tree_root = block_merkle_tree.commitment();
2129 let fee_merkle_tree_root = fee_merkle_tree.commitment();
2130 parent_state.block_merkle_tree = block_merkle_tree.clone();
2131 parent_state.fee_merkle_tree = fee_merkle_tree.clone();
2132
2133 let mut parent_header = genesis.header.clone();
2134 *parent_header.block_merkle_tree_root_mut() = block_merkle_tree_root;
2135 *parent_header.fee_merkle_tree_root_mut() = fee_merkle_tree_root;
2136
2137 let mut parent_leaf = genesis.leaf.clone();
2138 *parent_leaf.block_header_mut() = parent_header.clone();
2139
2140 let forgotten_state = parent_state.forget();
2142 genesis_state.state_catchup = Arc::new(MockStateCatchup::from_iter([(
2143 parent_leaf.view_number(),
2144 Arc::new(parent_state.clone()),
2145 )]));
2146 let key_pair = EthKeyPair::for_test();
2151 let fee_amount = 0u64;
2152 let payload_commitment = parent_header.payload_commitment();
2153 let builder_commitment = parent_header.builder_commitment();
2154 let ns_table = genesis.ns_table;
2155 let fee_signature = FeeAccount::sign_fee(&key_pair, fee_amount, &ns_table).unwrap();
2156 let builder_fee = BuilderFee {
2157 fee_amount,
2158 fee_account: key_pair.fee_account(),
2159 fee_signature,
2160 };
2161 let proposal = Header::new(
2162 &forgotten_state,
2163 &genesis_state,
2164 &parent_leaf,
2165 payload_commitment,
2166 builder_commitment.clone(),
2167 ns_table,
2168 builder_fee,
2169 version(0, 1),
2170 *parent_leaf.view_number() + 1,
2171 )
2172 .await
2173 .unwrap();
2174
2175 let mut proposal_state = parent_state.clone();
2176 for fee_info in genesis_state
2177 .l1_client
2178 .get_finalized_deposits(Address::default(), None, 0)
2179 .await
2180 {
2181 proposal_state.insert_fee_deposit(fee_info).unwrap();
2182 }
2183
2184 let mut block_merkle_tree = proposal_state.block_merkle_tree.clone();
2185 block_merkle_tree.push(proposal.commit()).unwrap();
2186
2187 let _proposal_state = proposal_state
2188 .apply_header(
2189 &genesis_state,
2190 &genesis_state.state_catchup,
2191 &parent_leaf,
2192 &proposal,
2193 version(0, 1),
2194 parent_leaf.view_number() + 1,
2195 )
2196 .await
2197 .unwrap()
2198 .0;
2199
2200 }
2213
2214 #[test_log::test]
2215 fn verify_builder_signature() {
2216 let message = ";)";
2218 let mut commitment = [0u8; 32];
2219 commitment[..message.len()].copy_from_slice(message.as_bytes());
2220
2221 let key = FeeAccount::generated_from_seed_indexed([0; 32], 0).1;
2222 let signature = FeeAccount::sign_builder_message(&key, &commitment).unwrap();
2223 assert!(
2224 key.fee_account()
2225 .validate_builder_signature(&signature, &commitment)
2226 );
2227 }
2228
2229 #[test_log::test(tokio::test(flavor = "multi_thread"))]
2230 async fn test_versioned_header_serialization() {
2231 let genesis = GenesisForTest::default().await;
2232 let header = genesis.header.clone();
2233 let ns_table = genesis.ns_table;
2234
2235 let (fee_account, _) = FeeAccount::generated_from_seed_indexed([0; 32], 0);
2236
2237 let v1_header = Header::create(
2238 genesis.instance_state.chain_config,
2239 1,
2240 2,
2241 2_000_000_000,
2242 3,
2243 Default::default(),
2244 header.payload_commitment(),
2245 header.builder_commitment().clone(),
2246 ns_table.clone(),
2247 header.fee_merkle_tree_root(),
2248 header.block_merkle_tree_root(),
2249 header.reward_merkle_tree_root().left().unwrap_or_else(|| {
2250 RewardMerkleTreeV1::new(REWARD_MERKLE_TREE_V1_HEIGHT).commitment()
2251 }),
2252 header.reward_merkle_tree_root().right().unwrap_or_else(|| {
2253 RewardMerkleTreeV2::new(REWARD_MERKLE_TREE_V2_HEIGHT).commitment()
2254 }),
2255 vec![FeeInfo {
2256 amount: 0.into(),
2257 account: fee_account,
2258 }],
2259 Default::default(),
2260 None,
2261 version(0, 1),
2262 None,
2263 None, );
2265
2266 let serialized = serde_json::to_string(&v1_header).unwrap();
2267 let deserialized: Header = serde_json::from_str(&serialized).unwrap();
2268 assert_eq!(v1_header, deserialized);
2269
2270 let v2_header = Header::create(
2271 genesis.instance_state.chain_config,
2272 1,
2273 2,
2274 2_000_000_000,
2275 3,
2276 Default::default(),
2277 header.payload_commitment(),
2278 header.builder_commitment().clone(),
2279 ns_table.clone(),
2280 header.fee_merkle_tree_root(),
2281 header.block_merkle_tree_root(),
2282 header.reward_merkle_tree_root().left().unwrap_or_else(|| {
2283 RewardMerkleTreeV1::new(REWARD_MERKLE_TREE_V1_HEIGHT).commitment()
2284 }),
2285 header.reward_merkle_tree_root().right().unwrap_or_else(|| {
2286 RewardMerkleTreeV2::new(REWARD_MERKLE_TREE_V2_HEIGHT).commitment()
2287 }),
2288 vec![FeeInfo {
2289 amount: 0.into(),
2290 account: fee_account,
2291 }],
2292 Default::default(),
2293 None,
2294 version(0, 2),
2295 None,
2296 None, );
2298
2299 let serialized = serde_json::to_string(&v2_header).unwrap();
2300 let deserialized: Header = serde_json::from_str(&serialized).unwrap();
2301 assert_eq!(v2_header, deserialized);
2302
2303 let v3_header = Header::create(
2304 genesis.instance_state.chain_config,
2305 1,
2306 2,
2307 2_000_000_000,
2308 3,
2309 Default::default(),
2310 header.payload_commitment(),
2311 header.builder_commitment().clone(),
2312 ns_table.clone(),
2313 header.fee_merkle_tree_root(),
2314 header.block_merkle_tree_root(),
2315 header.reward_merkle_tree_root().left().unwrap_or_else(|| {
2316 RewardMerkleTreeV1::new(REWARD_MERKLE_TREE_V1_HEIGHT).commitment()
2317 }),
2318 header.reward_merkle_tree_root().right().unwrap_or_else(|| {
2319 RewardMerkleTreeV2::new(REWARD_MERKLE_TREE_V2_HEIGHT).commitment()
2320 }),
2321 vec![FeeInfo {
2322 amount: 0.into(),
2323 account: fee_account,
2324 }],
2325 Default::default(),
2326 None,
2327 version(0, 3),
2328 None,
2329 None, );
2331
2332 let serialized = serde_json::to_string(&v3_header).unwrap();
2333 let deserialized: Header = serde_json::from_str(&serialized).unwrap();
2334 assert_eq!(v3_header, deserialized);
2335
2336 let v1_bytes = BincodeSerializer::<StaticVersion<0, 1>>::serialize(&v1_header).unwrap();
2337 let deserialized: Header =
2338 BincodeSerializer::<StaticVersion<0, 1>>::deserialize(&v1_bytes).unwrap();
2339 assert_eq!(v1_header, deserialized);
2340
2341 let v2_bytes = BincodeSerializer::<StaticVersion<0, 2>>::serialize(&v2_header).unwrap();
2342 let deserialized: Header =
2343 BincodeSerializer::<StaticVersion<0, 2>>::deserialize(&v2_bytes).unwrap();
2344 assert_eq!(v2_header, deserialized);
2345
2346 let v3_bytes = BincodeSerializer::<StaticVersion<0, 3>>::serialize(&v3_header).unwrap();
2347 let deserialized: Header =
2348 BincodeSerializer::<StaticVersion<0, 3>>::deserialize(&v3_bytes).unwrap();
2349 assert_eq!(v3_header, deserialized);
2350 }
2351}