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, TimeoutCertificate3, TimeoutEvidence, UpgradeCertificate,
40 ViewSyncFinalizeCertificate, ViewSyncFinalizeCertificate2,
41 },
42 simple_vote::{
43 HasEpoch, QuorumData, QuorumData2, UpgradeProposalData, UpgradeProposalData2,
44 VersionedVoteData,
45 },
46 traits::{
47 BlockPayload,
48 block_contents::{BlockHeader, BuilderFee, EncodeBytes, TestableBlock},
49 node_implementation::NodeType,
50 signature_key::SignatureKey,
51 states::TestableState,
52 },
53 utils::{
54 EpochTransitionIndicator, bincode_opts, genesis_epoch_from_version,
55 option_epoch_from_block_number,
56 },
57 vid::{
58 advz::{ADVZScheme, advz_scheme},
59 avidm::{AvidMScheme, init_avidm_param},
60 avidm_gf2::{AvidmGf2Scheme, init_avidm_gf2_param},
61 },
62 vote::{Certificate, HasViewNumber},
63};
64
65macro_rules! impl_u64_wrapper {
68 ($t:ty, $genesis_val:expr) => {
69 impl $t {
70 pub const fn genesis() -> Self {
72 Self($genesis_val)
73 }
74 pub const fn new(n: u64) -> Self {
76 Self(n)
77 }
78 pub const fn u64(&self) -> u64 {
80 self.0
81 }
82 }
83
84 impl From<u64> for $t {
85 fn from(n: u64) -> Self {
86 Self(n)
87 }
88 }
89
90 impl From<$t> for u64 {
91 fn from(n: $t) -> Self {
92 n.0
93 }
94 }
95
96 impl Display for $t {
97 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98 write!(f, "{}", self.0)
99 }
100 }
101
102 impl std::ops::Add<u64> for $t {
103 type Output = $t;
104
105 fn add(self, rhs: u64) -> Self::Output {
106 Self(self.0 + rhs)
107 }
108 }
109
110 impl std::ops::AddAssign<u64> for $t {
111 fn add_assign(&mut self, rhs: u64) {
112 self.0 += rhs;
113 }
114 }
115
116 impl std::ops::Deref for $t {
117 type Target = u64;
118
119 fn deref(&self) -> &Self::Target {
120 &self.0
121 }
122 }
123
124 impl std::ops::Sub<u64> for $t {
125 type Output = $t;
126 fn sub(self, rhs: u64) -> Self::Output {
127 Self(self.0 - rhs)
128 }
129 }
130 };
131}
132
133#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
135pub struct ViewNumber(u64);
136
137impl Committable for ViewNumber {
138 fn commit(&self) -> Commitment<Self> {
139 let builder = RawCommitmentBuilder::new("View Number Commitment");
140 builder.u64(self.0).finalize()
141 }
142}
143
144impl_u64_wrapper!(ViewNumber, 0u64);
145
146#[derive(
148 Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
149)]
150#[cfg_attr(
151 feature = "rlp",
152 derive(alloy_rlp::RlpEncodableWrapper, alloy_rlp::RlpDecodableWrapper)
153)]
154pub struct EpochNumber(u64);
155
156impl Committable for EpochNumber {
157 fn commit(&self) -> Commitment<Self> {
158 let builder = RawCommitmentBuilder::new("Epoch Number Commitment");
159 builder.u64(self.0).finalize()
160 }
161}
162
163impl_u64_wrapper!(EpochNumber, 1u64);
164
165#[derive(
166 Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
167)]
168#[serde(transparent)]
169pub struct BlockNumber(u64);
170
171impl Committable for BlockNumber {
172 fn commit(&self) -> Commitment<Self> {
173 let builder = RawCommitmentBuilder::new("BlockNumber Commitment");
174 builder.u64(self.0).finalize()
175 }
176}
177
178impl_u64_wrapper!(BlockNumber, 0u64);
179
180#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
182#[serde(bound = "TYPES: NodeType")]
183pub struct DaProposal<TYPES: NodeType> {
184 #[serde(with = "crate::arc_bytes")]
186 pub encoded_transactions: Arc<[u8]>,
187 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
189 pub view_number: ViewNumber,
191}
192
193#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
195#[serde(bound = "TYPES: NodeType")]
196pub struct DaProposal2<TYPES: NodeType> {
197 #[serde(with = "crate::arc_bytes")]
199 pub encoded_transactions: Arc<[u8]>,
200 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
202 pub view_number: ViewNumber,
204 pub epoch: Option<EpochNumber>,
206 pub epoch_transition_indicator: EpochTransitionIndicator,
209}
210
211impl<TYPES: NodeType> From<DaProposal<TYPES>> for DaProposal2<TYPES> {
212 fn from(da_proposal: DaProposal<TYPES>) -> Self {
213 Self {
214 encoded_transactions: da_proposal.encoded_transactions,
215 metadata: da_proposal.metadata,
216 view_number: da_proposal.view_number,
217 epoch: None,
218 epoch_transition_indicator: EpochTransitionIndicator::NotInTransition,
219 }
220 }
221}
222
223impl<TYPES: NodeType> From<DaProposal2<TYPES>> for DaProposal<TYPES> {
224 fn from(da_proposal2: DaProposal2<TYPES>) -> Self {
225 Self {
226 encoded_transactions: da_proposal2.encoded_transactions,
227 metadata: da_proposal2.metadata,
228 view_number: da_proposal2.view_number,
229 }
230 }
231}
232
233#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
235pub struct UpgradeProposal {
236 pub upgrade_proposal: UpgradeProposalData,
238 pub view_number: ViewNumber,
240}
241
242#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
244pub struct UpgradeProposal2 {
245 pub upgrade_proposal: UpgradeProposalData2,
247 pub view_number: ViewNumber,
249}
250
251pub type VidCommitment0 = crate::vid::advz::ADVZCommitment;
253pub type VidCommitment1 = crate::vid::avidm::AvidMCommitment;
254pub type VidCommitment2 = crate::vid::avidm_gf2::AvidmGf2Commitment;
255
256#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, Ord, PartialOrd)]
258#[serde(
259 try_from = "tagged_base64::TaggedBase64",
260 into = "tagged_base64::TaggedBase64"
261)]
262pub enum VidCommitment {
263 V0(VidCommitment0),
264 V1(VidCommitment1),
265 V2(VidCommitment2),
266}
267
268impl Default for VidCommitment {
269 fn default() -> Self {
270 Self::V0(Default::default())
271 }
272}
273
274impl Display for VidCommitment {
275 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
276 std::write!(f, "{}", TaggedBase64::from(self))
277 }
278}
279
280impl Debug for VidCommitment {
281 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
282 std::fmt::Display::fmt(self, f)
283 }
284}
285
286impl From<VidCommitment> for TaggedBase64 {
287 fn from(val: VidCommitment) -> Self {
288 match val {
289 VidCommitment::V0(comm) => comm.into(),
290 VidCommitment::V1(comm) => comm.into(),
291 VidCommitment::V2(comm) => comm.into(),
292 }
293 }
294}
295
296impl From<&VidCommitment> for TaggedBase64 {
297 fn from(val: &VidCommitment) -> Self {
298 match val {
299 VidCommitment::V0(comm) => comm.into(),
300 VidCommitment::V1(comm) => comm.into(),
301 VidCommitment::V2(comm) => comm.into(),
302 }
303 }
304}
305
306impl TryFrom<TaggedBase64> for VidCommitment {
307 type Error = tagged_base64::Tb64Error;
308
309 fn try_from(value: TaggedBase64) -> std::result::Result<Self, Self::Error> {
310 match value.tag().as_str() {
311 "HASH" => VidCommitment0::try_from(value).map(Self::V0),
312 "AvidMCommit" => VidCommitment1::try_from(value).map(Self::V1),
313 "AvidmGf2Commit" => VidCommitment2::try_from(value).map(Self::V2),
314 _ => Err(Tb64Error::InvalidTag),
315 }
316 }
317}
318
319impl<'a> TryFrom<&'a TaggedBase64> for VidCommitment {
320 type Error = tagged_base64::Tb64Error;
321
322 fn try_from(value: &'a TaggedBase64) -> std::result::Result<Self, Self::Error> {
323 match value.tag().as_str() {
324 "HASH" => VidCommitment0::try_from(value).map(Self::V0),
325 "AvidMCommit" => VidCommitment1::try_from(value).map(Self::V1),
326 "AvidmGf2Commit" => VidCommitment2::try_from(value).map(Self::V2),
327 _ => Err(Tb64Error::InvalidTag),
328 }
329 }
330}
331
332impl std::str::FromStr for VidCommitment {
333 type Err = tagged_base64::Tb64Error;
334 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
335 use core::convert::TryFrom;
336 Self::try_from(TaggedBase64::from_str(s)?)
337 .map_err(|_| tagged_base64::Tb64Error::InvalidData)
338 }
339}
340
341impl From<VidCommitment1> for VidCommitment {
349 fn from(comm: VidCommitment1) -> Self {
350 Self::V1(comm)
351 }
352}
353
354impl From<VidCommitment2> for VidCommitment {
355 fn from(comm: VidCommitment2) -> Self {
356 Self::V2(comm)
357 }
358}
359
360impl AsRef<[u8]> for VidCommitment {
361 fn as_ref(&self) -> &[u8] {
362 match self {
363 Self::V0(comm) => comm.as_ref(),
364 Self::V1(comm) => comm.as_ref(),
365 Self::V2(comm) => comm.as_ref(),
366 }
367 }
368}
369
370impl AsRef<[u8; 32]> for VidCommitment {
371 fn as_ref(&self) -> &[u8; 32] {
372 match self {
373 Self::V0(comm) => comm.as_ref().as_ref(),
374 Self::V1(comm) => comm.as_ref(),
375 Self::V2(comm) => comm.as_ref(),
376 }
377 }
378}
379
380#[must_use]
385#[allow(clippy::panic)]
386pub fn vid_commitment(
387 encoded_transactions: &[u8],
388 metadata: &[u8],
389 total_weight: usize,
390 version: Version,
391) -> VidCommitment {
392 if version < EPOCH_VERSION {
393 let encoded_tx_len = encoded_transactions.len();
394 advz_scheme(total_weight)
395 .commit_only(encoded_transactions)
396 .map(VidCommitment::V0)
397 .unwrap_or_else(|err| {
398 panic!(
399 "VidScheme::commit_only \
400 failure:(total_weight,payload_byte_len)=({total_weight},{encoded_tx_len}) \
401 error: {err}"
402 )
403 })
404 } else if version < NEW_PROTOCOL_VERSION {
405 let param = init_avidm_param(total_weight).unwrap();
406 let encoded_tx_len = encoded_transactions.len();
407 AvidMScheme::commit(
408 ¶m,
409 encoded_transactions,
410 ns_table::parse_ns_table(encoded_tx_len, metadata),
411 )
412 .map(VidCommitment::V1)
413 .unwrap()
414 } else {
415 let param = init_avidm_gf2_param(total_weight).unwrap();
416 let encoded_tx_len = encoded_transactions.len();
417 AvidmGf2Scheme::commit(
418 ¶m,
419 encoded_transactions,
420 ns_table::parse_ns_table(encoded_tx_len, metadata),
421 )
422 .map(|(comm, _)| VidCommitment::V2(comm))
423 .unwrap()
424 }
425}
426
427pub type VidCommon0 = crate::vid::advz::ADVZCommon;
429pub type VidCommon1 = crate::vid::avidm::AvidMCommon;
430pub type VidCommon2 = crate::vid::avidm_gf2::AvidmGf2Common;
431
432#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
434pub enum VidCommon {
435 V0(VidCommon0),
436 V1(VidCommon1),
437 V2(VidCommon2),
438}
439
440impl From<VidCommon1> for VidCommon {
441 fn from(comm: VidCommon1) -> Self {
442 Self::V1(comm)
443 }
444}
445
446impl From<VidCommon2> for VidCommon {
447 fn from(comm: VidCommon2) -> Self {
448 Self::V2(comm)
449 }
450}
451
452#[derive(Clone, Copy, Debug, Eq, PartialEq)]
454pub enum VidCommonRef<'a> {
455 V0(&'a VidCommon0),
456 V1(&'a VidCommon1),
457 V2(&'a VidCommon2),
458}
459
460impl<'a> VidCommonRef<'a> {
461 pub fn is_consistent(&self, comm: &VidCommitment) -> bool {
462 match (self, comm) {
463 (Self::V0(common), VidCommitment::V0(comm)) => {
464 ADVZScheme::is_consistent(comm, common).is_ok()
465 },
466 (Self::V1(_), VidCommitment::V1(_)) => true,
470 (Self::V2(common), VidCommitment::V2(comm)) => {
471 AvidmGf2Scheme::is_consistent(comm, common)
472 },
473 _ => false,
474 }
475 }
476}
477
478impl VidCommon {
479 pub fn as_ref(&self) -> VidCommonRef<'_> {
480 match self {
481 Self::V0(c) => VidCommonRef::V0(c),
482 Self::V1(c) => VidCommonRef::V1(c),
483 Self::V2(c) => VidCommonRef::V2(c),
484 }
485 }
486
487 pub fn is_consistent(&self, comm: &VidCommitment) -> bool {
488 self.as_ref().is_consistent(comm)
489 }
490}
491
492pub type VidShare0 = crate::vid::advz::ADVZShare;
494pub type VidShare1 = crate::vid::avidm::AvidMShare;
495pub type VidShare2 = crate::vid::avidm_gf2::AvidmGf2Share;
496
497#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
499pub enum VidShare {
500 V0(VidShare0),
501 V1(VidShare1),
502 V2(VidShare2),
503}
504
505impl From<VidShare1> for VidShare {
513 fn from(share: VidShare1) -> Self {
514 Self::V1(share)
515 }
516}
517
518impl From<VidShare2> for VidShare {
519 fn from(share: VidShare2) -> Self {
520 Self::V2(share)
521 }
522}
523
524pub mod ns_table;
525pub mod vid_disperse;
526
527pub struct VidDisperseAndDuration<TYPES: NodeType> {
529 pub disperse: VidDisperse<TYPES>,
531 pub duration: Duration,
533}
534
535pub type VidDisperse0<TYPES> = vid_disperse::ADVZDisperse<TYPES>;
537pub type VidDisperse1<TYPES> = vid_disperse::AvidMDisperse<TYPES>;
538pub type VidDisperse2<TYPES> = vid_disperse::AvidmGf2Disperse<TYPES>;
539
540#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
546#[serde(bound = "TYPES: NodeType")]
547pub enum VidDisperse<TYPES: NodeType> {
548 V0(VidDisperse0<TYPES>),
550 V1(VidDisperse1<TYPES>),
552 V2(VidDisperse2<TYPES>),
554}
555
556impl<TYPES: NodeType> From<VidDisperse0<TYPES>> for VidDisperse<TYPES> {
557 fn from(disperse: VidDisperse0<TYPES>) -> Self {
558 Self::V0(disperse)
559 }
560}
561
562impl<TYPES: NodeType> From<VidDisperse1<TYPES>> for VidDisperse<TYPES> {
563 fn from(disperse: VidDisperse1<TYPES>) -> Self {
564 Self::V1(disperse)
565 }
566}
567
568impl<TYPES: NodeType> From<VidDisperse2<TYPES>> for VidDisperse<TYPES> {
569 fn from(disperse: VidDisperse2<TYPES>) -> Self {
570 Self::V2(disperse)
571 }
572}
573
574impl<TYPES: NodeType> HasViewNumber for VidDisperse<TYPES> {
575 fn view_number(&self) -> ViewNumber {
576 match self {
577 Self::V0(disperse) => disperse.view_number(),
578 Self::V1(disperse) => disperse.view_number(),
579 Self::V2(disperse) => disperse.view_number(),
580 }
581 }
582}
583
584impl<TYPES: NodeType> HasEpoch for VidDisperse<TYPES> {
585 fn epoch(&self) -> Option<EpochNumber> {
586 match self {
587 Self::V0(disperse) => disperse.epoch(),
588 Self::V1(disperse) => disperse.epoch(),
589 Self::V2(disperse) => disperse.epoch(),
590 }
591 }
592}
593
594impl<TYPES: NodeType> VidDisperse<TYPES> {
595 #[allow(clippy::panic)]
601 pub async fn calculate_vid_disperse(
602 payload: &TYPES::BlockPayload,
603 membership: &EpochMembershipCoordinator<TYPES>,
604 view: ViewNumber,
605 target_epoch: Option<EpochNumber>,
606 data_epoch: Option<EpochNumber>,
607 metadata: &<TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
608 upgrade_lock: &UpgradeLock<TYPES>,
609 ) -> Result<VidDisperseAndDuration<TYPES>> {
610 let epochs_enabled = upgrade_lock.epochs_enabled(view);
611 let upgraded_vid2 = upgrade_lock.upgraded_vid2(view);
612 if upgraded_vid2 {
613 VidDisperse2::calculate_vid_disperse(
614 payload,
615 membership,
616 view,
617 target_epoch,
618 data_epoch,
619 metadata,
620 )
621 .await
622 .map(|(disperse, duration)| VidDisperseAndDuration {
623 disperse: Self::V2(disperse),
624 duration,
625 })
626 } else if epochs_enabled {
627 VidDisperse1::calculate_vid_disperse(
628 payload,
629 membership,
630 view,
631 target_epoch,
632 data_epoch,
633 metadata,
634 )
635 .await
636 .map(|(disperse, duration)| VidDisperseAndDuration {
637 disperse: Self::V1(disperse),
638 duration,
639 })
640 } else {
641 VidDisperse0::calculate_vid_disperse(
642 payload,
643 membership,
644 view,
645 target_epoch,
646 data_epoch,
647 )
648 .await
649 .map(|(disperse, duration)| VidDisperseAndDuration {
650 disperse: Self::V0(disperse),
651 duration,
652 })
653 }
654 }
655
656 pub fn payload_commitment(&self) -> VidCommitment {
658 match self {
659 Self::V0(disperse) => VidCommitment::V0(disperse.payload_commitment),
660 Self::V1(disperse) => disperse.payload_commitment.into(),
661 Self::V2(disperse) => disperse.payload_commitment.into(),
662 }
663 }
664
665 pub fn payload_commitment_ref(&self) -> &[u8] {
667 match self {
668 Self::V0(disperse) => disperse.payload_commitment.as_ref(),
669 Self::V1(disperse) => disperse.payload_commitment.as_ref(),
670 Self::V2(disperse) => disperse.payload_commitment.as_ref(),
671 }
672 }
673
674 pub fn set_view_number(&mut self, view_number: ViewNumber) {
676 match self {
677 Self::V0(share) => share.view_number = view_number,
678 Self::V1(share) => share.view_number = view_number,
679 Self::V2(share) => share.view_number = view_number,
680 }
681 }
682
683 pub fn to_shares(self) -> Vec<VidDisperseShare<TYPES>> {
684 match self {
685 VidDisperse::V0(disperse) => disperse
686 .to_shares()
687 .into_iter()
688 .map(|share| VidDisperseShare::V0(share))
689 .collect(),
690 VidDisperse::V1(disperse) => disperse
691 .to_shares()
692 .into_iter()
693 .map(|share| VidDisperseShare::V1(share))
694 .collect(),
695 VidDisperse::V2(disperse) => disperse
696 .to_shares()
697 .into_iter()
698 .map(|share| VidDisperseShare::V2(share))
699 .collect(),
700 }
701 }
702
703 pub fn to_share_proposals(
705 proposal: Proposal<TYPES, Self>,
706 ) -> Vec<Proposal<TYPES, VidDisperseShare<TYPES>>> {
707 match proposal.data {
708 VidDisperse::V0(disperse) => disperse
709 .to_share_proposals(&proposal.signature)
710 .into_iter()
711 .map(|proposal| convert_proposal(proposal))
712 .collect(),
713 VidDisperse::V1(disperse) => disperse
714 .to_share_proposals(&proposal.signature)
715 .into_iter()
716 .map(|proposal| convert_proposal(proposal))
717 .collect(),
718 VidDisperse::V2(disperse) => disperse
719 .to_share_proposals(&proposal.signature)
720 .into_iter()
721 .map(|proposal| convert_proposal(proposal))
722 .collect(),
723 }
724 }
725}
726
727pub type VidDisperseShare0<TYPES> = vid_disperse::ADVZDisperseShare<TYPES>;
729pub type VidDisperseShare1<TYPES> = vid_disperse::AvidMDisperseShare<TYPES>;
730pub type VidDisperseShare2<TYPES> = vid_disperse::AvidmGf2DisperseShare<TYPES>;
731
732#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
734#[serde(bound = "TYPES: NodeType")]
735pub enum VidDisperseShare<TYPES: NodeType> {
736 V0(VidDisperseShare0<TYPES>),
738 V1(VidDisperseShare1<TYPES>),
740 V2(VidDisperseShare2<TYPES>),
742}
743
744impl<TYPES: NodeType> From<VidDisperseShare0<TYPES>> for VidDisperseShare<TYPES> {
745 fn from(share: VidDisperseShare0<TYPES>) -> Self {
746 Self::V0(share)
747 }
748}
749
750impl<TYPES: NodeType> From<VidDisperseShare1<TYPES>> for VidDisperseShare<TYPES> {
751 fn from(share: VidDisperseShare1<TYPES>) -> Self {
752 Self::V1(share)
753 }
754}
755
756impl<TYPES: NodeType> From<VidDisperseShare2<TYPES>> for VidDisperseShare<TYPES> {
757 fn from(share: VidDisperseShare2<TYPES>) -> Self {
758 Self::V2(share)
759 }
760}
761
762impl<TYPES: NodeType> VidDisperseShare<TYPES> {
763 pub fn to_proposal(
765 self,
766 private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
767 ) -> Option<Proposal<TYPES, Self>> {
768 let payload_commitment_ref: &[u8] = match &self {
769 Self::V0(share) => share.payload_commitment.as_ref(),
770 Self::V1(share) => share.payload_commitment.as_ref(),
771 Self::V2(share) => share.payload_commitment.as_ref(),
772 };
773 let Ok(signature) = TYPES::SignatureKey::sign(private_key, payload_commitment_ref) else {
774 tracing::error!("VID: failed to sign dispersal share payload");
775 return None;
776 };
777 Some(Proposal {
778 signature,
779 _pd: PhantomData,
780 data: self,
781 })
782 }
783
784 pub fn recipient_key(&self) -> &TYPES::SignatureKey {
786 match self {
787 Self::V0(share) => &share.recipient_key,
788 Self::V1(share) => &share.recipient_key,
789 Self::V2(share) => &share.recipient_key,
790 }
791 }
792
793 pub fn payload_byte_len(&self) -> u32 {
795 match self {
796 Self::V0(share) => share.payload_byte_len(),
797 Self::V1(share) => share.payload_byte_len(),
798 Self::V2(share) => share.payload_byte_len(),
799 }
800 }
801
802 pub fn payload_commitment_ref(&self) -> &[u8] {
804 match self {
805 Self::V0(share) => share.payload_commitment.as_ref(),
806 Self::V1(share) => share.payload_commitment.as_ref(),
807 Self::V2(share) => share.payload_commitment.as_ref(),
808 }
809 }
810
811 pub fn payload_commitment(&self) -> VidCommitment {
813 match self {
814 Self::V0(share) => VidCommitment::V0(share.payload_commitment),
815 Self::V1(share) => share.payload_commitment.into(),
816 Self::V2(share) => share.payload_commitment.into(),
817 }
818 }
819
820 pub fn target_epoch(&self) -> Option<EpochNumber> {
822 match self {
823 Self::V0(_) => None,
824 Self::V1(share) => share.target_epoch,
825 Self::V2(share) => share.target_epoch,
826 }
827 }
828
829 pub fn common(&self) -> VidCommonRef<'_> {
831 match self {
832 Self::V0(share) => VidCommonRef::V0(&share.common),
833 Self::V1(share) => VidCommonRef::V1(&share.common),
834 Self::V2(share) => VidCommonRef::V2(&share.common),
835 }
836 }
837
838 pub fn is_consistent(&self) -> bool {
840 match self {
841 Self::V0(share) => share.is_consistent(),
842 Self::V1(share) => share.is_consistent(),
843 Self::V2(share) => share.is_consistent(),
844 }
845 }
846
847 pub fn verify_with_verified_common(&self) -> bool {
850 match self {
851 Self::V0(share) => share.verify_with_verified_common(),
852 Self::V1(share) => share.verify_with_verified_common(),
853 Self::V2(share) => share.verify_with_verified_common(),
854 }
855 }
856
857 pub fn verify(&self, total_nodes: usize) -> bool {
859 match self {
860 Self::V0(share) => share.verify(total_nodes),
861 Self::V1(share) => share.verify(total_nodes),
862 Self::V2(share) => share.verify(total_nodes),
863 }
864 }
865
866 pub fn set_view_number(&mut self, view_number: ViewNumber) {
868 match self {
869 Self::V0(share) => share.view_number = view_number,
870 Self::V1(share) => share.view_number = view_number,
871 Self::V2(share) => share.view_number = view_number,
872 }
873 }
874}
875
876impl<TYPES: NodeType> HasViewNumber for VidDisperseShare<TYPES> {
877 fn view_number(&self) -> ViewNumber {
878 match self {
879 Self::V0(disperse) => disperse.view_number(),
880 Self::V1(disperse) => disperse.view_number(),
881 Self::V2(disperse) => disperse.view_number(),
882 }
883 }
884}
885
886impl<TYPES: NodeType> HasEpoch for VidDisperseShare<TYPES> {
887 fn epoch(&self) -> Option<EpochNumber> {
888 match self {
889 Self::V0(_) => None,
890 Self::V1(share) => share.epoch(),
891 Self::V2(share) => share.epoch(),
892 }
893 }
894}
895
896#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
899#[serde(bound(deserialize = ""))]
900pub enum ViewChangeEvidence<TYPES: NodeType> {
901 Timeout(TimeoutCertificate<TYPES>),
903 ViewSync(ViewSyncFinalizeCertificate<TYPES>),
905}
906
907impl<TYPES: NodeType> ViewChangeEvidence<TYPES> {
908 pub fn is_valid_for_view(&self, view: &ViewNumber) -> bool {
910 match self {
911 ViewChangeEvidence::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
912 ViewChangeEvidence::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
913 }
914 }
915
916 pub fn to_evidence2(self) -> ViewChangeEvidence2<TYPES> {
918 match self {
919 ViewChangeEvidence::Timeout(timeout_cert) => {
920 ViewChangeEvidence2::Timeout(timeout_cert.to_tc2())
921 },
922 ViewChangeEvidence::ViewSync(view_sync_cert) => {
923 ViewChangeEvidence2::ViewSync(view_sync_cert.to_vsc2())
924 },
925 }
926 }
927}
928
929#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
932#[serde(bound(deserialize = ""))]
933pub enum ViewChangeEvidence2<TYPES: NodeType> {
934 Timeout(TimeoutCertificate2<TYPES>),
936 ViewSync(ViewSyncFinalizeCertificate2<TYPES>),
938 Timeout3(TimeoutCertificate3<TYPES>),
940}
941
942impl<TYPES: NodeType> ViewChangeEvidence2<TYPES> {
943 pub fn is_valid_for_view(&self, view: &ViewNumber) -> bool {
945 match self {
946 ViewChangeEvidence2::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
947 ViewChangeEvidence2::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
948 ViewChangeEvidence2::Timeout3(timeout_cert) => timeout_cert.view_number == *view - 1,
949 }
950 }
951
952 pub fn timeout_evidence(self) -> Option<TimeoutEvidence<TYPES>> {
954 match self {
955 Self::Timeout(cert) => Some(TimeoutEvidence::V2(cert)),
956 Self::Timeout3(cert) => Some(TimeoutEvidence::V3(cert)),
957 Self::ViewSync(_) => None,
958 }
959 }
960}
961
962impl<TYPES: NodeType> From<TimeoutEvidence<TYPES>> for ViewChangeEvidence2<TYPES> {
963 fn from(evidence: TimeoutEvidence<TYPES>) -> Self {
964 match evidence {
965 TimeoutEvidence::V2(cert) => Self::Timeout(cert),
966 TimeoutEvidence::V3(cert) => Self::Timeout3(cert),
967 }
968 }
969}
970
971#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
973#[serde(bound(deserialize = ""))]
974pub struct QuorumProposal<TYPES: NodeType> {
975 pub block_header: TYPES::BlockHeader,
977
978 pub view_number: ViewNumber,
980
981 pub justify_qc: QuorumCertificate<TYPES>,
983
984 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
986
987 pub proposal_certificate: Option<ViewChangeEvidence<TYPES>>,
992}
993
994#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
996#[serde(bound(deserialize = ""))]
997pub struct QuorumProposal2<TYPES: NodeType> {
998 pub block_header: TYPES::BlockHeader,
1000
1001 pub view_number: ViewNumber,
1003
1004 pub epoch: Option<EpochNumber>,
1006
1007 pub justify_qc: QuorumCertificate2<TYPES>,
1009
1010 pub next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1012
1013 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1015
1016 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
1018
1019 #[serde(with = "serde_bytes")]
1024 pub next_drb_result: Option<DrbResult>,
1025
1026 pub state_cert: Option<LightClientStateUpdateCertificateV2<TYPES>>,
1029}
1030
1031impl<TYPES: NodeType> QuorumProposal2<TYPES> {
1032 pub fn is_validate_block_height(&self) -> bool {
1033 self.justify_qc
1034 .data()
1035 .block_number
1036 .is_some_and(|bn| bn + 1 == self.block_header.block_number())
1037 }
1038}
1039
1040#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
1049#[serde(bound(deserialize = ""))]
1050pub struct QuorumProposal2Legacy<TYPES: NodeType> {
1051 pub block_header: TYPES::BlockHeader,
1053
1054 pub view_number: ViewNumber,
1056
1057 pub epoch: Option<EpochNumber>,
1059
1060 pub justify_qc: QuorumCertificate2<TYPES>,
1062
1063 pub next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1065
1066 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1068
1069 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
1071
1072 #[serde(with = "serde_bytes")]
1077 pub next_drb_result: Option<DrbResult>,
1078
1079 pub state_cert: Option<LightClientStateUpdateCertificateV1<TYPES>>,
1083}
1084
1085impl<TYPES: NodeType> From<QuorumProposal2Legacy<TYPES>> for QuorumProposal2<TYPES> {
1086 fn from(quorum_proposal2: QuorumProposal2Legacy<TYPES>) -> Self {
1087 Self {
1088 block_header: quorum_proposal2.block_header,
1089 view_number: quorum_proposal2.view_number,
1090 epoch: quorum_proposal2.epoch,
1091 justify_qc: quorum_proposal2.justify_qc,
1092 next_epoch_justify_qc: quorum_proposal2.next_epoch_justify_qc,
1093 upgrade_certificate: quorum_proposal2.upgrade_certificate,
1094 view_change_evidence: quorum_proposal2.view_change_evidence,
1095 next_drb_result: quorum_proposal2.next_drb_result,
1096 state_cert: quorum_proposal2.state_cert.map(Into::into),
1097 }
1098 }
1099}
1100
1101impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposal2Legacy<TYPES> {
1102 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1103 Self {
1104 block_header: quorum_proposal2.block_header,
1105 view_number: quorum_proposal2.view_number,
1106 epoch: quorum_proposal2.epoch,
1107 justify_qc: quorum_proposal2.justify_qc,
1108 next_epoch_justify_qc: quorum_proposal2.next_epoch_justify_qc,
1109 upgrade_certificate: quorum_proposal2.upgrade_certificate,
1110 view_change_evidence: quorum_proposal2.view_change_evidence,
1111 next_drb_result: quorum_proposal2.next_drb_result,
1112 state_cert: quorum_proposal2.state_cert.map(Into::into),
1113 }
1114 }
1115}
1116
1117#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
1123#[serde(bound(deserialize = ""))]
1124pub struct QuorumProposalWrapperLegacy<TYPES: NodeType> {
1125 pub proposal: QuorumProposal2Legacy<TYPES>,
1127}
1128
1129#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
1131#[serde(bound(deserialize = ""))]
1132pub struct QuorumProposalWrapper<TYPES: NodeType> {
1133 pub proposal: QuorumProposal2<TYPES>,
1135}
1136
1137impl<TYPES: NodeType> From<QuorumProposalWrapperLegacy<TYPES>> for QuorumProposalWrapper<TYPES> {
1138 fn from(v3: QuorumProposalWrapperLegacy<TYPES>) -> Self {
1139 Self {
1140 proposal: v3.proposal.into(),
1141 }
1142 }
1143}
1144
1145impl<TYPES: NodeType> QuorumProposal2<TYPES> {
1146 pub async fn validate_epoch(
1150 &self,
1151 upgrade_lock: &UpgradeLock<TYPES>,
1152 epoch_height: u64,
1153 ) -> Result<()> {
1154 let calculated_epoch = option_epoch_from_block_number(
1155 upgrade_lock.epochs_enabled(self.view_number()),
1156 self.block_header.block_number(),
1157 epoch_height,
1158 );
1159 ensure!(
1160 calculated_epoch == self.epoch(),
1161 "Quorum proposal invalid: inconsistent epoch."
1162 );
1163 Ok(())
1164 }
1165}
1166
1167impl<TYPES: NodeType> QuorumProposalWrapper<TYPES> {
1168 pub fn block_header(&self) -> &TYPES::BlockHeader {
1170 &self.proposal.block_header
1171 }
1172
1173 pub fn view_number(&self) -> ViewNumber {
1175 self.proposal.view_number
1176 }
1177
1178 pub fn justify_qc(&self) -> &QuorumCertificate2<TYPES> {
1180 &self.proposal.justify_qc
1181 }
1182
1183 pub fn next_epoch_justify_qc(&self) -> &Option<NextEpochQuorumCertificate2<TYPES>> {
1185 &self.proposal.next_epoch_justify_qc
1186 }
1187
1188 pub fn upgrade_certificate(&self) -> &Option<UpgradeCertificate<TYPES>> {
1190 &self.proposal.upgrade_certificate
1191 }
1192
1193 pub fn view_change_evidence(&self) -> &Option<ViewChangeEvidence2<TYPES>> {
1195 &self.proposal.view_change_evidence
1196 }
1197
1198 pub fn next_drb_result(&self) -> &Option<DrbResult> {
1200 &self.proposal.next_drb_result
1201 }
1202
1203 pub async fn validate_epoch(
1207 &self,
1208 upgrade_lock: &UpgradeLock<TYPES>,
1209 epoch_height: u64,
1210 ) -> Result<()> {
1211 self.proposal
1212 .validate_epoch(upgrade_lock, epoch_height)
1213 .await
1214 }
1215
1216 pub fn state_cert(&self) -> &Option<LightClientStateUpdateCertificateV2<TYPES>> {
1218 &self.proposal.state_cert
1219 }
1220}
1221
1222impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposalWrapper<TYPES> {
1223 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
1224 Self {
1225 proposal: quorum_proposal.into(),
1226 }
1227 }
1228}
1229
1230impl<TYPES: NodeType> From<QuorumProposal2Legacy<TYPES>> for QuorumProposalWrapper<TYPES> {
1231 fn from(quorum_proposal: QuorumProposal2Legacy<TYPES>) -> Self {
1232 Self {
1233 proposal: quorum_proposal.into(),
1234 }
1235 }
1236}
1237
1238impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposalWrapper<TYPES> {
1239 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1240 Self {
1241 proposal: quorum_proposal2,
1242 }
1243 }
1244}
1245
1246impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal2Legacy<TYPES> {
1247 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1248 quorum_proposal_wrapper.proposal.into()
1249 }
1250}
1251
1252impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal2<TYPES> {
1253 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1254 quorum_proposal_wrapper.proposal
1255 }
1256}
1257
1258impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposal2<TYPES> {
1259 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
1260 Self {
1261 block_header: quorum_proposal.block_header,
1262 view_number: quorum_proposal.view_number,
1263 epoch: None,
1264 justify_qc: quorum_proposal.justify_qc.to_qc2(),
1265 next_epoch_justify_qc: None,
1266 upgrade_certificate: quorum_proposal.upgrade_certificate,
1267 view_change_evidence: quorum_proposal
1268 .proposal_certificate
1269 .map(ViewChangeEvidence::to_evidence2),
1270 next_drb_result: None,
1271 state_cert: None,
1272 }
1273 }
1274}
1275
1276impl<TYPES: NodeType> From<Leaf<TYPES>> for Leaf2<TYPES> {
1277 fn from(leaf: Leaf<TYPES>) -> Self {
1278 let bytes: [u8; 32] = leaf.parent_commitment.into();
1279
1280 Self {
1281 view_number: leaf.view_number,
1282 justify_qc: leaf.justify_qc.to_qc2(),
1283 next_epoch_justify_qc: None,
1284 parent_commitment: Commitment::from_raw(bytes),
1285 block_header: leaf.block_header,
1286 upgrade_certificate: leaf.upgrade_certificate,
1287 block_payload: leaf.block_payload,
1288 view_change_evidence: None,
1289 next_drb_result: None,
1290 with_epoch: false,
1291 }
1292 }
1293}
1294
1295impl<TYPES: NodeType> HasViewNumber for DaProposal<TYPES> {
1296 fn view_number(&self) -> ViewNumber {
1297 self.view_number
1298 }
1299}
1300
1301impl<TYPES: NodeType> HasViewNumber for DaProposal2<TYPES> {
1302 fn view_number(&self) -> ViewNumber {
1303 self.view_number
1304 }
1305}
1306
1307impl<TYPES: NodeType> HasViewNumber for QuorumProposal<TYPES> {
1308 fn view_number(&self) -> ViewNumber {
1309 self.view_number
1310 }
1311}
1312
1313impl<TYPES: NodeType> HasViewNumber for QuorumProposal2<TYPES> {
1314 fn view_number(&self) -> ViewNumber {
1315 self.view_number
1316 }
1317}
1318
1319impl<TYPES: NodeType> HasViewNumber for QuorumProposal2Legacy<TYPES> {
1320 fn view_number(&self) -> ViewNumber {
1321 self.view_number
1322 }
1323}
1324
1325impl<TYPES: NodeType> HasViewNumber for QuorumProposalWrapper<TYPES> {
1326 fn view_number(&self) -> ViewNumber {
1327 self.proposal.view_number
1328 }
1329}
1330
1331impl<TYPES: NodeType> HasViewNumber for QuorumProposalWrapperLegacy<TYPES> {
1332 fn view_number(&self) -> ViewNumber {
1333 self.proposal.view_number
1334 }
1335}
1336
1337impl HasViewNumber for UpgradeProposal {
1338 fn view_number(&self) -> ViewNumber {
1339 self.view_number
1340 }
1341}
1342
1343impl HasViewNumber for UpgradeProposal2 {
1344 fn view_number(&self) -> ViewNumber {
1345 self.view_number
1346 }
1347}
1348
1349impl<NODE: NodeType> HasEpoch for QuorumProposal2<NODE> {
1350 fn epoch(&self) -> Option<EpochNumber> {
1351 self.epoch
1352 }
1353}
1354
1355impl<NODE: NodeType> HasEpoch for DaProposal2<NODE> {
1356 fn epoch(&self) -> Option<EpochNumber> {
1357 self.epoch
1358 }
1359}
1360
1361impl<NODE: NodeType> HasEpoch for QuorumProposal2Legacy<NODE> {
1362 fn epoch(&self) -> Option<EpochNumber> {
1363 self.epoch
1364 }
1365}
1366
1367impl HasEpoch for UpgradeProposal {
1368 fn epoch(&self) -> Option<EpochNumber> {
1369 None
1370 }
1371}
1372
1373impl HasEpoch for UpgradeProposal2 {
1374 fn epoch(&self) -> Option<EpochNumber> {
1375 Some(self.upgrade_proposal.epoch)
1376 }
1377}
1378
1379impl<NODE: NodeType> HasEpoch for QuorumProposal<NODE> {
1380 fn epoch(&self) -> Option<EpochNumber> {
1381 None
1382 }
1383}
1384
1385impl<NODE: NodeType> HasEpoch for DaProposal<NODE> {
1386 fn epoch(&self) -> Option<EpochNumber> {
1387 None
1388 }
1389}
1390
1391impl<NODE: NodeType> HasEpoch for QuorumProposalWrapper<NODE> {
1392 #[allow(clippy::panic)]
1394 fn epoch(&self) -> Option<EpochNumber> {
1395 self.proposal.epoch()
1396 }
1397}
1398
1399impl<TYPES: NodeType> HasEpoch for QuorumProposalWrapperLegacy<TYPES> {
1400 #[allow(clippy::panic)]
1402 fn epoch(&self) -> Option<EpochNumber> {
1403 self.proposal.epoch()
1404 }
1405}
1406
1407#[derive(Error, Debug, Serialize, Deserialize)]
1409pub enum BlockError {
1410 #[error("Invalid block header: {0}")]
1412 InvalidBlockHeader(String),
1413
1414 #[error("Inconsistent payload commitment")]
1416 InconsistentPayloadCommitment,
1417
1418 #[error("Failed to apply block header: {0}")]
1420 FailedHeaderApply(String),
1421}
1422
1423pub trait TestableLeaf {
1425 type NodeType: NodeType;
1427
1428 fn create_random_transaction(
1430 &self,
1431 rng: &mut dyn rand::RngCore,
1432 padding: u64,
1433 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction;
1434}
1435
1436#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1440#[serde(bound(deserialize = ""))]
1441pub struct Leaf<TYPES: NodeType> {
1442 view_number: ViewNumber,
1444
1445 justify_qc: QuorumCertificate<TYPES>,
1447
1448 parent_commitment: Commitment<Self>,
1451
1452 block_header: TYPES::BlockHeader,
1454
1455 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1457
1458 block_payload: Option<TYPES::BlockPayload>,
1462}
1463
1464#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1467#[serde(bound(deserialize = ""))]
1468pub struct Leaf2<TYPES: NodeType> {
1469 view_number: ViewNumber,
1471
1472 justify_qc: QuorumCertificate2<TYPES>,
1474
1475 next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1477
1478 parent_commitment: Commitment<Self>,
1481
1482 block_header: TYPES::BlockHeader,
1484
1485 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1487
1488 block_payload: Option<TYPES::BlockPayload>,
1492
1493 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
1495
1496 #[serde(with = "serde_bytes")]
1501 pub next_drb_result: Option<DrbResult>,
1502
1503 pub with_epoch: bool,
1505}
1506
1507impl<TYPES: NodeType> Leaf2<TYPES> {
1508 #[must_use]
1515 pub async fn genesis(
1516 validated_state: &TYPES::ValidatedState,
1517 instance_state: &TYPES::InstanceState,
1518 version: Version,
1519 ) -> Self {
1520 let epoch = genesis_epoch_from_version(version);
1521
1522 let (payload, metadata) =
1523 TYPES::BlockPayload::from_transactions(&[], validated_state, instance_state)
1524 .await
1525 .unwrap();
1526
1527 let genesis_view = ViewNumber::genesis();
1528
1529 let block_header =
1530 TYPES::BlockHeader::genesis(instance_state, payload.clone(), &metadata, version);
1531
1532 let block_number = if version < EPOCH_VERSION {
1533 None
1534 } else {
1535 Some(0u64)
1536 };
1537
1538 let null_quorum_data = QuorumData2 {
1539 leaf_commit: Commitment::<Leaf2<TYPES>>::default_commitment_no_preimage(),
1540 epoch,
1541 block_number,
1542 };
1543
1544 let justify_qc = QuorumCertificate2::new(
1545 null_quorum_data,
1546 null_quorum_data.commit(),
1547 genesis_view,
1548 None,
1549 PhantomData,
1550 );
1551
1552 Self {
1553 view_number: genesis_view,
1554 justify_qc,
1555 next_epoch_justify_qc: None,
1556 parent_commitment: null_quorum_data.leaf_commit,
1557 upgrade_certificate: None,
1558 block_header: block_header.clone(),
1559 block_payload: Some(payload),
1560 view_change_evidence: None,
1561 next_drb_result: None,
1562 with_epoch: epoch.is_some(),
1563 }
1564 }
1565 pub fn view_number(&self) -> ViewNumber {
1567 self.view_number
1568 }
1569 pub fn epoch(&self, epoch_height: u64) -> Option<EpochNumber> {
1571 option_epoch_from_block_number(
1572 self.with_epoch,
1573 self.block_header.block_number(),
1574 epoch_height,
1575 )
1576 }
1577 pub fn height(&self) -> u64 {
1581 self.block_header.block_number()
1582 }
1583 pub fn justify_qc(&self) -> &QuorumCertificate2<TYPES> {
1585 &self.justify_qc
1586 }
1587 pub fn next_epoch_justify_qc(&self) -> Option<&NextEpochQuorumCertificate2<TYPES>> {
1591 self.next_epoch_justify_qc.as_ref()
1592 }
1593 pub fn upgrade_certificate(&self) -> Option<&UpgradeCertificate<TYPES>> {
1595 self.upgrade_certificate.as_ref()
1596 }
1597 pub fn parent_commitment(&self) -> Commitment<Self> {
1599 self.parent_commitment
1600 }
1601 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1603 &self.block_header
1604 }
1605
1606 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1608 &mut self.block_header
1609 }
1610 pub fn fill_block_payload(
1617 &mut self,
1618 block_payload: TYPES::BlockPayload,
1619 num_storage_nodes: usize,
1620 version: Version,
1621 ) -> std::result::Result<(), BlockError> {
1622 let encoded_txns = block_payload.encode();
1623 let commitment = vid_commitment(
1624 &encoded_txns,
1625 &self.block_header.metadata().encode(),
1626 num_storage_nodes,
1627 version,
1628 );
1629 if commitment != self.block_header.payload_commitment() {
1630 return Err(BlockError::InconsistentPayloadCommitment);
1631 }
1632 self.block_payload = Some(block_payload);
1633 Ok(())
1634 }
1635
1636 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
1638 self.block_payload.take()
1639 }
1640
1641 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
1644 self.block_payload = Some(block_payload);
1645 }
1646
1647 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
1649 self.block_payload.clone()
1650 }
1651
1652 pub fn block_payload_ref(&self) -> Option<&TYPES::BlockPayload> {
1653 self.block_payload.as_ref()
1654 }
1655
1656 pub fn payload_commitment(&self) -> VidCommitment {
1658 self.block_header().payload_commitment()
1659 }
1660
1661 pub fn extends_upgrade(&self, parent: &Self, upgrade: &UpgradeLock<TYPES>) -> Result<()> {
1669 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
1670 (None | Some(_), None) => {},
1674 (None, Some(parent_cert)) => {
1678 let decided_upgrade_certificate_read = upgrade.decided_upgrade_cert();
1679 ensure!(
1680 self.view_number() > parent_cert.data.new_version_first_view
1681 || (self.view_number() > parent_cert.data.decide_by
1682 && decided_upgrade_certificate_read.is_none()),
1683 "The new leaf is missing an upgrade certificate that was present in its \
1684 parent, and should still be live."
1685 );
1686 },
1687 (Some(cert), Some(parent_cert)) => {
1691 ensure!(
1692 cert == parent_cert,
1693 "The new leaf does not extend the parent leaf, because it has attached a \
1694 different upgrade certificate."
1695 );
1696 },
1697 }
1698
1699 Ok(())
1703 }
1704
1705 pub fn to_leaf_unsafe(self) -> Leaf<TYPES> {
1707 let bytes: [u8; 32] = self.parent_commitment.into();
1708
1709 Leaf {
1710 view_number: self.view_number,
1711 justify_qc: self.justify_qc.to_qc(),
1712 parent_commitment: Commitment::from_raw(bytes),
1713 block_header: self.block_header,
1714 upgrade_certificate: self.upgrade_certificate,
1715 block_payload: self.block_payload,
1716 }
1717 }
1718}
1719
1720impl<TYPES: NodeType> Committable for Leaf2<TYPES> {
1721 fn commit(&self) -> committable::Commitment<Self> {
1722 let Leaf2 {
1723 view_number,
1724 justify_qc,
1725 next_epoch_justify_qc,
1726 parent_commitment,
1727 block_header,
1728 upgrade_certificate,
1729 block_payload: _,
1730 view_change_evidence,
1731 next_drb_result,
1732 with_epoch,
1733 } = self;
1734
1735 let mut cb = RawCommitmentBuilder::new("leaf commitment")
1736 .u64_field("view number", **view_number)
1737 .field("parent leaf commitment", *parent_commitment)
1738 .field("block header", block_header.commit())
1739 .field("justify qc", justify_qc.commit())
1740 .optional("upgrade certificate", upgrade_certificate);
1741
1742 if *with_epoch {
1743 cb = cb
1744 .constant_str("with_epoch")
1745 .optional("next_epoch_justify_qc", next_epoch_justify_qc);
1746
1747 if let Some(next_drb_result) = next_drb_result {
1748 cb = cb
1749 .constant_str("next_drb_result")
1750 .fixed_size_bytes(next_drb_result);
1751 }
1752
1753 match view_change_evidence {
1754 Some(ViewChangeEvidence2::Timeout(cert)) => {
1755 cb = cb.field("timeout cert", cert.commit());
1756 },
1757 Some(ViewChangeEvidence2::ViewSync(cert)) => {
1758 cb = cb.field("viewsync cert", cert.commit());
1759 },
1760 Some(ViewChangeEvidence2::Timeout3(cert)) => {
1761 cb = cb.field("timeout cert v3", cert.commit());
1762 },
1763 None => {},
1764 }
1765 }
1766
1767 cb.finalize()
1768 }
1769}
1770
1771impl<TYPES: NodeType> Leaf<TYPES> {
1772 pub fn commit(&self, _upgrade_lock: &UpgradeLock<TYPES>) -> Commitment<Self> {
1775 <Self as Committable>::commit(self)
1776 }
1777}
1778
1779impl<TYPES: NodeType> PartialEq for Leaf<TYPES> {
1780 fn eq(&self, other: &Self) -> bool {
1781 self.view_number == other.view_number
1782 && self.justify_qc == other.justify_qc
1783 && self.parent_commitment == other.parent_commitment
1784 && self.block_header == other.block_header
1785 }
1786}
1787
1788impl<TYPES: NodeType> PartialEq for Leaf2<TYPES> {
1789 fn eq(&self, other: &Self) -> bool {
1790 let Leaf2 {
1791 view_number,
1792 justify_qc,
1793 next_epoch_justify_qc,
1794 parent_commitment,
1795 block_header,
1796 upgrade_certificate,
1797 block_payload: _,
1798 view_change_evidence,
1799 next_drb_result,
1800 with_epoch,
1801 } = self;
1802
1803 *view_number == other.view_number
1804 && *justify_qc == other.justify_qc
1805 && *next_epoch_justify_qc == other.next_epoch_justify_qc
1806 && *parent_commitment == other.parent_commitment
1807 && *block_header == other.block_header
1808 && *upgrade_certificate == other.upgrade_certificate
1809 && *view_change_evidence == other.view_change_evidence
1810 && *next_drb_result == other.next_drb_result
1811 && *with_epoch == other.with_epoch
1812 }
1813}
1814
1815impl<TYPES: NodeType> Hash for Leaf<TYPES> {
1816 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1817 self.view_number.hash(state);
1818 self.justify_qc.hash(state);
1819 self.parent_commitment.hash(state);
1820 self.block_header.hash(state);
1821 }
1822}
1823
1824impl<TYPES: NodeType> Hash for Leaf2<TYPES> {
1825 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1826 self.commit().hash(state);
1827 self.view_number.hash(state);
1828 self.justify_qc.hash(state);
1829 self.parent_commitment.hash(state);
1830 self.block_header.hash(state);
1831 }
1832}
1833
1834impl<TYPES: NodeType> Display for Leaf<TYPES> {
1835 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1836 write!(
1837 f,
1838 "view: {:?}, height: {:?}, justify: {}",
1839 self.view_number,
1840 self.height(),
1841 self.justify_qc
1842 )
1843 }
1844}
1845
1846impl<TYPES: NodeType> QuorumCertificate<TYPES> {
1847 #[must_use]
1849 pub async fn genesis(
1850 validated_state: &TYPES::ValidatedState,
1851 instance_state: &TYPES::InstanceState,
1852 upgrade: Upgrade,
1853 ) -> Self {
1854 let upgrade_lock = UpgradeLock::<TYPES>::new(upgrade);
1856
1857 let genesis_view = ViewNumber::genesis();
1858
1859 let data = QuorumData {
1860 leaf_commit: Leaf::genesis(validated_state, instance_state, upgrade.base)
1861 .await
1862 .commit(&upgrade_lock),
1863 };
1864
1865 let versioned_data =
1866 VersionedVoteData::<_, _>::new_infallible(data.clone(), genesis_view, &upgrade_lock);
1867
1868 let bytes: [u8; 32] = versioned_data.commit().into();
1869
1870 Self::new(
1871 data,
1872 Commitment::from_raw(bytes),
1873 genesis_view,
1874 None,
1875 PhantomData,
1876 )
1877 }
1878}
1879
1880impl<TYPES: NodeType> QuorumCertificate2<TYPES> {
1881 #[must_use]
1883 pub async fn genesis(
1884 validated_state: &TYPES::ValidatedState,
1885 instance_state: &TYPES::InstanceState,
1886 upgrade: Upgrade,
1887 ) -> Self {
1888 let upgrade_lock = UpgradeLock::<TYPES>::new(upgrade);
1890
1891 let genesis_view = ViewNumber::genesis();
1892
1893 let genesis_leaf = Leaf2::genesis(validated_state, instance_state, upgrade.base).await;
1894 let block_number = if upgrade_lock.epochs_enabled(genesis_view) {
1895 Some(genesis_leaf.height())
1896 } else {
1897 None
1898 };
1899 let data = QuorumData2 {
1900 leaf_commit: genesis_leaf.commit(),
1901 epoch: genesis_epoch_from_version(upgrade.base), block_number,
1903 };
1904
1905 let versioned_data =
1906 VersionedVoteData::<_, _>::new_infallible(data, genesis_view, &upgrade_lock);
1907
1908 let bytes: [u8; 32] = versioned_data.commit().into();
1909
1910 Self::new(
1911 data,
1912 Commitment::from_raw(bytes),
1913 genesis_view,
1914 None,
1915 PhantomData,
1916 )
1917 }
1918}
1919
1920impl<TYPES: NodeType> Leaf<TYPES> {
1921 #[must_use]
1928 pub async fn genesis(
1929 validated_state: &TYPES::ValidatedState,
1930 instance_state: &TYPES::InstanceState,
1931 version: Version,
1932 ) -> Self {
1933 let (payload, metadata) =
1934 TYPES::BlockPayload::from_transactions(&[], validated_state, instance_state)
1935 .await
1936 .unwrap();
1937
1938 let genesis_view = ViewNumber::genesis();
1939
1940 let block_header =
1941 TYPES::BlockHeader::genesis(instance_state, payload.clone(), &metadata, version);
1942
1943 let null_quorum_data = QuorumData {
1944 leaf_commit: Commitment::<Leaf<TYPES>>::default_commitment_no_preimage(),
1945 };
1946
1947 let justify_qc = QuorumCertificate::new(
1948 null_quorum_data.clone(),
1949 null_quorum_data.commit(),
1950 genesis_view,
1951 None,
1952 PhantomData,
1953 );
1954
1955 Self {
1956 view_number: genesis_view,
1957 justify_qc,
1958 parent_commitment: null_quorum_data.leaf_commit,
1959 upgrade_certificate: None,
1960 block_header: block_header.clone(),
1961 block_payload: Some(payload),
1962 }
1963 }
1964
1965 pub fn view_number(&self) -> ViewNumber {
1967 self.view_number
1968 }
1969 pub fn height(&self) -> u64 {
1973 self.block_header.block_number()
1974 }
1975 pub fn justify_qc(&self) -> QuorumCertificate<TYPES> {
1977 self.justify_qc.clone()
1978 }
1979 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1981 self.upgrade_certificate.clone()
1982 }
1983 pub fn parent_commitment(&self) -> Commitment<Self> {
1985 self.parent_commitment
1986 }
1987 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1989 &self.block_header
1990 }
1991
1992 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1994 &mut self.block_header
1995 }
1996 pub fn fill_block_payload(
2003 &mut self,
2004 block_payload: TYPES::BlockPayload,
2005 num_storage_nodes: usize,
2006 version: Version,
2007 ) -> std::result::Result<(), BlockError> {
2008 let encoded_txns = block_payload.encode();
2009 let commitment = vid_commitment(
2010 &encoded_txns,
2011 &self.block_header.metadata().encode(),
2012 num_storage_nodes,
2013 version,
2014 );
2015 if commitment != self.block_header.payload_commitment() {
2016 return Err(BlockError::InconsistentPayloadCommitment);
2017 }
2018 self.block_payload = Some(block_payload);
2019 Ok(())
2020 }
2021
2022 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
2024 self.block_payload.take()
2025 }
2026
2027 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
2030 self.block_payload = Some(block_payload);
2031 }
2032
2033 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
2035 self.block_payload.clone()
2036 }
2037
2038 pub fn payload_commitment(&self) -> VidCommitment {
2040 self.block_header().payload_commitment()
2041 }
2042
2043 pub fn extends_upgrade(&self, parent: &Self, upgrade: &UpgradeLock<TYPES>) -> Result<()> {
2051 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
2052 (None | Some(_), None) => {},
2056 (None, Some(parent_cert)) => {
2060 let decided_upgrade_certificate_read = upgrade.decided_upgrade_cert();
2061 ensure!(
2062 self.view_number() > parent_cert.data.new_version_first_view
2063 || (self.view_number() > parent_cert.data.decide_by
2064 && decided_upgrade_certificate_read.is_none()),
2065 "The new leaf is missing an upgrade certificate that was present in its \
2066 parent, and should still be live."
2067 );
2068 },
2069 (Some(cert), Some(parent_cert)) => {
2073 ensure!(
2074 cert == parent_cert,
2075 "The new leaf does not extend the parent leaf, because it has attached a \
2076 different upgrade certificate."
2077 );
2078 },
2079 }
2080
2081 Ok(())
2085 }
2086}
2087
2088impl<TYPES: NodeType> TestableLeaf for Leaf<TYPES>
2089where
2090 TYPES::ValidatedState: TestableState<TYPES>,
2091 TYPES::BlockPayload: TestableBlock<TYPES>,
2092{
2093 type NodeType = TYPES;
2094
2095 fn create_random_transaction(
2096 &self,
2097 rng: &mut dyn rand::RngCore,
2098 padding: u64,
2099 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
2100 {
2101 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
2102 }
2103}
2104impl<TYPES: NodeType> TestableLeaf for Leaf2<TYPES>
2105where
2106 TYPES::ValidatedState: TestableState<TYPES>,
2107 TYPES::BlockPayload: TestableBlock<TYPES>,
2108{
2109 type NodeType = TYPES;
2110
2111 fn create_random_transaction(
2112 &self,
2113 rng: &mut dyn rand::RngCore,
2114 padding: u64,
2115 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
2116 {
2117 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
2118 }
2119}
2120#[must_use]
2122pub fn fake_commitment<S: Committable>() -> Commitment<S> {
2123 RawCommitmentBuilder::new("Dummy commitment for arbitrary genesis").finalize()
2124}
2125
2126#[must_use]
2128pub fn random_commitment<S: Committable>(rng: &mut dyn rand::RngCore) -> Commitment<S> {
2129 let random_array: Vec<u8> = (0u8..100u8).map(|_| rng.gen_range(0..255)).collect();
2130 RawCommitmentBuilder::new("Random Commitment")
2131 .constant_str("Random Field")
2132 .var_size_bytes(&random_array)
2133 .finalize()
2134}
2135
2136pub fn serialize_signature2<TYPES: NodeType>(
2140 signatures: &<TYPES::SignatureKey as SignatureKey>::QcType,
2141) -> Vec<u8> {
2142 let mut signatures_bytes = vec![];
2143 signatures_bytes.extend("Yes".as_bytes());
2144
2145 let (sig, proof) = TYPES::SignatureKey::sig_proof(signatures);
2146 let proof_bytes = bincode_opts()
2147 .serialize(&proof.as_bitslice())
2148 .expect("This serialization shouldn't be able to fail");
2149 signatures_bytes.extend("bitvec proof".as_bytes());
2150 signatures_bytes.extend(proof_bytes.as_slice());
2151 let sig_bytes = bincode_opts()
2152 .serialize(&sig)
2153 .expect("This serialization shouldn't be able to fail");
2154 signatures_bytes.extend("aggregated signature".as_bytes());
2155 signatures_bytes.extend(sig_bytes.as_slice());
2156 signatures_bytes
2157}
2158
2159impl<TYPES: NodeType> Committable for Leaf<TYPES> {
2160 fn commit(&self) -> committable::Commitment<Self> {
2161 RawCommitmentBuilder::new("leaf commitment")
2162 .u64_field("view number", *self.view_number)
2163 .field("parent leaf commitment", self.parent_commitment)
2164 .field("block header", self.block_header.commit())
2165 .field("justify qc", self.justify_qc.commit())
2166 .optional("upgrade certificate", &self.upgrade_certificate)
2167 .finalize()
2168 }
2169}
2170
2171impl<TYPES: NodeType> Leaf2<TYPES> {
2172 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposalWrapper<TYPES>) -> Self {
2174 let QuorumProposalWrapper {
2177 proposal:
2178 QuorumProposal2 {
2179 view_number,
2180 epoch,
2181 justify_qc,
2182 next_epoch_justify_qc,
2183 block_header,
2184 upgrade_certificate,
2185 view_change_evidence,
2186 next_drb_result,
2187 state_cert: _,
2188 },
2189 } = quorum_proposal;
2190
2191 Self {
2192 view_number: *view_number,
2193 justify_qc: justify_qc.clone(),
2194 next_epoch_justify_qc: next_epoch_justify_qc.clone(),
2195 parent_commitment: justify_qc.data().leaf_commit,
2196 block_header: block_header.clone(),
2197 upgrade_certificate: upgrade_certificate.clone(),
2198 block_payload: None,
2199 view_change_evidence: view_change_evidence.clone(),
2200 next_drb_result: *next_drb_result,
2201 with_epoch: epoch.is_some(),
2202 }
2203 }
2204}
2205
2206impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for Leaf2<TYPES> {
2207 fn from(value: QuorumProposalWrapper<TYPES>) -> Self {
2208 let QuorumProposalWrapper {
2209 proposal:
2210 QuorumProposal2 {
2211 view_number,
2212 epoch,
2213 justify_qc,
2214 next_epoch_justify_qc,
2215 block_header,
2216 upgrade_certificate,
2217 view_change_evidence,
2218 next_drb_result,
2219 state_cert: _,
2220 },
2221 } = value;
2222
2223 let parent_commitment = justify_qc.data().leaf_commit;
2224
2225 Self {
2226 view_number,
2227 justify_qc,
2228 next_epoch_justify_qc,
2229 parent_commitment,
2230 block_header,
2231 upgrade_certificate,
2232 block_payload: None,
2233 view_change_evidence,
2234 next_drb_result,
2235 with_epoch: epoch.is_some(),
2236 }
2237 }
2238}
2239
2240impl<TYPES: NodeType> Leaf<TYPES> {
2241 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposal<TYPES>) -> Self {
2243 let QuorumProposal {
2246 view_number,
2247 justify_qc,
2248 block_header,
2249 upgrade_certificate,
2250 proposal_certificate: _,
2251 } = quorum_proposal;
2252
2253 Self {
2254 view_number: *view_number,
2255 justify_qc: justify_qc.clone(),
2256 parent_commitment: justify_qc.data().leaf_commit,
2257 block_header: block_header.clone(),
2258 upgrade_certificate: upgrade_certificate.clone(),
2259 block_payload: None,
2260 }
2261 }
2262}
2263
2264pub mod null_block {
2265 #![allow(missing_docs)]
2266
2267 use jf_advz::VidScheme;
2268 use vbs::version::Version;
2269 use versions::EPOCH_VERSION;
2270
2271 use crate::{
2272 data::VidCommitment,
2273 traits::{
2274 BlockPayload, block_contents::BuilderFee, node_implementation::NodeType,
2275 signature_key::BuilderSignatureKey,
2276 },
2277 vid::advz::advz_scheme,
2278 };
2279
2280 #[must_use]
2289 pub fn commitment(num_storage_nodes: usize) -> Option<VidCommitment> {
2290 let vid_result = advz_scheme(num_storage_nodes).commit_only(Vec::new());
2291
2292 match vid_result {
2293 Ok(r) => Some(VidCommitment::V0(r)),
2294 Err(_) => None,
2295 }
2296 }
2297
2298 #[must_use]
2300 pub fn builder_fee<TYPES: NodeType>(
2301 num_storage_nodes: usize,
2302 version: Version,
2303 ) -> Option<BuilderFee<TYPES>> {
2304 const FEE_AMOUNT: u64 = 0;
2306
2307 let (pub_key, priv_key) =
2308 <TYPES::BuilderSignatureKey as BuilderSignatureKey>::generated_from_seed_indexed(
2309 [0_u8; 32], 0,
2310 );
2311
2312 if version >= EPOCH_VERSION {
2313 let (_null_block, null_block_metadata) =
2314 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2315
2316 match TYPES::BuilderSignatureKey::sign_fee(&priv_key, FEE_AMOUNT, &null_block_metadata)
2317 {
2318 Ok(sig) => Some(BuilderFee {
2319 fee_amount: FEE_AMOUNT,
2320 fee_account: pub_key,
2321 fee_signature: sig,
2322 }),
2323 Err(_) => None,
2324 }
2325 } else {
2326 let (_null_block, null_block_metadata) =
2327 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2328
2329 match TYPES::BuilderSignatureKey::sign_fee_with_vid_commitment(
2330 &priv_key,
2331 FEE_AMOUNT,
2332 &null_block_metadata,
2333 &commitment(num_storage_nodes)?,
2334 ) {
2335 Ok(sig) => Some(BuilderFee {
2336 fee_amount: FEE_AMOUNT,
2337 fee_account: pub_key,
2338 fee_signature: sig,
2339 }),
2340 Err(_) => None,
2341 }
2342 }
2343 }
2344}
2345
2346#[derive(Debug, Eq, PartialEq, Clone)]
2348pub struct PackedBundle<TYPES: NodeType> {
2349 pub encoded_transactions: Arc<[u8]>,
2351
2352 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2354
2355 pub view_number: ViewNumber,
2357
2358 pub epoch_number: Option<EpochNumber>,
2360
2361 pub sequencing_fees: Vec1<BuilderFee<TYPES>>,
2363}
2364
2365impl<TYPES: NodeType> PackedBundle<TYPES> {
2366 pub fn new(
2368 encoded_transactions: Arc<[u8]>,
2369 metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2370 view_number: ViewNumber,
2371 epoch_number: Option<EpochNumber>,
2372 sequencing_fees: Vec1<BuilderFee<TYPES>>,
2373 ) -> Self {
2374 Self {
2375 encoded_transactions,
2376 metadata,
2377 view_number,
2378 epoch_number,
2379 sequencing_fees,
2380 }
2381 }
2382}
2383
2384#[cfg(test)]
2385mod test {
2386 use super::*;
2387
2388 #[test]
2389 fn test_vid_commitment_display() {
2390 let vc = VidCommitment::V0(VidCommitment0::default());
2391 assert_eq!(
2392 format!("{vc}"),
2393 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2394 );
2395 assert_eq!(
2396 format!("{vc:?}"),
2397 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2398 );
2399
2400 let vc = VidCommitment::V1(VidCommitment1::default());
2401 assert_eq!(
2402 format!("{vc}"),
2403 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2404 );
2405 assert_eq!(
2406 format!("{vc:?}"),
2407 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2408 );
2409
2410 let vc = VidCommitment::V2(VidCommitment2::default());
2411 assert_eq!(
2412 format!("{vc}"),
2413 "AvidmGf2Commit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq"
2414 );
2415 assert_eq!(
2416 format!("{vc:?}"),
2417 "AvidmGf2Commit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq"
2418 );
2419 }
2420}