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, NEW_PROTOCOL_VERSION, Upgrade};
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 < NEW_PROTOCOL_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)?;
1012 let entries = StakeTableEntries::from_iter(stake_table.stake_table()).0;
1013 let threshold = stake_table.success_threshold();
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,
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 pub fn commit(&self, _upgrade_lock: &UpgradeLock<TYPES>) -> Commitment<Self> {
1778 <Self as Committable>::commit(self)
1779 }
1780}
1781
1782impl<TYPES: NodeType> PartialEq for Leaf<TYPES> {
1783 fn eq(&self, other: &Self) -> bool {
1784 self.view_number == other.view_number
1785 && self.justify_qc == other.justify_qc
1786 && self.parent_commitment == other.parent_commitment
1787 && self.block_header == other.block_header
1788 }
1789}
1790
1791impl<TYPES: NodeType> PartialEq for Leaf2<TYPES> {
1792 fn eq(&self, other: &Self) -> bool {
1793 let Leaf2 {
1794 view_number,
1795 justify_qc,
1796 next_epoch_justify_qc,
1797 parent_commitment,
1798 block_header,
1799 upgrade_certificate,
1800 block_payload: _,
1801 view_change_evidence,
1802 next_drb_result,
1803 with_epoch,
1804 } = self;
1805
1806 *view_number == other.view_number
1807 && *justify_qc == other.justify_qc
1808 && *next_epoch_justify_qc == other.next_epoch_justify_qc
1809 && *parent_commitment == other.parent_commitment
1810 && *block_header == other.block_header
1811 && *upgrade_certificate == other.upgrade_certificate
1812 && *view_change_evidence == other.view_change_evidence
1813 && *next_drb_result == other.next_drb_result
1814 && *with_epoch == other.with_epoch
1815 }
1816}
1817
1818impl<TYPES: NodeType> Hash for Leaf<TYPES> {
1819 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1820 self.view_number.hash(state);
1821 self.justify_qc.hash(state);
1822 self.parent_commitment.hash(state);
1823 self.block_header.hash(state);
1824 }
1825}
1826
1827impl<TYPES: NodeType> Hash for Leaf2<TYPES> {
1828 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1829 self.commit().hash(state);
1830 self.view_number.hash(state);
1831 self.justify_qc.hash(state);
1832 self.parent_commitment.hash(state);
1833 self.block_header.hash(state);
1834 }
1835}
1836
1837impl<TYPES: NodeType> Display for Leaf<TYPES> {
1838 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1839 write!(
1840 f,
1841 "view: {:?}, height: {:?}, justify: {}",
1842 self.view_number,
1843 self.height(),
1844 self.justify_qc
1845 )
1846 }
1847}
1848
1849impl<TYPES: NodeType> QuorumCertificate<TYPES> {
1850 #[must_use]
1852 pub async fn genesis(
1853 validated_state: &TYPES::ValidatedState,
1854 instance_state: &TYPES::InstanceState,
1855 upgrade: Upgrade,
1856 ) -> Self {
1857 let upgrade_lock = UpgradeLock::<TYPES>::new(upgrade);
1859
1860 let genesis_view = ViewNumber::genesis();
1861
1862 let data = QuorumData {
1863 leaf_commit: Leaf::genesis(validated_state, instance_state, upgrade.base)
1864 .await
1865 .commit(&upgrade_lock),
1866 };
1867
1868 let versioned_data =
1869 VersionedVoteData::<_, _>::new_infallible(data.clone(), genesis_view, &upgrade_lock);
1870
1871 let bytes: [u8; 32] = versioned_data.commit().into();
1872
1873 Self::new(
1874 data,
1875 Commitment::from_raw(bytes),
1876 genesis_view,
1877 None,
1878 PhantomData,
1879 )
1880 }
1881}
1882
1883impl<TYPES: NodeType> QuorumCertificate2<TYPES> {
1884 #[must_use]
1886 pub async fn genesis(
1887 validated_state: &TYPES::ValidatedState,
1888 instance_state: &TYPES::InstanceState,
1889 upgrade: Upgrade,
1890 ) -> Self {
1891 let upgrade_lock = UpgradeLock::<TYPES>::new(upgrade);
1893
1894 let genesis_view = ViewNumber::genesis();
1895
1896 let genesis_leaf = Leaf2::genesis(validated_state, instance_state, upgrade.base).await;
1897 let block_number = if upgrade_lock.epochs_enabled(genesis_view) {
1898 Some(genesis_leaf.height())
1899 } else {
1900 None
1901 };
1902 let data = QuorumData2 {
1903 leaf_commit: genesis_leaf.commit(),
1904 epoch: genesis_epoch_from_version(upgrade.base), block_number,
1906 };
1907
1908 let versioned_data =
1909 VersionedVoteData::<_, _>::new_infallible(data, genesis_view, &upgrade_lock);
1910
1911 let bytes: [u8; 32] = versioned_data.commit().into();
1912
1913 Self::new(
1914 data,
1915 Commitment::from_raw(bytes),
1916 genesis_view,
1917 None,
1918 PhantomData,
1919 )
1920 }
1921}
1922
1923impl<TYPES: NodeType> Leaf<TYPES> {
1924 #[must_use]
1931 pub async fn genesis(
1932 validated_state: &TYPES::ValidatedState,
1933 instance_state: &TYPES::InstanceState,
1934 version: Version,
1935 ) -> Self {
1936 let (payload, metadata) =
1937 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1938 .await
1939 .unwrap();
1940
1941 let genesis_view = ViewNumber::genesis();
1942
1943 let block_header =
1944 TYPES::BlockHeader::genesis(instance_state, payload.clone(), &metadata, version);
1945
1946 let null_quorum_data = QuorumData {
1947 leaf_commit: Commitment::<Leaf<TYPES>>::default_commitment_no_preimage(),
1948 };
1949
1950 let justify_qc = QuorumCertificate::new(
1951 null_quorum_data.clone(),
1952 null_quorum_data.commit(),
1953 genesis_view,
1954 None,
1955 PhantomData,
1956 );
1957
1958 Self {
1959 view_number: genesis_view,
1960 justify_qc,
1961 parent_commitment: null_quorum_data.leaf_commit,
1962 upgrade_certificate: None,
1963 block_header: block_header.clone(),
1964 block_payload: Some(payload),
1965 }
1966 }
1967
1968 pub fn view_number(&self) -> ViewNumber {
1970 self.view_number
1971 }
1972 pub fn height(&self) -> u64 {
1976 self.block_header.block_number()
1977 }
1978 pub fn justify_qc(&self) -> QuorumCertificate<TYPES> {
1980 self.justify_qc.clone()
1981 }
1982 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1984 self.upgrade_certificate.clone()
1985 }
1986 pub fn parent_commitment(&self) -> Commitment<Self> {
1988 self.parent_commitment
1989 }
1990 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1992 &self.block_header
1993 }
1994
1995 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1997 &mut self.block_header
1998 }
1999 pub fn fill_block_payload(
2006 &mut self,
2007 block_payload: TYPES::BlockPayload,
2008 num_storage_nodes: usize,
2009 version: Version,
2010 ) -> std::result::Result<(), BlockError> {
2011 let encoded_txns = block_payload.encode();
2012 let commitment = vid_commitment(
2013 &encoded_txns,
2014 &self.block_header.metadata().encode(),
2015 num_storage_nodes,
2016 version,
2017 );
2018 if commitment != self.block_header.payload_commitment() {
2019 return Err(BlockError::InconsistentPayloadCommitment);
2020 }
2021 self.block_payload = Some(block_payload);
2022 Ok(())
2023 }
2024
2025 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
2027 self.block_payload.take()
2028 }
2029
2030 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
2033 self.block_payload = Some(block_payload);
2034 }
2035
2036 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
2038 self.block_payload.clone()
2039 }
2040
2041 pub fn payload_commitment(&self) -> VidCommitment {
2043 self.block_header().payload_commitment()
2044 }
2045
2046 pub fn extends_upgrade(&self, parent: &Self, upgrade: &UpgradeLock<TYPES>) -> Result<()> {
2054 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
2055 (None | Some(_), None) => {},
2059 (None, Some(parent_cert)) => {
2063 let decided_upgrade_certificate_read = upgrade.decided_upgrade_cert();
2064 ensure!(
2065 self.view_number() > parent_cert.data.new_version_first_view
2066 || (self.view_number() > parent_cert.data.decide_by
2067 && decided_upgrade_certificate_read.is_none()),
2068 "The new leaf is missing an upgrade certificate that was present in its \
2069 parent, and should still be live."
2070 );
2071 },
2072 (Some(cert), Some(parent_cert)) => {
2076 ensure!(
2077 cert == parent_cert,
2078 "The new leaf does not extend the parent leaf, because it has attached a \
2079 different upgrade certificate."
2080 );
2081 },
2082 }
2083
2084 Ok(())
2088 }
2089}
2090
2091impl<TYPES: NodeType> TestableLeaf for Leaf<TYPES>
2092where
2093 TYPES::ValidatedState: TestableState<TYPES>,
2094 TYPES::BlockPayload: TestableBlock<TYPES>,
2095{
2096 type NodeType = TYPES;
2097
2098 fn create_random_transaction(
2099 &self,
2100 rng: &mut dyn rand::RngCore,
2101 padding: u64,
2102 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
2103 {
2104 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
2105 }
2106}
2107impl<TYPES: NodeType> TestableLeaf for Leaf2<TYPES>
2108where
2109 TYPES::ValidatedState: TestableState<TYPES>,
2110 TYPES::BlockPayload: TestableBlock<TYPES>,
2111{
2112 type NodeType = TYPES;
2113
2114 fn create_random_transaction(
2115 &self,
2116 rng: &mut dyn rand::RngCore,
2117 padding: u64,
2118 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
2119 {
2120 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
2121 }
2122}
2123#[must_use]
2125pub fn fake_commitment<S: Committable>() -> Commitment<S> {
2126 RawCommitmentBuilder::new("Dummy commitment for arbitrary genesis").finalize()
2127}
2128
2129#[must_use]
2131pub fn random_commitment<S: Committable>(rng: &mut dyn rand::RngCore) -> Commitment<S> {
2132 let random_array: Vec<u8> = (0u8..100u8).map(|_| rng.gen_range(0..255)).collect();
2133 RawCommitmentBuilder::new("Random Commitment")
2134 .constant_str("Random Field")
2135 .var_size_bytes(&random_array)
2136 .finalize()
2137}
2138
2139pub fn serialize_signature2<TYPES: NodeType>(
2143 signatures: &<TYPES::SignatureKey as SignatureKey>::QcType,
2144) -> Vec<u8> {
2145 let mut signatures_bytes = vec![];
2146 signatures_bytes.extend("Yes".as_bytes());
2147
2148 let (sig, proof) = TYPES::SignatureKey::sig_proof(signatures);
2149 let proof_bytes = bincode_opts()
2150 .serialize(&proof.as_bitslice())
2151 .expect("This serialization shouldn't be able to fail");
2152 signatures_bytes.extend("bitvec proof".as_bytes());
2153 signatures_bytes.extend(proof_bytes.as_slice());
2154 let sig_bytes = bincode_opts()
2155 .serialize(&sig)
2156 .expect("This serialization shouldn't be able to fail");
2157 signatures_bytes.extend("aggregated signature".as_bytes());
2158 signatures_bytes.extend(sig_bytes.as_slice());
2159 signatures_bytes
2160}
2161
2162impl<TYPES: NodeType> Committable for Leaf<TYPES> {
2163 fn commit(&self) -> committable::Commitment<Self> {
2164 RawCommitmentBuilder::new("leaf commitment")
2165 .u64_field("view number", *self.view_number)
2166 .field("parent leaf commitment", self.parent_commitment)
2167 .field("block header", self.block_header.commit())
2168 .field("justify qc", self.justify_qc.commit())
2169 .optional("upgrade certificate", &self.upgrade_certificate)
2170 .finalize()
2171 }
2172}
2173
2174impl<TYPES: NodeType> Leaf2<TYPES> {
2175 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposalWrapper<TYPES>) -> Self {
2177 let QuorumProposalWrapper {
2180 proposal:
2181 QuorumProposal2 {
2182 view_number,
2183 epoch,
2184 justify_qc,
2185 next_epoch_justify_qc,
2186 block_header,
2187 upgrade_certificate,
2188 view_change_evidence,
2189 next_drb_result,
2190 state_cert: _,
2191 },
2192 } = quorum_proposal;
2193
2194 Self {
2195 view_number: *view_number,
2196 justify_qc: justify_qc.clone(),
2197 next_epoch_justify_qc: next_epoch_justify_qc.clone(),
2198 parent_commitment: justify_qc.data().leaf_commit,
2199 block_header: block_header.clone(),
2200 upgrade_certificate: upgrade_certificate.clone(),
2201 block_payload: None,
2202 view_change_evidence: view_change_evidence.clone(),
2203 next_drb_result: *next_drb_result,
2204 with_epoch: epoch.is_some(),
2205 }
2206 }
2207}
2208
2209impl<TYPES: NodeType> Leaf<TYPES> {
2210 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposal<TYPES>) -> Self {
2212 let QuorumProposal {
2215 view_number,
2216 justify_qc,
2217 block_header,
2218 upgrade_certificate,
2219 proposal_certificate: _,
2220 } = quorum_proposal;
2221
2222 Self {
2223 view_number: *view_number,
2224 justify_qc: justify_qc.clone(),
2225 parent_commitment: justify_qc.data().leaf_commit,
2226 block_header: block_header.clone(),
2227 upgrade_certificate: upgrade_certificate.clone(),
2228 block_payload: None,
2229 }
2230 }
2231}
2232
2233pub mod null_block {
2234 #![allow(missing_docs)]
2235
2236 use jf_advz::VidScheme;
2237 use vbs::version::Version;
2238 use versions::EPOCH_VERSION;
2239
2240 use crate::{
2241 data::VidCommitment,
2242 traits::{
2243 BlockPayload, block_contents::BuilderFee, node_implementation::NodeType,
2244 signature_key::BuilderSignatureKey,
2245 },
2246 vid::advz::advz_scheme,
2247 };
2248
2249 #[must_use]
2258 pub fn commitment(num_storage_nodes: usize) -> Option<VidCommitment> {
2259 let vid_result = advz_scheme(num_storage_nodes).commit_only(Vec::new());
2260
2261 match vid_result {
2262 Ok(r) => Some(VidCommitment::V0(r)),
2263 Err(_) => None,
2264 }
2265 }
2266
2267 #[must_use]
2269 pub fn builder_fee<TYPES: NodeType>(
2270 num_storage_nodes: usize,
2271 version: Version,
2272 ) -> Option<BuilderFee<TYPES>> {
2273 const FEE_AMOUNT: u64 = 0;
2275
2276 let (pub_key, priv_key) =
2277 <TYPES::BuilderSignatureKey as BuilderSignatureKey>::generated_from_seed_indexed(
2278 [0_u8; 32], 0,
2279 );
2280
2281 if version >= EPOCH_VERSION {
2282 let (_null_block, null_block_metadata) =
2283 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2284
2285 match TYPES::BuilderSignatureKey::sign_fee(&priv_key, FEE_AMOUNT, &null_block_metadata)
2286 {
2287 Ok(sig) => Some(BuilderFee {
2288 fee_amount: FEE_AMOUNT,
2289 fee_account: pub_key,
2290 fee_signature: sig,
2291 }),
2292 Err(_) => None,
2293 }
2294 } else {
2295 let (_null_block, null_block_metadata) =
2296 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2297
2298 match TYPES::BuilderSignatureKey::sign_fee_with_vid_commitment(
2299 &priv_key,
2300 FEE_AMOUNT,
2301 &null_block_metadata,
2302 &commitment(num_storage_nodes)?,
2303 ) {
2304 Ok(sig) => Some(BuilderFee {
2305 fee_amount: FEE_AMOUNT,
2306 fee_account: pub_key,
2307 fee_signature: sig,
2308 }),
2309 Err(_) => None,
2310 }
2311 }
2312 }
2313}
2314
2315#[derive(Debug, Eq, PartialEq, Clone)]
2317pub struct PackedBundle<TYPES: NodeType> {
2318 pub encoded_transactions: Arc<[u8]>,
2320
2321 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2323
2324 pub view_number: ViewNumber,
2326
2327 pub epoch_number: Option<EpochNumber>,
2329
2330 pub sequencing_fees: Vec1<BuilderFee<TYPES>>,
2332}
2333
2334impl<TYPES: NodeType> PackedBundle<TYPES> {
2335 pub fn new(
2337 encoded_transactions: Arc<[u8]>,
2338 metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2339 view_number: ViewNumber,
2340 epoch_number: Option<EpochNumber>,
2341 sequencing_fees: Vec1<BuilderFee<TYPES>>,
2342 ) -> Self {
2343 Self {
2344 encoded_transactions,
2345 metadata,
2346 view_number,
2347 epoch_number,
2348 sequencing_fees,
2349 }
2350 }
2351}
2352
2353#[cfg(test)]
2354mod test {
2355 use super::*;
2356
2357 #[test]
2358 fn test_vid_commitment_display() {
2359 let vc = VidCommitment::V0(VidCommitment0::default());
2360 assert_eq!(
2361 format!("{vc}"),
2362 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2363 );
2364 assert_eq!(
2365 format!("{vc:?}"),
2366 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2367 );
2368
2369 let vc = VidCommitment::V1(VidCommitment1::default());
2370 assert_eq!(
2371 format!("{vc}"),
2372 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2373 );
2374 assert_eq!(
2375 format!("{vc:?}"),
2376 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2377 );
2378
2379 let vc = VidCommitment::V2(VidCommitment2::default());
2380 assert_eq!(
2381 format!("{vc}"),
2382 "AvidmGf2Commit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq"
2383 );
2384 assert_eq!(
2385 format!("{vc:?}"),
2386 "AvidmGf2Commit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq"
2387 );
2388 }
2389}