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 const fn genesis() -> Self {
70 Self($genesis_val)
71 }
72 pub const fn new(n: u64) -> Self {
74 Self(n)
75 }
76 pub const 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)]
148#[cfg_attr(
149 feature = "rlp",
150 derive(alloy_rlp::RlpEncodableWrapper, alloy_rlp::RlpDecodableWrapper)
151)]
152pub struct EpochNumber(u64);
153
154impl Committable for EpochNumber {
155 fn commit(&self) -> Commitment<Self> {
156 let builder = RawCommitmentBuilder::new("Epoch Number Commitment");
157 builder.u64(self.0).finalize()
158 }
159}
160
161impl_u64_wrapper!(EpochNumber, 1u64);
162
163#[derive(
164 Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
165)]
166#[serde(transparent)]
167pub struct BlockNumber(u64);
168
169impl Committable for BlockNumber {
170 fn commit(&self) -> Commitment<Self> {
171 let builder = RawCommitmentBuilder::new("BlockNumber Commitment");
172 builder.u64(self.0).finalize()
173 }
174}
175
176impl_u64_wrapper!(BlockNumber, 0u64);
177
178#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
180#[serde(bound = "TYPES: NodeType")]
181pub struct DaProposal<TYPES: NodeType> {
182 #[serde(with = "crate::arc_bytes")]
184 pub encoded_transactions: Arc<[u8]>,
185 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
187 pub view_number: ViewNumber,
189}
190
191#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
193#[serde(bound = "TYPES: NodeType")]
194pub struct DaProposal2<TYPES: NodeType> {
195 #[serde(with = "crate::arc_bytes")]
197 pub encoded_transactions: Arc<[u8]>,
198 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
200 pub view_number: ViewNumber,
202 pub epoch: Option<EpochNumber>,
204 pub epoch_transition_indicator: EpochTransitionIndicator,
207}
208
209impl<TYPES: NodeType> From<DaProposal<TYPES>> for DaProposal2<TYPES> {
210 fn from(da_proposal: DaProposal<TYPES>) -> Self {
211 Self {
212 encoded_transactions: da_proposal.encoded_transactions,
213 metadata: da_proposal.metadata,
214 view_number: da_proposal.view_number,
215 epoch: None,
216 epoch_transition_indicator: EpochTransitionIndicator::NotInTransition,
217 }
218 }
219}
220
221impl<TYPES: NodeType> From<DaProposal2<TYPES>> for DaProposal<TYPES> {
222 fn from(da_proposal2: DaProposal2<TYPES>) -> Self {
223 Self {
224 encoded_transactions: da_proposal2.encoded_transactions,
225 metadata: da_proposal2.metadata,
226 view_number: da_proposal2.view_number,
227 }
228 }
229}
230
231#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
233pub struct UpgradeProposal {
234 pub upgrade_proposal: UpgradeProposalData,
236 pub view_number: ViewNumber,
238}
239
240pub type VidCommitment0 = crate::vid::advz::ADVZCommitment;
242pub type VidCommitment1 = crate::vid::avidm::AvidMCommitment;
243pub type VidCommitment2 = crate::vid::avidm_gf2::AvidmGf2Commitment;
244
245#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, Ord, PartialOrd)]
247#[serde(
248 try_from = "tagged_base64::TaggedBase64",
249 into = "tagged_base64::TaggedBase64"
250)]
251pub enum VidCommitment {
252 V0(VidCommitment0),
253 V1(VidCommitment1),
254 V2(VidCommitment2),
255}
256
257impl Default for VidCommitment {
258 fn default() -> Self {
259 Self::V0(Default::default())
260 }
261}
262
263impl Display for VidCommitment {
264 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265 std::write!(f, "{}", TaggedBase64::from(self))
266 }
267}
268
269impl Debug for VidCommitment {
270 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
271 std::fmt::Display::fmt(self, f)
272 }
273}
274
275impl From<VidCommitment> for TaggedBase64 {
276 fn from(val: VidCommitment) -> Self {
277 match val {
278 VidCommitment::V0(comm) => comm.into(),
279 VidCommitment::V1(comm) => comm.into(),
280 VidCommitment::V2(comm) => comm.into(),
281 }
282 }
283}
284
285impl From<&VidCommitment> for TaggedBase64 {
286 fn from(val: &VidCommitment) -> Self {
287 match val {
288 VidCommitment::V0(comm) => comm.into(),
289 VidCommitment::V1(comm) => comm.into(),
290 VidCommitment::V2(comm) => comm.into(),
291 }
292 }
293}
294
295impl TryFrom<TaggedBase64> for VidCommitment {
296 type Error = tagged_base64::Tb64Error;
297
298 fn try_from(value: TaggedBase64) -> std::result::Result<Self, Self::Error> {
299 match value.tag().as_str() {
300 "HASH" => VidCommitment0::try_from(value).map(Self::V0),
301 "AvidMCommit" => VidCommitment1::try_from(value).map(Self::V1),
302 "AvidmGf2Commit" => VidCommitment2::try_from(value).map(Self::V2),
303 _ => Err(Tb64Error::InvalidTag),
304 }
305 }
306}
307
308impl<'a> TryFrom<&'a TaggedBase64> for VidCommitment {
309 type Error = tagged_base64::Tb64Error;
310
311 fn try_from(value: &'a TaggedBase64) -> std::result::Result<Self, Self::Error> {
312 match value.tag().as_str() {
313 "HASH" => VidCommitment0::try_from(value).map(Self::V0),
314 "AvidMCommit" => VidCommitment1::try_from(value).map(Self::V1),
315 "AvidmGf2Commit" => VidCommitment2::try_from(value).map(Self::V2),
316 _ => Err(Tb64Error::InvalidTag),
317 }
318 }
319}
320
321impl std::str::FromStr for VidCommitment {
322 type Err = tagged_base64::Tb64Error;
323 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
324 use core::convert::TryFrom;
325 Self::try_from(TaggedBase64::from_str(s)?)
326 .map_err(|_| tagged_base64::Tb64Error::InvalidData)
327 }
328}
329
330impl From<VidCommitment1> for VidCommitment {
338 fn from(comm: VidCommitment1) -> Self {
339 Self::V1(comm)
340 }
341}
342
343impl From<VidCommitment2> for VidCommitment {
344 fn from(comm: VidCommitment2) -> Self {
345 Self::V2(comm)
346 }
347}
348
349impl AsRef<[u8]> for VidCommitment {
350 fn as_ref(&self) -> &[u8] {
351 match self {
352 Self::V0(comm) => comm.as_ref(),
353 Self::V1(comm) => comm.as_ref(),
354 Self::V2(comm) => comm.as_ref(),
355 }
356 }
357}
358
359impl AsRef<[u8; 32]> for VidCommitment {
360 fn as_ref(&self) -> &[u8; 32] {
361 match self {
362 Self::V0(comm) => comm.as_ref().as_ref(),
363 Self::V1(comm) => comm.as_ref(),
364 Self::V2(comm) => comm.as_ref(),
365 }
366 }
367}
368
369#[must_use]
374#[allow(clippy::panic)]
375pub fn vid_commitment(
376 encoded_transactions: &[u8],
377 metadata: &[u8],
378 total_weight: usize,
379 version: Version,
380) -> VidCommitment {
381 if version < EPOCH_VERSION {
382 let encoded_tx_len = encoded_transactions.len();
383 advz_scheme(total_weight)
384 .commit_only(encoded_transactions)
385 .map(VidCommitment::V0)
386 .unwrap_or_else(|err| {
387 panic!(
388 "VidScheme::commit_only \
389 failure:(total_weight,payload_byte_len)=({total_weight},{encoded_tx_len}) \
390 error: {err}"
391 )
392 })
393 } else if version < NEW_PROTOCOL_VERSION {
394 let param = init_avidm_param(total_weight).unwrap();
395 let encoded_tx_len = encoded_transactions.len();
396 AvidMScheme::commit(
397 ¶m,
398 encoded_transactions,
399 ns_table::parse_ns_table(encoded_tx_len, metadata),
400 )
401 .map(VidCommitment::V1)
402 .unwrap()
403 } else {
404 let param = init_avidm_gf2_param(total_weight).unwrap();
405 let encoded_tx_len = encoded_transactions.len();
406 AvidmGf2Scheme::commit(
407 ¶m,
408 encoded_transactions,
409 ns_table::parse_ns_table(encoded_tx_len, metadata),
410 )
411 .map(|(comm, _)| VidCommitment::V2(comm))
412 .unwrap()
413 }
414}
415
416pub type VidCommon0 = crate::vid::advz::ADVZCommon;
418pub type VidCommon1 = crate::vid::avidm::AvidMCommon;
419pub type VidCommon2 = crate::vid::avidm_gf2::AvidmGf2Common;
420
421#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
423pub enum VidCommon {
424 V0(VidCommon0),
425 V1(VidCommon1),
426 V2(VidCommon2),
427}
428
429impl From<VidCommon1> for VidCommon {
430 fn from(comm: VidCommon1) -> Self {
431 Self::V1(comm)
432 }
433}
434
435impl From<VidCommon2> for VidCommon {
436 fn from(comm: VidCommon2) -> Self {
437 Self::V2(comm)
438 }
439}
440
441#[derive(Clone, Copy, Debug, Eq, PartialEq)]
443pub enum VidCommonRef<'a> {
444 V0(&'a VidCommon0),
445 V1(&'a VidCommon1),
446 V2(&'a VidCommon2),
447}
448
449impl<'a> VidCommonRef<'a> {
450 pub fn is_consistent(&self, comm: &VidCommitment) -> bool {
451 match (self, comm) {
452 (Self::V0(common), VidCommitment::V0(comm)) => {
453 ADVZScheme::is_consistent(comm, common).is_ok()
454 },
455 (Self::V1(_), VidCommitment::V1(_)) => true,
459 (Self::V2(common), VidCommitment::V2(comm)) => {
460 AvidmGf2Scheme::is_consistent(comm, common)
461 },
462 _ => false,
463 }
464 }
465}
466
467impl VidCommon {
468 pub fn as_ref(&self) -> VidCommonRef<'_> {
469 match self {
470 Self::V0(c) => VidCommonRef::V0(c),
471 Self::V1(c) => VidCommonRef::V1(c),
472 Self::V2(c) => VidCommonRef::V2(c),
473 }
474 }
475
476 pub fn is_consistent(&self, comm: &VidCommitment) -> bool {
477 self.as_ref().is_consistent(comm)
478 }
479}
480
481pub type VidShare0 = crate::vid::advz::ADVZShare;
483pub type VidShare1 = crate::vid::avidm::AvidMShare;
484pub type VidShare2 = crate::vid::avidm_gf2::AvidmGf2Share;
485
486#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
488pub enum VidShare {
489 V0(VidShare0),
490 V1(VidShare1),
491 V2(VidShare2),
492}
493
494impl From<VidShare1> for VidShare {
502 fn from(share: VidShare1) -> Self {
503 Self::V1(share)
504 }
505}
506
507impl From<VidShare2> for VidShare {
508 fn from(share: VidShare2) -> Self {
509 Self::V2(share)
510 }
511}
512
513pub mod ns_table;
514pub mod vid_disperse;
515
516pub struct VidDisperseAndDuration<TYPES: NodeType> {
518 pub disperse: VidDisperse<TYPES>,
520 pub duration: Duration,
522}
523
524pub type VidDisperse0<TYPES> = vid_disperse::ADVZDisperse<TYPES>;
526pub type VidDisperse1<TYPES> = vid_disperse::AvidMDisperse<TYPES>;
527pub type VidDisperse2<TYPES> = vid_disperse::AvidmGf2Disperse<TYPES>;
528
529#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
535#[serde(bound = "TYPES: NodeType")]
536pub enum VidDisperse<TYPES: NodeType> {
537 V0(VidDisperse0<TYPES>),
539 V1(VidDisperse1<TYPES>),
541 V2(VidDisperse2<TYPES>),
543}
544
545impl<TYPES: NodeType> From<VidDisperse0<TYPES>> for VidDisperse<TYPES> {
546 fn from(disperse: VidDisperse0<TYPES>) -> Self {
547 Self::V0(disperse)
548 }
549}
550
551impl<TYPES: NodeType> From<VidDisperse1<TYPES>> for VidDisperse<TYPES> {
552 fn from(disperse: VidDisperse1<TYPES>) -> Self {
553 Self::V1(disperse)
554 }
555}
556
557impl<TYPES: NodeType> From<VidDisperse2<TYPES>> for VidDisperse<TYPES> {
558 fn from(disperse: VidDisperse2<TYPES>) -> Self {
559 Self::V2(disperse)
560 }
561}
562
563impl<TYPES: NodeType> HasViewNumber for VidDisperse<TYPES> {
564 fn view_number(&self) -> ViewNumber {
565 match self {
566 Self::V0(disperse) => disperse.view_number(),
567 Self::V1(disperse) => disperse.view_number(),
568 Self::V2(disperse) => disperse.view_number(),
569 }
570 }
571}
572
573impl<TYPES: NodeType> HasEpoch for VidDisperse<TYPES> {
574 fn epoch(&self) -> Option<EpochNumber> {
575 match self {
576 Self::V0(disperse) => disperse.epoch(),
577 Self::V1(disperse) => disperse.epoch(),
578 Self::V2(disperse) => disperse.epoch(),
579 }
580 }
581}
582
583impl<TYPES: NodeType> VidDisperse<TYPES> {
584 #[allow(clippy::panic)]
590 pub async fn calculate_vid_disperse(
591 payload: &TYPES::BlockPayload,
592 membership: &EpochMembershipCoordinator<TYPES>,
593 view: ViewNumber,
594 target_epoch: Option<EpochNumber>,
595 data_epoch: Option<EpochNumber>,
596 metadata: &<TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
597 upgrade_lock: &UpgradeLock<TYPES>,
598 ) -> Result<VidDisperseAndDuration<TYPES>> {
599 let epochs_enabled = upgrade_lock.epochs_enabled(view);
600 let upgraded_vid2 = upgrade_lock.upgraded_vid2(view);
601 if upgraded_vid2 {
602 VidDisperse2::calculate_vid_disperse(
603 payload,
604 membership,
605 view,
606 target_epoch,
607 data_epoch,
608 metadata,
609 )
610 .await
611 .map(|(disperse, duration)| VidDisperseAndDuration {
612 disperse: Self::V2(disperse),
613 duration,
614 })
615 } else if epochs_enabled {
616 VidDisperse1::calculate_vid_disperse(
617 payload,
618 membership,
619 view,
620 target_epoch,
621 data_epoch,
622 metadata,
623 )
624 .await
625 .map(|(disperse, duration)| VidDisperseAndDuration {
626 disperse: Self::V1(disperse),
627 duration,
628 })
629 } else {
630 VidDisperse0::calculate_vid_disperse(
631 payload,
632 membership,
633 view,
634 target_epoch,
635 data_epoch,
636 )
637 .await
638 .map(|(disperse, duration)| VidDisperseAndDuration {
639 disperse: Self::V0(disperse),
640 duration,
641 })
642 }
643 }
644
645 pub fn payload_commitment(&self) -> VidCommitment {
647 match self {
648 Self::V0(disperse) => VidCommitment::V0(disperse.payload_commitment),
649 Self::V1(disperse) => disperse.payload_commitment.into(),
650 Self::V2(disperse) => disperse.payload_commitment.into(),
651 }
652 }
653
654 pub fn payload_commitment_ref(&self) -> &[u8] {
656 match self {
657 Self::V0(disperse) => disperse.payload_commitment.as_ref(),
658 Self::V1(disperse) => disperse.payload_commitment.as_ref(),
659 Self::V2(disperse) => disperse.payload_commitment.as_ref(),
660 }
661 }
662
663 pub fn set_view_number(&mut self, view_number: ViewNumber) {
665 match self {
666 Self::V0(share) => share.view_number = view_number,
667 Self::V1(share) => share.view_number = view_number,
668 Self::V2(share) => share.view_number = view_number,
669 }
670 }
671
672 pub fn to_shares(self) -> Vec<VidDisperseShare<TYPES>> {
673 match self {
674 VidDisperse::V0(disperse) => disperse
675 .to_shares()
676 .into_iter()
677 .map(|share| VidDisperseShare::V0(share))
678 .collect(),
679 VidDisperse::V1(disperse) => disperse
680 .to_shares()
681 .into_iter()
682 .map(|share| VidDisperseShare::V1(share))
683 .collect(),
684 VidDisperse::V2(disperse) => disperse
685 .to_shares()
686 .into_iter()
687 .map(|share| VidDisperseShare::V2(share))
688 .collect(),
689 }
690 }
691
692 pub fn to_share_proposals(
694 proposal: Proposal<TYPES, Self>,
695 ) -> Vec<Proposal<TYPES, VidDisperseShare<TYPES>>> {
696 match proposal.data {
697 VidDisperse::V0(disperse) => disperse
698 .to_share_proposals(&proposal.signature)
699 .into_iter()
700 .map(|proposal| convert_proposal(proposal))
701 .collect(),
702 VidDisperse::V1(disperse) => disperse
703 .to_share_proposals(&proposal.signature)
704 .into_iter()
705 .map(|proposal| convert_proposal(proposal))
706 .collect(),
707 VidDisperse::V2(disperse) => disperse
708 .to_share_proposals(&proposal.signature)
709 .into_iter()
710 .map(|proposal| convert_proposal(proposal))
711 .collect(),
712 }
713 }
714}
715
716pub type VidDisperseShare0<TYPES> = vid_disperse::ADVZDisperseShare<TYPES>;
718pub type VidDisperseShare1<TYPES> = vid_disperse::AvidMDisperseShare<TYPES>;
719pub type VidDisperseShare2<TYPES> = vid_disperse::AvidmGf2DisperseShare<TYPES>;
720
721#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
723#[serde(bound = "TYPES: NodeType")]
724pub enum VidDisperseShare<TYPES: NodeType> {
725 V0(VidDisperseShare0<TYPES>),
727 V1(VidDisperseShare1<TYPES>),
729 V2(VidDisperseShare2<TYPES>),
731}
732
733impl<TYPES: NodeType> From<VidDisperseShare0<TYPES>> for VidDisperseShare<TYPES> {
734 fn from(share: VidDisperseShare0<TYPES>) -> Self {
735 Self::V0(share)
736 }
737}
738
739impl<TYPES: NodeType> From<VidDisperseShare1<TYPES>> for VidDisperseShare<TYPES> {
740 fn from(share: VidDisperseShare1<TYPES>) -> Self {
741 Self::V1(share)
742 }
743}
744
745impl<TYPES: NodeType> From<VidDisperseShare2<TYPES>> for VidDisperseShare<TYPES> {
746 fn from(share: VidDisperseShare2<TYPES>) -> Self {
747 Self::V2(share)
748 }
749}
750
751impl<TYPES: NodeType> VidDisperseShare<TYPES> {
752 pub fn to_proposal(
754 self,
755 private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
756 ) -> Option<Proposal<TYPES, Self>> {
757 let payload_commitment_ref: &[u8] = match &self {
758 Self::V0(share) => share.payload_commitment.as_ref(),
759 Self::V1(share) => share.payload_commitment.as_ref(),
760 Self::V2(share) => share.payload_commitment.as_ref(),
761 };
762 let Ok(signature) = TYPES::SignatureKey::sign(private_key, payload_commitment_ref) else {
763 tracing::error!("VID: failed to sign dispersal share payload");
764 return None;
765 };
766 Some(Proposal {
767 signature,
768 _pd: PhantomData,
769 data: self,
770 })
771 }
772
773 pub fn recipient_key(&self) -> &TYPES::SignatureKey {
775 match self {
776 Self::V0(share) => &share.recipient_key,
777 Self::V1(share) => &share.recipient_key,
778 Self::V2(share) => &share.recipient_key,
779 }
780 }
781
782 pub fn payload_byte_len(&self) -> u32 {
784 match self {
785 Self::V0(share) => share.payload_byte_len(),
786 Self::V1(share) => share.payload_byte_len(),
787 Self::V2(share) => share.payload_byte_len(),
788 }
789 }
790
791 pub fn payload_commitment_ref(&self) -> &[u8] {
793 match self {
794 Self::V0(share) => share.payload_commitment.as_ref(),
795 Self::V1(share) => share.payload_commitment.as_ref(),
796 Self::V2(share) => share.payload_commitment.as_ref(),
797 }
798 }
799
800 pub fn payload_commitment(&self) -> VidCommitment {
802 match self {
803 Self::V0(share) => VidCommitment::V0(share.payload_commitment),
804 Self::V1(share) => share.payload_commitment.into(),
805 Self::V2(share) => share.payload_commitment.into(),
806 }
807 }
808
809 pub fn target_epoch(&self) -> Option<EpochNumber> {
811 match self {
812 Self::V0(_) => None,
813 Self::V1(share) => share.target_epoch,
814 Self::V2(share) => share.target_epoch,
815 }
816 }
817
818 pub fn common(&self) -> VidCommonRef<'_> {
820 match self {
821 Self::V0(share) => VidCommonRef::V0(&share.common),
822 Self::V1(share) => VidCommonRef::V1(&share.common),
823 Self::V2(share) => VidCommonRef::V2(&share.common),
824 }
825 }
826
827 pub fn is_consistent(&self) -> bool {
829 match self {
830 Self::V0(share) => share.is_consistent(),
831 Self::V1(share) => share.is_consistent(),
832 Self::V2(share) => share.is_consistent(),
833 }
834 }
835
836 pub fn verify_with_verified_common(&self) -> bool {
839 match self {
840 Self::V0(share) => share.verify_with_verified_common(),
841 Self::V1(share) => share.verify_with_verified_common(),
842 Self::V2(share) => share.verify_with_verified_common(),
843 }
844 }
845
846 pub fn verify(&self, total_nodes: usize) -> bool {
848 match self {
849 Self::V0(share) => share.verify(total_nodes),
850 Self::V1(share) => share.verify(total_nodes),
851 Self::V2(share) => share.verify(total_nodes),
852 }
853 }
854
855 pub fn set_view_number(&mut self, view_number: ViewNumber) {
857 match self {
858 Self::V0(share) => share.view_number = view_number,
859 Self::V1(share) => share.view_number = view_number,
860 Self::V2(share) => share.view_number = view_number,
861 }
862 }
863}
864
865impl<TYPES: NodeType> HasViewNumber for VidDisperseShare<TYPES> {
866 fn view_number(&self) -> ViewNumber {
867 match self {
868 Self::V0(disperse) => disperse.view_number(),
869 Self::V1(disperse) => disperse.view_number(),
870 Self::V2(disperse) => disperse.view_number(),
871 }
872 }
873}
874
875impl<TYPES: NodeType> HasEpoch for VidDisperseShare<TYPES> {
876 fn epoch(&self) -> Option<EpochNumber> {
877 match self {
878 Self::V0(_) => None,
879 Self::V1(share) => share.epoch(),
880 Self::V2(share) => share.epoch(),
881 }
882 }
883}
884
885#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
888#[serde(bound(deserialize = ""))]
889pub enum ViewChangeEvidence<TYPES: NodeType> {
890 Timeout(TimeoutCertificate<TYPES>),
892 ViewSync(ViewSyncFinalizeCertificate<TYPES>),
894}
895
896impl<TYPES: NodeType> ViewChangeEvidence<TYPES> {
897 pub fn is_valid_for_view(&self, view: &ViewNumber) -> bool {
899 match self {
900 ViewChangeEvidence::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
901 ViewChangeEvidence::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
902 }
903 }
904
905 pub fn to_evidence2(self) -> ViewChangeEvidence2<TYPES> {
907 match self {
908 ViewChangeEvidence::Timeout(timeout_cert) => {
909 ViewChangeEvidence2::Timeout(timeout_cert.to_tc2())
910 },
911 ViewChangeEvidence::ViewSync(view_sync_cert) => {
912 ViewChangeEvidence2::ViewSync(view_sync_cert.to_vsc2())
913 },
914 }
915 }
916}
917
918#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
921#[serde(bound(deserialize = ""))]
922pub enum ViewChangeEvidence2<TYPES: NodeType> {
923 Timeout(TimeoutCertificate2<TYPES>),
925 ViewSync(ViewSyncFinalizeCertificate2<TYPES>),
927}
928
929impl<TYPES: NodeType> ViewChangeEvidence2<TYPES> {
930 pub fn is_valid_for_view(&self, view: &ViewNumber) -> bool {
932 match self {
933 ViewChangeEvidence2::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
934 ViewChangeEvidence2::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
935 }
936 }
937
938 pub fn to_evidence(self) -> ViewChangeEvidence<TYPES> {
940 match self {
941 ViewChangeEvidence2::Timeout(timeout_cert) => {
942 ViewChangeEvidence::Timeout(timeout_cert.to_tc())
943 },
944 ViewChangeEvidence2::ViewSync(view_sync_cert) => {
945 ViewChangeEvidence::ViewSync(view_sync_cert.to_vsc())
946 },
947 }
948 }
949}
950
951#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
953#[serde(bound(deserialize = ""))]
954pub struct QuorumProposal<TYPES: NodeType> {
955 pub block_header: TYPES::BlockHeader,
957
958 pub view_number: ViewNumber,
960
961 pub justify_qc: QuorumCertificate<TYPES>,
963
964 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
966
967 pub proposal_certificate: Option<ViewChangeEvidence<TYPES>>,
972}
973
974#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
976#[serde(bound(deserialize = ""))]
977pub struct QuorumProposal2<TYPES: NodeType> {
978 pub block_header: TYPES::BlockHeader,
980
981 pub view_number: ViewNumber,
983
984 pub epoch: Option<EpochNumber>,
986
987 pub justify_qc: QuorumCertificate2<TYPES>,
989
990 pub next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
992
993 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
995
996 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
998
999 #[serde(with = "serde_bytes")]
1004 pub next_drb_result: Option<DrbResult>,
1005
1006 pub state_cert: Option<LightClientStateUpdateCertificateV2<TYPES>>,
1009}
1010
1011impl<TYPES: NodeType> QuorumProposal2<TYPES> {
1012 pub async fn validate_certs(
1013 &self,
1014 membership: EpochMembershipCoordinator<TYPES>,
1015 upgrade_lock: &UpgradeLock<TYPES>,
1016 ) -> Result<()> {
1017 let stake_table = membership.membership_for_epoch(self.epoch)?;
1018 let entries = StakeTableEntries::from_iter(stake_table.stake_table()).0;
1019 let threshold = stake_table.success_threshold();
1020 self.justify_qc
1021 .is_valid_cert(&entries, threshold, upgrade_lock)?;
1022 let view_change_view = match &self.view_change_evidence {
1023 Some(ViewChangeEvidence2::Timeout(timeout_cert)) => {
1024 timeout_cert.is_valid_cert(&entries, threshold, upgrade_lock)?;
1025 Some(timeout_cert.view_number() + 1)
1026 },
1027 Some(ViewChangeEvidence2::ViewSync(view_sync_cert)) => {
1028 view_sync_cert.is_valid_cert(&entries, threshold, upgrade_lock)?;
1029 Some(view_sync_cert.view_number())
1030 },
1031 _ => None,
1032 };
1033 if !(self.justify_qc.view_number() + 1 == self.view_number()
1034 || view_change_view == Some(self.view_number()))
1035 {
1036 bail!("Invalid view change evidence");
1037 }
1038 Ok(())
1039 }
1040 pub fn is_validate_block_height(&self) -> bool {
1041 self.justify_qc
1042 .data()
1043 .block_number
1044 .is_some_and(|bn| bn + 1 == self.block_header.block_number())
1045 }
1046}
1047
1048#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
1057#[serde(bound(deserialize = ""))]
1058pub struct QuorumProposal2Legacy<TYPES: NodeType> {
1059 pub block_header: TYPES::BlockHeader,
1061
1062 pub view_number: ViewNumber,
1064
1065 pub epoch: Option<EpochNumber>,
1067
1068 pub justify_qc: QuorumCertificate2<TYPES>,
1070
1071 pub next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1073
1074 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1076
1077 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
1079
1080 #[serde(with = "serde_bytes")]
1085 pub next_drb_result: Option<DrbResult>,
1086
1087 pub state_cert: Option<LightClientStateUpdateCertificateV1<TYPES>>,
1091}
1092
1093impl<TYPES: NodeType> From<QuorumProposal2Legacy<TYPES>> for QuorumProposal2<TYPES> {
1094 fn from(quorum_proposal2: QuorumProposal2Legacy<TYPES>) -> Self {
1095 Self {
1096 block_header: quorum_proposal2.block_header,
1097 view_number: quorum_proposal2.view_number,
1098 epoch: quorum_proposal2.epoch,
1099 justify_qc: quorum_proposal2.justify_qc,
1100 next_epoch_justify_qc: quorum_proposal2.next_epoch_justify_qc,
1101 upgrade_certificate: quorum_proposal2.upgrade_certificate,
1102 view_change_evidence: quorum_proposal2.view_change_evidence,
1103 next_drb_result: quorum_proposal2.next_drb_result,
1104 state_cert: quorum_proposal2.state_cert.map(Into::into),
1105 }
1106 }
1107}
1108
1109impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposal2Legacy<TYPES> {
1110 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1111 Self {
1112 block_header: quorum_proposal2.block_header,
1113 view_number: quorum_proposal2.view_number,
1114 epoch: quorum_proposal2.epoch,
1115 justify_qc: quorum_proposal2.justify_qc,
1116 next_epoch_justify_qc: quorum_proposal2.next_epoch_justify_qc,
1117 upgrade_certificate: quorum_proposal2.upgrade_certificate,
1118 view_change_evidence: quorum_proposal2.view_change_evidence,
1119 next_drb_result: quorum_proposal2.next_drb_result,
1120 state_cert: quorum_proposal2.state_cert.map(Into::into),
1121 }
1122 }
1123}
1124
1125#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
1131#[serde(bound(deserialize = ""))]
1132pub struct QuorumProposalWrapperLegacy<TYPES: NodeType> {
1133 pub proposal: QuorumProposal2Legacy<TYPES>,
1135}
1136
1137#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
1139#[serde(bound(deserialize = ""))]
1140pub struct QuorumProposalWrapper<TYPES: NodeType> {
1141 pub proposal: QuorumProposal2<TYPES>,
1143}
1144
1145impl<TYPES: NodeType> From<QuorumProposalWrapperLegacy<TYPES>> for QuorumProposalWrapper<TYPES> {
1146 fn from(v3: QuorumProposalWrapperLegacy<TYPES>) -> Self {
1147 Self {
1148 proposal: v3.proposal.into(),
1149 }
1150 }
1151}
1152
1153impl<TYPES: NodeType> QuorumProposal2<TYPES> {
1154 pub async fn validate_epoch(
1158 &self,
1159 upgrade_lock: &UpgradeLock<TYPES>,
1160 epoch_height: u64,
1161 ) -> Result<()> {
1162 let calculated_epoch = option_epoch_from_block_number(
1163 upgrade_lock.epochs_enabled(self.view_number()),
1164 self.block_header.block_number(),
1165 epoch_height,
1166 );
1167 ensure!(
1168 calculated_epoch == self.epoch(),
1169 "Quorum proposal invalid: inconsistent epoch."
1170 );
1171 Ok(())
1172 }
1173}
1174
1175impl<TYPES: NodeType> QuorumProposalWrapper<TYPES> {
1176 pub fn block_header(&self) -> &TYPES::BlockHeader {
1178 &self.proposal.block_header
1179 }
1180
1181 pub fn view_number(&self) -> ViewNumber {
1183 self.proposal.view_number
1184 }
1185
1186 pub fn justify_qc(&self) -> &QuorumCertificate2<TYPES> {
1188 &self.proposal.justify_qc
1189 }
1190
1191 pub fn next_epoch_justify_qc(&self) -> &Option<NextEpochQuorumCertificate2<TYPES>> {
1193 &self.proposal.next_epoch_justify_qc
1194 }
1195
1196 pub fn upgrade_certificate(&self) -> &Option<UpgradeCertificate<TYPES>> {
1198 &self.proposal.upgrade_certificate
1199 }
1200
1201 pub fn view_change_evidence(&self) -> &Option<ViewChangeEvidence2<TYPES>> {
1203 &self.proposal.view_change_evidence
1204 }
1205
1206 pub fn next_drb_result(&self) -> &Option<DrbResult> {
1208 &self.proposal.next_drb_result
1209 }
1210
1211 pub async fn validate_epoch(
1215 &self,
1216 upgrade_lock: &UpgradeLock<TYPES>,
1217 epoch_height: u64,
1218 ) -> Result<()> {
1219 self.proposal
1220 .validate_epoch(upgrade_lock, epoch_height)
1221 .await
1222 }
1223
1224 pub fn state_cert(&self) -> &Option<LightClientStateUpdateCertificateV2<TYPES>> {
1226 &self.proposal.state_cert
1227 }
1228}
1229
1230impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposalWrapper<TYPES> {
1231 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
1232 Self {
1233 proposal: quorum_proposal.into(),
1234 }
1235 }
1236}
1237
1238impl<TYPES: NodeType> From<QuorumProposal2Legacy<TYPES>> for QuorumProposalWrapper<TYPES> {
1239 fn from(quorum_proposal: QuorumProposal2Legacy<TYPES>) -> Self {
1240 Self {
1241 proposal: quorum_proposal.into(),
1242 }
1243 }
1244}
1245
1246impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposalWrapper<TYPES> {
1247 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1248 Self {
1249 proposal: quorum_proposal2,
1250 }
1251 }
1252}
1253
1254impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal<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 QuorumProposal2Legacy<TYPES> {
1261 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1262 quorum_proposal_wrapper.proposal.into()
1263 }
1264}
1265
1266impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal2<TYPES> {
1267 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1268 quorum_proposal_wrapper.proposal
1269 }
1270}
1271
1272impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposal2<TYPES> {
1273 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
1274 Self {
1275 block_header: quorum_proposal.block_header,
1276 view_number: quorum_proposal.view_number,
1277 epoch: None,
1278 justify_qc: quorum_proposal.justify_qc.to_qc2(),
1279 next_epoch_justify_qc: None,
1280 upgrade_certificate: quorum_proposal.upgrade_certificate,
1281 view_change_evidence: quorum_proposal
1282 .proposal_certificate
1283 .map(ViewChangeEvidence::to_evidence2),
1284 next_drb_result: None,
1285 state_cert: None,
1286 }
1287 }
1288}
1289
1290impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposal<TYPES> {
1291 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1292 Self {
1293 block_header: quorum_proposal2.block_header,
1294 view_number: quorum_proposal2.view_number,
1295 justify_qc: quorum_proposal2.justify_qc.to_qc(),
1296 upgrade_certificate: quorum_proposal2.upgrade_certificate,
1297 proposal_certificate: quorum_proposal2
1298 .view_change_evidence
1299 .map(ViewChangeEvidence2::to_evidence),
1300 }
1301 }
1302}
1303
1304impl<TYPES: NodeType> From<Leaf<TYPES>> for Leaf2<TYPES> {
1305 fn from(leaf: Leaf<TYPES>) -> Self {
1306 let bytes: [u8; 32] = leaf.parent_commitment.into();
1307
1308 Self {
1309 view_number: leaf.view_number,
1310 justify_qc: leaf.justify_qc.to_qc2(),
1311 next_epoch_justify_qc: None,
1312 parent_commitment: Commitment::from_raw(bytes),
1313 block_header: leaf.block_header,
1314 upgrade_certificate: leaf.upgrade_certificate,
1315 block_payload: leaf.block_payload,
1316 view_change_evidence: None,
1317 next_drb_result: None,
1318 with_epoch: false,
1319 }
1320 }
1321}
1322
1323impl<TYPES: NodeType> HasViewNumber for DaProposal<TYPES> {
1324 fn view_number(&self) -> ViewNumber {
1325 self.view_number
1326 }
1327}
1328
1329impl<TYPES: NodeType> HasViewNumber for DaProposal2<TYPES> {
1330 fn view_number(&self) -> ViewNumber {
1331 self.view_number
1332 }
1333}
1334
1335impl<TYPES: NodeType> HasViewNumber for QuorumProposal<TYPES> {
1336 fn view_number(&self) -> ViewNumber {
1337 self.view_number
1338 }
1339}
1340
1341impl<TYPES: NodeType> HasViewNumber for QuorumProposal2<TYPES> {
1342 fn view_number(&self) -> ViewNumber {
1343 self.view_number
1344 }
1345}
1346
1347impl<TYPES: NodeType> HasViewNumber for QuorumProposal2Legacy<TYPES> {
1348 fn view_number(&self) -> ViewNumber {
1349 self.view_number
1350 }
1351}
1352
1353impl<TYPES: NodeType> HasViewNumber for QuorumProposalWrapper<TYPES> {
1354 fn view_number(&self) -> ViewNumber {
1355 self.proposal.view_number
1356 }
1357}
1358
1359impl<TYPES: NodeType> HasViewNumber for QuorumProposalWrapperLegacy<TYPES> {
1360 fn view_number(&self) -> ViewNumber {
1361 self.proposal.view_number
1362 }
1363}
1364
1365impl HasViewNumber for UpgradeProposal {
1366 fn view_number(&self) -> ViewNumber {
1367 self.view_number
1368 }
1369}
1370
1371impl<NODE: NodeType> HasEpoch for QuorumProposal2<NODE> {
1372 fn epoch(&self) -> Option<EpochNumber> {
1373 self.epoch
1374 }
1375}
1376
1377impl<NODE: NodeType> HasEpoch for DaProposal2<NODE> {
1378 fn epoch(&self) -> Option<EpochNumber> {
1379 self.epoch
1380 }
1381}
1382
1383impl<NODE: NodeType> HasEpoch for QuorumProposal2Legacy<NODE> {
1384 fn epoch(&self) -> Option<EpochNumber> {
1385 self.epoch
1386 }
1387}
1388
1389impl HasEpoch for UpgradeProposal {
1390 fn epoch(&self) -> Option<EpochNumber> {
1391 None
1392 }
1393}
1394
1395impl<NODE: NodeType> HasEpoch for QuorumProposal<NODE> {
1396 fn epoch(&self) -> Option<EpochNumber> {
1397 None
1398 }
1399}
1400
1401impl<NODE: NodeType> HasEpoch for DaProposal<NODE> {
1402 fn epoch(&self) -> Option<EpochNumber> {
1403 None
1404 }
1405}
1406
1407impl<NODE: NodeType> HasEpoch for QuorumProposalWrapper<NODE> {
1408 #[allow(clippy::panic)]
1410 fn epoch(&self) -> Option<EpochNumber> {
1411 self.proposal.epoch()
1412 }
1413}
1414
1415impl<TYPES: NodeType> HasEpoch for QuorumProposalWrapperLegacy<TYPES> {
1416 #[allow(clippy::panic)]
1418 fn epoch(&self) -> Option<EpochNumber> {
1419 self.proposal.epoch()
1420 }
1421}
1422
1423#[derive(Error, Debug, Serialize, Deserialize)]
1425pub enum BlockError {
1426 #[error("Invalid block header: {0}")]
1428 InvalidBlockHeader(String),
1429
1430 #[error("Inconsistent payload commitment")]
1432 InconsistentPayloadCommitment,
1433
1434 #[error("Failed to apply block header: {0}")]
1436 FailedHeaderApply(String),
1437}
1438
1439pub trait TestableLeaf {
1441 type NodeType: NodeType;
1443
1444 fn create_random_transaction(
1446 &self,
1447 rng: &mut dyn rand::RngCore,
1448 padding: u64,
1449 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction;
1450}
1451
1452#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1456#[serde(bound(deserialize = ""))]
1457pub struct Leaf<TYPES: NodeType> {
1458 view_number: ViewNumber,
1460
1461 justify_qc: QuorumCertificate<TYPES>,
1463
1464 parent_commitment: Commitment<Self>,
1467
1468 block_header: TYPES::BlockHeader,
1470
1471 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1473
1474 block_payload: Option<TYPES::BlockPayload>,
1478}
1479
1480#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1483#[serde(bound(deserialize = ""))]
1484pub struct Leaf2<TYPES: NodeType> {
1485 view_number: ViewNumber,
1487
1488 justify_qc: QuorumCertificate2<TYPES>,
1490
1491 next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1493
1494 parent_commitment: Commitment<Self>,
1497
1498 block_header: TYPES::BlockHeader,
1500
1501 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1503
1504 block_payload: Option<TYPES::BlockPayload>,
1508
1509 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
1511
1512 #[serde(with = "serde_bytes")]
1517 pub next_drb_result: Option<DrbResult>,
1518
1519 pub with_epoch: bool,
1521}
1522
1523impl<TYPES: NodeType> Leaf2<TYPES> {
1524 #[must_use]
1531 pub async fn genesis(
1532 validated_state: &TYPES::ValidatedState,
1533 instance_state: &TYPES::InstanceState,
1534 version: Version,
1535 ) -> Self {
1536 let epoch = genesis_epoch_from_version(version);
1537
1538 let (payload, metadata) =
1539 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1540 .await
1541 .unwrap();
1542
1543 let genesis_view = ViewNumber::genesis();
1544
1545 let block_header =
1546 TYPES::BlockHeader::genesis(instance_state, payload.clone(), &metadata, version);
1547
1548 let block_number = if version < EPOCH_VERSION {
1549 None
1550 } else {
1551 Some(0u64)
1552 };
1553
1554 let null_quorum_data = QuorumData2 {
1555 leaf_commit: Commitment::<Leaf2<TYPES>>::default_commitment_no_preimage(),
1556 epoch,
1557 block_number,
1558 };
1559
1560 let justify_qc = QuorumCertificate2::new(
1561 null_quorum_data,
1562 null_quorum_data.commit(),
1563 genesis_view,
1564 None,
1565 PhantomData,
1566 );
1567
1568 Self {
1569 view_number: genesis_view,
1570 justify_qc,
1571 next_epoch_justify_qc: None,
1572 parent_commitment: null_quorum_data.leaf_commit,
1573 upgrade_certificate: None,
1574 block_header: block_header.clone(),
1575 block_payload: Some(payload),
1576 view_change_evidence: None,
1577 next_drb_result: None,
1578 with_epoch: epoch.is_some(),
1579 }
1580 }
1581 pub fn view_number(&self) -> ViewNumber {
1583 self.view_number
1584 }
1585 pub fn epoch(&self, epoch_height: u64) -> Option<EpochNumber> {
1587 option_epoch_from_block_number(
1588 self.with_epoch,
1589 self.block_header.block_number(),
1590 epoch_height,
1591 )
1592 }
1593 pub fn height(&self) -> u64 {
1597 self.block_header.block_number()
1598 }
1599 pub fn justify_qc(&self) -> QuorumCertificate2<TYPES> {
1601 self.justify_qc.clone()
1602 }
1603 pub fn next_epoch_justify_qc(&self) -> Option<NextEpochQuorumCertificate2<TYPES>> {
1607 self.next_epoch_justify_qc.clone()
1608 }
1609 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1611 self.upgrade_certificate.clone()
1612 }
1613 pub fn parent_commitment(&self) -> Commitment<Self> {
1615 self.parent_commitment
1616 }
1617 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1619 &self.block_header
1620 }
1621
1622 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1624 &mut self.block_header
1625 }
1626 pub fn fill_block_payload(
1633 &mut self,
1634 block_payload: TYPES::BlockPayload,
1635 num_storage_nodes: usize,
1636 version: Version,
1637 ) -> std::result::Result<(), BlockError> {
1638 let encoded_txns = block_payload.encode();
1639 let commitment = vid_commitment(
1640 &encoded_txns,
1641 &self.block_header.metadata().encode(),
1642 num_storage_nodes,
1643 version,
1644 );
1645 if commitment != self.block_header.payload_commitment() {
1646 return Err(BlockError::InconsistentPayloadCommitment);
1647 }
1648 self.block_payload = Some(block_payload);
1649 Ok(())
1650 }
1651
1652 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
1654 self.block_payload.take()
1655 }
1656
1657 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
1660 self.block_payload = Some(block_payload);
1661 }
1662
1663 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
1665 self.block_payload.clone()
1666 }
1667
1668 pub fn block_payload_ref(&self) -> Option<&TYPES::BlockPayload> {
1669 self.block_payload.as_ref()
1670 }
1671
1672 pub fn payload_commitment(&self) -> VidCommitment {
1674 self.block_header().payload_commitment()
1675 }
1676
1677 pub fn extends_upgrade(&self, parent: &Self, upgrade: &UpgradeLock<TYPES>) -> Result<()> {
1685 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
1686 (None | Some(_), None) => {},
1690 (None, Some(parent_cert)) => {
1694 let decided_upgrade_certificate_read = upgrade.decided_upgrade_cert();
1695 ensure!(
1696 self.view_number() > parent_cert.data.new_version_first_view
1697 || (self.view_number() > parent_cert.data.decide_by
1698 && decided_upgrade_certificate_read.is_none()),
1699 "The new leaf is missing an upgrade certificate that was present in its \
1700 parent, and should still be live."
1701 );
1702 },
1703 (Some(cert), Some(parent_cert)) => {
1707 ensure!(
1708 cert == parent_cert,
1709 "The new leaf does not extend the parent leaf, because it has attached a \
1710 different upgrade certificate."
1711 );
1712 },
1713 }
1714
1715 Ok(())
1719 }
1720
1721 pub fn to_leaf_unsafe(self) -> Leaf<TYPES> {
1723 let bytes: [u8; 32] = self.parent_commitment.into();
1724
1725 Leaf {
1726 view_number: self.view_number,
1727 justify_qc: self.justify_qc.to_qc(),
1728 parent_commitment: Commitment::from_raw(bytes),
1729 block_header: self.block_header,
1730 upgrade_certificate: self.upgrade_certificate,
1731 block_payload: self.block_payload,
1732 }
1733 }
1734}
1735
1736impl<TYPES: NodeType> Committable for Leaf2<TYPES> {
1737 fn commit(&self) -> committable::Commitment<Self> {
1738 let Leaf2 {
1739 view_number,
1740 justify_qc,
1741 next_epoch_justify_qc,
1742 parent_commitment,
1743 block_header,
1744 upgrade_certificate,
1745 block_payload: _,
1746 view_change_evidence,
1747 next_drb_result,
1748 with_epoch,
1749 } = self;
1750
1751 let mut cb = RawCommitmentBuilder::new("leaf commitment")
1752 .u64_field("view number", **view_number)
1753 .field("parent leaf commitment", *parent_commitment)
1754 .field("block header", block_header.commit())
1755 .field("justify qc", justify_qc.commit())
1756 .optional("upgrade certificate", upgrade_certificate);
1757
1758 if *with_epoch {
1759 cb = cb
1760 .constant_str("with_epoch")
1761 .optional("next_epoch_justify_qc", next_epoch_justify_qc);
1762
1763 if let Some(next_drb_result) = next_drb_result {
1764 cb = cb
1765 .constant_str("next_drb_result")
1766 .fixed_size_bytes(next_drb_result);
1767 }
1768
1769 match view_change_evidence {
1770 Some(ViewChangeEvidence2::Timeout(cert)) => {
1771 cb = cb.field("timeout cert", cert.commit());
1772 },
1773 Some(ViewChangeEvidence2::ViewSync(cert)) => {
1774 cb = cb.field("viewsync cert", cert.commit());
1775 },
1776 None => {},
1777 }
1778 }
1779
1780 cb.finalize()
1781 }
1782}
1783
1784impl<TYPES: NodeType> Leaf<TYPES> {
1785 pub fn commit(&self, _upgrade_lock: &UpgradeLock<TYPES>) -> Commitment<Self> {
1788 <Self as Committable>::commit(self)
1789 }
1790}
1791
1792impl<TYPES: NodeType> PartialEq for Leaf<TYPES> {
1793 fn eq(&self, other: &Self) -> bool {
1794 self.view_number == other.view_number
1795 && self.justify_qc == other.justify_qc
1796 && self.parent_commitment == other.parent_commitment
1797 && self.block_header == other.block_header
1798 }
1799}
1800
1801impl<TYPES: NodeType> PartialEq for Leaf2<TYPES> {
1802 fn eq(&self, other: &Self) -> bool {
1803 let Leaf2 {
1804 view_number,
1805 justify_qc,
1806 next_epoch_justify_qc,
1807 parent_commitment,
1808 block_header,
1809 upgrade_certificate,
1810 block_payload: _,
1811 view_change_evidence,
1812 next_drb_result,
1813 with_epoch,
1814 } = self;
1815
1816 *view_number == other.view_number
1817 && *justify_qc == other.justify_qc
1818 && *next_epoch_justify_qc == other.next_epoch_justify_qc
1819 && *parent_commitment == other.parent_commitment
1820 && *block_header == other.block_header
1821 && *upgrade_certificate == other.upgrade_certificate
1822 && *view_change_evidence == other.view_change_evidence
1823 && *next_drb_result == other.next_drb_result
1824 && *with_epoch == other.with_epoch
1825 }
1826}
1827
1828impl<TYPES: NodeType> Hash for Leaf<TYPES> {
1829 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
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> Hash for Leaf2<TYPES> {
1838 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1839 self.commit().hash(state);
1840 self.view_number.hash(state);
1841 self.justify_qc.hash(state);
1842 self.parent_commitment.hash(state);
1843 self.block_header.hash(state);
1844 }
1845}
1846
1847impl<TYPES: NodeType> Display for Leaf<TYPES> {
1848 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1849 write!(
1850 f,
1851 "view: {:?}, height: {:?}, justify: {}",
1852 self.view_number,
1853 self.height(),
1854 self.justify_qc
1855 )
1856 }
1857}
1858
1859impl<TYPES: NodeType> QuorumCertificate<TYPES> {
1860 #[must_use]
1862 pub async fn genesis(
1863 validated_state: &TYPES::ValidatedState,
1864 instance_state: &TYPES::InstanceState,
1865 upgrade: Upgrade,
1866 ) -> Self {
1867 let upgrade_lock = UpgradeLock::<TYPES>::new(upgrade);
1869
1870 let genesis_view = ViewNumber::genesis();
1871
1872 let data = QuorumData {
1873 leaf_commit: Leaf::genesis(validated_state, instance_state, upgrade.base)
1874 .await
1875 .commit(&upgrade_lock),
1876 };
1877
1878 let versioned_data =
1879 VersionedVoteData::<_, _>::new_infallible(data.clone(), genesis_view, &upgrade_lock);
1880
1881 let bytes: [u8; 32] = versioned_data.commit().into();
1882
1883 Self::new(
1884 data,
1885 Commitment::from_raw(bytes),
1886 genesis_view,
1887 None,
1888 PhantomData,
1889 )
1890 }
1891}
1892
1893impl<TYPES: NodeType> QuorumCertificate2<TYPES> {
1894 #[must_use]
1896 pub async fn genesis(
1897 validated_state: &TYPES::ValidatedState,
1898 instance_state: &TYPES::InstanceState,
1899 upgrade: Upgrade,
1900 ) -> Self {
1901 let upgrade_lock = UpgradeLock::<TYPES>::new(upgrade);
1903
1904 let genesis_view = ViewNumber::genesis();
1905
1906 let genesis_leaf = Leaf2::genesis(validated_state, instance_state, upgrade.base).await;
1907 let block_number = if upgrade_lock.epochs_enabled(genesis_view) {
1908 Some(genesis_leaf.height())
1909 } else {
1910 None
1911 };
1912 let data = QuorumData2 {
1913 leaf_commit: genesis_leaf.commit(),
1914 epoch: genesis_epoch_from_version(upgrade.base), block_number,
1916 };
1917
1918 let versioned_data =
1919 VersionedVoteData::<_, _>::new_infallible(data, genesis_view, &upgrade_lock);
1920
1921 let bytes: [u8; 32] = versioned_data.commit().into();
1922
1923 Self::new(
1924 data,
1925 Commitment::from_raw(bytes),
1926 genesis_view,
1927 None,
1928 PhantomData,
1929 )
1930 }
1931}
1932
1933impl<TYPES: NodeType> Leaf<TYPES> {
1934 #[must_use]
1941 pub async fn genesis(
1942 validated_state: &TYPES::ValidatedState,
1943 instance_state: &TYPES::InstanceState,
1944 version: Version,
1945 ) -> Self {
1946 let (payload, metadata) =
1947 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1948 .await
1949 .unwrap();
1950
1951 let genesis_view = ViewNumber::genesis();
1952
1953 let block_header =
1954 TYPES::BlockHeader::genesis(instance_state, payload.clone(), &metadata, version);
1955
1956 let null_quorum_data = QuorumData {
1957 leaf_commit: Commitment::<Leaf<TYPES>>::default_commitment_no_preimage(),
1958 };
1959
1960 let justify_qc = QuorumCertificate::new(
1961 null_quorum_data.clone(),
1962 null_quorum_data.commit(),
1963 genesis_view,
1964 None,
1965 PhantomData,
1966 );
1967
1968 Self {
1969 view_number: genesis_view,
1970 justify_qc,
1971 parent_commitment: null_quorum_data.leaf_commit,
1972 upgrade_certificate: None,
1973 block_header: block_header.clone(),
1974 block_payload: Some(payload),
1975 }
1976 }
1977
1978 pub fn view_number(&self) -> ViewNumber {
1980 self.view_number
1981 }
1982 pub fn height(&self) -> u64 {
1986 self.block_header.block_number()
1987 }
1988 pub fn justify_qc(&self) -> QuorumCertificate<TYPES> {
1990 self.justify_qc.clone()
1991 }
1992 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1994 self.upgrade_certificate.clone()
1995 }
1996 pub fn parent_commitment(&self) -> Commitment<Self> {
1998 self.parent_commitment
1999 }
2000 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
2002 &self.block_header
2003 }
2004
2005 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
2007 &mut self.block_header
2008 }
2009 pub fn fill_block_payload(
2016 &mut self,
2017 block_payload: TYPES::BlockPayload,
2018 num_storage_nodes: usize,
2019 version: Version,
2020 ) -> std::result::Result<(), BlockError> {
2021 let encoded_txns = block_payload.encode();
2022 let commitment = vid_commitment(
2023 &encoded_txns,
2024 &self.block_header.metadata().encode(),
2025 num_storage_nodes,
2026 version,
2027 );
2028 if commitment != self.block_header.payload_commitment() {
2029 return Err(BlockError::InconsistentPayloadCommitment);
2030 }
2031 self.block_payload = Some(block_payload);
2032 Ok(())
2033 }
2034
2035 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
2037 self.block_payload.take()
2038 }
2039
2040 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
2043 self.block_payload = Some(block_payload);
2044 }
2045
2046 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
2048 self.block_payload.clone()
2049 }
2050
2051 pub fn payload_commitment(&self) -> VidCommitment {
2053 self.block_header().payload_commitment()
2054 }
2055
2056 pub fn extends_upgrade(&self, parent: &Self, upgrade: &UpgradeLock<TYPES>) -> Result<()> {
2064 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
2065 (None | Some(_), None) => {},
2069 (None, Some(parent_cert)) => {
2073 let decided_upgrade_certificate_read = upgrade.decided_upgrade_cert();
2074 ensure!(
2075 self.view_number() > parent_cert.data.new_version_first_view
2076 || (self.view_number() > parent_cert.data.decide_by
2077 && decided_upgrade_certificate_read.is_none()),
2078 "The new leaf is missing an upgrade certificate that was present in its \
2079 parent, and should still be live."
2080 );
2081 },
2082 (Some(cert), Some(parent_cert)) => {
2086 ensure!(
2087 cert == parent_cert,
2088 "The new leaf does not extend the parent leaf, because it has attached a \
2089 different upgrade certificate."
2090 );
2091 },
2092 }
2093
2094 Ok(())
2098 }
2099}
2100
2101impl<TYPES: NodeType> TestableLeaf for Leaf<TYPES>
2102where
2103 TYPES::ValidatedState: TestableState<TYPES>,
2104 TYPES::BlockPayload: TestableBlock<TYPES>,
2105{
2106 type NodeType = TYPES;
2107
2108 fn create_random_transaction(
2109 &self,
2110 rng: &mut dyn rand::RngCore,
2111 padding: u64,
2112 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
2113 {
2114 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
2115 }
2116}
2117impl<TYPES: NodeType> TestableLeaf for Leaf2<TYPES>
2118where
2119 TYPES::ValidatedState: TestableState<TYPES>,
2120 TYPES::BlockPayload: TestableBlock<TYPES>,
2121{
2122 type NodeType = TYPES;
2123
2124 fn create_random_transaction(
2125 &self,
2126 rng: &mut dyn rand::RngCore,
2127 padding: u64,
2128 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
2129 {
2130 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
2131 }
2132}
2133#[must_use]
2135pub fn fake_commitment<S: Committable>() -> Commitment<S> {
2136 RawCommitmentBuilder::new("Dummy commitment for arbitrary genesis").finalize()
2137}
2138
2139#[must_use]
2141pub fn random_commitment<S: Committable>(rng: &mut dyn rand::RngCore) -> Commitment<S> {
2142 let random_array: Vec<u8> = (0u8..100u8).map(|_| rng.gen_range(0..255)).collect();
2143 RawCommitmentBuilder::new("Random Commitment")
2144 .constant_str("Random Field")
2145 .var_size_bytes(&random_array)
2146 .finalize()
2147}
2148
2149pub fn serialize_signature2<TYPES: NodeType>(
2153 signatures: &<TYPES::SignatureKey as SignatureKey>::QcType,
2154) -> Vec<u8> {
2155 let mut signatures_bytes = vec![];
2156 signatures_bytes.extend("Yes".as_bytes());
2157
2158 let (sig, proof) = TYPES::SignatureKey::sig_proof(signatures);
2159 let proof_bytes = bincode_opts()
2160 .serialize(&proof.as_bitslice())
2161 .expect("This serialization shouldn't be able to fail");
2162 signatures_bytes.extend("bitvec proof".as_bytes());
2163 signatures_bytes.extend(proof_bytes.as_slice());
2164 let sig_bytes = bincode_opts()
2165 .serialize(&sig)
2166 .expect("This serialization shouldn't be able to fail");
2167 signatures_bytes.extend("aggregated signature".as_bytes());
2168 signatures_bytes.extend(sig_bytes.as_slice());
2169 signatures_bytes
2170}
2171
2172impl<TYPES: NodeType> Committable for Leaf<TYPES> {
2173 fn commit(&self) -> committable::Commitment<Self> {
2174 RawCommitmentBuilder::new("leaf commitment")
2175 .u64_field("view number", *self.view_number)
2176 .field("parent leaf commitment", self.parent_commitment)
2177 .field("block header", self.block_header.commit())
2178 .field("justify qc", self.justify_qc.commit())
2179 .optional("upgrade certificate", &self.upgrade_certificate)
2180 .finalize()
2181 }
2182}
2183
2184impl<TYPES: NodeType> Leaf2<TYPES> {
2185 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposalWrapper<TYPES>) -> Self {
2187 let QuorumProposalWrapper {
2190 proposal:
2191 QuorumProposal2 {
2192 view_number,
2193 epoch,
2194 justify_qc,
2195 next_epoch_justify_qc,
2196 block_header,
2197 upgrade_certificate,
2198 view_change_evidence,
2199 next_drb_result,
2200 state_cert: _,
2201 },
2202 } = quorum_proposal;
2203
2204 Self {
2205 view_number: *view_number,
2206 justify_qc: justify_qc.clone(),
2207 next_epoch_justify_qc: next_epoch_justify_qc.clone(),
2208 parent_commitment: justify_qc.data().leaf_commit,
2209 block_header: block_header.clone(),
2210 upgrade_certificate: upgrade_certificate.clone(),
2211 block_payload: None,
2212 view_change_evidence: view_change_evidence.clone(),
2213 next_drb_result: *next_drb_result,
2214 with_epoch: epoch.is_some(),
2215 }
2216 }
2217}
2218
2219impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for Leaf2<TYPES> {
2220 fn from(value: QuorumProposalWrapper<TYPES>) -> Self {
2221 let QuorumProposalWrapper {
2222 proposal:
2223 QuorumProposal2 {
2224 view_number,
2225 epoch,
2226 justify_qc,
2227 next_epoch_justify_qc,
2228 block_header,
2229 upgrade_certificate,
2230 view_change_evidence,
2231 next_drb_result,
2232 state_cert: _,
2233 },
2234 } = value;
2235
2236 let parent_commitment = justify_qc.data().leaf_commit;
2237
2238 Self {
2239 view_number,
2240 justify_qc,
2241 next_epoch_justify_qc,
2242 parent_commitment,
2243 block_header,
2244 upgrade_certificate,
2245 block_payload: None,
2246 view_change_evidence,
2247 next_drb_result,
2248 with_epoch: epoch.is_some(),
2249 }
2250 }
2251}
2252
2253impl<TYPES: NodeType> Leaf<TYPES> {
2254 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposal<TYPES>) -> Self {
2256 let QuorumProposal {
2259 view_number,
2260 justify_qc,
2261 block_header,
2262 upgrade_certificate,
2263 proposal_certificate: _,
2264 } = quorum_proposal;
2265
2266 Self {
2267 view_number: *view_number,
2268 justify_qc: justify_qc.clone(),
2269 parent_commitment: justify_qc.data().leaf_commit,
2270 block_header: block_header.clone(),
2271 upgrade_certificate: upgrade_certificate.clone(),
2272 block_payload: None,
2273 }
2274 }
2275}
2276
2277pub mod null_block {
2278 #![allow(missing_docs)]
2279
2280 use jf_advz::VidScheme;
2281 use vbs::version::Version;
2282 use versions::EPOCH_VERSION;
2283
2284 use crate::{
2285 data::VidCommitment,
2286 traits::{
2287 BlockPayload, block_contents::BuilderFee, node_implementation::NodeType,
2288 signature_key::BuilderSignatureKey,
2289 },
2290 vid::advz::advz_scheme,
2291 };
2292
2293 #[must_use]
2302 pub fn commitment(num_storage_nodes: usize) -> Option<VidCommitment> {
2303 let vid_result = advz_scheme(num_storage_nodes).commit_only(Vec::new());
2304
2305 match vid_result {
2306 Ok(r) => Some(VidCommitment::V0(r)),
2307 Err(_) => None,
2308 }
2309 }
2310
2311 #[must_use]
2313 pub fn builder_fee<TYPES: NodeType>(
2314 num_storage_nodes: usize,
2315 version: Version,
2316 ) -> Option<BuilderFee<TYPES>> {
2317 const FEE_AMOUNT: u64 = 0;
2319
2320 let (pub_key, priv_key) =
2321 <TYPES::BuilderSignatureKey as BuilderSignatureKey>::generated_from_seed_indexed(
2322 [0_u8; 32], 0,
2323 );
2324
2325 if version >= EPOCH_VERSION {
2326 let (_null_block, null_block_metadata) =
2327 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2328
2329 match TYPES::BuilderSignatureKey::sign_fee(&priv_key, FEE_AMOUNT, &null_block_metadata)
2330 {
2331 Ok(sig) => Some(BuilderFee {
2332 fee_amount: FEE_AMOUNT,
2333 fee_account: pub_key,
2334 fee_signature: sig,
2335 }),
2336 Err(_) => None,
2337 }
2338 } else {
2339 let (_null_block, null_block_metadata) =
2340 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2341
2342 match TYPES::BuilderSignatureKey::sign_fee_with_vid_commitment(
2343 &priv_key,
2344 FEE_AMOUNT,
2345 &null_block_metadata,
2346 &commitment(num_storage_nodes)?,
2347 ) {
2348 Ok(sig) => Some(BuilderFee {
2349 fee_amount: FEE_AMOUNT,
2350 fee_account: pub_key,
2351 fee_signature: sig,
2352 }),
2353 Err(_) => None,
2354 }
2355 }
2356 }
2357}
2358
2359#[derive(Debug, Eq, PartialEq, Clone)]
2361pub struct PackedBundle<TYPES: NodeType> {
2362 pub encoded_transactions: Arc<[u8]>,
2364
2365 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2367
2368 pub view_number: ViewNumber,
2370
2371 pub epoch_number: Option<EpochNumber>,
2373
2374 pub sequencing_fees: Vec1<BuilderFee<TYPES>>,
2376}
2377
2378impl<TYPES: NodeType> PackedBundle<TYPES> {
2379 pub fn new(
2381 encoded_transactions: Arc<[u8]>,
2382 metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2383 view_number: ViewNumber,
2384 epoch_number: Option<EpochNumber>,
2385 sequencing_fees: Vec1<BuilderFee<TYPES>>,
2386 ) -> Self {
2387 Self {
2388 encoded_transactions,
2389 metadata,
2390 view_number,
2391 epoch_number,
2392 sequencing_fees,
2393 }
2394 }
2395}
2396
2397#[cfg(test)]
2398mod test {
2399 use super::*;
2400
2401 #[test]
2402 fn test_vid_commitment_display() {
2403 let vc = VidCommitment::V0(VidCommitment0::default());
2404 assert_eq!(
2405 format!("{vc}"),
2406 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2407 );
2408 assert_eq!(
2409 format!("{vc:?}"),
2410 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2411 );
2412
2413 let vc = VidCommitment::V1(VidCommitment1::default());
2414 assert_eq!(
2415 format!("{vc}"),
2416 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2417 );
2418 assert_eq!(
2419 format!("{vc:?}"),
2420 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2421 );
2422
2423 let vc = VidCommitment::V2(VidCommitment2::default());
2424 assert_eq!(
2425 format!("{vc}"),
2426 "AvidmGf2Commit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq"
2427 );
2428 assert_eq!(
2429 format!("{vc:?}"),
2430 "AvidmGf2Commit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq"
2431 );
2432 }
2433}