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