1use std::{
13 fmt::{Debug, Display},
14 hash::Hash,
15 marker::PhantomData,
16 sync::Arc,
17 time::Duration,
18};
19
20use bincode::Options;
21use committable::{Commitment, CommitmentBoundsArkless, Committable, RawCommitmentBuilder};
22use hotshot_utils::anytrace::*;
23use jf_advz::VidScheme;
24use rand::Rng;
25use serde::{Deserialize, Serialize};
26use tagged_base64::{TaggedBase64, Tb64Error};
27use thiserror::Error;
28use vbs::version::Version;
29use vec1::Vec1;
30use versions::{EPOCH_VERSION, Upgrade, VID2_UPGRADE_VERSION};
31
32use crate::{
33 drb::DrbResult,
34 epoch_membership::EpochMembershipCoordinator,
35 message::{Proposal, UpgradeLock, convert_proposal},
36 simple_certificate::{
37 LightClientStateUpdateCertificateV1, LightClientStateUpdateCertificateV2,
38 NextEpochQuorumCertificate2, QuorumCertificate, QuorumCertificate2, TimeoutCertificate,
39 TimeoutCertificate2, UpgradeCertificate, ViewSyncFinalizeCertificate,
40 ViewSyncFinalizeCertificate2,
41 },
42 simple_vote::{HasEpoch, QuorumData, QuorumData2, UpgradeProposalData, VersionedVoteData},
43 traits::{
44 BlockPayload,
45 block_contents::{BlockHeader, BuilderFee, EncodeBytes, TestableBlock},
46 node_implementation::NodeType,
47 signature_key::SignatureKey,
48 states::TestableState,
49 },
50 utils::{
51 EpochTransitionIndicator, bincode_opts, genesis_epoch_from_version,
52 option_epoch_from_block_number,
53 },
54 vid::{
55 advz::{ADVZScheme, advz_scheme},
56 avidm::{AvidMScheme, init_avidm_param},
57 avidm_gf2::{AvidmGf2Scheme, init_avidm_gf2_param},
58 },
59 vote::{Certificate, HasViewNumber},
60};
61
62macro_rules! impl_u64_wrapper {
65 ($t:ty, $genesis_val:expr) => {
66 impl $t {
67 pub fn genesis() -> Self {
69 Self($genesis_val)
70 }
71 pub fn new(n: u64) -> Self {
73 Self(n)
74 }
75 pub fn u64(&self) -> u64 {
77 self.0
78 }
79 }
80
81 impl From<u64> for $t {
82 fn from(n: u64) -> Self {
83 Self(n)
84 }
85 }
86
87 impl From<$t> for u64 {
88 fn from(n: $t) -> Self {
89 n.0
90 }
91 }
92
93 impl Display for $t {
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95 write!(f, "{}", self.0)
96 }
97 }
98
99 impl std::ops::Add<u64> for $t {
100 type Output = $t;
101
102 fn add(self, rhs: u64) -> Self::Output {
103 Self(self.0 + rhs)
104 }
105 }
106
107 impl std::ops::AddAssign<u64> for $t {
108 fn add_assign(&mut self, rhs: u64) {
109 self.0 += rhs;
110 }
111 }
112
113 impl std::ops::Deref for $t {
114 type Target = u64;
115
116 fn deref(&self) -> &Self::Target {
117 &self.0
118 }
119 }
120
121 impl std::ops::Sub<u64> for $t {
122 type Output = $t;
123 fn sub(self, rhs: u64) -> Self::Output {
124 Self(self.0 - rhs)
125 }
126 }
127 };
128}
129
130#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
132pub struct ViewNumber(u64);
133
134impl Committable for ViewNumber {
135 fn commit(&self) -> Commitment<Self> {
136 let builder = RawCommitmentBuilder::new("View Number Commitment");
137 builder.u64(self.0).finalize()
138 }
139}
140
141impl_u64_wrapper!(ViewNumber, 0u64);
142
143#[derive(
145 Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
146)]
147pub struct EpochNumber(u64);
148
149impl Committable for EpochNumber {
150 fn commit(&self) -> Commitment<Self> {
151 let builder = RawCommitmentBuilder::new("Epoch Number Commitment");
152 builder.u64(self.0).finalize()
153 }
154}
155
156impl_u64_wrapper!(EpochNumber, 1u64);
157
158#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
160#[serde(bound = "TYPES: NodeType")]
161pub struct DaProposal<TYPES: NodeType> {
162 pub encoded_transactions: Arc<[u8]>,
164 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
166 pub view_number: ViewNumber,
168}
169
170#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
172#[serde(bound = "TYPES: NodeType")]
173pub struct DaProposal2<TYPES: NodeType> {
174 pub encoded_transactions: Arc<[u8]>,
176 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
178 pub view_number: ViewNumber,
180 pub epoch: Option<EpochNumber>,
182 pub epoch_transition_indicator: EpochTransitionIndicator,
185}
186
187impl<TYPES: NodeType> From<DaProposal<TYPES>> for DaProposal2<TYPES> {
188 fn from(da_proposal: DaProposal<TYPES>) -> Self {
189 Self {
190 encoded_transactions: da_proposal.encoded_transactions,
191 metadata: da_proposal.metadata,
192 view_number: da_proposal.view_number,
193 epoch: None,
194 epoch_transition_indicator: EpochTransitionIndicator::NotInTransition,
195 }
196 }
197}
198
199impl<TYPES: NodeType> From<DaProposal2<TYPES>> for DaProposal<TYPES> {
200 fn from(da_proposal2: DaProposal2<TYPES>) -> Self {
201 Self {
202 encoded_transactions: da_proposal2.encoded_transactions,
203 metadata: da_proposal2.metadata,
204 view_number: da_proposal2.view_number,
205 }
206 }
207}
208
209#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
211pub struct UpgradeProposal {
212 pub upgrade_proposal: UpgradeProposalData,
214 pub view_number: ViewNumber,
216}
217
218pub type VidCommitment0 = crate::vid::advz::ADVZCommitment;
220pub type VidCommitment1 = crate::vid::avidm::AvidMCommitment;
221pub type VidCommitment2 = crate::vid::avidm_gf2::AvidmGf2Commitment;
222
223#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, Ord, PartialOrd)]
225#[serde(
226 try_from = "tagged_base64::TaggedBase64",
227 into = "tagged_base64::TaggedBase64"
228)]
229pub enum VidCommitment {
230 V0(VidCommitment0),
231 V1(VidCommitment1),
232 V2(VidCommitment2),
233}
234
235impl Default for VidCommitment {
236 fn default() -> Self {
237 Self::V0(Default::default())
238 }
239}
240
241impl Display for VidCommitment {
242 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243 std::write!(f, "{}", TaggedBase64::from(self))
244 }
245}
246
247impl Debug for VidCommitment {
248 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249 std::fmt::Display::fmt(self, f)
250 }
251}
252
253impl From<VidCommitment> for TaggedBase64 {
254 fn from(val: VidCommitment) -> Self {
255 match val {
256 VidCommitment::V0(comm) => comm.into(),
257 VidCommitment::V1(comm) => comm.into(),
258 VidCommitment::V2(comm) => comm.into(),
259 }
260 }
261}
262
263impl From<&VidCommitment> for TaggedBase64 {
264 fn from(val: &VidCommitment) -> Self {
265 match val {
266 VidCommitment::V0(comm) => comm.into(),
267 VidCommitment::V1(comm) => comm.into(),
268 VidCommitment::V2(comm) => comm.into(),
269 }
270 }
271}
272
273impl TryFrom<TaggedBase64> for VidCommitment {
274 type Error = tagged_base64::Tb64Error;
275
276 fn try_from(value: TaggedBase64) -> std::result::Result<Self, Self::Error> {
277 match value.tag().as_str() {
278 "HASH" => VidCommitment0::try_from(value).map(Self::V0),
279 "AvidMCommit" => VidCommitment1::try_from(value).map(Self::V1),
280 "AvidmGf2Commit" => VidCommitment2::try_from(value).map(Self::V2),
281 _ => Err(Tb64Error::InvalidTag),
282 }
283 }
284}
285
286impl<'a> TryFrom<&'a TaggedBase64> for VidCommitment {
287 type Error = tagged_base64::Tb64Error;
288
289 fn try_from(value: &'a TaggedBase64) -> std::result::Result<Self, Self::Error> {
290 match value.tag().as_str() {
291 "HASH" => VidCommitment0::try_from(value).map(Self::V0),
292 "AvidMCommit" => VidCommitment1::try_from(value).map(Self::V1),
293 "AvidmGf2Commit" => VidCommitment2::try_from(value).map(Self::V2),
294 _ => Err(Tb64Error::InvalidTag),
295 }
296 }
297}
298
299impl std::str::FromStr for VidCommitment {
300 type Err = tagged_base64::Tb64Error;
301 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
302 use core::convert::TryFrom;
303 Self::try_from(TaggedBase64::from_str(s)?)
304 .map_err(|_| tagged_base64::Tb64Error::InvalidData)
305 }
306}
307
308impl From<VidCommitment1> for VidCommitment {
316 fn from(comm: VidCommitment1) -> Self {
317 Self::V1(comm)
318 }
319}
320
321impl From<VidCommitment2> for VidCommitment {
322 fn from(comm: VidCommitment2) -> Self {
323 Self::V2(comm)
324 }
325}
326
327impl AsRef<[u8]> for VidCommitment {
328 fn as_ref(&self) -> &[u8] {
329 match self {
330 Self::V0(comm) => comm.as_ref(),
331 Self::V1(comm) => comm.as_ref(),
332 Self::V2(comm) => comm.as_ref(),
333 }
334 }
335}
336
337impl AsRef<[u8; 32]> for VidCommitment {
338 fn as_ref(&self) -> &[u8; 32] {
339 match self {
340 Self::V0(comm) => comm.as_ref().as_ref(),
341 Self::V1(comm) => comm.as_ref(),
342 Self::V2(comm) => comm.as_ref(),
343 }
344 }
345}
346
347#[must_use]
352#[allow(clippy::panic)]
353pub fn vid_commitment(
354 encoded_transactions: &[u8],
355 metadata: &[u8],
356 total_weight: usize,
357 version: Version,
358) -> VidCommitment {
359 if version < EPOCH_VERSION {
360 let encoded_tx_len = encoded_transactions.len();
361 advz_scheme(total_weight)
362 .commit_only(encoded_transactions)
363 .map(VidCommitment::V0)
364 .unwrap_or_else(|err| {
365 panic!(
366 "VidScheme::commit_only \
367 failure:(total_weight,payload_byte_len)=({total_weight},{encoded_tx_len}) \
368 error: {err}"
369 )
370 })
371 } else if version < VID2_UPGRADE_VERSION {
372 let param = init_avidm_param(total_weight).unwrap();
373 let encoded_tx_len = encoded_transactions.len();
374 AvidMScheme::commit(
375 ¶m,
376 encoded_transactions,
377 ns_table::parse_ns_table(encoded_tx_len, metadata),
378 )
379 .map(VidCommitment::V1)
380 .unwrap()
381 } else {
382 let param = init_avidm_gf2_param(total_weight).unwrap();
383 let encoded_tx_len = encoded_transactions.len();
384 AvidmGf2Scheme::commit(
385 ¶m,
386 encoded_transactions,
387 ns_table::parse_ns_table(encoded_tx_len, metadata),
388 )
389 .map(|(comm, _)| VidCommitment::V2(comm))
390 .unwrap()
391 }
392}
393
394pub type VidCommon0 = crate::vid::advz::ADVZCommon;
396pub type VidCommon1 = crate::vid::avidm::AvidMCommon;
397pub type VidCommon2 = crate::vid::avidm_gf2::AvidmGf2Common;
398
399#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
401pub enum VidCommon {
402 V0(VidCommon0),
403 V1(VidCommon1),
404 V2(VidCommon2),
405}
406
407impl From<VidCommon1> for VidCommon {
408 fn from(comm: VidCommon1) -> Self {
409 Self::V1(comm)
410 }
411}
412
413impl From<VidCommon2> for VidCommon {
414 fn from(comm: VidCommon2) -> Self {
415 Self::V2(comm)
416 }
417}
418
419#[derive(Clone, Copy, Debug, Eq, PartialEq)]
421pub enum VidCommonRef<'a> {
422 V0(&'a VidCommon0),
423 V1(&'a VidCommon1),
424 V2(&'a VidCommon2),
425}
426
427impl<'a> VidCommonRef<'a> {
428 pub fn is_consistent(&self, comm: &VidCommitment) -> bool {
429 match (self, comm) {
430 (Self::V0(common), VidCommitment::V0(comm)) => {
431 ADVZScheme::is_consistent(comm, common).is_ok()
432 },
433 (Self::V1(_), VidCommitment::V1(_)) => true,
437 (Self::V2(common), VidCommitment::V2(comm)) => {
438 AvidmGf2Scheme::is_consistent(comm, common)
439 },
440 _ => false,
441 }
442 }
443}
444
445impl VidCommon {
446 pub fn as_ref(&self) -> VidCommonRef<'_> {
447 match self {
448 Self::V0(c) => VidCommonRef::V0(c),
449 Self::V1(c) => VidCommonRef::V1(c),
450 Self::V2(c) => VidCommonRef::V2(c),
451 }
452 }
453
454 pub fn is_consistent(&self, comm: &VidCommitment) -> bool {
455 self.as_ref().is_consistent(comm)
456 }
457}
458
459pub type VidShare0 = crate::vid::advz::ADVZShare;
461pub type VidShare1 = crate::vid::avidm::AvidMShare;
462pub type VidShare2 = crate::vid::avidm_gf2::AvidmGf2Share;
463
464#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
466pub enum VidShare {
467 V0(VidShare0),
468 V1(VidShare1),
469 V2(VidShare2),
470}
471
472impl From<VidShare1> for VidShare {
480 fn from(share: VidShare1) -> Self {
481 Self::V1(share)
482 }
483}
484
485impl From<VidShare2> for VidShare {
486 fn from(share: VidShare2) -> Self {
487 Self::V2(share)
488 }
489}
490
491pub mod ns_table;
492pub mod vid_disperse;
493
494pub struct VidDisperseAndDuration<TYPES: NodeType> {
496 pub disperse: VidDisperse<TYPES>,
498 pub duration: Duration,
500}
501
502pub type VidDisperse0<TYPES> = vid_disperse::ADVZDisperse<TYPES>;
504pub type VidDisperse1<TYPES> = vid_disperse::AvidMDisperse<TYPES>;
505pub type VidDisperse2<TYPES> = vid_disperse::AvidmGf2Disperse<TYPES>;
506
507#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
513#[serde(bound = "TYPES: NodeType")]
514pub enum VidDisperse<TYPES: NodeType> {
515 V0(VidDisperse0<TYPES>),
517 V1(VidDisperse1<TYPES>),
519 V2(VidDisperse2<TYPES>),
521}
522
523impl<TYPES: NodeType> From<VidDisperse0<TYPES>> for VidDisperse<TYPES> {
524 fn from(disperse: VidDisperse0<TYPES>) -> Self {
525 Self::V0(disperse)
526 }
527}
528
529impl<TYPES: NodeType> From<VidDisperse1<TYPES>> for VidDisperse<TYPES> {
530 fn from(disperse: VidDisperse1<TYPES>) -> Self {
531 Self::V1(disperse)
532 }
533}
534
535impl<TYPES: NodeType> From<VidDisperse2<TYPES>> for VidDisperse<TYPES> {
536 fn from(disperse: VidDisperse2<TYPES>) -> Self {
537 Self::V2(disperse)
538 }
539}
540
541impl<TYPES: NodeType> HasViewNumber for VidDisperse<TYPES> {
542 fn view_number(&self) -> ViewNumber {
543 match self {
544 Self::V0(disperse) => disperse.view_number(),
545 Self::V1(disperse) => disperse.view_number(),
546 Self::V2(disperse) => disperse.view_number(),
547 }
548 }
549}
550
551impl<TYPES: NodeType> HasEpoch for VidDisperse<TYPES> {
552 fn epoch(&self) -> Option<EpochNumber> {
553 match self {
554 Self::V0(disperse) => disperse.epoch(),
555 Self::V1(disperse) => disperse.epoch(),
556 Self::V2(disperse) => disperse.epoch(),
557 }
558 }
559}
560
561impl<TYPES: NodeType> VidDisperse<TYPES> {
562 #[allow(clippy::panic)]
568 pub async fn calculate_vid_disperse(
569 payload: &TYPES::BlockPayload,
570 membership: &EpochMembershipCoordinator<TYPES>,
571 view: ViewNumber,
572 target_epoch: Option<EpochNumber>,
573 data_epoch: Option<EpochNumber>,
574 metadata: &<TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
575 upgrade_lock: &UpgradeLock<TYPES>,
576 ) -> Result<VidDisperseAndDuration<TYPES>> {
577 let epochs_enabled = upgrade_lock.epochs_enabled(view);
578 let upgraded_vid2 = upgrade_lock.upgraded_vid2(view);
579 if upgraded_vid2 {
580 VidDisperse2::calculate_vid_disperse(
581 payload,
582 membership,
583 view,
584 target_epoch,
585 data_epoch,
586 metadata,
587 )
588 .await
589 .map(|(disperse, duration)| VidDisperseAndDuration {
590 disperse: Self::V2(disperse),
591 duration,
592 })
593 } else if epochs_enabled {
594 VidDisperse1::calculate_vid_disperse(
595 payload,
596 membership,
597 view,
598 target_epoch,
599 data_epoch,
600 metadata,
601 )
602 .await
603 .map(|(disperse, duration)| VidDisperseAndDuration {
604 disperse: Self::V1(disperse),
605 duration,
606 })
607 } else {
608 VidDisperse0::calculate_vid_disperse(
609 payload,
610 membership,
611 view,
612 target_epoch,
613 data_epoch,
614 )
615 .await
616 .map(|(disperse, duration)| VidDisperseAndDuration {
617 disperse: Self::V0(disperse),
618 duration,
619 })
620 }
621 }
622
623 pub fn payload_commitment(&self) -> VidCommitment {
625 match self {
626 Self::V0(disperse) => VidCommitment::V0(disperse.payload_commitment),
627 Self::V1(disperse) => disperse.payload_commitment.into(),
628 Self::V2(disperse) => disperse.payload_commitment.into(),
629 }
630 }
631
632 pub fn payload_commitment_ref(&self) -> &[u8] {
634 match self {
635 Self::V0(disperse) => disperse.payload_commitment.as_ref(),
636 Self::V1(disperse) => disperse.payload_commitment.as_ref(),
637 Self::V2(disperse) => disperse.payload_commitment.as_ref(),
638 }
639 }
640
641 pub fn set_view_number(&mut self, view_number: ViewNumber) {
643 match self {
644 Self::V0(share) => share.view_number = view_number,
645 Self::V1(share) => share.view_number = view_number,
646 Self::V2(share) => share.view_number = view_number,
647 }
648 }
649
650 pub fn to_shares(self) -> Vec<VidDisperseShare<TYPES>> {
651 match self {
652 VidDisperse::V0(disperse) => disperse
653 .to_shares()
654 .into_iter()
655 .map(|share| VidDisperseShare::V0(share))
656 .collect(),
657 VidDisperse::V1(disperse) => disperse
658 .to_shares()
659 .into_iter()
660 .map(|share| VidDisperseShare::V1(share))
661 .collect(),
662 VidDisperse::V2(disperse) => disperse
663 .to_shares()
664 .into_iter()
665 .map(|share| VidDisperseShare::V2(share))
666 .collect(),
667 }
668 }
669
670 pub fn to_share_proposals(
672 proposal: Proposal<TYPES, Self>,
673 ) -> Vec<Proposal<TYPES, VidDisperseShare<TYPES>>> {
674 match proposal.data {
675 VidDisperse::V0(disperse) => disperse
676 .to_share_proposals(&proposal.signature)
677 .into_iter()
678 .map(|proposal| convert_proposal(proposal))
679 .collect(),
680 VidDisperse::V1(disperse) => disperse
681 .to_share_proposals(&proposal.signature)
682 .into_iter()
683 .map(|proposal| convert_proposal(proposal))
684 .collect(),
685 VidDisperse::V2(disperse) => disperse
686 .to_share_proposals(&proposal.signature)
687 .into_iter()
688 .map(|proposal| convert_proposal(proposal))
689 .collect(),
690 }
691 }
692}
693
694pub type VidDisperseShare0<TYPES> = vid_disperse::ADVZDisperseShare<TYPES>;
696pub type VidDisperseShare1<TYPES> = vid_disperse::AvidMDisperseShare<TYPES>;
697pub type VidDisperseShare2<TYPES> = vid_disperse::AvidmGf2DisperseShare<TYPES>;
698
699#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
701#[serde(bound = "TYPES: NodeType")]
702pub enum VidDisperseShare<TYPES: NodeType> {
703 V0(VidDisperseShare0<TYPES>),
705 V1(VidDisperseShare1<TYPES>),
707 V2(VidDisperseShare2<TYPES>),
709}
710
711impl<TYPES: NodeType> From<VidDisperseShare0<TYPES>> for VidDisperseShare<TYPES> {
712 fn from(share: VidDisperseShare0<TYPES>) -> Self {
713 Self::V0(share)
714 }
715}
716
717impl<TYPES: NodeType> From<VidDisperseShare1<TYPES>> for VidDisperseShare<TYPES> {
718 fn from(share: VidDisperseShare1<TYPES>) -> Self {
719 Self::V1(share)
720 }
721}
722
723impl<TYPES: NodeType> From<VidDisperseShare2<TYPES>> for VidDisperseShare<TYPES> {
724 fn from(share: VidDisperseShare2<TYPES>) -> Self {
725 Self::V2(share)
726 }
727}
728
729impl<TYPES: NodeType> VidDisperseShare<TYPES> {
730 pub fn to_proposal(
732 self,
733 private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
734 ) -> Option<Proposal<TYPES, Self>> {
735 let payload_commitment_ref: &[u8] = match &self {
736 Self::V0(share) => share.payload_commitment.as_ref(),
737 Self::V1(share) => share.payload_commitment.as_ref(),
738 Self::V2(share) => share.payload_commitment.as_ref(),
739 };
740 let Ok(signature) = TYPES::SignatureKey::sign(private_key, payload_commitment_ref) else {
741 tracing::error!("VID: failed to sign dispersal share payload");
742 return None;
743 };
744 Some(Proposal {
745 signature,
746 _pd: PhantomData,
747 data: self,
748 })
749 }
750
751 pub fn recipient_key(&self) -> &TYPES::SignatureKey {
753 match self {
754 Self::V0(share) => &share.recipient_key,
755 Self::V1(share) => &share.recipient_key,
756 Self::V2(share) => &share.recipient_key,
757 }
758 }
759
760 pub fn payload_byte_len(&self) -> u32 {
762 match self {
763 Self::V0(share) => share.payload_byte_len(),
764 Self::V1(share) => share.payload_byte_len(),
765 Self::V2(share) => share.payload_byte_len(),
766 }
767 }
768
769 pub fn payload_commitment_ref(&self) -> &[u8] {
771 match self {
772 Self::V0(share) => share.payload_commitment.as_ref(),
773 Self::V1(share) => share.payload_commitment.as_ref(),
774 Self::V2(share) => share.payload_commitment.as_ref(),
775 }
776 }
777
778 pub fn payload_commitment(&self) -> VidCommitment {
780 match self {
781 Self::V0(share) => VidCommitment::V0(share.payload_commitment),
782 Self::V1(share) => share.payload_commitment.into(),
783 Self::V2(share) => share.payload_commitment.into(),
784 }
785 }
786
787 pub fn target_epoch(&self) -> Option<EpochNumber> {
789 match self {
790 Self::V0(_) => None,
791 Self::V1(share) => share.target_epoch,
792 Self::V2(share) => share.target_epoch,
793 }
794 }
795
796 pub fn common(&self) -> VidCommonRef<'_> {
798 match self {
799 Self::V0(share) => VidCommonRef::V0(&share.common),
800 Self::V1(share) => VidCommonRef::V1(&share.common),
801 Self::V2(share) => VidCommonRef::V2(&share.common),
802 }
803 }
804
805 pub fn is_consistent(&self) -> bool {
807 match self {
808 Self::V0(share) => share.is_consistent(),
809 Self::V1(share) => share.is_consistent(),
810 Self::V2(share) => share.is_consistent(),
811 }
812 }
813
814 pub fn verify_with_verified_common(&self) -> bool {
817 match self {
818 Self::V0(share) => share.verify_with_verified_common(),
819 Self::V1(share) => share.verify_with_verified_common(),
820 Self::V2(share) => share.verify_with_verified_common(),
821 }
822 }
823
824 pub fn verify(&self, total_nodes: usize) -> bool {
826 match self {
827 Self::V0(share) => share.verify(total_nodes),
828 Self::V1(share) => share.verify(total_nodes),
829 Self::V2(share) => share.verify(total_nodes),
830 }
831 }
832
833 pub fn set_view_number(&mut self, view_number: ViewNumber) {
835 match self {
836 Self::V0(share) => share.view_number = view_number,
837 Self::V1(share) => share.view_number = view_number,
838 Self::V2(share) => share.view_number = view_number,
839 }
840 }
841}
842
843impl<TYPES: NodeType> HasViewNumber for VidDisperseShare<TYPES> {
844 fn view_number(&self) -> ViewNumber {
845 match self {
846 Self::V0(disperse) => disperse.view_number(),
847 Self::V1(disperse) => disperse.view_number(),
848 Self::V2(disperse) => disperse.view_number(),
849 }
850 }
851}
852
853impl<TYPES: NodeType> HasEpoch for VidDisperseShare<TYPES> {
854 fn epoch(&self) -> Option<EpochNumber> {
855 match self {
856 Self::V0(_) => None,
857 Self::V1(share) => share.epoch(),
858 Self::V2(share) => share.epoch(),
859 }
860 }
861}
862
863#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
866#[serde(bound(deserialize = ""))]
867pub enum ViewChangeEvidence<TYPES: NodeType> {
868 Timeout(TimeoutCertificate<TYPES>),
870 ViewSync(ViewSyncFinalizeCertificate<TYPES>),
872}
873
874impl<TYPES: NodeType> ViewChangeEvidence<TYPES> {
875 pub fn is_valid_for_view(&self, view: &ViewNumber) -> bool {
877 match self {
878 ViewChangeEvidence::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
879 ViewChangeEvidence::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
880 }
881 }
882
883 pub fn to_evidence2(self) -> ViewChangeEvidence2<TYPES> {
885 match self {
886 ViewChangeEvidence::Timeout(timeout_cert) => {
887 ViewChangeEvidence2::Timeout(timeout_cert.to_tc2())
888 },
889 ViewChangeEvidence::ViewSync(view_sync_cert) => {
890 ViewChangeEvidence2::ViewSync(view_sync_cert.to_vsc2())
891 },
892 }
893 }
894}
895
896#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
899#[serde(bound(deserialize = ""))]
900pub enum ViewChangeEvidence2<TYPES: NodeType> {
901 Timeout(TimeoutCertificate2<TYPES>),
903 ViewSync(ViewSyncFinalizeCertificate2<TYPES>),
905}
906
907impl<TYPES: NodeType> ViewChangeEvidence2<TYPES> {
908 pub fn is_valid_for_view(&self, view: &ViewNumber) -> bool {
910 match self {
911 ViewChangeEvidence2::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
912 ViewChangeEvidence2::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
913 }
914 }
915
916 pub fn to_evidence(self) -> ViewChangeEvidence<TYPES> {
918 match self {
919 ViewChangeEvidence2::Timeout(timeout_cert) => {
920 ViewChangeEvidence::Timeout(timeout_cert.to_tc())
921 },
922 ViewChangeEvidence2::ViewSync(view_sync_cert) => {
923 ViewChangeEvidence::ViewSync(view_sync_cert.to_vsc())
924 },
925 }
926 }
927}
928
929#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
931#[serde(bound(deserialize = ""))]
932pub struct QuorumProposal<TYPES: NodeType> {
933 pub block_header: TYPES::BlockHeader,
935
936 pub view_number: ViewNumber,
938
939 pub justify_qc: QuorumCertificate<TYPES>,
941
942 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
944
945 pub proposal_certificate: Option<ViewChangeEvidence<TYPES>>,
950}
951
952#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
954#[serde(bound(deserialize = ""))]
955pub struct QuorumProposal2<TYPES: NodeType> {
956 pub block_header: TYPES::BlockHeader,
958
959 pub view_number: ViewNumber,
961
962 pub epoch: Option<EpochNumber>,
964
965 pub justify_qc: QuorumCertificate2<TYPES>,
967
968 pub next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
970
971 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
973
974 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
976
977 #[serde(with = "serde_bytes")]
982 pub next_drb_result: Option<DrbResult>,
983
984 pub state_cert: Option<LightClientStateUpdateCertificateV2<TYPES>>,
987}
988
989#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
998#[serde(bound(deserialize = ""))]
999pub struct QuorumProposal2Legacy<TYPES: NodeType> {
1000 pub block_header: TYPES::BlockHeader,
1002
1003 pub view_number: ViewNumber,
1005
1006 pub epoch: Option<EpochNumber>,
1008
1009 pub justify_qc: QuorumCertificate2<TYPES>,
1011
1012 pub next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1014
1015 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1017
1018 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
1020
1021 #[serde(with = "serde_bytes")]
1026 pub next_drb_result: Option<DrbResult>,
1027
1028 pub state_cert: Option<LightClientStateUpdateCertificateV1<TYPES>>,
1032}
1033
1034impl<TYPES: NodeType> From<QuorumProposal2Legacy<TYPES>> for QuorumProposal2<TYPES> {
1035 fn from(quorum_proposal2: QuorumProposal2Legacy<TYPES>) -> Self {
1036 Self {
1037 block_header: quorum_proposal2.block_header,
1038 view_number: quorum_proposal2.view_number,
1039 epoch: quorum_proposal2.epoch,
1040 justify_qc: quorum_proposal2.justify_qc,
1041 next_epoch_justify_qc: quorum_proposal2.next_epoch_justify_qc,
1042 upgrade_certificate: quorum_proposal2.upgrade_certificate,
1043 view_change_evidence: quorum_proposal2.view_change_evidence,
1044 next_drb_result: quorum_proposal2.next_drb_result,
1045 state_cert: quorum_proposal2.state_cert.map(Into::into),
1046 }
1047 }
1048}
1049
1050impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposal2Legacy<TYPES> {
1051 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1052 Self {
1053 block_header: quorum_proposal2.block_header,
1054 view_number: quorum_proposal2.view_number,
1055 epoch: quorum_proposal2.epoch,
1056 justify_qc: quorum_proposal2.justify_qc,
1057 next_epoch_justify_qc: quorum_proposal2.next_epoch_justify_qc,
1058 upgrade_certificate: quorum_proposal2.upgrade_certificate,
1059 view_change_evidence: quorum_proposal2.view_change_evidence,
1060 next_drb_result: quorum_proposal2.next_drb_result,
1061 state_cert: quorum_proposal2.state_cert.map(Into::into),
1062 }
1063 }
1064}
1065
1066#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
1072#[serde(bound(deserialize = ""))]
1073pub struct QuorumProposalWrapperLegacy<TYPES: NodeType> {
1074 pub proposal: QuorumProposal2Legacy<TYPES>,
1076}
1077
1078#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
1080#[serde(bound(deserialize = ""))]
1081pub struct QuorumProposalWrapper<TYPES: NodeType> {
1082 pub proposal: QuorumProposal2<TYPES>,
1084}
1085
1086impl<TYPES: NodeType> From<QuorumProposalWrapperLegacy<TYPES>> for QuorumProposalWrapper<TYPES> {
1087 fn from(v3: QuorumProposalWrapperLegacy<TYPES>) -> Self {
1088 Self {
1089 proposal: v3.proposal.into(),
1090 }
1091 }
1092}
1093
1094impl<TYPES: NodeType> QuorumProposal2<TYPES> {
1095 pub async fn validate_epoch(
1099 &self,
1100 upgrade_lock: &UpgradeLock<TYPES>,
1101 epoch_height: u64,
1102 ) -> Result<()> {
1103 let calculated_epoch = option_epoch_from_block_number(
1104 upgrade_lock.epochs_enabled(self.view_number()),
1105 self.block_header.block_number(),
1106 epoch_height,
1107 );
1108 ensure!(
1109 calculated_epoch == self.epoch(),
1110 "Quorum proposal invalid: inconsistent epoch."
1111 );
1112 Ok(())
1113 }
1114}
1115
1116impl<TYPES: NodeType> QuorumProposalWrapper<TYPES> {
1117 pub fn block_header(&self) -> &TYPES::BlockHeader {
1119 &self.proposal.block_header
1120 }
1121
1122 pub fn view_number(&self) -> ViewNumber {
1124 self.proposal.view_number
1125 }
1126
1127 pub fn justify_qc(&self) -> &QuorumCertificate2<TYPES> {
1129 &self.proposal.justify_qc
1130 }
1131
1132 pub fn next_epoch_justify_qc(&self) -> &Option<NextEpochQuorumCertificate2<TYPES>> {
1134 &self.proposal.next_epoch_justify_qc
1135 }
1136
1137 pub fn upgrade_certificate(&self) -> &Option<UpgradeCertificate<TYPES>> {
1139 &self.proposal.upgrade_certificate
1140 }
1141
1142 pub fn view_change_evidence(&self) -> &Option<ViewChangeEvidence2<TYPES>> {
1144 &self.proposal.view_change_evidence
1145 }
1146
1147 pub fn next_drb_result(&self) -> &Option<DrbResult> {
1149 &self.proposal.next_drb_result
1150 }
1151
1152 pub async fn validate_epoch(
1156 &self,
1157 upgrade_lock: &UpgradeLock<TYPES>,
1158 epoch_height: u64,
1159 ) -> Result<()> {
1160 self.proposal
1161 .validate_epoch(upgrade_lock, epoch_height)
1162 .await
1163 }
1164
1165 pub fn state_cert(&self) -> &Option<LightClientStateUpdateCertificateV2<TYPES>> {
1167 &self.proposal.state_cert
1168 }
1169}
1170
1171impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposalWrapper<TYPES> {
1172 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
1173 Self {
1174 proposal: quorum_proposal.into(),
1175 }
1176 }
1177}
1178
1179impl<TYPES: NodeType> From<QuorumProposal2Legacy<TYPES>> for QuorumProposalWrapper<TYPES> {
1180 fn from(quorum_proposal: QuorumProposal2Legacy<TYPES>) -> Self {
1181 Self {
1182 proposal: quorum_proposal.into(),
1183 }
1184 }
1185}
1186
1187impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposalWrapper<TYPES> {
1188 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1189 Self {
1190 proposal: quorum_proposal2,
1191 }
1192 }
1193}
1194
1195impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal<TYPES> {
1196 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1197 quorum_proposal_wrapper.proposal.into()
1198 }
1199}
1200
1201impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal2Legacy<TYPES> {
1202 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1203 quorum_proposal_wrapper.proposal.into()
1204 }
1205}
1206
1207impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal2<TYPES> {
1208 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1209 quorum_proposal_wrapper.proposal
1210 }
1211}
1212
1213impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposal2<TYPES> {
1214 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
1215 Self {
1216 block_header: quorum_proposal.block_header,
1217 view_number: quorum_proposal.view_number,
1218 epoch: None,
1219 justify_qc: quorum_proposal.justify_qc.to_qc2(),
1220 next_epoch_justify_qc: None,
1221 upgrade_certificate: quorum_proposal.upgrade_certificate,
1222 view_change_evidence: quorum_proposal
1223 .proposal_certificate
1224 .map(ViewChangeEvidence::to_evidence2),
1225 next_drb_result: None,
1226 state_cert: None,
1227 }
1228 }
1229}
1230
1231impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposal<TYPES> {
1232 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1233 Self {
1234 block_header: quorum_proposal2.block_header,
1235 view_number: quorum_proposal2.view_number,
1236 justify_qc: quorum_proposal2.justify_qc.to_qc(),
1237 upgrade_certificate: quorum_proposal2.upgrade_certificate,
1238 proposal_certificate: quorum_proposal2
1239 .view_change_evidence
1240 .map(ViewChangeEvidence2::to_evidence),
1241 }
1242 }
1243}
1244
1245impl<TYPES: NodeType> From<Leaf<TYPES>> for Leaf2<TYPES> {
1246 fn from(leaf: Leaf<TYPES>) -> Self {
1247 let bytes: [u8; 32] = leaf.parent_commitment.into();
1248
1249 Self {
1250 view_number: leaf.view_number,
1251 justify_qc: leaf.justify_qc.to_qc2(),
1252 next_epoch_justify_qc: None,
1253 parent_commitment: Commitment::from_raw(bytes),
1254 block_header: leaf.block_header,
1255 upgrade_certificate: leaf.upgrade_certificate,
1256 block_payload: leaf.block_payload,
1257 view_change_evidence: None,
1258 next_drb_result: None,
1259 with_epoch: false,
1260 }
1261 }
1262}
1263
1264impl<TYPES: NodeType> HasViewNumber for DaProposal<TYPES> {
1265 fn view_number(&self) -> ViewNumber {
1266 self.view_number
1267 }
1268}
1269
1270impl<TYPES: NodeType> HasViewNumber for DaProposal2<TYPES> {
1271 fn view_number(&self) -> ViewNumber {
1272 self.view_number
1273 }
1274}
1275
1276impl<TYPES: NodeType> HasViewNumber for QuorumProposal<TYPES> {
1277 fn view_number(&self) -> ViewNumber {
1278 self.view_number
1279 }
1280}
1281
1282impl<TYPES: NodeType> HasViewNumber for QuorumProposal2<TYPES> {
1283 fn view_number(&self) -> ViewNumber {
1284 self.view_number
1285 }
1286}
1287
1288impl<TYPES: NodeType> HasViewNumber for QuorumProposal2Legacy<TYPES> {
1289 fn view_number(&self) -> ViewNumber {
1290 self.view_number
1291 }
1292}
1293
1294impl<TYPES: NodeType> HasViewNumber for QuorumProposalWrapper<TYPES> {
1295 fn view_number(&self) -> ViewNumber {
1296 self.proposal.view_number
1297 }
1298}
1299
1300impl<TYPES: NodeType> HasViewNumber for QuorumProposalWrapperLegacy<TYPES> {
1301 fn view_number(&self) -> ViewNumber {
1302 self.proposal.view_number
1303 }
1304}
1305
1306impl HasViewNumber for UpgradeProposal {
1307 fn view_number(&self) -> ViewNumber {
1308 self.view_number
1309 }
1310}
1311
1312impl<NODE: NodeType> HasEpoch for QuorumProposal2<NODE> {
1313 fn epoch(&self) -> Option<EpochNumber> {
1314 self.epoch
1315 }
1316}
1317
1318impl<NODE: NodeType> HasEpoch for DaProposal2<NODE> {
1319 fn epoch(&self) -> Option<EpochNumber> {
1320 self.epoch
1321 }
1322}
1323
1324impl<NODE: NodeType> HasEpoch for QuorumProposal2Legacy<NODE> {
1325 fn epoch(&self) -> Option<EpochNumber> {
1326 self.epoch
1327 }
1328}
1329
1330impl HasEpoch for UpgradeProposal {
1331 fn epoch(&self) -> Option<EpochNumber> {
1332 None
1333 }
1334}
1335
1336impl<NODE: NodeType> HasEpoch for QuorumProposal<NODE> {
1337 fn epoch(&self) -> Option<EpochNumber> {
1338 None
1339 }
1340}
1341
1342impl<NODE: NodeType> HasEpoch for DaProposal<NODE> {
1343 fn epoch(&self) -> Option<EpochNumber> {
1344 None
1345 }
1346}
1347
1348impl<NODE: NodeType> HasEpoch for QuorumProposalWrapper<NODE> {
1349 #[allow(clippy::panic)]
1351 fn epoch(&self) -> Option<EpochNumber> {
1352 self.proposal.epoch()
1353 }
1354}
1355
1356impl<TYPES: NodeType> HasEpoch for QuorumProposalWrapperLegacy<TYPES> {
1357 #[allow(clippy::panic)]
1359 fn epoch(&self) -> Option<EpochNumber> {
1360 self.proposal.epoch()
1361 }
1362}
1363
1364#[derive(Error, Debug, Serialize, Deserialize)]
1366pub enum BlockError {
1367 #[error("Invalid block header: {0}")]
1369 InvalidBlockHeader(String),
1370
1371 #[error("Inconsistent payload commitment")]
1373 InconsistentPayloadCommitment,
1374
1375 #[error("Failed to apply block header: {0}")]
1377 FailedHeaderApply(String),
1378}
1379
1380pub trait TestableLeaf {
1382 type NodeType: NodeType;
1384
1385 fn create_random_transaction(
1387 &self,
1388 rng: &mut dyn rand::RngCore,
1389 padding: u64,
1390 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction;
1391}
1392
1393#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1397#[serde(bound(deserialize = ""))]
1398pub struct Leaf<TYPES: NodeType> {
1399 view_number: ViewNumber,
1401
1402 justify_qc: QuorumCertificate<TYPES>,
1404
1405 parent_commitment: Commitment<Self>,
1408
1409 block_header: TYPES::BlockHeader,
1411
1412 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1414
1415 block_payload: Option<TYPES::BlockPayload>,
1419}
1420
1421#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1424#[serde(bound(deserialize = ""))]
1425pub struct Leaf2<TYPES: NodeType> {
1426 view_number: ViewNumber,
1428
1429 justify_qc: QuorumCertificate2<TYPES>,
1431
1432 next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1434
1435 parent_commitment: Commitment<Self>,
1438
1439 block_header: TYPES::BlockHeader,
1441
1442 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1444
1445 block_payload: Option<TYPES::BlockPayload>,
1449
1450 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
1452
1453 #[serde(with = "serde_bytes")]
1458 pub next_drb_result: Option<DrbResult>,
1459
1460 pub with_epoch: bool,
1462}
1463
1464impl<TYPES: NodeType> Leaf2<TYPES> {
1465 #[must_use]
1472 pub async fn genesis(
1473 validated_state: &TYPES::ValidatedState,
1474 instance_state: &TYPES::InstanceState,
1475 version: Version,
1476 ) -> Self {
1477 let epoch = genesis_epoch_from_version(version);
1478
1479 let (payload, metadata) =
1480 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1481 .await
1482 .unwrap();
1483
1484 let genesis_view = ViewNumber::genesis();
1485
1486 let block_header =
1487 TYPES::BlockHeader::genesis(instance_state, payload.clone(), &metadata, version);
1488
1489 let block_number = if version < EPOCH_VERSION {
1490 None
1491 } else {
1492 Some(0u64)
1493 };
1494
1495 let null_quorum_data = QuorumData2 {
1496 leaf_commit: Commitment::<Leaf2<TYPES>>::default_commitment_no_preimage(),
1497 epoch,
1498 block_number,
1499 };
1500
1501 let justify_qc = QuorumCertificate2::new(
1502 null_quorum_data.clone(),
1503 null_quorum_data.commit(),
1504 genesis_view,
1505 None,
1506 PhantomData,
1507 );
1508
1509 Self {
1510 view_number: genesis_view,
1511 justify_qc,
1512 next_epoch_justify_qc: None,
1513 parent_commitment: null_quorum_data.leaf_commit,
1514 upgrade_certificate: None,
1515 block_header: block_header.clone(),
1516 block_payload: Some(payload),
1517 view_change_evidence: None,
1518 next_drb_result: None,
1519 with_epoch: epoch.is_some(),
1520 }
1521 }
1522 pub fn view_number(&self) -> ViewNumber {
1524 self.view_number
1525 }
1526 pub fn epoch(&self, epoch_height: u64) -> Option<EpochNumber> {
1528 option_epoch_from_block_number(
1529 self.with_epoch,
1530 self.block_header.block_number(),
1531 epoch_height,
1532 )
1533 }
1534 pub fn height(&self) -> u64 {
1538 self.block_header.block_number()
1539 }
1540 pub fn justify_qc(&self) -> QuorumCertificate2<TYPES> {
1542 self.justify_qc.clone()
1543 }
1544 pub fn next_epoch_justify_qc(&self) -> Option<NextEpochQuorumCertificate2<TYPES>> {
1548 self.next_epoch_justify_qc.clone()
1549 }
1550 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1552 self.upgrade_certificate.clone()
1553 }
1554 pub fn parent_commitment(&self) -> Commitment<Self> {
1556 self.parent_commitment
1557 }
1558 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1560 &self.block_header
1561 }
1562
1563 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1565 &mut self.block_header
1566 }
1567 pub fn fill_block_payload(
1574 &mut self,
1575 block_payload: TYPES::BlockPayload,
1576 num_storage_nodes: usize,
1577 version: Version,
1578 ) -> std::result::Result<(), BlockError> {
1579 let encoded_txns = block_payload.encode();
1580 let commitment = vid_commitment(
1581 &encoded_txns,
1582 &self.block_header.metadata().encode(),
1583 num_storage_nodes,
1584 version,
1585 );
1586 if commitment != self.block_header.payload_commitment() {
1587 return Err(BlockError::InconsistentPayloadCommitment);
1588 }
1589 self.block_payload = Some(block_payload);
1590 Ok(())
1591 }
1592
1593 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
1595 self.block_payload.take()
1596 }
1597
1598 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
1601 self.block_payload = Some(block_payload);
1602 }
1603
1604 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
1606 self.block_payload.clone()
1607 }
1608
1609 pub fn payload_commitment(&self) -> VidCommitment {
1611 self.block_header().payload_commitment()
1612 }
1613
1614 pub fn extends_upgrade(&self, parent: &Self, upgrade: &UpgradeLock<TYPES>) -> Result<()> {
1622 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
1623 (None | Some(_), None) => {},
1627 (None, Some(parent_cert)) => {
1631 let decided_upgrade_certificate_read = upgrade.decided_upgrade_cert();
1632 ensure!(
1633 self.view_number() > parent_cert.data.new_version_first_view
1634 || (self.view_number() > parent_cert.data.decide_by
1635 && decided_upgrade_certificate_read.is_none()),
1636 "The new leaf is missing an upgrade certificate that was present in its \
1637 parent, and should still be live."
1638 );
1639 },
1640 (Some(cert), Some(parent_cert)) => {
1644 ensure!(
1645 cert == parent_cert,
1646 "The new leaf does not extend the parent leaf, because it has attached a \
1647 different upgrade certificate."
1648 );
1649 },
1650 }
1651
1652 Ok(())
1656 }
1657
1658 pub fn to_leaf_unsafe(self) -> Leaf<TYPES> {
1660 let bytes: [u8; 32] = self.parent_commitment.into();
1661
1662 Leaf {
1663 view_number: self.view_number,
1664 justify_qc: self.justify_qc.to_qc(),
1665 parent_commitment: Commitment::from_raw(bytes),
1666 block_header: self.block_header,
1667 upgrade_certificate: self.upgrade_certificate,
1668 block_payload: self.block_payload,
1669 }
1670 }
1671}
1672
1673impl<TYPES: NodeType> Committable for Leaf2<TYPES> {
1674 fn commit(&self) -> committable::Commitment<Self> {
1675 let Leaf2 {
1676 view_number,
1677 justify_qc,
1678 next_epoch_justify_qc,
1679 parent_commitment,
1680 block_header,
1681 upgrade_certificate,
1682 block_payload: _,
1683 view_change_evidence,
1684 next_drb_result,
1685 with_epoch,
1686 } = self;
1687
1688 let mut cb = RawCommitmentBuilder::new("leaf commitment")
1689 .u64_field("view number", **view_number)
1690 .field("parent leaf commitment", *parent_commitment)
1691 .field("block header", block_header.commit())
1692 .field("justify qc", justify_qc.commit())
1693 .optional("upgrade certificate", upgrade_certificate);
1694
1695 if *with_epoch {
1696 cb = cb
1697 .constant_str("with_epoch")
1698 .optional("next_epoch_justify_qc", next_epoch_justify_qc);
1699
1700 if let Some(next_drb_result) = next_drb_result {
1701 cb = cb
1702 .constant_str("next_drb_result")
1703 .fixed_size_bytes(next_drb_result);
1704 }
1705
1706 match view_change_evidence {
1707 Some(ViewChangeEvidence2::Timeout(cert)) => {
1708 cb = cb.field("timeout cert", cert.commit());
1709 },
1710 Some(ViewChangeEvidence2::ViewSync(cert)) => {
1711 cb = cb.field("viewsync cert", cert.commit());
1712 },
1713 None => {},
1714 }
1715 }
1716
1717 cb.finalize()
1718 }
1719}
1720
1721impl<TYPES: NodeType> Leaf<TYPES> {
1722 #[allow(clippy::unused_async)]
1723 pub async fn commit(&self, _upgrade_lock: &UpgradeLock<TYPES>) -> Commitment<Self> {
1726 <Self as Committable>::commit(self)
1727 }
1728}
1729
1730impl<TYPES: NodeType> PartialEq for Leaf<TYPES> {
1731 fn eq(&self, other: &Self) -> bool {
1732 self.view_number == other.view_number
1733 && self.justify_qc == other.justify_qc
1734 && self.parent_commitment == other.parent_commitment
1735 && self.block_header == other.block_header
1736 }
1737}
1738
1739impl<TYPES: NodeType> PartialEq for Leaf2<TYPES> {
1740 fn eq(&self, other: &Self) -> bool {
1741 let Leaf2 {
1742 view_number,
1743 justify_qc,
1744 next_epoch_justify_qc,
1745 parent_commitment,
1746 block_header,
1747 upgrade_certificate,
1748 block_payload: _,
1749 view_change_evidence,
1750 next_drb_result,
1751 with_epoch,
1752 } = self;
1753
1754 *view_number == other.view_number
1755 && *justify_qc == other.justify_qc
1756 && *next_epoch_justify_qc == other.next_epoch_justify_qc
1757 && *parent_commitment == other.parent_commitment
1758 && *block_header == other.block_header
1759 && *upgrade_certificate == other.upgrade_certificate
1760 && *view_change_evidence == other.view_change_evidence
1761 && *next_drb_result == other.next_drb_result
1762 && *with_epoch == other.with_epoch
1763 }
1764}
1765
1766impl<TYPES: NodeType> Hash for Leaf<TYPES> {
1767 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1768 self.view_number.hash(state);
1769 self.justify_qc.hash(state);
1770 self.parent_commitment.hash(state);
1771 self.block_header.hash(state);
1772 }
1773}
1774
1775impl<TYPES: NodeType> Hash for Leaf2<TYPES> {
1776 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1777 self.commit().hash(state);
1778 self.view_number.hash(state);
1779 self.justify_qc.hash(state);
1780 self.parent_commitment.hash(state);
1781 self.block_header.hash(state);
1782 }
1783}
1784
1785impl<TYPES: NodeType> Display for Leaf<TYPES> {
1786 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1787 write!(
1788 f,
1789 "view: {:?}, height: {:?}, justify: {}",
1790 self.view_number,
1791 self.height(),
1792 self.justify_qc
1793 )
1794 }
1795}
1796
1797impl<TYPES: NodeType> QuorumCertificate<TYPES> {
1798 #[must_use]
1800 pub async fn genesis(
1801 validated_state: &TYPES::ValidatedState,
1802 instance_state: &TYPES::InstanceState,
1803 upgrade: Upgrade,
1804 ) -> Self {
1805 let upgrade_lock = UpgradeLock::<TYPES>::new(upgrade);
1807
1808 let genesis_view = ViewNumber::genesis();
1809
1810 let data = QuorumData {
1811 leaf_commit: Leaf::genesis(validated_state, instance_state, upgrade.base)
1812 .await
1813 .commit(&upgrade_lock)
1814 .await,
1815 };
1816
1817 let versioned_data =
1818 VersionedVoteData::<_, _>::new_infallible(data.clone(), genesis_view, &upgrade_lock)
1819 .await;
1820
1821 let bytes: [u8; 32] = versioned_data.commit().into();
1822
1823 Self::new(
1824 data,
1825 Commitment::from_raw(bytes),
1826 genesis_view,
1827 None,
1828 PhantomData,
1829 )
1830 }
1831}
1832
1833impl<TYPES: NodeType> QuorumCertificate2<TYPES> {
1834 #[must_use]
1836 pub async fn genesis(
1837 validated_state: &TYPES::ValidatedState,
1838 instance_state: &TYPES::InstanceState,
1839 upgrade: Upgrade,
1840 ) -> Self {
1841 let upgrade_lock = UpgradeLock::<TYPES>::new(upgrade);
1843
1844 let genesis_view = ViewNumber::genesis();
1845
1846 let genesis_leaf = Leaf2::genesis(validated_state, instance_state, upgrade.base).await;
1847 let block_number = if upgrade_lock.epochs_enabled(genesis_view) {
1848 Some(genesis_leaf.height())
1849 } else {
1850 None
1851 };
1852 let data = QuorumData2 {
1853 leaf_commit: genesis_leaf.commit(),
1854 epoch: genesis_epoch_from_version(upgrade.base), block_number,
1856 };
1857
1858 let versioned_data =
1859 VersionedVoteData::<_, _>::new_infallible(data.clone(), genesis_view, &upgrade_lock)
1860 .await;
1861
1862 let bytes: [u8; 32] = versioned_data.commit().into();
1863
1864 Self::new(
1865 data,
1866 Commitment::from_raw(bytes),
1867 genesis_view,
1868 None,
1869 PhantomData,
1870 )
1871 }
1872}
1873
1874impl<TYPES: NodeType> Leaf<TYPES> {
1875 #[must_use]
1882 pub async fn genesis(
1883 validated_state: &TYPES::ValidatedState,
1884 instance_state: &TYPES::InstanceState,
1885 version: Version,
1886 ) -> Self {
1887 let (payload, metadata) =
1888 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1889 .await
1890 .unwrap();
1891
1892 let genesis_view = ViewNumber::genesis();
1893
1894 let block_header =
1895 TYPES::BlockHeader::genesis(instance_state, payload.clone(), &metadata, version);
1896
1897 let null_quorum_data = QuorumData {
1898 leaf_commit: Commitment::<Leaf<TYPES>>::default_commitment_no_preimage(),
1899 };
1900
1901 let justify_qc = QuorumCertificate::new(
1902 null_quorum_data.clone(),
1903 null_quorum_data.commit(),
1904 genesis_view,
1905 None,
1906 PhantomData,
1907 );
1908
1909 Self {
1910 view_number: genesis_view,
1911 justify_qc,
1912 parent_commitment: null_quorum_data.leaf_commit,
1913 upgrade_certificate: None,
1914 block_header: block_header.clone(),
1915 block_payload: Some(payload),
1916 }
1917 }
1918
1919 pub fn view_number(&self) -> ViewNumber {
1921 self.view_number
1922 }
1923 pub fn height(&self) -> u64 {
1927 self.block_header.block_number()
1928 }
1929 pub fn justify_qc(&self) -> QuorumCertificate<TYPES> {
1931 self.justify_qc.clone()
1932 }
1933 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1935 self.upgrade_certificate.clone()
1936 }
1937 pub fn parent_commitment(&self) -> Commitment<Self> {
1939 self.parent_commitment
1940 }
1941 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1943 &self.block_header
1944 }
1945
1946 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1948 &mut self.block_header
1949 }
1950 pub fn fill_block_payload(
1957 &mut self,
1958 block_payload: TYPES::BlockPayload,
1959 num_storage_nodes: usize,
1960 version: Version,
1961 ) -> std::result::Result<(), BlockError> {
1962 let encoded_txns = block_payload.encode();
1963 let commitment = vid_commitment(
1964 &encoded_txns,
1965 &self.block_header.metadata().encode(),
1966 num_storage_nodes,
1967 version,
1968 );
1969 if commitment != self.block_header.payload_commitment() {
1970 return Err(BlockError::InconsistentPayloadCommitment);
1971 }
1972 self.block_payload = Some(block_payload);
1973 Ok(())
1974 }
1975
1976 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
1978 self.block_payload.take()
1979 }
1980
1981 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
1984 self.block_payload = Some(block_payload);
1985 }
1986
1987 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
1989 self.block_payload.clone()
1990 }
1991
1992 pub fn payload_commitment(&self) -> VidCommitment {
1994 self.block_header().payload_commitment()
1995 }
1996
1997 pub fn extends_upgrade(&self, parent: &Self, upgrade: &UpgradeLock<TYPES>) -> Result<()> {
2005 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
2006 (None | Some(_), None) => {},
2010 (None, Some(parent_cert)) => {
2014 let decided_upgrade_certificate_read = upgrade.decided_upgrade_cert();
2015 ensure!(
2016 self.view_number() > parent_cert.data.new_version_first_view
2017 || (self.view_number() > parent_cert.data.decide_by
2018 && decided_upgrade_certificate_read.is_none()),
2019 "The new leaf is missing an upgrade certificate that was present in its \
2020 parent, and should still be live."
2021 );
2022 },
2023 (Some(cert), Some(parent_cert)) => {
2027 ensure!(
2028 cert == parent_cert,
2029 "The new leaf does not extend the parent leaf, because it has attached a \
2030 different upgrade certificate."
2031 );
2032 },
2033 }
2034
2035 Ok(())
2039 }
2040}
2041
2042impl<TYPES: NodeType> TestableLeaf for Leaf<TYPES>
2043where
2044 TYPES::ValidatedState: TestableState<TYPES>,
2045 TYPES::BlockPayload: TestableBlock<TYPES>,
2046{
2047 type NodeType = TYPES;
2048
2049 fn create_random_transaction(
2050 &self,
2051 rng: &mut dyn rand::RngCore,
2052 padding: u64,
2053 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
2054 {
2055 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
2056 }
2057}
2058impl<TYPES: NodeType> TestableLeaf for Leaf2<TYPES>
2059where
2060 TYPES::ValidatedState: TestableState<TYPES>,
2061 TYPES::BlockPayload: TestableBlock<TYPES>,
2062{
2063 type NodeType = TYPES;
2064
2065 fn create_random_transaction(
2066 &self,
2067 rng: &mut dyn rand::RngCore,
2068 padding: u64,
2069 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
2070 {
2071 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
2072 }
2073}
2074#[must_use]
2076pub fn fake_commitment<S: Committable>() -> Commitment<S> {
2077 RawCommitmentBuilder::new("Dummy commitment for arbitrary genesis").finalize()
2078}
2079
2080#[must_use]
2082pub fn random_commitment<S: Committable>(rng: &mut dyn rand::RngCore) -> Commitment<S> {
2083 let random_array: Vec<u8> = (0u8..100u8).map(|_| rng.gen_range(0..255)).collect();
2084 RawCommitmentBuilder::new("Random Commitment")
2085 .constant_str("Random Field")
2086 .var_size_bytes(&random_array)
2087 .finalize()
2088}
2089
2090pub fn serialize_signature2<TYPES: NodeType>(
2094 signatures: &<TYPES::SignatureKey as SignatureKey>::QcType,
2095) -> Vec<u8> {
2096 let mut signatures_bytes = vec![];
2097 signatures_bytes.extend("Yes".as_bytes());
2098
2099 let (sig, proof) = TYPES::SignatureKey::sig_proof(signatures);
2100 let proof_bytes = bincode_opts()
2101 .serialize(&proof.as_bitslice())
2102 .expect("This serialization shouldn't be able to fail");
2103 signatures_bytes.extend("bitvec proof".as_bytes());
2104 signatures_bytes.extend(proof_bytes.as_slice());
2105 let sig_bytes = bincode_opts()
2106 .serialize(&sig)
2107 .expect("This serialization shouldn't be able to fail");
2108 signatures_bytes.extend("aggregated signature".as_bytes());
2109 signatures_bytes.extend(sig_bytes.as_slice());
2110 signatures_bytes
2111}
2112
2113impl<TYPES: NodeType> Committable for Leaf<TYPES> {
2114 fn commit(&self) -> committable::Commitment<Self> {
2115 RawCommitmentBuilder::new("leaf commitment")
2116 .u64_field("view number", *self.view_number)
2117 .field("parent leaf commitment", self.parent_commitment)
2118 .field("block header", self.block_header.commit())
2119 .field("justify qc", self.justify_qc.commit())
2120 .optional("upgrade certificate", &self.upgrade_certificate)
2121 .finalize()
2122 }
2123}
2124
2125impl<TYPES: NodeType> Leaf2<TYPES> {
2126 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposalWrapper<TYPES>) -> Self {
2128 let QuorumProposalWrapper {
2131 proposal:
2132 QuorumProposal2 {
2133 view_number,
2134 epoch,
2135 justify_qc,
2136 next_epoch_justify_qc,
2137 block_header,
2138 upgrade_certificate,
2139 view_change_evidence,
2140 next_drb_result,
2141 state_cert: _,
2142 },
2143 } = quorum_proposal;
2144
2145 Self {
2146 view_number: *view_number,
2147 justify_qc: justify_qc.clone(),
2148 next_epoch_justify_qc: next_epoch_justify_qc.clone(),
2149 parent_commitment: justify_qc.data().leaf_commit,
2150 block_header: block_header.clone(),
2151 upgrade_certificate: upgrade_certificate.clone(),
2152 block_payload: None,
2153 view_change_evidence: view_change_evidence.clone(),
2154 next_drb_result: *next_drb_result,
2155 with_epoch: epoch.is_some(),
2156 }
2157 }
2158}
2159
2160impl<TYPES: NodeType> Leaf<TYPES> {
2161 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposal<TYPES>) -> Self {
2163 let QuorumProposal {
2166 view_number,
2167 justify_qc,
2168 block_header,
2169 upgrade_certificate,
2170 proposal_certificate: _,
2171 } = quorum_proposal;
2172
2173 Self {
2174 view_number: *view_number,
2175 justify_qc: justify_qc.clone(),
2176 parent_commitment: justify_qc.data().leaf_commit,
2177 block_header: block_header.clone(),
2178 upgrade_certificate: upgrade_certificate.clone(),
2179 block_payload: None,
2180 }
2181 }
2182}
2183
2184pub mod null_block {
2185 #![allow(missing_docs)]
2186
2187 use jf_advz::VidScheme;
2188 use vbs::version::Version;
2189 use versions::EPOCH_VERSION;
2190
2191 use crate::{
2192 data::VidCommitment,
2193 traits::{
2194 BlockPayload, block_contents::BuilderFee, node_implementation::NodeType,
2195 signature_key::BuilderSignatureKey,
2196 },
2197 vid::advz::advz_scheme,
2198 };
2199
2200 #[must_use]
2209 pub fn commitment(num_storage_nodes: usize) -> Option<VidCommitment> {
2210 let vid_result = advz_scheme(num_storage_nodes).commit_only(Vec::new());
2211
2212 match vid_result {
2213 Ok(r) => Some(VidCommitment::V0(r)),
2214 Err(_) => None,
2215 }
2216 }
2217
2218 #[must_use]
2220 pub fn builder_fee<TYPES: NodeType>(
2221 num_storage_nodes: usize,
2222 version: Version,
2223 ) -> Option<BuilderFee<TYPES>> {
2224 const FEE_AMOUNT: u64 = 0;
2226
2227 let (pub_key, priv_key) =
2228 <TYPES::BuilderSignatureKey as BuilderSignatureKey>::generated_from_seed_indexed(
2229 [0_u8; 32], 0,
2230 );
2231
2232 if version >= EPOCH_VERSION {
2233 let (_null_block, null_block_metadata) =
2234 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2235
2236 match TYPES::BuilderSignatureKey::sign_fee(&priv_key, FEE_AMOUNT, &null_block_metadata)
2237 {
2238 Ok(sig) => Some(BuilderFee {
2239 fee_amount: FEE_AMOUNT,
2240 fee_account: pub_key,
2241 fee_signature: sig,
2242 }),
2243 Err(_) => None,
2244 }
2245 } else {
2246 let (_null_block, null_block_metadata) =
2247 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2248
2249 match TYPES::BuilderSignatureKey::sign_fee_with_vid_commitment(
2250 &priv_key,
2251 FEE_AMOUNT,
2252 &null_block_metadata,
2253 &commitment(num_storage_nodes)?,
2254 ) {
2255 Ok(sig) => Some(BuilderFee {
2256 fee_amount: FEE_AMOUNT,
2257 fee_account: pub_key,
2258 fee_signature: sig,
2259 }),
2260 Err(_) => None,
2261 }
2262 }
2263 }
2264}
2265
2266#[derive(Debug, Eq, PartialEq, Clone)]
2268pub struct PackedBundle<TYPES: NodeType> {
2269 pub encoded_transactions: Arc<[u8]>,
2271
2272 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2274
2275 pub view_number: ViewNumber,
2277
2278 pub epoch_number: Option<EpochNumber>,
2280
2281 pub sequencing_fees: Vec1<BuilderFee<TYPES>>,
2283}
2284
2285impl<TYPES: NodeType> PackedBundle<TYPES> {
2286 pub fn new(
2288 encoded_transactions: Arc<[u8]>,
2289 metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2290 view_number: ViewNumber,
2291 epoch_number: Option<EpochNumber>,
2292 sequencing_fees: Vec1<BuilderFee<TYPES>>,
2293 ) -> Self {
2294 Self {
2295 encoded_transactions,
2296 metadata,
2297 view_number,
2298 epoch_number,
2299 sequencing_fees,
2300 }
2301 }
2302}
2303
2304#[cfg(test)]
2305mod test {
2306 use super::*;
2307
2308 #[test]
2309 fn test_vid_commitment_display() {
2310 let vc = VidCommitment::V0(VidCommitment0::default());
2311 assert_eq!(
2312 format!("{vc}"),
2313 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2314 );
2315 assert_eq!(
2316 format!("{vc:?}"),
2317 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2318 );
2319
2320 let vc = VidCommitment::V1(VidCommitment1::default());
2321 assert_eq!(
2322 format!("{vc}"),
2323 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2324 );
2325 assert_eq!(
2326 format!("{vc:?}"),
2327 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2328 );
2329
2330 let vc = VidCommitment::V2(VidCommitment2::default());
2331 assert_eq!(
2332 format!("{vc}"),
2333 "AvidmGf2Commit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq"
2334 );
2335 assert_eq!(
2336 format!("{vc:?}"),
2337 "AvidmGf2Commit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACq"
2338 );
2339 }
2340}