1use std::{
13 fmt::{Debug, Display},
14 hash::Hash,
15 marker::PhantomData,
16 sync::Arc,
17 time::Duration,
18};
19
20use bincode::Options;
21use committable::{Commitment, CommitmentBoundsArkless, Committable, RawCommitmentBuilder};
22use hotshot_utils::anytrace::*;
23use jf_advz::VidScheme;
24use rand::Rng;
25use serde::{Deserialize, Serialize};
26use tagged_base64::{TaggedBase64, Tb64Error};
27use thiserror::Error;
28use vbs::version::Version;
29use vec1::Vec1;
30use versions::{EPOCH_VERSION, Upgrade, VID2_UPGRADE_VERSION};
31
32use crate::{
33 drb::DrbResult,
34 epoch_membership::EpochMembershipCoordinator,
35 message::{Proposal, UpgradeLock, convert_proposal},
36 simple_certificate::{
37 LightClientStateUpdateCertificateV1, LightClientStateUpdateCertificateV2,
38 NextEpochQuorumCertificate2, QuorumCertificate, QuorumCertificate2, TimeoutCertificate,
39 TimeoutCertificate2, UpgradeCertificate, ViewSyncFinalizeCertificate,
40 ViewSyncFinalizeCertificate2,
41 },
42 simple_vote::{HasEpoch, QuorumData, QuorumData2, UpgradeProposalData, VersionedVoteData},
43 stake_table::StakeTableEntries,
44 traits::{
45 BlockPayload,
46 block_contents::{BlockHeader, BuilderFee, EncodeBytes, TestableBlock},
47 node_implementation::NodeType,
48 signature_key::SignatureKey,
49 states::TestableState,
50 },
51 utils::{
52 EpochTransitionIndicator, bincode_opts, genesis_epoch_from_version,
53 option_epoch_from_block_number,
54 },
55 vid::{
56 advz::{ADVZScheme, advz_scheme},
57 avidm::{AvidMScheme, init_avidm_param},
58 avidm_gf2::{AvidmGf2Scheme, init_avidm_gf2_param},
59 },
60 vote::{Certificate, HasViewNumber},
61};
62
63macro_rules! impl_u64_wrapper {
66 ($t:ty, $genesis_val:expr) => {
67 impl $t {
68 pub fn genesis() -> Self {
70 Self($genesis_val)
71 }
72 pub fn new(n: u64) -> Self {
74 Self(n)
75 }
76 pub fn u64(&self) -> u64 {
78 self.0
79 }
80 }
81
82 impl From<u64> for $t {
83 fn from(n: u64) -> Self {
84 Self(n)
85 }
86 }
87
88 impl From<$t> for u64 {
89 fn from(n: $t) -> Self {
90 n.0
91 }
92 }
93
94 impl Display for $t {
95 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 write!(f, "{}", self.0)
97 }
98 }
99
100 impl std::ops::Add<u64> for $t {
101 type Output = $t;
102
103 fn add(self, rhs: u64) -> Self::Output {
104 Self(self.0 + rhs)
105 }
106 }
107
108 impl std::ops::AddAssign<u64> for $t {
109 fn add_assign(&mut self, rhs: u64) {
110 self.0 += rhs;
111 }
112 }
113
114 impl std::ops::Deref for $t {
115 type Target = u64;
116
117 fn deref(&self) -> &Self::Target {
118 &self.0
119 }
120 }
121
122 impl std::ops::Sub<u64> for $t {
123 type Output = $t;
124 fn sub(self, rhs: u64) -> Self::Output {
125 Self(self.0 - rhs)
126 }
127 }
128 };
129}
130
131#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
133pub struct ViewNumber(u64);
134
135impl Committable for ViewNumber {
136 fn commit(&self) -> Commitment<Self> {
137 let builder = RawCommitmentBuilder::new("View Number Commitment");
138 builder.u64(self.0).finalize()
139 }
140}
141
142impl_u64_wrapper!(ViewNumber, 0u64);
143
144#[derive(
146 Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
147)]
148pub struct EpochNumber(u64);
149
150impl Committable for EpochNumber {
151 fn commit(&self) -> Commitment<Self> {
152 let builder = RawCommitmentBuilder::new("Epoch Number Commitment");
153 builder.u64(self.0).finalize()
154 }
155}
156
157impl_u64_wrapper!(EpochNumber, 1u64);
158
159#[derive(
160 Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
161)]
162#[serde(transparent)]
163pub struct BlockNumber(u64);
164
165impl Committable for BlockNumber {
166 fn commit(&self) -> Commitment<Self> {
167 let builder = RawCommitmentBuilder::new("BlockNumber Commitment");
168 builder.u64(self.0).finalize()
169 }
170}
171
172impl_u64_wrapper!(BlockNumber, 0u64);
173
174#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
176#[serde(bound = "TYPES: NodeType")]
177pub struct DaProposal<TYPES: NodeType> {
178 pub encoded_transactions: Arc<[u8]>,
180 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
182 pub view_number: ViewNumber,
184}
185
186#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
188#[serde(bound = "TYPES: NodeType")]
189pub struct DaProposal2<TYPES: NodeType> {
190 pub encoded_transactions: Arc<[u8]>,
192 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
194 pub view_number: ViewNumber,
196 pub epoch: Option<EpochNumber>,
198 pub epoch_transition_indicator: EpochTransitionIndicator,
201}
202
203impl<TYPES: NodeType> From<DaProposal<TYPES>> for DaProposal2<TYPES> {
204 fn from(da_proposal: DaProposal<TYPES>) -> Self {
205 Self {
206 encoded_transactions: da_proposal.encoded_transactions,
207 metadata: da_proposal.metadata,
208 view_number: da_proposal.view_number,
209 epoch: None,
210 epoch_transition_indicator: EpochTransitionIndicator::NotInTransition,
211 }
212 }
213}
214
215impl<TYPES: NodeType> From<DaProposal2<TYPES>> for DaProposal<TYPES> {
216 fn from(da_proposal2: DaProposal2<TYPES>) -> Self {
217 Self {
218 encoded_transactions: da_proposal2.encoded_transactions,
219 metadata: da_proposal2.metadata,
220 view_number: da_proposal2.view_number,
221 }
222 }
223}
224
225#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
227pub struct UpgradeProposal {
228 pub upgrade_proposal: UpgradeProposalData,
230 pub view_number: ViewNumber,
232}
233
234pub type VidCommitment0 = crate::vid::advz::ADVZCommitment;
236pub type VidCommitment1 = crate::vid::avidm::AvidMCommitment;
237pub type VidCommitment2 = crate::vid::avidm_gf2::AvidmGf2Commitment;
238
239#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, Ord, PartialOrd)]
241#[serde(
242 try_from = "tagged_base64::TaggedBase64",
243 into = "tagged_base64::TaggedBase64"
244)]
245pub enum VidCommitment {
246 V0(VidCommitment0),
247 V1(VidCommitment1),
248 V2(VidCommitment2),
249}
250
251impl Default for VidCommitment {
252 fn default() -> Self {
253 Self::V0(Default::default())
254 }
255}
256
257impl Display for VidCommitment {
258 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
259 std::write!(f, "{}", TaggedBase64::from(self))
260 }
261}
262
263impl Debug for VidCommitment {
264 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265 std::fmt::Display::fmt(self, f)
266 }
267}
268
269impl From<VidCommitment> for TaggedBase64 {
270 fn from(val: VidCommitment) -> Self {
271 match val {
272 VidCommitment::V0(comm) => comm.into(),
273 VidCommitment::V1(comm) => comm.into(),
274 VidCommitment::V2(comm) => comm.into(),
275 }
276 }
277}
278
279impl From<&VidCommitment> for TaggedBase64 {
280 fn from(val: &VidCommitment) -> Self {
281 match val {
282 VidCommitment::V0(comm) => comm.into(),
283 VidCommitment::V1(comm) => comm.into(),
284 VidCommitment::V2(comm) => comm.into(),
285 }
286 }
287}
288
289impl TryFrom<TaggedBase64> for VidCommitment {
290 type Error = tagged_base64::Tb64Error;
291
292 fn try_from(value: TaggedBase64) -> std::result::Result<Self, Self::Error> {
293 match value.tag().as_str() {
294 "HASH" => VidCommitment0::try_from(value).map(Self::V0),
295 "AvidMCommit" => VidCommitment1::try_from(value).map(Self::V1),
296 "AvidmGf2Commit" => VidCommitment2::try_from(value).map(Self::V2),
297 _ => Err(Tb64Error::InvalidTag),
298 }
299 }
300}
301
302impl<'a> TryFrom<&'a TaggedBase64> for VidCommitment {
303 type Error = tagged_base64::Tb64Error;
304
305 fn try_from(value: &'a TaggedBase64) -> std::result::Result<Self, Self::Error> {
306 match value.tag().as_str() {
307 "HASH" => VidCommitment0::try_from(value).map(Self::V0),
308 "AvidMCommit" => VidCommitment1::try_from(value).map(Self::V1),
309 "AvidmGf2Commit" => VidCommitment2::try_from(value).map(Self::V2),
310 _ => Err(Tb64Error::InvalidTag),
311 }
312 }
313}
314
315impl std::str::FromStr for VidCommitment {
316 type Err = tagged_base64::Tb64Error;
317 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
318 use core::convert::TryFrom;
319 Self::try_from(TaggedBase64::from_str(s)?)
320 .map_err(|_| tagged_base64::Tb64Error::InvalidData)
321 }
322}
323
324impl From<VidCommitment1> for VidCommitment {
332 fn from(comm: VidCommitment1) -> Self {
333 Self::V1(comm)
334 }
335}
336
337impl From<VidCommitment2> for VidCommitment {
338 fn from(comm: VidCommitment2) -> Self {
339 Self::V2(comm)
340 }
341}
342
343impl AsRef<[u8]> for VidCommitment {
344 fn as_ref(&self) -> &[u8] {
345 match self {
346 Self::V0(comm) => comm.as_ref(),
347 Self::V1(comm) => comm.as_ref(),
348 Self::V2(comm) => comm.as_ref(),
349 }
350 }
351}
352
353impl AsRef<[u8; 32]> for VidCommitment {
354 fn as_ref(&self) -> &[u8; 32] {
355 match self {
356 Self::V0(comm) => comm.as_ref().as_ref(),
357 Self::V1(comm) => comm.as_ref(),
358 Self::V2(comm) => comm.as_ref(),
359 }
360 }
361}
362
363#[must_use]
368#[allow(clippy::panic)]
369pub fn vid_commitment(
370 encoded_transactions: &[u8],
371 metadata: &[u8],
372 total_weight: usize,
373 version: Version,
374) -> VidCommitment {
375 if version < EPOCH_VERSION {
376 let encoded_tx_len = encoded_transactions.len();
377 advz_scheme(total_weight)
378 .commit_only(encoded_transactions)
379 .map(VidCommitment::V0)
380 .unwrap_or_else(|err| {
381 panic!(
382 "VidScheme::commit_only \
383 failure:(total_weight,payload_byte_len)=({total_weight},{encoded_tx_len}) \
384 error: {err}"
385 )
386 })
387 } else if version < VID2_UPGRADE_VERSION {
388 let param = init_avidm_param(total_weight).unwrap();
389 let encoded_tx_len = encoded_transactions.len();
390 AvidMScheme::commit(
391 ¶m,
392 encoded_transactions,
393 ns_table::parse_ns_table(encoded_tx_len, metadata),
394 )
395 .map(VidCommitment::V1)
396 .unwrap()
397 } else {
398 let param = init_avidm_gf2_param(total_weight).unwrap();
399 let encoded_tx_len = encoded_transactions.len();
400 AvidmGf2Scheme::commit(
401 ¶m,
402 encoded_transactions,
403 ns_table::parse_ns_table(encoded_tx_len, metadata),
404 )
405 .map(|(comm, _)| VidCommitment::V2(comm))
406 .unwrap()
407 }
408}
409
410pub type VidCommon0 = crate::vid::advz::ADVZCommon;
412pub type VidCommon1 = crate::vid::avidm::AvidMCommon;
413pub type VidCommon2 = crate::vid::avidm_gf2::AvidmGf2Common;
414
415#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
417pub enum VidCommon {
418 V0(VidCommon0),
419 V1(VidCommon1),
420 V2(VidCommon2),
421}
422
423impl From<VidCommon1> for VidCommon {
424 fn from(comm: VidCommon1) -> Self {
425 Self::V1(comm)
426 }
427}
428
429impl From<VidCommon2> for VidCommon {
430 fn from(comm: VidCommon2) -> Self {
431 Self::V2(comm)
432 }
433}
434
435#[derive(Clone, Copy, Debug, Eq, PartialEq)]
437pub enum VidCommonRef<'a> {
438 V0(&'a VidCommon0),
439 V1(&'a VidCommon1),
440 V2(&'a VidCommon2),
441}
442
443impl<'a> VidCommonRef<'a> {
444 pub fn is_consistent(&self, comm: &VidCommitment) -> bool {
445 match (self, comm) {
446 (Self::V0(common), VidCommitment::V0(comm)) => {
447 ADVZScheme::is_consistent(comm, common).is_ok()
448 },
449 (Self::V1(_), VidCommitment::V1(_)) => true,
453 (Self::V2(common), VidCommitment::V2(comm)) => {
454 AvidmGf2Scheme::is_consistent(comm, common)
455 },
456 _ => false,
457 }
458 }
459}
460
461impl VidCommon {
462 pub fn as_ref(&self) -> VidCommonRef<'_> {
463 match self {
464 Self::V0(c) => VidCommonRef::V0(c),
465 Self::V1(c) => VidCommonRef::V1(c),
466 Self::V2(c) => VidCommonRef::V2(c),
467 }
468 }
469
470 pub fn is_consistent(&self, comm: &VidCommitment) -> bool {
471 self.as_ref().is_consistent(comm)
472 }
473}
474
475pub type VidShare0 = crate::vid::advz::ADVZShare;
477pub type VidShare1 = crate::vid::avidm::AvidMShare;
478pub type VidShare2 = crate::vid::avidm_gf2::AvidmGf2Share;
479
480#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
482pub enum VidShare {
483 V0(VidShare0),
484 V1(VidShare1),
485 V2(VidShare2),
486}
487
488impl From<VidShare1> for VidShare {
496 fn from(share: VidShare1) -> Self {
497 Self::V1(share)
498 }
499}
500
501impl From<VidShare2> for VidShare {
502 fn from(share: VidShare2) -> Self {
503 Self::V2(share)
504 }
505}
506
507pub mod ns_table;
508pub mod vid_disperse;
509
510pub struct VidDisperseAndDuration<TYPES: NodeType> {
512 pub disperse: VidDisperse<TYPES>,
514 pub duration: Duration,
516}
517
518pub type VidDisperse0<TYPES> = vid_disperse::ADVZDisperse<TYPES>;
520pub type VidDisperse1<TYPES> = vid_disperse::AvidMDisperse<TYPES>;
521pub type VidDisperse2<TYPES> = vid_disperse::AvidmGf2Disperse<TYPES>;
522
523#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
529#[serde(bound = "TYPES: NodeType")]
530pub enum VidDisperse<TYPES: NodeType> {
531 V0(VidDisperse0<TYPES>),
533 V1(VidDisperse1<TYPES>),
535 V2(VidDisperse2<TYPES>),
537}
538
539impl<TYPES: NodeType> From<VidDisperse0<TYPES>> for VidDisperse<TYPES> {
540 fn from(disperse: VidDisperse0<TYPES>) -> Self {
541 Self::V0(disperse)
542 }
543}
544
545impl<TYPES: NodeType> From<VidDisperse1<TYPES>> for VidDisperse<TYPES> {
546 fn from(disperse: VidDisperse1<TYPES>) -> Self {
547 Self::V1(disperse)
548 }
549}
550
551impl<TYPES: NodeType> From<VidDisperse2<TYPES>> for VidDisperse<TYPES> {
552 fn from(disperse: VidDisperse2<TYPES>) -> Self {
553 Self::V2(disperse)
554 }
555}
556
557impl<TYPES: NodeType> HasViewNumber for VidDisperse<TYPES> {
558 fn view_number(&self) -> ViewNumber {
559 match self {
560 Self::V0(disperse) => disperse.view_number(),
561 Self::V1(disperse) => disperse.view_number(),
562 Self::V2(disperse) => disperse.view_number(),
563 }
564 }
565}
566
567impl<TYPES: NodeType> HasEpoch for VidDisperse<TYPES> {
568 fn epoch(&self) -> Option<EpochNumber> {
569 match self {
570 Self::V0(disperse) => disperse.epoch(),
571 Self::V1(disperse) => disperse.epoch(),
572 Self::V2(disperse) => disperse.epoch(),
573 }
574 }
575}
576
577impl<TYPES: NodeType> VidDisperse<TYPES> {
578 #[allow(clippy::panic)]
584 pub async fn calculate_vid_disperse(
585 payload: &TYPES::BlockPayload,
586 membership: &EpochMembershipCoordinator<TYPES>,
587 view: ViewNumber,
588 target_epoch: Option<EpochNumber>,
589 data_epoch: Option<EpochNumber>,
590 metadata: &<TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
591 upgrade_lock: &UpgradeLock<TYPES>,
592 ) -> Result<VidDisperseAndDuration<TYPES>> {
593 let epochs_enabled = upgrade_lock.epochs_enabled(view);
594 let upgraded_vid2 = upgrade_lock.upgraded_vid2(view);
595 if upgraded_vid2 {
596 VidDisperse2::calculate_vid_disperse(
597 payload,
598 membership,
599 view,
600 target_epoch,
601 data_epoch,
602 metadata,
603 )
604 .await
605 .map(|(disperse, duration)| VidDisperseAndDuration {
606 disperse: Self::V2(disperse),
607 duration,
608 })
609 } else if epochs_enabled {
610 VidDisperse1::calculate_vid_disperse(
611 payload,
612 membership,
613 view,
614 target_epoch,
615 data_epoch,
616 metadata,
617 )
618 .await
619 .map(|(disperse, duration)| VidDisperseAndDuration {
620 disperse: Self::V1(disperse),
621 duration,
622 })
623 } else {
624 VidDisperse0::calculate_vid_disperse(
625 payload,
626 membership,
627 view,
628 target_epoch,
629 data_epoch,
630 )
631 .await
632 .map(|(disperse, duration)| VidDisperseAndDuration {
633 disperse: Self::V0(disperse),
634 duration,
635 })
636 }
637 }
638
639 pub fn payload_commitment(&self) -> VidCommitment {
641 match self {
642 Self::V0(disperse) => VidCommitment::V0(disperse.payload_commitment),
643 Self::V1(disperse) => disperse.payload_commitment.into(),
644 Self::V2(disperse) => disperse.payload_commitment.into(),
645 }
646 }
647
648 pub fn payload_commitment_ref(&self) -> &[u8] {
650 match self {
651 Self::V0(disperse) => disperse.payload_commitment.as_ref(),
652 Self::V1(disperse) => disperse.payload_commitment.as_ref(),
653 Self::V2(disperse) => disperse.payload_commitment.as_ref(),
654 }
655 }
656
657 pub fn set_view_number(&mut self, view_number: ViewNumber) {
659 match self {
660 Self::V0(share) => share.view_number = view_number,
661 Self::V1(share) => share.view_number = view_number,
662 Self::V2(share) => share.view_number = view_number,
663 }
664 }
665
666 pub fn to_shares(self) -> Vec<VidDisperseShare<TYPES>> {
667 match self {
668 VidDisperse::V0(disperse) => disperse
669 .to_shares()
670 .into_iter()
671 .map(|share| VidDisperseShare::V0(share))
672 .collect(),
673 VidDisperse::V1(disperse) => disperse
674 .to_shares()
675 .into_iter()
676 .map(|share| VidDisperseShare::V1(share))
677 .collect(),
678 VidDisperse::V2(disperse) => disperse
679 .to_shares()
680 .into_iter()
681 .map(|share| VidDisperseShare::V2(share))
682 .collect(),
683 }
684 }
685
686 pub fn to_share_proposals(
688 proposal: Proposal<TYPES, Self>,
689 ) -> Vec<Proposal<TYPES, VidDisperseShare<TYPES>>> {
690 match proposal.data {
691 VidDisperse::V0(disperse) => disperse
692 .to_share_proposals(&proposal.signature)
693 .into_iter()
694 .map(|proposal| convert_proposal(proposal))
695 .collect(),
696 VidDisperse::V1(disperse) => disperse
697 .to_share_proposals(&proposal.signature)
698 .into_iter()
699 .map(|proposal| convert_proposal(proposal))
700 .collect(),
701 VidDisperse::V2(disperse) => disperse
702 .to_share_proposals(&proposal.signature)
703 .into_iter()
704 .map(|proposal| convert_proposal(proposal))
705 .collect(),
706 }
707 }
708}
709
710pub type VidDisperseShare0<TYPES> = vid_disperse::ADVZDisperseShare<TYPES>;
712pub type VidDisperseShare1<TYPES> = vid_disperse::AvidMDisperseShare<TYPES>;
713pub type VidDisperseShare2<TYPES> = vid_disperse::AvidmGf2DisperseShare<TYPES>;
714
715#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
717#[serde(bound = "TYPES: NodeType")]
718pub enum VidDisperseShare<TYPES: NodeType> {
719 V0(VidDisperseShare0<TYPES>),
721 V1(VidDisperseShare1<TYPES>),
723 V2(VidDisperseShare2<TYPES>),
725}
726
727impl<TYPES: NodeType> From<VidDisperseShare0<TYPES>> for VidDisperseShare<TYPES> {
728 fn from(share: VidDisperseShare0<TYPES>) -> Self {
729 Self::V0(share)
730 }
731}
732
733impl<TYPES: NodeType> From<VidDisperseShare1<TYPES>> for VidDisperseShare<TYPES> {
734 fn from(share: VidDisperseShare1<TYPES>) -> Self {
735 Self::V1(share)
736 }
737}
738
739impl<TYPES: NodeType> From<VidDisperseShare2<TYPES>> for VidDisperseShare<TYPES> {
740 fn from(share: VidDisperseShare2<TYPES>) -> Self {
741 Self::V2(share)
742 }
743}
744
745impl<TYPES: NodeType> VidDisperseShare<TYPES> {
746 pub fn to_proposal(
748 self,
749 private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
750 ) -> Option<Proposal<TYPES, Self>> {
751 let payload_commitment_ref: &[u8] = match &self {
752 Self::V0(share) => share.payload_commitment.as_ref(),
753 Self::V1(share) => share.payload_commitment.as_ref(),
754 Self::V2(share) => share.payload_commitment.as_ref(),
755 };
756 let Ok(signature) = TYPES::SignatureKey::sign(private_key, payload_commitment_ref) else {
757 tracing::error!("VID: failed to sign dispersal share payload");
758 return None;
759 };
760 Some(Proposal {
761 signature,
762 _pd: PhantomData,
763 data: self,
764 })
765 }
766
767 pub fn recipient_key(&self) -> &TYPES::SignatureKey {
769 match self {
770 Self::V0(share) => &share.recipient_key,
771 Self::V1(share) => &share.recipient_key,
772 Self::V2(share) => &share.recipient_key,
773 }
774 }
775
776 pub fn payload_byte_len(&self) -> u32 {
778 match self {
779 Self::V0(share) => share.payload_byte_len(),
780 Self::V1(share) => share.payload_byte_len(),
781 Self::V2(share) => share.payload_byte_len(),
782 }
783 }
784
785 pub fn payload_commitment_ref(&self) -> &[u8] {
787 match self {
788 Self::V0(share) => share.payload_commitment.as_ref(),
789 Self::V1(share) => share.payload_commitment.as_ref(),
790 Self::V2(share) => share.payload_commitment.as_ref(),
791 }
792 }
793
794 pub fn payload_commitment(&self) -> VidCommitment {
796 match self {
797 Self::V0(share) => VidCommitment::V0(share.payload_commitment),
798 Self::V1(share) => share.payload_commitment.into(),
799 Self::V2(share) => share.payload_commitment.into(),
800 }
801 }
802
803 pub fn target_epoch(&self) -> Option<EpochNumber> {
805 match self {
806 Self::V0(_) => None,
807 Self::V1(share) => share.target_epoch,
808 Self::V2(share) => share.target_epoch,
809 }
810 }
811
812 pub fn common(&self) -> VidCommonRef<'_> {
814 match self {
815 Self::V0(share) => VidCommonRef::V0(&share.common),
816 Self::V1(share) => VidCommonRef::V1(&share.common),
817 Self::V2(share) => VidCommonRef::V2(&share.common),
818 }
819 }
820
821 pub fn is_consistent(&self) -> bool {
823 match self {
824 Self::V0(share) => share.is_consistent(),
825 Self::V1(share) => share.is_consistent(),
826 Self::V2(share) => share.is_consistent(),
827 }
828 }
829
830 pub fn verify_with_verified_common(&self) -> bool {
833 match self {
834 Self::V0(share) => share.verify_with_verified_common(),
835 Self::V1(share) => share.verify_with_verified_common(),
836 Self::V2(share) => share.verify_with_verified_common(),
837 }
838 }
839
840 pub fn verify(&self, total_nodes: usize) -> bool {
842 match self {
843 Self::V0(share) => share.verify(total_nodes),
844 Self::V1(share) => share.verify(total_nodes),
845 Self::V2(share) => share.verify(total_nodes),
846 }
847 }
848
849 pub fn set_view_number(&mut self, view_number: ViewNumber) {
851 match self {
852 Self::V0(share) => share.view_number = view_number,
853 Self::V1(share) => share.view_number = view_number,
854 Self::V2(share) => share.view_number = view_number,
855 }
856 }
857}
858
859impl<TYPES: NodeType> HasViewNumber for VidDisperseShare<TYPES> {
860 fn view_number(&self) -> ViewNumber {
861 match self {
862 Self::V0(disperse) => disperse.view_number(),
863 Self::V1(disperse) => disperse.view_number(),
864 Self::V2(disperse) => disperse.view_number(),
865 }
866 }
867}
868
869impl<TYPES: NodeType> HasEpoch for VidDisperseShare<TYPES> {
870 fn epoch(&self) -> Option<EpochNumber> {
871 match self {
872 Self::V0(_) => None,
873 Self::V1(share) => share.epoch(),
874 Self::V2(share) => share.epoch(),
875 }
876 }
877}
878
879#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
882#[serde(bound(deserialize = ""))]
883pub enum ViewChangeEvidence<TYPES: NodeType> {
884 Timeout(TimeoutCertificate<TYPES>),
886 ViewSync(ViewSyncFinalizeCertificate<TYPES>),
888}
889
890impl<TYPES: NodeType> ViewChangeEvidence<TYPES> {
891 pub fn is_valid_for_view(&self, view: &ViewNumber) -> bool {
893 match self {
894 ViewChangeEvidence::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
895 ViewChangeEvidence::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
896 }
897 }
898
899 pub fn to_evidence2(self) -> ViewChangeEvidence2<TYPES> {
901 match self {
902 ViewChangeEvidence::Timeout(timeout_cert) => {
903 ViewChangeEvidence2::Timeout(timeout_cert.to_tc2())
904 },
905 ViewChangeEvidence::ViewSync(view_sync_cert) => {
906 ViewChangeEvidence2::ViewSync(view_sync_cert.to_vsc2())
907 },
908 }
909 }
910}
911
912#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
915#[serde(bound(deserialize = ""))]
916pub enum ViewChangeEvidence2<TYPES: NodeType> {
917 Timeout(TimeoutCertificate2<TYPES>),
919 ViewSync(ViewSyncFinalizeCertificate2<TYPES>),
921}
922
923impl<TYPES: NodeType> ViewChangeEvidence2<TYPES> {
924 pub fn is_valid_for_view(&self, view: &ViewNumber) -> bool {
926 match self {
927 ViewChangeEvidence2::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
928 ViewChangeEvidence2::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
929 }
930 }
931
932 pub fn to_evidence(self) -> ViewChangeEvidence<TYPES> {
934 match self {
935 ViewChangeEvidence2::Timeout(timeout_cert) => {
936 ViewChangeEvidence::Timeout(timeout_cert.to_tc())
937 },
938 ViewChangeEvidence2::ViewSync(view_sync_cert) => {
939 ViewChangeEvidence::ViewSync(view_sync_cert.to_vsc())
940 },
941 }
942 }
943}
944
945#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
947#[serde(bound(deserialize = ""))]
948pub struct QuorumProposal<TYPES: NodeType> {
949 pub block_header: TYPES::BlockHeader,
951
952 pub view_number: ViewNumber,
954
955 pub justify_qc: QuorumCertificate<TYPES>,
957
958 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
960
961 pub proposal_certificate: Option<ViewChangeEvidence<TYPES>>,
966}
967
968#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
970#[serde(bound(deserialize = ""))]
971pub struct QuorumProposal2<TYPES: NodeType> {
972 pub block_header: TYPES::BlockHeader,
974
975 pub view_number: ViewNumber,
977
978 pub epoch: Option<EpochNumber>,
980
981 pub justify_qc: QuorumCertificate2<TYPES>,
983
984 pub next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
986
987 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
989
990 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
992
993 #[serde(with = "serde_bytes")]
998 pub next_drb_result: Option<DrbResult>,
999
1000 pub state_cert: Option<LightClientStateUpdateCertificateV2<TYPES>>,
1003}
1004
1005impl<TYPES: NodeType> QuorumProposal2<TYPES> {
1006 pub async fn validate_certs(
1007 &self,
1008 membership: EpochMembershipCoordinator<TYPES>,
1009 upgrade_lock: &UpgradeLock<TYPES>,
1010 ) -> Result<()> {
1011 let stake_table = membership.membership_for_epoch(self.epoch).await?;
1012 let entries = StakeTableEntries::<TYPES>::from(stake_table.stake_table().await).0;
1013 let threshold = stake_table.success_threshold().await;
1014 self.justify_qc
1015 .is_valid_cert(&entries, threshold, upgrade_lock)?;
1016 let view_change_view = match &self.view_change_evidence {
1017 Some(ViewChangeEvidence2::Timeout(timeout_cert)) => {
1018 timeout_cert.is_valid_cert(&entries, threshold, upgrade_lock)?;
1019 Some(timeout_cert.view_number() + 1)
1020 },
1021 Some(ViewChangeEvidence2::ViewSync(view_sync_cert)) => {
1022 view_sync_cert.is_valid_cert(&entries, threshold, upgrade_lock)?;
1023 Some(view_sync_cert.view_number())
1024 },
1025 _ => None,
1026 };
1027 if !(self.justify_qc.view_number() + 1 == self.view_number()
1028 || view_change_view == Some(self.view_number()))
1029 {
1030 bail!("Invalid view change evidence");
1031 }
1032 Ok(())
1033 }
1034 pub fn is_validate_block_height(&self) -> bool {
1035 self.justify_qc
1036 .data()
1037 .block_number
1038 .is_some_and(|bn| bn + 1 == self.block_header.block_number())
1039 }
1040}
1041
1042#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
1051#[serde(bound(deserialize = ""))]
1052pub struct QuorumProposal2Legacy<TYPES: NodeType> {
1053 pub block_header: TYPES::BlockHeader,
1055
1056 pub view_number: ViewNumber,
1058
1059 pub epoch: Option<EpochNumber>,
1061
1062 pub justify_qc: QuorumCertificate2<TYPES>,
1064
1065 pub next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1067
1068 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1070
1071 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
1073
1074 #[serde(with = "serde_bytes")]
1079 pub next_drb_result: Option<DrbResult>,
1080
1081 pub state_cert: Option<LightClientStateUpdateCertificateV1<TYPES>>,
1085}
1086
1087impl<TYPES: NodeType> From<QuorumProposal2Legacy<TYPES>> for QuorumProposal2<TYPES> {
1088 fn from(quorum_proposal2: QuorumProposal2Legacy<TYPES>) -> Self {
1089 Self {
1090 block_header: quorum_proposal2.block_header,
1091 view_number: quorum_proposal2.view_number,
1092 epoch: quorum_proposal2.epoch,
1093 justify_qc: quorum_proposal2.justify_qc,
1094 next_epoch_justify_qc: quorum_proposal2.next_epoch_justify_qc,
1095 upgrade_certificate: quorum_proposal2.upgrade_certificate,
1096 view_change_evidence: quorum_proposal2.view_change_evidence,
1097 next_drb_result: quorum_proposal2.next_drb_result,
1098 state_cert: quorum_proposal2.state_cert.map(Into::into),
1099 }
1100 }
1101}
1102
1103impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposal2Legacy<TYPES> {
1104 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1105 Self {
1106 block_header: quorum_proposal2.block_header,
1107 view_number: quorum_proposal2.view_number,
1108 epoch: quorum_proposal2.epoch,
1109 justify_qc: quorum_proposal2.justify_qc,
1110 next_epoch_justify_qc: quorum_proposal2.next_epoch_justify_qc,
1111 upgrade_certificate: quorum_proposal2.upgrade_certificate,
1112 view_change_evidence: quorum_proposal2.view_change_evidence,
1113 next_drb_result: quorum_proposal2.next_drb_result,
1114 state_cert: quorum_proposal2.state_cert.map(Into::into),
1115 }
1116 }
1117}
1118
1119#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
1125#[serde(bound(deserialize = ""))]
1126pub struct QuorumProposalWrapperLegacy<TYPES: NodeType> {
1127 pub proposal: QuorumProposal2Legacy<TYPES>,
1129}
1130
1131#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
1133#[serde(bound(deserialize = ""))]
1134pub struct QuorumProposalWrapper<TYPES: NodeType> {
1135 pub proposal: QuorumProposal2<TYPES>,
1137}
1138
1139impl<TYPES: NodeType> From<QuorumProposalWrapperLegacy<TYPES>> for QuorumProposalWrapper<TYPES> {
1140 fn from(v3: QuorumProposalWrapperLegacy<TYPES>) -> Self {
1141 Self {
1142 proposal: v3.proposal.into(),
1143 }
1144 }
1145}
1146
1147impl<TYPES: NodeType> QuorumProposal2<TYPES> {
1148 pub async fn validate_epoch(
1152 &self,
1153 upgrade_lock: &UpgradeLock<TYPES>,
1154 epoch_height: u64,
1155 ) -> Result<()> {
1156 let calculated_epoch = option_epoch_from_block_number(
1157 upgrade_lock.epochs_enabled(self.view_number()),
1158 self.block_header.block_number(),
1159 epoch_height,
1160 );
1161 ensure!(
1162 calculated_epoch == self.epoch(),
1163 "Quorum proposal invalid: inconsistent epoch."
1164 );
1165 Ok(())
1166 }
1167}
1168
1169impl<TYPES: NodeType> QuorumProposalWrapper<TYPES> {
1170 pub fn block_header(&self) -> &TYPES::BlockHeader {
1172 &self.proposal.block_header
1173 }
1174
1175 pub fn view_number(&self) -> ViewNumber {
1177 self.proposal.view_number
1178 }
1179
1180 pub fn justify_qc(&self) -> &QuorumCertificate2<TYPES> {
1182 &self.proposal.justify_qc
1183 }
1184
1185 pub fn next_epoch_justify_qc(&self) -> &Option<NextEpochQuorumCertificate2<TYPES>> {
1187 &self.proposal.next_epoch_justify_qc
1188 }
1189
1190 pub fn upgrade_certificate(&self) -> &Option<UpgradeCertificate<TYPES>> {
1192 &self.proposal.upgrade_certificate
1193 }
1194
1195 pub fn view_change_evidence(&self) -> &Option<ViewChangeEvidence2<TYPES>> {
1197 &self.proposal.view_change_evidence
1198 }
1199
1200 pub fn next_drb_result(&self) -> &Option<DrbResult> {
1202 &self.proposal.next_drb_result
1203 }
1204
1205 pub async fn validate_epoch(
1209 &self,
1210 upgrade_lock: &UpgradeLock<TYPES>,
1211 epoch_height: u64,
1212 ) -> Result<()> {
1213 self.proposal
1214 .validate_epoch(upgrade_lock, epoch_height)
1215 .await
1216 }
1217
1218 pub fn state_cert(&self) -> &Option<LightClientStateUpdateCertificateV2<TYPES>> {
1220 &self.proposal.state_cert
1221 }
1222}
1223
1224impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposalWrapper<TYPES> {
1225 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
1226 Self {
1227 proposal: quorum_proposal.into(),
1228 }
1229 }
1230}
1231
1232impl<TYPES: NodeType> From<QuorumProposal2Legacy<TYPES>> for QuorumProposalWrapper<TYPES> {
1233 fn from(quorum_proposal: QuorumProposal2Legacy<TYPES>) -> Self {
1234 Self {
1235 proposal: quorum_proposal.into(),
1236 }
1237 }
1238}
1239
1240impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposalWrapper<TYPES> {
1241 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1242 Self {
1243 proposal: quorum_proposal2,
1244 }
1245 }
1246}
1247
1248impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal<TYPES> {
1249 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1250 quorum_proposal_wrapper.proposal.into()
1251 }
1252}
1253
1254impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal2Legacy<TYPES> {
1255 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1256 quorum_proposal_wrapper.proposal.into()
1257 }
1258}
1259
1260impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal2<TYPES> {
1261 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1262 quorum_proposal_wrapper.proposal
1263 }
1264}
1265
1266impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposal2<TYPES> {
1267 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
1268 Self {
1269 block_header: quorum_proposal.block_header,
1270 view_number: quorum_proposal.view_number,
1271 epoch: None,
1272 justify_qc: quorum_proposal.justify_qc.to_qc2(),
1273 next_epoch_justify_qc: None,
1274 upgrade_certificate: quorum_proposal.upgrade_certificate,
1275 view_change_evidence: quorum_proposal
1276 .proposal_certificate
1277 .map(ViewChangeEvidence::to_evidence2),
1278 next_drb_result: None,
1279 state_cert: None,
1280 }
1281 }
1282}
1283
1284impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposal<TYPES> {
1285 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1286 Self {
1287 block_header: quorum_proposal2.block_header,
1288 view_number: quorum_proposal2.view_number,
1289 justify_qc: quorum_proposal2.justify_qc.to_qc(),
1290 upgrade_certificate: quorum_proposal2.upgrade_certificate,
1291 proposal_certificate: quorum_proposal2
1292 .view_change_evidence
1293 .map(ViewChangeEvidence2::to_evidence),
1294 }
1295 }
1296}
1297
1298impl<TYPES: NodeType> From<Leaf<TYPES>> for Leaf2<TYPES> {
1299 fn from(leaf: Leaf<TYPES>) -> Self {
1300 let bytes: [u8; 32] = leaf.parent_commitment.into();
1301
1302 Self {
1303 view_number: leaf.view_number,
1304 justify_qc: leaf.justify_qc.to_qc2(),
1305 next_epoch_justify_qc: None,
1306 parent_commitment: Commitment::from_raw(bytes),
1307 block_header: leaf.block_header,
1308 upgrade_certificate: leaf.upgrade_certificate,
1309 block_payload: leaf.block_payload,
1310 view_change_evidence: None,
1311 next_drb_result: None,
1312 with_epoch: false,
1313 }
1314 }
1315}
1316
1317impl<TYPES: NodeType> HasViewNumber for DaProposal<TYPES> {
1318 fn view_number(&self) -> ViewNumber {
1319 self.view_number
1320 }
1321}
1322
1323impl<TYPES: NodeType> HasViewNumber for DaProposal2<TYPES> {
1324 fn view_number(&self) -> ViewNumber {
1325 self.view_number
1326 }
1327}
1328
1329impl<TYPES: NodeType> HasViewNumber for QuorumProposal<TYPES> {
1330 fn view_number(&self) -> ViewNumber {
1331 self.view_number
1332 }
1333}
1334
1335impl<TYPES: NodeType> HasViewNumber for QuorumProposal2<TYPES> {
1336 fn view_number(&self) -> ViewNumber {
1337 self.view_number
1338 }
1339}
1340
1341impl<TYPES: NodeType> HasViewNumber for QuorumProposal2Legacy<TYPES> {
1342 fn view_number(&self) -> ViewNumber {
1343 self.view_number
1344 }
1345}
1346
1347impl<TYPES: NodeType> HasViewNumber for QuorumProposalWrapper<TYPES> {
1348 fn view_number(&self) -> ViewNumber {
1349 self.proposal.view_number
1350 }
1351}
1352
1353impl<TYPES: NodeType> HasViewNumber for QuorumProposalWrapperLegacy<TYPES> {
1354 fn view_number(&self) -> ViewNumber {
1355 self.proposal.view_number
1356 }
1357}
1358
1359impl HasViewNumber for UpgradeProposal {
1360 fn view_number(&self) -> ViewNumber {
1361 self.view_number
1362 }
1363}
1364
1365impl<NODE: NodeType> HasEpoch for QuorumProposal2<NODE> {
1366 fn epoch(&self) -> Option<EpochNumber> {
1367 self.epoch
1368 }
1369}
1370
1371impl<NODE: NodeType> HasEpoch for DaProposal2<NODE> {
1372 fn epoch(&self) -> Option<EpochNumber> {
1373 self.epoch
1374 }
1375}
1376
1377impl<NODE: NodeType> HasEpoch for QuorumProposal2Legacy<NODE> {
1378 fn epoch(&self) -> Option<EpochNumber> {
1379 self.epoch
1380 }
1381}
1382
1383impl HasEpoch for UpgradeProposal {
1384 fn epoch(&self) -> Option<EpochNumber> {
1385 None
1386 }
1387}
1388
1389impl<NODE: NodeType> HasEpoch for QuorumProposal<NODE> {
1390 fn epoch(&self) -> Option<EpochNumber> {
1391 None
1392 }
1393}
1394
1395impl<NODE: NodeType> HasEpoch for DaProposal<NODE> {
1396 fn epoch(&self) -> Option<EpochNumber> {
1397 None
1398 }
1399}
1400
1401impl<NODE: NodeType> HasEpoch for QuorumProposalWrapper<NODE> {
1402 #[allow(clippy::panic)]
1404 fn epoch(&self) -> Option<EpochNumber> {
1405 self.proposal.epoch()
1406 }
1407}
1408
1409impl<TYPES: NodeType> HasEpoch for QuorumProposalWrapperLegacy<TYPES> {
1410 #[allow(clippy::panic)]
1412 fn epoch(&self) -> Option<EpochNumber> {
1413 self.proposal.epoch()
1414 }
1415}
1416
1417#[derive(Error, Debug, Serialize, Deserialize)]
1419pub enum BlockError {
1420 #[error("Invalid block header: {0}")]
1422 InvalidBlockHeader(String),
1423
1424 #[error("Inconsistent payload commitment")]
1426 InconsistentPayloadCommitment,
1427
1428 #[error("Failed to apply block header: {0}")]
1430 FailedHeaderApply(String),
1431}
1432
1433pub trait TestableLeaf {
1435 type NodeType: NodeType;
1437
1438 fn create_random_transaction(
1440 &self,
1441 rng: &mut dyn rand::RngCore,
1442 padding: u64,
1443 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction;
1444}
1445
1446#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1450#[serde(bound(deserialize = ""))]
1451pub struct Leaf<TYPES: NodeType> {
1452 view_number: ViewNumber,
1454
1455 justify_qc: QuorumCertificate<TYPES>,
1457
1458 parent_commitment: Commitment<Self>,
1461
1462 block_header: TYPES::BlockHeader,
1464
1465 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1467
1468 block_payload: Option<TYPES::BlockPayload>,
1472}
1473
1474#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1477#[serde(bound(deserialize = ""))]
1478pub struct Leaf2<TYPES: NodeType> {
1479 view_number: ViewNumber,
1481
1482 justify_qc: QuorumCertificate2<TYPES>,
1484
1485 next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1487
1488 parent_commitment: Commitment<Self>,
1491
1492 block_header: TYPES::BlockHeader,
1494
1495 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1497
1498 block_payload: Option<TYPES::BlockPayload>,
1502
1503 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
1505
1506 #[serde(with = "serde_bytes")]
1511 pub next_drb_result: Option<DrbResult>,
1512
1513 pub with_epoch: bool,
1515}
1516
1517impl<TYPES: NodeType> Leaf2<TYPES> {
1518 #[must_use]
1525 pub async fn genesis(
1526 validated_state: &TYPES::ValidatedState,
1527 instance_state: &TYPES::InstanceState,
1528 version: Version,
1529 ) -> Self {
1530 let epoch = genesis_epoch_from_version(version);
1531
1532 let (payload, metadata) =
1533 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1534 .await
1535 .unwrap();
1536
1537 let genesis_view = ViewNumber::genesis();
1538
1539 let block_header =
1540 TYPES::BlockHeader::genesis(instance_state, payload.clone(), &metadata, version);
1541
1542 let block_number = if version < EPOCH_VERSION {
1543 None
1544 } else {
1545 Some(0u64)
1546 };
1547
1548 let null_quorum_data = QuorumData2 {
1549 leaf_commit: Commitment::<Leaf2<TYPES>>::default_commitment_no_preimage(),
1550 epoch,
1551 block_number,
1552 };
1553
1554 let justify_qc = QuorumCertificate2::new(
1555 null_quorum_data.clone(),
1556 null_quorum_data.commit(),
1557 genesis_view,
1558 None,
1559 PhantomData,
1560 );
1561
1562 Self {
1563 view_number: genesis_view,
1564 justify_qc,
1565 next_epoch_justify_qc: None,
1566 parent_commitment: null_quorum_data.leaf_commit,
1567 upgrade_certificate: None,
1568 block_header: block_header.clone(),
1569 block_payload: Some(payload),
1570 view_change_evidence: None,
1571 next_drb_result: None,
1572 with_epoch: epoch.is_some(),
1573 }
1574 }
1575 pub fn view_number(&self) -> ViewNumber {
1577 self.view_number
1578 }
1579 pub fn epoch(&self, epoch_height: u64) -> Option<EpochNumber> {
1581 option_epoch_from_block_number(
1582 self.with_epoch,
1583 self.block_header.block_number(),
1584 epoch_height,
1585 )
1586 }
1587 pub fn height(&self) -> u64 {
1591 self.block_header.block_number()
1592 }
1593 pub fn justify_qc(&self) -> QuorumCertificate2<TYPES> {
1595 self.justify_qc.clone()
1596 }
1597 pub fn next_epoch_justify_qc(&self) -> Option<NextEpochQuorumCertificate2<TYPES>> {
1601 self.next_epoch_justify_qc.clone()
1602 }
1603 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1605 self.upgrade_certificate.clone()
1606 }
1607 pub fn parent_commitment(&self) -> Commitment<Self> {
1609 self.parent_commitment
1610 }
1611 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1613 &self.block_header
1614 }
1615
1616 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1618 &mut self.block_header
1619 }
1620 pub fn fill_block_payload(
1627 &mut self,
1628 block_payload: TYPES::BlockPayload,
1629 num_storage_nodes: usize,
1630 version: Version,
1631 ) -> std::result::Result<(), BlockError> {
1632 let encoded_txns = block_payload.encode();
1633 let commitment = vid_commitment(
1634 &encoded_txns,
1635 &self.block_header.metadata().encode(),
1636 num_storage_nodes,
1637 version,
1638 );
1639 if commitment != self.block_header.payload_commitment() {
1640 return Err(BlockError::InconsistentPayloadCommitment);
1641 }
1642 self.block_payload = Some(block_payload);
1643 Ok(())
1644 }
1645
1646 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
1648 self.block_payload.take()
1649 }
1650
1651 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
1654 self.block_payload = Some(block_payload);
1655 }
1656
1657 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
1659 self.block_payload.clone()
1660 }
1661
1662 pub fn payload_commitment(&self) -> VidCommitment {
1664 self.block_header().payload_commitment()
1665 }
1666
1667 pub fn extends_upgrade(&self, parent: &Self, upgrade: &UpgradeLock<TYPES>) -> Result<()> {
1675 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
1676 (None | Some(_), None) => {},
1680 (None, Some(parent_cert)) => {
1684 let decided_upgrade_certificate_read = upgrade.decided_upgrade_cert();
1685 ensure!(
1686 self.view_number() > parent_cert.data.new_version_first_view
1687 || (self.view_number() > parent_cert.data.decide_by
1688 && decided_upgrade_certificate_read.is_none()),
1689 "The new leaf is missing an upgrade certificate that was present in its \
1690 parent, and should still be live."
1691 );
1692 },
1693 (Some(cert), Some(parent_cert)) => {
1697 ensure!(
1698 cert == parent_cert,
1699 "The new leaf does not extend the parent leaf, because it has attached a \
1700 different upgrade certificate."
1701 );
1702 },
1703 }
1704
1705 Ok(())
1709 }
1710
1711 pub fn to_leaf_unsafe(self) -> Leaf<TYPES> {
1713 let bytes: [u8; 32] = self.parent_commitment.into();
1714
1715 Leaf {
1716 view_number: self.view_number,
1717 justify_qc: self.justify_qc.to_qc(),
1718 parent_commitment: Commitment::from_raw(bytes),
1719 block_header: self.block_header,
1720 upgrade_certificate: self.upgrade_certificate,
1721 block_payload: self.block_payload,
1722 }
1723 }
1724}
1725
1726impl<TYPES: NodeType> Committable for Leaf2<TYPES> {
1727 fn commit(&self) -> committable::Commitment<Self> {
1728 let Leaf2 {
1729 view_number,
1730 justify_qc,
1731 next_epoch_justify_qc,
1732 parent_commitment,
1733 block_header,
1734 upgrade_certificate,
1735 block_payload: _,
1736 view_change_evidence,
1737 next_drb_result,
1738 with_epoch,
1739 } = self;
1740
1741 let mut cb = RawCommitmentBuilder::new("leaf commitment")
1742 .u64_field("view number", **view_number)
1743 .field("parent leaf commitment", *parent_commitment)
1744 .field("block header", block_header.commit())
1745 .field("justify qc", justify_qc.commit())
1746 .optional("upgrade certificate", upgrade_certificate);
1747
1748 if *with_epoch {
1749 cb = cb
1750 .constant_str("with_epoch")
1751 .optional("next_epoch_justify_qc", next_epoch_justify_qc);
1752
1753 if let Some(next_drb_result) = next_drb_result {
1754 cb = cb
1755 .constant_str("next_drb_result")
1756 .fixed_size_bytes(next_drb_result);
1757 }
1758
1759 match view_change_evidence {
1760 Some(ViewChangeEvidence2::Timeout(cert)) => {
1761 cb = cb.field("timeout cert", cert.commit());
1762 },
1763 Some(ViewChangeEvidence2::ViewSync(cert)) => {
1764 cb = cb.field("viewsync cert", cert.commit());
1765 },
1766 None => {},
1767 }
1768 }
1769
1770 cb.finalize()
1771 }
1772}
1773
1774impl<TYPES: NodeType> Leaf<TYPES> {
1775 #[allow(clippy::unused_async)]
1776 pub async fn commit(&self, _upgrade_lock: &UpgradeLock<TYPES>) -> Commitment<Self> {
1779 <Self as Committable>::commit(self)
1780 }
1781}
1782
1783impl<TYPES: NodeType> PartialEq for Leaf<TYPES> {
1784 fn eq(&self, other: &Self) -> bool {
1785 self.view_number == other.view_number
1786 && self.justify_qc == other.justify_qc
1787 && self.parent_commitment == other.parent_commitment
1788 && self.block_header == other.block_header
1789 }
1790}
1791
1792impl<TYPES: NodeType> PartialEq for Leaf2<TYPES> {
1793 fn eq(&self, other: &Self) -> bool {
1794 let Leaf2 {
1795 view_number,
1796 justify_qc,
1797 next_epoch_justify_qc,
1798 parent_commitment,
1799 block_header,
1800 upgrade_certificate,
1801 block_payload: _,
1802 view_change_evidence,
1803 next_drb_result,
1804 with_epoch,
1805 } = self;
1806
1807 *view_number == other.view_number
1808 && *justify_qc == other.justify_qc
1809 && *next_epoch_justify_qc == other.next_epoch_justify_qc
1810 && *parent_commitment == other.parent_commitment
1811 && *block_header == other.block_header
1812 && *upgrade_certificate == other.upgrade_certificate
1813 && *view_change_evidence == other.view_change_evidence
1814 && *next_drb_result == other.next_drb_result
1815 && *with_epoch == other.with_epoch
1816 }
1817}
1818
1819impl<TYPES: NodeType> Hash for Leaf<TYPES> {
1820 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1821 self.view_number.hash(state);
1822 self.justify_qc.hash(state);
1823 self.parent_commitment.hash(state);
1824 self.block_header.hash(state);
1825 }
1826}
1827
1828impl<TYPES: NodeType> Hash for Leaf2<TYPES> {
1829 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1830 self.commit().hash(state);
1831 self.view_number.hash(state);
1832 self.justify_qc.hash(state);
1833 self.parent_commitment.hash(state);
1834 self.block_header.hash(state);
1835 }
1836}
1837
1838impl<TYPES: NodeType> Display for Leaf<TYPES> {
1839 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1840 write!(
1841 f,
1842 "view: {:?}, height: {:?}, justify: {}",
1843 self.view_number,
1844 self.height(),
1845 self.justify_qc
1846 )
1847 }
1848}
1849
1850impl<TYPES: NodeType> QuorumCertificate<TYPES> {
1851 #[must_use]
1853 pub async fn genesis(
1854 validated_state: &TYPES::ValidatedState,
1855 instance_state: &TYPES::InstanceState,
1856 upgrade: Upgrade,
1857 ) -> Self {
1858 let upgrade_lock = UpgradeLock::<TYPES>::new(upgrade);
1860
1861 let genesis_view = ViewNumber::genesis();
1862
1863 let data = QuorumData {
1864 leaf_commit: Leaf::genesis(validated_state, instance_state, upgrade.base)
1865 .await
1866 .commit(&upgrade_lock)
1867 .await,
1868 };
1869
1870 let versioned_data =
1871 VersionedVoteData::<_, _>::new_infallible(data.clone(), genesis_view, &upgrade_lock);
1872
1873 let bytes: [u8; 32] = versioned_data.commit().into();
1874
1875 Self::new(
1876 data,
1877 Commitment::from_raw(bytes),
1878 genesis_view,
1879 None,
1880 PhantomData,
1881 )
1882 }
1883}
1884
1885impl<TYPES: NodeType> QuorumCertificate2<TYPES> {
1886 #[must_use]
1888 pub async fn genesis(
1889 validated_state: &TYPES::ValidatedState,
1890 instance_state: &TYPES::InstanceState,
1891 upgrade: Upgrade,
1892 ) -> Self {
1893 let upgrade_lock = UpgradeLock::<TYPES>::new(upgrade);
1895
1896 let genesis_view = ViewNumber::genesis();
1897
1898 let genesis_leaf = Leaf2::genesis(validated_state, instance_state, upgrade.base).await;
1899 let block_number = if upgrade_lock.epochs_enabled(genesis_view) {
1900 Some(genesis_leaf.height())
1901 } else {
1902 None
1903 };
1904 let data = QuorumData2 {
1905 leaf_commit: genesis_leaf.commit(),
1906 epoch: genesis_epoch_from_version(upgrade.base), block_number,
1908 };
1909
1910 let versioned_data =
1911 VersionedVoteData::<_, _>::new_infallible(data.clone(), genesis_view, &upgrade_lock);
1912
1913 let bytes: [u8; 32] = versioned_data.commit().into();
1914
1915 Self::new(
1916 data,
1917 Commitment::from_raw(bytes),
1918 genesis_view,
1919 None,
1920 PhantomData,
1921 )
1922 }
1923}
1924
1925impl<TYPES: NodeType> Leaf<TYPES> {
1926 #[must_use]
1933 pub async fn genesis(
1934 validated_state: &TYPES::ValidatedState,
1935 instance_state: &TYPES::InstanceState,
1936 version: Version,
1937 ) -> Self {
1938 let (payload, metadata) =
1939 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1940 .await
1941 .unwrap();
1942
1943 let genesis_view = ViewNumber::genesis();
1944
1945 let block_header =
1946 TYPES::BlockHeader::genesis(instance_state, payload.clone(), &metadata, version);
1947
1948 let null_quorum_data = QuorumData {
1949 leaf_commit: Commitment::<Leaf<TYPES>>::default_commitment_no_preimage(),
1950 };
1951
1952 let justify_qc = QuorumCertificate::new(
1953 null_quorum_data.clone(),
1954 null_quorum_data.commit(),
1955 genesis_view,
1956 None,
1957 PhantomData,
1958 );
1959
1960 Self {
1961 view_number: genesis_view,
1962 justify_qc,
1963 parent_commitment: null_quorum_data.leaf_commit,
1964 upgrade_certificate: None,
1965 block_header: block_header.clone(),
1966 block_payload: Some(payload),
1967 }
1968 }
1969
1970 pub fn view_number(&self) -> ViewNumber {
1972 self.view_number
1973 }
1974 pub fn height(&self) -> u64 {
1978 self.block_header.block_number()
1979 }
1980 pub fn justify_qc(&self) -> QuorumCertificate<TYPES> {
1982 self.justify_qc.clone()
1983 }
1984 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1986 self.upgrade_certificate.clone()
1987 }
1988 pub fn parent_commitment(&self) -> Commitment<Self> {
1990 self.parent_commitment
1991 }
1992 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1994 &self.block_header
1995 }
1996
1997 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1999 &mut self.block_header
2000 }
2001 pub fn fill_block_payload(
2008 &mut self,
2009 block_payload: TYPES::BlockPayload,
2010 num_storage_nodes: usize,
2011 version: Version,
2012 ) -> std::result::Result<(), BlockError> {
2013 let encoded_txns = block_payload.encode();
2014 let commitment = vid_commitment(
2015 &encoded_txns,
2016 &self.block_header.metadata().encode(),
2017 num_storage_nodes,
2018 version,
2019 );
2020 if commitment != self.block_header.payload_commitment() {
2021 return Err(BlockError::InconsistentPayloadCommitment);
2022 }
2023 self.block_payload = Some(block_payload);
2024 Ok(())
2025 }
2026
2027 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
2029 self.block_payload.take()
2030 }
2031
2032 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
2035 self.block_payload = Some(block_payload);
2036 }
2037
2038 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
2040 self.block_payload.clone()
2041 }
2042
2043 pub fn payload_commitment(&self) -> VidCommitment {
2045 self.block_header().payload_commitment()
2046 }
2047
2048 pub fn extends_upgrade(&self, parent: &Self, upgrade: &UpgradeLock<TYPES>) -> Result<()> {
2056 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
2057 (None | Some(_), None) => {},
2061 (None, Some(parent_cert)) => {
2065 let decided_upgrade_certificate_read = upgrade.decided_upgrade_cert();
2066 ensure!(
2067 self.view_number() > parent_cert.data.new_version_first_view
2068 || (self.view_number() > parent_cert.data.decide_by
2069 && decided_upgrade_certificate_read.is_none()),
2070 "The new leaf is missing an upgrade certificate that was present in its \
2071 parent, and should still be live."
2072 );
2073 },
2074 (Some(cert), Some(parent_cert)) => {
2078 ensure!(
2079 cert == parent_cert,
2080 "The new leaf does not extend the parent leaf, because it has attached a \
2081 different upgrade certificate."
2082 );
2083 },
2084 }
2085
2086 Ok(())
2090 }
2091}
2092
2093impl<TYPES: NodeType> TestableLeaf for Leaf<TYPES>
2094where
2095 TYPES::ValidatedState: TestableState<TYPES>,
2096 TYPES::BlockPayload: TestableBlock<TYPES>,
2097{
2098 type NodeType = TYPES;
2099
2100 fn create_random_transaction(
2101 &self,
2102 rng: &mut dyn rand::RngCore,
2103 padding: u64,
2104 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
2105 {
2106 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
2107 }
2108}
2109impl<TYPES: NodeType> TestableLeaf for Leaf2<TYPES>
2110where
2111 TYPES::ValidatedState: TestableState<TYPES>,
2112 TYPES::BlockPayload: TestableBlock<TYPES>,
2113{
2114 type NodeType = TYPES;
2115
2116 fn create_random_transaction(
2117 &self,
2118 rng: &mut dyn rand::RngCore,
2119 padding: u64,
2120 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
2121 {
2122 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
2123 }
2124}
2125#[must_use]
2127pub fn fake_commitment<S: Committable>() -> Commitment<S> {
2128 RawCommitmentBuilder::new("Dummy commitment for arbitrary genesis").finalize()
2129}
2130
2131#[must_use]
2133pub fn random_commitment<S: Committable>(rng: &mut dyn rand::RngCore) -> Commitment<S> {
2134 let random_array: Vec<u8> = (0u8..100u8).map(|_| rng.gen_range(0..255)).collect();
2135 RawCommitmentBuilder::new("Random Commitment")
2136 .constant_str("Random Field")
2137 .var_size_bytes(&random_array)
2138 .finalize()
2139}
2140
2141pub fn serialize_signature2<TYPES: NodeType>(
2145 signatures: &<TYPES::SignatureKey as SignatureKey>::QcType,
2146) -> Vec<u8> {
2147 let mut signatures_bytes = vec![];
2148 signatures_bytes.extend("Yes".as_bytes());
2149
2150 let (sig, proof) = TYPES::SignatureKey::sig_proof(signatures);
2151 let proof_bytes = bincode_opts()
2152 .serialize(&proof.as_bitslice())
2153 .expect("This serialization shouldn't be able to fail");
2154 signatures_bytes.extend("bitvec proof".as_bytes());
2155 signatures_bytes.extend(proof_bytes.as_slice());
2156 let sig_bytes = bincode_opts()
2157 .serialize(&sig)
2158 .expect("This serialization shouldn't be able to fail");
2159 signatures_bytes.extend("aggregated signature".as_bytes());
2160 signatures_bytes.extend(sig_bytes.as_slice());
2161 signatures_bytes
2162}
2163
2164impl<TYPES: NodeType> Committable for Leaf<TYPES> {
2165 fn commit(&self) -> committable::Commitment<Self> {
2166 RawCommitmentBuilder::new("leaf commitment")
2167 .u64_field("view number", *self.view_number)
2168 .field("parent leaf commitment", self.parent_commitment)
2169 .field("block header", self.block_header.commit())
2170 .field("justify qc", self.justify_qc.commit())
2171 .optional("upgrade certificate", &self.upgrade_certificate)
2172 .finalize()
2173 }
2174}
2175
2176impl<TYPES: NodeType> Leaf2<TYPES> {
2177 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposalWrapper<TYPES>) -> Self {
2179 let QuorumProposalWrapper {
2182 proposal:
2183 QuorumProposal2 {
2184 view_number,
2185 epoch,
2186 justify_qc,
2187 next_epoch_justify_qc,
2188 block_header,
2189 upgrade_certificate,
2190 view_change_evidence,
2191 next_drb_result,
2192 state_cert: _,
2193 },
2194 } = quorum_proposal;
2195
2196 Self {
2197 view_number: *view_number,
2198 justify_qc: justify_qc.clone(),
2199 next_epoch_justify_qc: next_epoch_justify_qc.clone(),
2200 parent_commitment: justify_qc.data().leaf_commit,
2201 block_header: block_header.clone(),
2202 upgrade_certificate: upgrade_certificate.clone(),
2203 block_payload: None,
2204 view_change_evidence: view_change_evidence.clone(),
2205 next_drb_result: *next_drb_result,
2206 with_epoch: epoch.is_some(),
2207 }
2208 }
2209}
2210
2211impl<TYPES: NodeType> Leaf<TYPES> {
2212 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposal<TYPES>) -> Self {
2214 let QuorumProposal {
2217 view_number,
2218 justify_qc,
2219 block_header,
2220 upgrade_certificate,
2221 proposal_certificate: _,
2222 } = quorum_proposal;
2223
2224 Self {
2225 view_number: *view_number,
2226 justify_qc: justify_qc.clone(),
2227 parent_commitment: justify_qc.data().leaf_commit,
2228 block_header: block_header.clone(),
2229 upgrade_certificate: upgrade_certificate.clone(),
2230 block_payload: None,
2231 }
2232 }
2233}
2234
2235pub mod null_block {
2236 #![allow(missing_docs)]
2237
2238 use jf_advz::VidScheme;
2239 use vbs::version::Version;
2240 use versions::EPOCH_VERSION;
2241
2242 use crate::{
2243 data::VidCommitment,
2244 traits::{
2245 BlockPayload, block_contents::BuilderFee, node_implementation::NodeType,
2246 signature_key::BuilderSignatureKey,
2247 },
2248 vid::advz::advz_scheme,
2249 };
2250
2251 #[must_use]
2260 pub fn commitment(num_storage_nodes: usize) -> Option<VidCommitment> {
2261 let vid_result = advz_scheme(num_storage_nodes).commit_only(Vec::new());
2262
2263 match vid_result {
2264 Ok(r) => Some(VidCommitment::V0(r)),
2265 Err(_) => None,
2266 }
2267 }
2268
2269 #[must_use]
2271 pub fn builder_fee<TYPES: NodeType>(
2272 num_storage_nodes: usize,
2273 version: Version,
2274 ) -> Option<BuilderFee<TYPES>> {
2275 const FEE_AMOUNT: u64 = 0;
2277
2278 let (pub_key, priv_key) =
2279 <TYPES::BuilderSignatureKey as BuilderSignatureKey>::generated_from_seed_indexed(
2280 [0_u8; 32], 0,
2281 );
2282
2283 if version >= EPOCH_VERSION {
2284 let (_null_block, null_block_metadata) =
2285 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2286
2287 match TYPES::BuilderSignatureKey::sign_fee(&priv_key, FEE_AMOUNT, &null_block_metadata)
2288 {
2289 Ok(sig) => Some(BuilderFee {
2290 fee_amount: FEE_AMOUNT,
2291 fee_account: pub_key,
2292 fee_signature: sig,
2293 }),
2294 Err(_) => None,
2295 }
2296 } else {
2297 let (_null_block, null_block_metadata) =
2298 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2299
2300 match TYPES::BuilderSignatureKey::sign_fee_with_vid_commitment(
2301 &priv_key,
2302 FEE_AMOUNT,
2303 &null_block_metadata,
2304 &commitment(num_storage_nodes)?,
2305 ) {
2306 Ok(sig) => Some(BuilderFee {
2307 fee_amount: FEE_AMOUNT,
2308 fee_account: pub_key,
2309 fee_signature: sig,
2310 }),
2311 Err(_) => None,
2312 }
2313 }
2314 }
2315}
2316
2317#[derive(Debug, Eq, PartialEq, Clone)]
2319pub struct PackedBundle<TYPES: NodeType> {
2320 pub encoded_transactions: Arc<[u8]>,
2322
2323 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2325
2326 pub view_number: ViewNumber,
2328
2329 pub epoch_number: Option<EpochNumber>,
2331
2332 pub sequencing_fees: Vec1<BuilderFee<TYPES>>,
2334}
2335
2336impl<TYPES: NodeType> PackedBundle<TYPES> {
2337 pub fn new(
2339 encoded_transactions: Arc<[u8]>,
2340 metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2341 view_number: ViewNumber,
2342 epoch_number: Option<EpochNumber>,
2343 sequencing_fees: Vec1<BuilderFee<TYPES>>,
2344 ) -> Self {
2345 Self {
2346 encoded_transactions,
2347 metadata,
2348 view_number,
2349 epoch_number,
2350 sequencing_fees,
2351 }
2352 }
2353}
2354
2355#[cfg(test)]
2356mod test {
2357 use super::*;
2358
2359 #[test]
2360 fn test_vid_commitment_display() {
2361 let vc = VidCommitment::V0(VidCommitment0::default());
2362 assert_eq!(
2363 format!("{vc}"),
2364 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2365 );
2366 assert_eq!(
2367 format!("{vc:?}"),
2368 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2369 );
2370
2371 let vc = VidCommitment::V1(VidCommitment1::default());
2372 assert_eq!(
2373 format!("{vc}"),
2374 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2375 );
2376 assert_eq!(
2377 format!("{vc:?}"),
2378 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2379 );
2380
2381 let vc = VidCommitment::V2(VidCommitment2::default());
2382 assert_eq!(
2383 format!("{vc}"),
2384 "AvidmGf2Commit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq"
2385 );
2386 assert_eq!(
2387 format!("{vc:?}"),
2388 "AvidmGf2Commit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq"
2389 );
2390 }
2391}