1use std::{
13 fmt::{Debug, Display},
14 hash::Hash,
15 marker::PhantomData,
16 sync::Arc,
17 time::Duration,
18};
19
20use async_lock::RwLock;
21use bincode::Options;
22use committable::{Commitment, CommitmentBoundsArkless, Committable, RawCommitmentBuilder};
23use hotshot_utils::anytrace::*;
24use jf_vid::VidScheme;
25use rand::Rng;
26use serde::{Deserialize, Serialize};
27use tagged_base64::TaggedBase64;
28use thiserror::Error;
29use vbs::version::{StaticVersionType, Version};
30use vec1::Vec1;
31use vid_disperse::{ADVZDisperse, ADVZDisperseShare, AvidMDisperse, VidDisperseShare2};
32
33use crate::{
34 drb::DrbResult,
35 epoch_membership::EpochMembershipCoordinator,
36 impl_has_epoch, impl_has_none_epoch,
37 message::{convert_proposal, Proposal, UpgradeLock},
38 simple_certificate::{
39 LightClientStateUpdateCertificateV1, LightClientStateUpdateCertificateV2,
40 NextEpochQuorumCertificate2, QuorumCertificate, QuorumCertificate2, TimeoutCertificate,
41 TimeoutCertificate2, UpgradeCertificate, ViewSyncFinalizeCertificate,
42 ViewSyncFinalizeCertificate2,
43 },
44 simple_vote::{HasEpoch, QuorumData, QuorumData2, UpgradeProposalData, VersionedVoteData},
45 traits::{
46 block_contents::{BlockHeader, BuilderFee, EncodeBytes, TestableBlock},
47 node_implementation::{ConsensusTime, NodeType, Versions},
48 signature_key::SignatureKey,
49 states::TestableState,
50 BlockPayload,
51 },
52 utils::{
53 bincode_opts, genesis_epoch_from_version, option_epoch_from_block_number,
54 EpochTransitionIndicator,
55 },
56 vid::{
57 advz::{advz_scheme, ADVZCommitment, ADVZShare},
58 avidm::{init_avidm_param, AvidMCommitment, AvidMScheme, AvidMShare},
59 },
60 vote::{Certificate, HasViewNumber},
61};
62
63macro_rules! impl_u64_wrapper {
66 ($t:ty, $genesis_val:expr) => {
67 impl ConsensusTime for $t {
68 fn genesis() -> Self {
70 Self($genesis_val)
71 }
72 fn new(n: u64) -> Self {
74 Self(n)
75 }
76 fn u64(&self) -> u64 {
78 self.0
79 }
80 }
81
82 impl Display for $t {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 write!(f, "{}", self.0)
85 }
86 }
87
88 impl std::ops::Add<u64> for $t {
89 type Output = $t;
90
91 fn add(self, rhs: u64) -> Self::Output {
92 Self(self.0 + rhs)
93 }
94 }
95
96 impl std::ops::AddAssign<u64> for $t {
97 fn add_assign(&mut self, rhs: u64) {
98 self.0 += rhs;
99 }
100 }
101
102 impl std::ops::Deref for $t {
103 type Target = u64;
104
105 fn deref(&self) -> &Self::Target {
106 &self.0
107 }
108 }
109
110 impl std::ops::Sub<u64> for $t {
111 type Output = $t;
112 fn sub(self, rhs: u64) -> Self::Output {
113 Self(self.0 - rhs)
114 }
115 }
116 };
117}
118
119#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
121pub struct ViewNumber(u64);
122
123impl Committable for ViewNumber {
124 fn commit(&self) -> Commitment<Self> {
125 let builder = RawCommitmentBuilder::new("View Number Commitment");
126 builder.u64(self.0).finalize()
127 }
128}
129
130impl_u64_wrapper!(ViewNumber, 0u64);
131
132#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
134pub struct EpochNumber(u64);
135
136impl Committable for EpochNumber {
137 fn commit(&self) -> Commitment<Self> {
138 let builder = RawCommitmentBuilder::new("Epoch Number Commitment");
139 builder.u64(self.0).finalize()
140 }
141}
142
143impl_u64_wrapper!(EpochNumber, 1u64);
144
145#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
147#[serde(bound = "TYPES: NodeType")]
148pub struct DaProposal<TYPES: NodeType> {
149 pub encoded_transactions: Arc<[u8]>,
151 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
153 pub view_number: TYPES::View,
155}
156
157#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
159#[serde(bound = "TYPES: NodeType")]
160pub struct DaProposal2<TYPES: NodeType> {
161 pub encoded_transactions: Arc<[u8]>,
163 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
165 pub view_number: TYPES::View,
167 pub epoch: Option<TYPES::Epoch>,
169 pub epoch_transition_indicator: EpochTransitionIndicator,
172}
173
174impl<TYPES: NodeType> From<DaProposal<TYPES>> for DaProposal2<TYPES> {
175 fn from(da_proposal: DaProposal<TYPES>) -> Self {
176 Self {
177 encoded_transactions: da_proposal.encoded_transactions,
178 metadata: da_proposal.metadata,
179 view_number: da_proposal.view_number,
180 epoch: None,
181 epoch_transition_indicator: EpochTransitionIndicator::NotInTransition,
182 }
183 }
184}
185
186impl<TYPES: NodeType> From<DaProposal2<TYPES>> for DaProposal<TYPES> {
187 fn from(da_proposal2: DaProposal2<TYPES>) -> Self {
188 Self {
189 encoded_transactions: da_proposal2.encoded_transactions,
190 metadata: da_proposal2.metadata,
191 view_number: da_proposal2.view_number,
192 }
193 }
194}
195
196#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
198#[serde(bound = "TYPES: NodeType")]
199pub struct UpgradeProposal<TYPES>
200where
201 TYPES: NodeType,
202{
203 pub upgrade_proposal: UpgradeProposalData<TYPES>,
205 pub view_number: TYPES::View,
207}
208
209#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, Ord, PartialOrd)]
211#[serde(
212 try_from = "tagged_base64::TaggedBase64",
213 into = "tagged_base64::TaggedBase64"
214)]
215pub enum VidCommitment {
216 V0(ADVZCommitment),
217 V1(AvidMCommitment),
218}
219
220impl Default for VidCommitment {
221 fn default() -> Self {
222 Self::V0(Default::default())
223 }
224}
225
226impl Display for VidCommitment {
227 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
228 std::write!(f, "{}", TaggedBase64::from(self))
229 }
230}
231
232impl Debug for VidCommitment {
233 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
234 std::fmt::Display::fmt(self, f)
235 }
236}
237
238impl From<VidCommitment> for TaggedBase64 {
239 fn from(val: VidCommitment) -> Self {
240 match val {
241 VidCommitment::V0(comm) => comm.into(),
242 VidCommitment::V1(comm) => comm.into(),
243 }
244 }
245}
246
247impl From<&VidCommitment> for TaggedBase64 {
248 fn from(val: &VidCommitment) -> Self {
249 match val {
250 VidCommitment::V0(comm) => comm.into(),
251 VidCommitment::V1(comm) => comm.into(),
252 }
253 }
254}
255
256impl TryFrom<TaggedBase64> for VidCommitment {
257 type Error = tagged_base64::Tb64Error;
258
259 fn try_from(value: TaggedBase64) -> std::result::Result<Self, Self::Error> {
260 ADVZCommitment::try_from(&value)
261 .map(Self::V0)
262 .or(AvidMCommitment::try_from(value).map(Self::V1))
263 }
264}
265
266impl<'a> TryFrom<&'a TaggedBase64> for VidCommitment {
267 type Error = tagged_base64::Tb64Error;
268
269 fn try_from(value: &'a TaggedBase64) -> std::result::Result<Self, Self::Error> {
270 ADVZCommitment::try_from(value)
271 .map(Self::V0)
272 .or(AvidMCommitment::try_from(value).map(Self::V1))
273 }
274}
275
276impl std::str::FromStr for VidCommitment {
277 type Err = tagged_base64::Tb64Error;
278 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
279 use core::convert::TryFrom;
280 Self::try_from(TaggedBase64::from_str(s)?)
281 .map_err(|_| tagged_base64::Tb64Error::InvalidData)
282 }
283}
284
285impl From<AvidMCommitment> for VidCommitment {
293 fn from(comm: AvidMCommitment) -> Self {
294 Self::V1(comm)
295 }
296}
297
298impl AsRef<[u8]> for VidCommitment {
299 fn as_ref(&self) -> &[u8] {
300 match self {
301 Self::V0(comm) => comm.as_ref(),
302 Self::V1(comm) => comm.as_ref(),
303 }
304 }
305}
306
307impl AsRef<[u8; 32]> for VidCommitment {
308 fn as_ref(&self) -> &[u8; 32] {
309 match self {
310 Self::V0(comm) => comm.as_ref().as_ref(),
311 Self::V1(comm) => comm.as_ref(),
312 }
313 }
314}
315
316impl VidCommitment {
317 pub fn unwrap_v0(self) -> ADVZCommitment {
319 match self {
320 VidCommitment::V0(comm) => comm,
321 _ => panic!("Unexpected version for this commitment"),
322 }
323 }
324 pub fn unwrap_v1(self) -> AvidMCommitment {
326 match self {
327 VidCommitment::V1(comm) => comm,
328 _ => panic!("Unexpected version for this commitment"),
329 }
330 }
331}
332
333#[must_use]
338#[allow(clippy::panic)]
339pub fn vid_commitment<V: Versions>(
340 encoded_transactions: &[u8],
341 metadata: &[u8],
342 total_weight: usize,
343 version: Version,
344) -> VidCommitment {
345 if version < V::Epochs::VERSION {
346 let encoded_tx_len = encoded_transactions.len();
347 advz_scheme(total_weight)
348 .commit_only(encoded_transactions)
349 .map(VidCommitment::V0)
350 .unwrap_or_else(|err| {
351 panic!(
352 "VidScheme::commit_only \
353 failure:(total_weight,payload_byte_len)=({total_weight},{encoded_tx_len}) \
354 error: {err}"
355 )
356 })
357 } else {
358 let param = init_avidm_param(total_weight).unwrap();
359 let encoded_tx_len = encoded_transactions.len();
360 AvidMScheme::commit(
361 ¶m,
362 encoded_transactions,
363 ns_table::parse_ns_table(encoded_tx_len, metadata),
364 )
365 .map(VidCommitment::V1)
366 .unwrap()
367 }
368}
369
370#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
372pub enum VidShare {
373 V0(ADVZShare),
374 V1(AvidMShare),
375}
376
377impl From<AvidMShare> for VidShare {
385 fn from(share: AvidMShare) -> Self {
386 Self::V1(share)
387 }
388}
389
390pub mod ns_table;
391pub mod vid_disperse;
392
393pub struct VidDisperseAndDuration<TYPES: NodeType> {
395 pub disperse: VidDisperse<TYPES>,
397 pub duration: Duration,
399}
400
401#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
407#[serde(bound = "TYPES: NodeType")]
408pub enum VidDisperse<TYPES: NodeType> {
409 V0(vid_disperse::ADVZDisperse<TYPES>),
411 V1(vid_disperse::AvidMDisperse<TYPES>),
413}
414
415impl<TYPES: NodeType> From<vid_disperse::ADVZDisperse<TYPES>> for VidDisperse<TYPES> {
416 fn from(disperse: vid_disperse::ADVZDisperse<TYPES>) -> Self {
417 Self::V0(disperse)
418 }
419}
420
421impl<TYPES: NodeType> From<vid_disperse::AvidMDisperse<TYPES>> for VidDisperse<TYPES> {
422 fn from(disperse: vid_disperse::AvidMDisperse<TYPES>) -> Self {
423 Self::V1(disperse)
424 }
425}
426
427impl<TYPES: NodeType> HasViewNumber<TYPES> for VidDisperse<TYPES> {
428 fn view_number(&self) -> TYPES::View {
429 match self {
430 Self::V0(disperse) => disperse.view_number(),
431 Self::V1(disperse) => disperse.view_number(),
432 }
433 }
434}
435
436impl<TYPES: NodeType> HasEpoch<TYPES> for VidDisperse<TYPES> {
437 fn epoch(&self) -> Option<TYPES::Epoch> {
438 match self {
439 Self::V0(disperse) => disperse.epoch(),
440 Self::V1(disperse) => disperse.epoch(),
441 }
442 }
443}
444
445impl<TYPES: NodeType> VidDisperse<TYPES> {
446 #[allow(clippy::panic)]
452 pub async fn calculate_vid_disperse<V: Versions>(
453 payload: &TYPES::BlockPayload,
454 membership: &EpochMembershipCoordinator<TYPES>,
455 view: TYPES::View,
456 target_epoch: Option<TYPES::Epoch>,
457 data_epoch: Option<TYPES::Epoch>,
458 metadata: &<TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
459 upgrade_lock: &UpgradeLock<TYPES, V>,
460 ) -> Result<VidDisperseAndDuration<TYPES>> {
461 let version = upgrade_lock.version_infallible(view).await;
462 if version < V::Epochs::VERSION {
463 ADVZDisperse::calculate_vid_disperse(
464 payload,
465 membership,
466 view,
467 target_epoch,
468 data_epoch,
469 )
470 .await
471 .map(|(disperse, duration)| VidDisperseAndDuration {
472 disperse: Self::V0(disperse),
473 duration,
474 })
475 } else {
476 AvidMDisperse::calculate_vid_disperse(
477 payload,
478 membership,
479 view,
480 target_epoch,
481 data_epoch,
482 metadata,
483 )
484 .await
485 .map(|(disperse, duration)| VidDisperseAndDuration {
486 disperse: Self::V1(disperse),
487 duration,
488 })
489 }
490 }
491
492 pub fn payload_commitment(&self) -> VidCommitment {
494 match self {
495 Self::V0(disperse) => VidCommitment::V0(disperse.payload_commitment),
496 Self::V1(disperse) => disperse.payload_commitment.into(),
497 }
498 }
499
500 pub fn payload_commitment_ref(&self) -> &[u8] {
502 match self {
503 Self::V0(disperse) => disperse.payload_commitment.as_ref(),
504 Self::V1(disperse) => disperse.payload_commitment.as_ref(),
505 }
506 }
507
508 pub fn set_view_number(&mut self, view_number: <TYPES as NodeType>::View) {
510 match self {
511 Self::V0(share) => share.view_number = view_number,
512 Self::V1(share) => share.view_number = view_number,
513 }
514 }
515}
516
517#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
519#[serde(bound = "TYPES: NodeType")]
520pub enum VidDisperseShare<TYPES: NodeType> {
521 V0(vid_disperse::ADVZDisperseShare<TYPES>),
523 V1(vid_disperse::VidDisperseShare2<TYPES>),
525}
526
527impl<TYPES: NodeType> VidDisperseShare<TYPES> {
528 pub fn from_vid_disperse(vid_disperse: VidDisperse<TYPES>) -> Vec<Self> {
530 match vid_disperse {
531 VidDisperse::V0(vid_disperse) => {
532 ADVZDisperseShare::<TYPES>::from_advz_disperse(vid_disperse)
533 .into_iter()
534 .map(|share| Self::V0(share))
535 .collect()
536 },
537 VidDisperse::V1(vid_disperse) => {
538 VidDisperseShare2::<TYPES>::from_vid_disperse(vid_disperse)
539 .into_iter()
540 .map(|share| Self::V1(share))
541 .collect()
542 },
543 }
544 }
545
546 pub fn to_proposal(
548 self,
549 private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
550 ) -> Option<Proposal<TYPES, Self>> {
551 let payload_commitment_ref: &[u8] = match &self {
552 Self::V0(share) => share.payload_commitment.as_ref(),
553 Self::V1(share) => share.payload_commitment.as_ref(),
554 };
555 let Ok(signature) = TYPES::SignatureKey::sign(private_key, payload_commitment_ref) else {
556 tracing::error!("VID: failed to sign dispersal share payload");
557 return None;
558 };
559 Some(Proposal {
560 signature,
561 _pd: PhantomData,
562 data: self,
563 })
564 }
565
566 pub fn to_vid_share_proposals(
568 vid_disperse_proposal: Proposal<TYPES, VidDisperse<TYPES>>,
569 ) -> Vec<Proposal<TYPES, Self>> {
570 match vid_disperse_proposal.data {
571 VidDisperse::V0(disperse) => ADVZDisperseShare::to_vid_share_proposals(
572 disperse,
573 &vid_disperse_proposal.signature,
574 )
575 .into_iter()
576 .map(|proposal| convert_proposal(proposal))
577 .collect(),
578 VidDisperse::V1(disperse) => VidDisperseShare2::to_vid_share_proposals(
579 disperse,
580 &vid_disperse_proposal.signature,
581 )
582 .into_iter()
583 .map(|proposal| convert_proposal(proposal))
584 .collect(),
585 }
586 }
587
588 pub fn recipient_key(&self) -> &TYPES::SignatureKey {
590 match self {
591 Self::V0(share) => &share.recipient_key,
592 Self::V1(share) => &share.recipient_key,
593 }
594 }
595
596 pub fn payload_byte_len(&self) -> u32 {
598 match self {
599 Self::V0(share) => share.payload_byte_len(),
600 Self::V1(share) => share.payload_byte_len(),
601 }
602 }
603
604 pub fn payload_commitment_ref(&self) -> &[u8] {
606 match self {
607 Self::V0(share) => share.payload_commitment.as_ref(),
608 Self::V1(share) => share.payload_commitment.as_ref(),
609 }
610 }
611
612 pub fn payload_commitment(&self) -> VidCommitment {
614 match self {
615 Self::V0(share) => VidCommitment::V0(share.payload_commitment),
616 Self::V1(share) => share.payload_commitment.into(),
617 }
618 }
619
620 pub fn target_epoch(&self) -> Option<<TYPES as NodeType>::Epoch> {
622 match self {
623 Self::V0(_) => None,
624 Self::V1(share) => share.target_epoch,
625 }
626 }
627
628 #[allow(clippy::result_unit_err)]
632 pub fn verify_share(&self, total_nodes: usize) -> std::result::Result<(), ()> {
633 match self {
634 Self::V0(share) => share.verify_share(total_nodes),
635 Self::V1(share) => share.verify_share(total_nodes),
636 }
637 }
638
639 pub fn set_view_number(&mut self, view_number: <TYPES as NodeType>::View) {
641 match self {
642 Self::V0(share) => share.view_number = view_number,
643 Self::V1(share) => share.view_number = view_number,
644 }
645 }
646}
647
648impl<TYPES: NodeType> HasViewNumber<TYPES> for VidDisperseShare<TYPES> {
649 fn view_number(&self) -> TYPES::View {
650 match self {
651 Self::V0(disperse) => disperse.view_number(),
652 Self::V1(disperse) => disperse.view_number(),
653 }
654 }
655}
656
657impl<TYPES: NodeType> HasEpoch<TYPES> for VidDisperseShare<TYPES> {
658 fn epoch(&self) -> Option<TYPES::Epoch> {
659 match self {
660 Self::V0(_) => None,
661 Self::V1(share) => share.epoch(),
662 }
663 }
664}
665
666impl<TYPES: NodeType> From<vid_disperse::ADVZDisperseShare<TYPES>> for VidDisperseShare<TYPES> {
667 fn from(share: vid_disperse::ADVZDisperseShare<TYPES>) -> Self {
668 Self::V0(share)
669 }
670}
671
672impl<TYPES: NodeType> From<vid_disperse::VidDisperseShare2<TYPES>> for VidDisperseShare<TYPES> {
673 fn from(share: vid_disperse::VidDisperseShare2<TYPES>) -> Self {
674 Self::V1(share)
675 }
676}
677
678#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
681#[serde(bound(deserialize = ""))]
682pub enum ViewChangeEvidence<TYPES: NodeType> {
683 Timeout(TimeoutCertificate<TYPES>),
685 ViewSync(ViewSyncFinalizeCertificate<TYPES>),
687}
688
689impl<TYPES: NodeType> ViewChangeEvidence<TYPES> {
690 pub fn is_valid_for_view(&self, view: &TYPES::View) -> bool {
692 match self {
693 ViewChangeEvidence::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
694 ViewChangeEvidence::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
695 }
696 }
697
698 pub fn to_evidence2(self) -> ViewChangeEvidence2<TYPES> {
700 match self {
701 ViewChangeEvidence::Timeout(timeout_cert) => {
702 ViewChangeEvidence2::Timeout(timeout_cert.to_tc2())
703 },
704 ViewChangeEvidence::ViewSync(view_sync_cert) => {
705 ViewChangeEvidence2::ViewSync(view_sync_cert.to_vsc2())
706 },
707 }
708 }
709}
710
711#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
714#[serde(bound(deserialize = ""))]
715pub enum ViewChangeEvidence2<TYPES: NodeType> {
716 Timeout(TimeoutCertificate2<TYPES>),
718 ViewSync(ViewSyncFinalizeCertificate2<TYPES>),
720}
721
722impl<TYPES: NodeType> ViewChangeEvidence2<TYPES> {
723 pub fn is_valid_for_view(&self, view: &TYPES::View) -> bool {
725 match self {
726 ViewChangeEvidence2::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
727 ViewChangeEvidence2::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
728 }
729 }
730
731 pub fn to_evidence(self) -> ViewChangeEvidence<TYPES> {
733 match self {
734 ViewChangeEvidence2::Timeout(timeout_cert) => {
735 ViewChangeEvidence::Timeout(timeout_cert.to_tc())
736 },
737 ViewChangeEvidence2::ViewSync(view_sync_cert) => {
738 ViewChangeEvidence::ViewSync(view_sync_cert.to_vsc())
739 },
740 }
741 }
742}
743
744#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
746#[serde(bound(deserialize = ""))]
747pub struct QuorumProposal<TYPES: NodeType> {
748 pub block_header: TYPES::BlockHeader,
750
751 pub view_number: TYPES::View,
753
754 pub justify_qc: QuorumCertificate<TYPES>,
756
757 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
759
760 pub proposal_certificate: Option<ViewChangeEvidence<TYPES>>,
765}
766
767#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
769#[serde(bound(deserialize = ""))]
770pub struct QuorumProposal2<TYPES: NodeType> {
771 pub block_header: TYPES::BlockHeader,
773
774 pub view_number: TYPES::View,
776
777 pub epoch: Option<TYPES::Epoch>,
779
780 pub justify_qc: QuorumCertificate2<TYPES>,
782
783 pub next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
785
786 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
788
789 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
791
792 #[serde(with = "serde_bytes")]
797 pub next_drb_result: Option<DrbResult>,
798
799 pub state_cert: Option<LightClientStateUpdateCertificateV2<TYPES>>,
802}
803
804#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
813#[serde(bound(deserialize = ""))]
814pub struct QuorumProposal2Legacy<TYPES: NodeType> {
815 pub block_header: TYPES::BlockHeader,
817
818 pub view_number: TYPES::View,
820
821 pub epoch: Option<TYPES::Epoch>,
823
824 pub justify_qc: QuorumCertificate2<TYPES>,
826
827 pub next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
829
830 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
832
833 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
835
836 #[serde(with = "serde_bytes")]
841 pub next_drb_result: Option<DrbResult>,
842
843 pub state_cert: Option<LightClientStateUpdateCertificateV1<TYPES>>,
847}
848
849impl<TYPES: NodeType> From<QuorumProposal2Legacy<TYPES>> for QuorumProposal2<TYPES> {
850 fn from(quorum_proposal2: QuorumProposal2Legacy<TYPES>) -> Self {
851 Self {
852 block_header: quorum_proposal2.block_header,
853 view_number: quorum_proposal2.view_number,
854 epoch: quorum_proposal2.epoch,
855 justify_qc: quorum_proposal2.justify_qc,
856 next_epoch_justify_qc: quorum_proposal2.next_epoch_justify_qc,
857 upgrade_certificate: quorum_proposal2.upgrade_certificate,
858 view_change_evidence: quorum_proposal2.view_change_evidence,
859 next_drb_result: quorum_proposal2.next_drb_result,
860 state_cert: quorum_proposal2.state_cert.map(Into::into),
861 }
862 }
863}
864
865impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposal2Legacy<TYPES> {
866 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
867 Self {
868 block_header: quorum_proposal2.block_header,
869 view_number: quorum_proposal2.view_number,
870 epoch: quorum_proposal2.epoch,
871 justify_qc: quorum_proposal2.justify_qc,
872 next_epoch_justify_qc: quorum_proposal2.next_epoch_justify_qc,
873 upgrade_certificate: quorum_proposal2.upgrade_certificate,
874 view_change_evidence: quorum_proposal2.view_change_evidence,
875 next_drb_result: quorum_proposal2.next_drb_result,
876 state_cert: quorum_proposal2.state_cert.map(Into::into),
877 }
878 }
879}
880
881#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
887#[serde(bound(deserialize = ""))]
888pub struct QuorumProposalWrapperLegacy<TYPES: NodeType> {
889 pub proposal: QuorumProposal2Legacy<TYPES>,
891}
892
893#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
895#[serde(bound(deserialize = ""))]
896pub struct QuorumProposalWrapper<TYPES: NodeType> {
897 pub proposal: QuorumProposal2<TYPES>,
899}
900
901impl<TYPES: NodeType> From<QuorumProposalWrapperLegacy<TYPES>> for QuorumProposalWrapper<TYPES> {
902 fn from(v3: QuorumProposalWrapperLegacy<TYPES>) -> Self {
903 Self {
904 proposal: v3.proposal.into(),
905 }
906 }
907}
908
909impl<TYPES: NodeType> QuorumProposal2<TYPES> {
910 pub async fn validate_epoch<V: Versions>(
914 &self,
915 upgrade_lock: &UpgradeLock<TYPES, V>,
916 epoch_height: u64,
917 ) -> Result<()> {
918 let calculated_epoch = option_epoch_from_block_number::<TYPES>(
919 upgrade_lock.epochs_enabled(self.view_number()).await,
920 self.block_header.block_number(),
921 epoch_height,
922 );
923 ensure!(
924 calculated_epoch == self.epoch(),
925 "Quorum proposal invalid: inconsistent epoch."
926 );
927 Ok(())
928 }
929}
930
931impl<TYPES: NodeType> QuorumProposalWrapper<TYPES> {
932 pub fn block_header(&self) -> &TYPES::BlockHeader {
934 &self.proposal.block_header
935 }
936
937 pub fn view_number(&self) -> TYPES::View {
939 self.proposal.view_number
940 }
941
942 pub fn justify_qc(&self) -> &QuorumCertificate2<TYPES> {
944 &self.proposal.justify_qc
945 }
946
947 pub fn next_epoch_justify_qc(&self) -> &Option<NextEpochQuorumCertificate2<TYPES>> {
949 &self.proposal.next_epoch_justify_qc
950 }
951
952 pub fn upgrade_certificate(&self) -> &Option<UpgradeCertificate<TYPES>> {
954 &self.proposal.upgrade_certificate
955 }
956
957 pub fn view_change_evidence(&self) -> &Option<ViewChangeEvidence2<TYPES>> {
959 &self.proposal.view_change_evidence
960 }
961
962 pub fn next_drb_result(&self) -> &Option<DrbResult> {
964 &self.proposal.next_drb_result
965 }
966
967 pub async fn validate_epoch<V: Versions>(
971 &self,
972 upgrade_lock: &UpgradeLock<TYPES, V>,
973 epoch_height: u64,
974 ) -> Result<()> {
975 self.proposal
976 .validate_epoch(upgrade_lock, epoch_height)
977 .await
978 }
979
980 pub fn state_cert(&self) -> &Option<LightClientStateUpdateCertificateV2<TYPES>> {
982 &self.proposal.state_cert
983 }
984}
985
986impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposalWrapper<TYPES> {
987 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
988 Self {
989 proposal: quorum_proposal.into(),
990 }
991 }
992}
993
994impl<TYPES: NodeType> From<QuorumProposal2Legacy<TYPES>> for QuorumProposalWrapper<TYPES> {
995 fn from(quorum_proposal: QuorumProposal2Legacy<TYPES>) -> Self {
996 Self {
997 proposal: quorum_proposal.into(),
998 }
999 }
1000}
1001
1002impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposalWrapper<TYPES> {
1003 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1004 Self {
1005 proposal: quorum_proposal2,
1006 }
1007 }
1008}
1009
1010impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal<TYPES> {
1011 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1012 quorum_proposal_wrapper.proposal.into()
1013 }
1014}
1015
1016impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal2Legacy<TYPES> {
1017 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1018 quorum_proposal_wrapper.proposal.into()
1019 }
1020}
1021
1022impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal2<TYPES> {
1023 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
1024 quorum_proposal_wrapper.proposal
1025 }
1026}
1027
1028impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposal2<TYPES> {
1029 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
1030 Self {
1031 block_header: quorum_proposal.block_header,
1032 view_number: quorum_proposal.view_number,
1033 epoch: None,
1034 justify_qc: quorum_proposal.justify_qc.to_qc2(),
1035 next_epoch_justify_qc: None,
1036 upgrade_certificate: quorum_proposal.upgrade_certificate,
1037 view_change_evidence: quorum_proposal
1038 .proposal_certificate
1039 .map(ViewChangeEvidence::to_evidence2),
1040 next_drb_result: None,
1041 state_cert: None,
1042 }
1043 }
1044}
1045
1046impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposal<TYPES> {
1047 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
1048 Self {
1049 block_header: quorum_proposal2.block_header,
1050 view_number: quorum_proposal2.view_number,
1051 justify_qc: quorum_proposal2.justify_qc.to_qc(),
1052 upgrade_certificate: quorum_proposal2.upgrade_certificate,
1053 proposal_certificate: quorum_proposal2
1054 .view_change_evidence
1055 .map(ViewChangeEvidence2::to_evidence),
1056 }
1057 }
1058}
1059
1060impl<TYPES: NodeType> From<Leaf<TYPES>> for Leaf2<TYPES> {
1061 fn from(leaf: Leaf<TYPES>) -> Self {
1062 let bytes: [u8; 32] = leaf.parent_commitment.into();
1063
1064 Self {
1065 view_number: leaf.view_number,
1066 justify_qc: leaf.justify_qc.to_qc2(),
1067 next_epoch_justify_qc: None,
1068 parent_commitment: Commitment::from_raw(bytes),
1069 block_header: leaf.block_header,
1070 upgrade_certificate: leaf.upgrade_certificate,
1071 block_payload: leaf.block_payload,
1072 view_change_evidence: None,
1073 next_drb_result: None,
1074 with_epoch: false,
1075 }
1076 }
1077}
1078
1079impl<TYPES: NodeType> HasViewNumber<TYPES> for DaProposal<TYPES> {
1080 fn view_number(&self) -> TYPES::View {
1081 self.view_number
1082 }
1083}
1084
1085impl<TYPES: NodeType> HasViewNumber<TYPES> for DaProposal2<TYPES> {
1086 fn view_number(&self) -> TYPES::View {
1087 self.view_number
1088 }
1089}
1090
1091impl<TYPES: NodeType> HasViewNumber<TYPES> for QuorumProposal<TYPES> {
1092 fn view_number(&self) -> TYPES::View {
1093 self.view_number
1094 }
1095}
1096
1097impl<TYPES: NodeType> HasViewNumber<TYPES> for QuorumProposal2<TYPES> {
1098 fn view_number(&self) -> TYPES::View {
1099 self.view_number
1100 }
1101}
1102
1103impl<TYPES: NodeType> HasViewNumber<TYPES> for QuorumProposal2Legacy<TYPES> {
1104 fn view_number(&self) -> TYPES::View {
1105 self.view_number
1106 }
1107}
1108
1109impl<TYPES: NodeType> HasViewNumber<TYPES> for QuorumProposalWrapper<TYPES> {
1110 fn view_number(&self) -> TYPES::View {
1111 self.proposal.view_number
1112 }
1113}
1114
1115impl<TYPES: NodeType> HasViewNumber<TYPES> for QuorumProposalWrapperLegacy<TYPES> {
1116 fn view_number(&self) -> TYPES::View {
1117 self.proposal.view_number
1118 }
1119}
1120
1121impl<TYPES: NodeType> HasViewNumber<TYPES> for UpgradeProposal<TYPES> {
1122 fn view_number(&self) -> TYPES::View {
1123 self.view_number
1124 }
1125}
1126
1127impl_has_epoch!(
1128 QuorumProposal2<TYPES>,
1129 DaProposal2<TYPES>,
1130 QuorumProposal2Legacy<TYPES>
1131);
1132
1133impl_has_none_epoch!(
1134 QuorumProposal<TYPES>,
1135 DaProposal<TYPES>,
1136 UpgradeProposal<TYPES>,
1137 ADVZDisperseShare<TYPES>
1138);
1139
1140impl<TYPES: NodeType> HasEpoch<TYPES> for QuorumProposalWrapper<TYPES> {
1141 #[allow(clippy::panic)]
1143 fn epoch(&self) -> Option<TYPES::Epoch> {
1144 self.proposal.epoch()
1145 }
1146}
1147
1148impl<TYPES: NodeType> HasEpoch<TYPES> for QuorumProposalWrapperLegacy<TYPES> {
1149 #[allow(clippy::panic)]
1151 fn epoch(&self) -> Option<TYPES::Epoch> {
1152 self.proposal.epoch()
1153 }
1154}
1155
1156#[derive(Error, Debug, Serialize, Deserialize)]
1158pub enum BlockError {
1159 #[error("Invalid block header: {0}")]
1161 InvalidBlockHeader(String),
1162
1163 #[error("Inconsistent payload commitment")]
1165 InconsistentPayloadCommitment,
1166
1167 #[error("Failed to apply block header: {0}")]
1169 FailedHeaderApply(String),
1170}
1171
1172pub trait TestableLeaf {
1174 type NodeType: NodeType;
1176
1177 fn create_random_transaction(
1179 &self,
1180 rng: &mut dyn rand::RngCore,
1181 padding: u64,
1182 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction;
1183}
1184
1185#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1189#[serde(bound(deserialize = ""))]
1190pub struct Leaf<TYPES: NodeType> {
1191 view_number: TYPES::View,
1193
1194 justify_qc: QuorumCertificate<TYPES>,
1196
1197 parent_commitment: Commitment<Self>,
1200
1201 block_header: TYPES::BlockHeader,
1203
1204 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1206
1207 block_payload: Option<TYPES::BlockPayload>,
1211}
1212
1213#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1216#[serde(bound(deserialize = ""))]
1217pub struct Leaf2<TYPES: NodeType> {
1218 view_number: TYPES::View,
1220
1221 justify_qc: QuorumCertificate2<TYPES>,
1223
1224 next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1226
1227 parent_commitment: Commitment<Self>,
1230
1231 block_header: TYPES::BlockHeader,
1233
1234 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1236
1237 block_payload: Option<TYPES::BlockPayload>,
1241
1242 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
1244
1245 #[serde(with = "serde_bytes")]
1250 pub next_drb_result: Option<DrbResult>,
1251
1252 pub with_epoch: bool,
1254}
1255
1256impl<TYPES: NodeType> Leaf2<TYPES> {
1257 #[must_use]
1264 pub async fn genesis<V: Versions>(
1265 validated_state: &TYPES::ValidatedState,
1266 instance_state: &TYPES::InstanceState,
1267 ) -> Self {
1268 let epoch = genesis_epoch_from_version::<V, TYPES>();
1269
1270 let (payload, metadata) =
1271 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1272 .await
1273 .unwrap();
1274
1275 let genesis_view = TYPES::View::genesis();
1276
1277 let block_header =
1278 TYPES::BlockHeader::genesis::<V>(instance_state, payload.clone(), &metadata);
1279
1280 let block_number = if V::Base::VERSION < V::Epochs::VERSION {
1281 None
1282 } else {
1283 Some(0u64)
1284 };
1285
1286 let null_quorum_data = QuorumData2 {
1287 leaf_commit: Commitment::<Leaf2<TYPES>>::default_commitment_no_preimage(),
1288 epoch,
1289 block_number,
1290 };
1291
1292 let justify_qc = QuorumCertificate2::new(
1293 null_quorum_data.clone(),
1294 null_quorum_data.commit(),
1295 genesis_view,
1296 None,
1297 PhantomData,
1298 );
1299
1300 Self {
1301 view_number: genesis_view,
1302 justify_qc,
1303 next_epoch_justify_qc: None,
1304 parent_commitment: null_quorum_data.leaf_commit,
1305 upgrade_certificate: None,
1306 block_header: block_header.clone(),
1307 block_payload: Some(payload),
1308 view_change_evidence: None,
1309 next_drb_result: None,
1310 with_epoch: epoch.is_some(),
1311 }
1312 }
1313 pub fn view_number(&self) -> TYPES::View {
1315 self.view_number
1316 }
1317 pub fn epoch(&self, epoch_height: u64) -> Option<TYPES::Epoch> {
1319 option_epoch_from_block_number::<TYPES>(
1320 self.with_epoch,
1321 self.block_header.block_number(),
1322 epoch_height,
1323 )
1324 }
1325 pub fn height(&self) -> u64 {
1329 self.block_header.block_number()
1330 }
1331 pub fn justify_qc(&self) -> QuorumCertificate2<TYPES> {
1333 self.justify_qc.clone()
1334 }
1335 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1337 self.upgrade_certificate.clone()
1338 }
1339 pub fn parent_commitment(&self) -> Commitment<Self> {
1341 self.parent_commitment
1342 }
1343 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1345 &self.block_header
1346 }
1347
1348 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1350 &mut self.block_header
1351 }
1352 pub fn fill_block_payload<V: Versions>(
1359 &mut self,
1360 block_payload: TYPES::BlockPayload,
1361 num_storage_nodes: usize,
1362 version: Version,
1363 ) -> std::result::Result<(), BlockError> {
1364 let encoded_txns = block_payload.encode();
1365 let commitment = vid_commitment::<V>(
1366 &encoded_txns,
1367 &self.block_header.metadata().encode(),
1368 num_storage_nodes,
1369 version,
1370 );
1371 if commitment != self.block_header.payload_commitment() {
1372 return Err(BlockError::InconsistentPayloadCommitment);
1373 }
1374 self.block_payload = Some(block_payload);
1375 Ok(())
1376 }
1377
1378 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
1380 self.block_payload.take()
1381 }
1382
1383 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
1386 self.block_payload = Some(block_payload);
1387 }
1388
1389 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
1391 self.block_payload.clone()
1392 }
1393
1394 pub fn payload_commitment(&self) -> VidCommitment {
1396 self.block_header().payload_commitment()
1397 }
1398
1399 pub async fn extends_upgrade(
1407 &self,
1408 parent: &Self,
1409 decided_upgrade_certificate: &Arc<RwLock<Option<UpgradeCertificate<TYPES>>>>,
1410 ) -> Result<()> {
1411 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
1412 (None | Some(_), None) => {},
1416 (None, Some(parent_cert)) => {
1420 let decided_upgrade_certificate_read = decided_upgrade_certificate.read().await;
1421 ensure!(
1422 self.view_number() > parent_cert.data.new_version_first_view
1423 || (self.view_number() > parent_cert.data.decide_by
1424 && decided_upgrade_certificate_read.is_none()),
1425 "The new leaf is missing an upgrade certificate that was present in its \
1426 parent, and should still be live."
1427 );
1428 },
1429 (Some(cert), Some(parent_cert)) => {
1433 ensure!(
1434 cert == parent_cert,
1435 "The new leaf does not extend the parent leaf, because it has attached a \
1436 different upgrade certificate."
1437 );
1438 },
1439 }
1440
1441 Ok(())
1445 }
1446
1447 pub fn to_leaf_unsafe(self) -> Leaf<TYPES> {
1449 let bytes: [u8; 32] = self.parent_commitment.into();
1450
1451 Leaf {
1452 view_number: self.view_number,
1453 justify_qc: self.justify_qc.to_qc(),
1454 parent_commitment: Commitment::from_raw(bytes),
1455 block_header: self.block_header,
1456 upgrade_certificate: self.upgrade_certificate,
1457 block_payload: self.block_payload,
1458 }
1459 }
1460}
1461
1462impl<TYPES: NodeType> Committable for Leaf2<TYPES> {
1463 fn commit(&self) -> committable::Commitment<Self> {
1464 let Leaf2 {
1465 view_number,
1466 justify_qc,
1467 next_epoch_justify_qc,
1468 parent_commitment,
1469 block_header,
1470 upgrade_certificate,
1471 block_payload: _,
1472 view_change_evidence,
1473 next_drb_result,
1474 with_epoch,
1475 } = self;
1476
1477 let mut cb = RawCommitmentBuilder::new("leaf commitment")
1478 .u64_field("view number", **view_number)
1479 .field("parent leaf commitment", *parent_commitment)
1480 .field("block header", block_header.commit())
1481 .field("justify qc", justify_qc.commit())
1482 .optional("upgrade certificate", upgrade_certificate);
1483
1484 if *with_epoch {
1485 cb = cb
1486 .constant_str("with_epoch")
1487 .optional("next_epoch_justify_qc", next_epoch_justify_qc);
1488
1489 if let Some(next_drb_result) = next_drb_result {
1490 cb = cb
1491 .constant_str("next_drb_result")
1492 .fixed_size_bytes(next_drb_result);
1493 }
1494
1495 match view_change_evidence {
1496 Some(ViewChangeEvidence2::Timeout(cert)) => {
1497 cb = cb.field("timeout cert", cert.commit());
1498 },
1499 Some(ViewChangeEvidence2::ViewSync(cert)) => {
1500 cb = cb.field("viewsync cert", cert.commit());
1501 },
1502 None => {},
1503 }
1504 }
1505
1506 cb.finalize()
1507 }
1508}
1509
1510impl<TYPES: NodeType> Leaf<TYPES> {
1511 #[allow(clippy::unused_async)]
1512 pub async fn commit<V: Versions>(
1515 &self,
1516 _upgrade_lock: &UpgradeLock<TYPES, V>,
1517 ) -> Commitment<Self> {
1518 <Self as Committable>::commit(self)
1519 }
1520}
1521
1522impl<TYPES: NodeType> PartialEq for Leaf<TYPES> {
1523 fn eq(&self, other: &Self) -> bool {
1524 self.view_number == other.view_number
1525 && self.justify_qc == other.justify_qc
1526 && self.parent_commitment == other.parent_commitment
1527 && self.block_header == other.block_header
1528 }
1529}
1530
1531impl<TYPES: NodeType> PartialEq for Leaf2<TYPES> {
1532 fn eq(&self, other: &Self) -> bool {
1533 let Leaf2 {
1534 view_number,
1535 justify_qc,
1536 next_epoch_justify_qc,
1537 parent_commitment,
1538 block_header,
1539 upgrade_certificate,
1540 block_payload: _,
1541 view_change_evidence,
1542 next_drb_result,
1543 with_epoch,
1544 } = self;
1545
1546 *view_number == other.view_number
1547 && *justify_qc == other.justify_qc
1548 && *next_epoch_justify_qc == other.next_epoch_justify_qc
1549 && *parent_commitment == other.parent_commitment
1550 && *block_header == other.block_header
1551 && *upgrade_certificate == other.upgrade_certificate
1552 && *view_change_evidence == other.view_change_evidence
1553 && *next_drb_result == other.next_drb_result
1554 && *with_epoch == other.with_epoch
1555 }
1556}
1557
1558impl<TYPES: NodeType> Hash for Leaf<TYPES> {
1559 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1560 self.view_number.hash(state);
1561 self.justify_qc.hash(state);
1562 self.parent_commitment.hash(state);
1563 self.block_header.hash(state);
1564 }
1565}
1566
1567impl<TYPES: NodeType> Hash for Leaf2<TYPES> {
1568 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1569 self.commit().hash(state);
1570 self.view_number.hash(state);
1571 self.justify_qc.hash(state);
1572 self.parent_commitment.hash(state);
1573 self.block_header.hash(state);
1574 }
1575}
1576
1577impl<TYPES: NodeType> Display for Leaf<TYPES> {
1578 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1579 write!(
1580 f,
1581 "view: {:?}, height: {:?}, justify: {}",
1582 self.view_number,
1583 self.height(),
1584 self.justify_qc
1585 )
1586 }
1587}
1588
1589impl<TYPES: NodeType> QuorumCertificate<TYPES> {
1590 #[must_use]
1591 pub async fn genesis<V: Versions>(
1593 validated_state: &TYPES::ValidatedState,
1594 instance_state: &TYPES::InstanceState,
1595 ) -> Self {
1596 let upgrade_lock = UpgradeLock::<TYPES, V>::new();
1598
1599 let genesis_view = <TYPES::View as ConsensusTime>::genesis();
1600
1601 let data = QuorumData {
1602 leaf_commit: Leaf::genesis::<V>(validated_state, instance_state)
1603 .await
1604 .commit(&upgrade_lock)
1605 .await,
1606 };
1607
1608 let versioned_data =
1609 VersionedVoteData::<_, _, V>::new_infallible(data.clone(), genesis_view, &upgrade_lock)
1610 .await;
1611
1612 let bytes: [u8; 32] = versioned_data.commit().into();
1613
1614 Self::new(
1615 data,
1616 Commitment::from_raw(bytes),
1617 genesis_view,
1618 None,
1619 PhantomData,
1620 )
1621 }
1622}
1623
1624impl<TYPES: NodeType> QuorumCertificate2<TYPES> {
1625 #[must_use]
1626 pub async fn genesis<V: Versions>(
1628 validated_state: &TYPES::ValidatedState,
1629 instance_state: &TYPES::InstanceState,
1630 ) -> Self {
1631 let upgrade_lock = UpgradeLock::<TYPES, V>::new();
1633
1634 let genesis_view = <TYPES::View as ConsensusTime>::genesis();
1635
1636 let genesis_leaf = Leaf2::genesis::<V>(validated_state, instance_state).await;
1637 let block_number = if upgrade_lock.epochs_enabled(genesis_view).await {
1638 Some(genesis_leaf.height())
1639 } else {
1640 None
1641 };
1642 let data = QuorumData2 {
1643 leaf_commit: genesis_leaf.commit(),
1644 epoch: genesis_epoch_from_version::<V, TYPES>(), block_number,
1646 };
1647
1648 let versioned_data =
1649 VersionedVoteData::<_, _, V>::new_infallible(data.clone(), genesis_view, &upgrade_lock)
1650 .await;
1651
1652 let bytes: [u8; 32] = versioned_data.commit().into();
1653
1654 Self::new(
1655 data,
1656 Commitment::from_raw(bytes),
1657 genesis_view,
1658 None,
1659 PhantomData,
1660 )
1661 }
1662}
1663
1664impl<TYPES: NodeType> Leaf<TYPES> {
1665 #[must_use]
1672 pub async fn genesis<V: Versions>(
1673 validated_state: &TYPES::ValidatedState,
1674 instance_state: &TYPES::InstanceState,
1675 ) -> Self {
1676 let (payload, metadata) =
1677 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1678 .await
1679 .unwrap();
1680
1681 let genesis_view = TYPES::View::genesis();
1682
1683 let block_header =
1684 TYPES::BlockHeader::genesis::<V>(instance_state, payload.clone(), &metadata);
1685
1686 let null_quorum_data = QuorumData {
1687 leaf_commit: Commitment::<Leaf<TYPES>>::default_commitment_no_preimage(),
1688 };
1689
1690 let justify_qc = QuorumCertificate::new(
1691 null_quorum_data.clone(),
1692 null_quorum_data.commit(),
1693 genesis_view,
1694 None,
1695 PhantomData,
1696 );
1697
1698 Self {
1699 view_number: genesis_view,
1700 justify_qc,
1701 parent_commitment: null_quorum_data.leaf_commit,
1702 upgrade_certificate: None,
1703 block_header: block_header.clone(),
1704 block_payload: Some(payload),
1705 }
1706 }
1707
1708 pub fn view_number(&self) -> TYPES::View {
1710 self.view_number
1711 }
1712 pub fn height(&self) -> u64 {
1716 self.block_header.block_number()
1717 }
1718 pub fn justify_qc(&self) -> QuorumCertificate<TYPES> {
1720 self.justify_qc.clone()
1721 }
1722 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1724 self.upgrade_certificate.clone()
1725 }
1726 pub fn parent_commitment(&self) -> Commitment<Self> {
1728 self.parent_commitment
1729 }
1730 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1732 &self.block_header
1733 }
1734
1735 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1737 &mut self.block_header
1738 }
1739 pub fn fill_block_payload<V: Versions>(
1746 &mut self,
1747 block_payload: TYPES::BlockPayload,
1748 num_storage_nodes: usize,
1749 version: Version,
1750 ) -> std::result::Result<(), BlockError> {
1751 let encoded_txns = block_payload.encode();
1752 let commitment = vid_commitment::<V>(
1753 &encoded_txns,
1754 &self.block_header.metadata().encode(),
1755 num_storage_nodes,
1756 version,
1757 );
1758 if commitment != self.block_header.payload_commitment() {
1759 return Err(BlockError::InconsistentPayloadCommitment);
1760 }
1761 self.block_payload = Some(block_payload);
1762 Ok(())
1763 }
1764
1765 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
1767 self.block_payload.take()
1768 }
1769
1770 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
1773 self.block_payload = Some(block_payload);
1774 }
1775
1776 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
1778 self.block_payload.clone()
1779 }
1780
1781 pub fn payload_commitment(&self) -> VidCommitment {
1783 self.block_header().payload_commitment()
1784 }
1785
1786 pub async fn extends_upgrade(
1794 &self,
1795 parent: &Self,
1796 decided_upgrade_certificate: &Arc<RwLock<Option<UpgradeCertificate<TYPES>>>>,
1797 ) -> Result<()> {
1798 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
1799 (None | Some(_), None) => {},
1803 (None, Some(parent_cert)) => {
1807 let decided_upgrade_certificate_read = decided_upgrade_certificate.read().await;
1808 ensure!(
1809 self.view_number() > parent_cert.data.new_version_first_view
1810 || (self.view_number() > parent_cert.data.decide_by
1811 && decided_upgrade_certificate_read.is_none()),
1812 "The new leaf is missing an upgrade certificate that was present in its \
1813 parent, and should still be live."
1814 );
1815 },
1816 (Some(cert), Some(parent_cert)) => {
1820 ensure!(
1821 cert == parent_cert,
1822 "The new leaf does not extend the parent leaf, because it has attached a \
1823 different upgrade certificate."
1824 );
1825 },
1826 }
1827
1828 Ok(())
1832 }
1833}
1834
1835impl<TYPES: NodeType> TestableLeaf for Leaf<TYPES>
1836where
1837 TYPES::ValidatedState: TestableState<TYPES>,
1838 TYPES::BlockPayload: TestableBlock<TYPES>,
1839{
1840 type NodeType = TYPES;
1841
1842 fn create_random_transaction(
1843 &self,
1844 rng: &mut dyn rand::RngCore,
1845 padding: u64,
1846 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
1847 {
1848 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
1849 }
1850}
1851impl<TYPES: NodeType> TestableLeaf for Leaf2<TYPES>
1852where
1853 TYPES::ValidatedState: TestableState<TYPES>,
1854 TYPES::BlockPayload: TestableBlock<TYPES>,
1855{
1856 type NodeType = TYPES;
1857
1858 fn create_random_transaction(
1859 &self,
1860 rng: &mut dyn rand::RngCore,
1861 padding: u64,
1862 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
1863 {
1864 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
1865 }
1866}
1867#[must_use]
1869pub fn fake_commitment<S: Committable>() -> Commitment<S> {
1870 RawCommitmentBuilder::new("Dummy commitment for arbitrary genesis").finalize()
1871}
1872
1873#[must_use]
1875pub fn random_commitment<S: Committable>(rng: &mut dyn rand::RngCore) -> Commitment<S> {
1876 let random_array: Vec<u8> = (0u8..100u8).map(|_| rng.gen_range(0..255)).collect();
1877 RawCommitmentBuilder::new("Random Commitment")
1878 .constant_str("Random Field")
1879 .var_size_bytes(&random_array)
1880 .finalize()
1881}
1882
1883pub fn serialize_signature2<TYPES: NodeType>(
1887 signatures: &<TYPES::SignatureKey as SignatureKey>::QcType,
1888) -> Vec<u8> {
1889 let mut signatures_bytes = vec![];
1890 signatures_bytes.extend("Yes".as_bytes());
1891
1892 let (sig, proof) = TYPES::SignatureKey::sig_proof(signatures);
1893 let proof_bytes = bincode_opts()
1894 .serialize(&proof.as_bitslice())
1895 .expect("This serialization shouldn't be able to fail");
1896 signatures_bytes.extend("bitvec proof".as_bytes());
1897 signatures_bytes.extend(proof_bytes.as_slice());
1898 let sig_bytes = bincode_opts()
1899 .serialize(&sig)
1900 .expect("This serialization shouldn't be able to fail");
1901 signatures_bytes.extend("aggregated signature".as_bytes());
1902 signatures_bytes.extend(sig_bytes.as_slice());
1903 signatures_bytes
1904}
1905
1906impl<TYPES: NodeType> Committable for Leaf<TYPES> {
1907 fn commit(&self) -> committable::Commitment<Self> {
1908 RawCommitmentBuilder::new("leaf commitment")
1909 .u64_field("view number", *self.view_number)
1910 .field("parent leaf commitment", self.parent_commitment)
1911 .field("block header", self.block_header.commit())
1912 .field("justify qc", self.justify_qc.commit())
1913 .optional("upgrade certificate", &self.upgrade_certificate)
1914 .finalize()
1915 }
1916}
1917
1918impl<TYPES: NodeType> Leaf2<TYPES> {
1919 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposalWrapper<TYPES>) -> Self {
1921 let QuorumProposalWrapper {
1924 proposal:
1925 QuorumProposal2 {
1926 view_number,
1927 epoch,
1928 justify_qc,
1929 next_epoch_justify_qc,
1930 block_header,
1931 upgrade_certificate,
1932 view_change_evidence,
1933 next_drb_result,
1934 state_cert: _,
1935 },
1936 } = quorum_proposal;
1937
1938 Self {
1939 view_number: *view_number,
1940 justify_qc: justify_qc.clone(),
1941 next_epoch_justify_qc: next_epoch_justify_qc.clone(),
1942 parent_commitment: justify_qc.data().leaf_commit,
1943 block_header: block_header.clone(),
1944 upgrade_certificate: upgrade_certificate.clone(),
1945 block_payload: None,
1946 view_change_evidence: view_change_evidence.clone(),
1947 next_drb_result: *next_drb_result,
1948 with_epoch: epoch.is_some(),
1949 }
1950 }
1951}
1952
1953impl<TYPES: NodeType> Leaf<TYPES> {
1954 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposal<TYPES>) -> Self {
1956 let QuorumProposal {
1959 view_number,
1960 justify_qc,
1961 block_header,
1962 upgrade_certificate,
1963 proposal_certificate: _,
1964 } = quorum_proposal;
1965
1966 Self {
1967 view_number: *view_number,
1968 justify_qc: justify_qc.clone(),
1969 parent_commitment: justify_qc.data().leaf_commit,
1970 block_header: block_header.clone(),
1971 upgrade_certificate: upgrade_certificate.clone(),
1972 block_payload: None,
1973 }
1974 }
1975}
1976
1977pub mod null_block {
1978 #![allow(missing_docs)]
1979
1980 use jf_vid::VidScheme;
1981 use vbs::version::StaticVersionType;
1982
1983 use crate::{
1984 data::VidCommitment,
1985 traits::{
1986 block_contents::BuilderFee,
1987 node_implementation::{NodeType, Versions},
1988 signature_key::BuilderSignatureKey,
1989 BlockPayload,
1990 },
1991 vid::advz::advz_scheme,
1992 };
1993
1994 #[must_use]
2003 pub fn commitment<V: Versions>(num_storage_nodes: usize) -> Option<VidCommitment> {
2004 let vid_result = advz_scheme(num_storage_nodes).commit_only(Vec::new());
2005
2006 match vid_result {
2007 Ok(r) => Some(VidCommitment::V0(r)),
2008 Err(_) => None,
2009 }
2010 }
2011
2012 #[must_use]
2014 pub fn builder_fee<TYPES: NodeType, V: Versions>(
2015 num_storage_nodes: usize,
2016 version: vbs::version::Version,
2017 ) -> Option<BuilderFee<TYPES>> {
2018 const FEE_AMOUNT: u64 = 0;
2020
2021 let (pub_key, priv_key) =
2022 <TYPES::BuilderSignatureKey as BuilderSignatureKey>::generated_from_seed_indexed(
2023 [0_u8; 32], 0,
2024 );
2025
2026 if version >= V::Epochs::VERSION {
2027 let (_null_block, null_block_metadata) =
2028 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2029
2030 match TYPES::BuilderSignatureKey::sign_fee(&priv_key, FEE_AMOUNT, &null_block_metadata)
2031 {
2032 Ok(sig) => Some(BuilderFee {
2033 fee_amount: FEE_AMOUNT,
2034 fee_account: pub_key,
2035 fee_signature: sig,
2036 }),
2037 Err(_) => None,
2038 }
2039 } else {
2040 let (_null_block, null_block_metadata) =
2041 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2042
2043 match TYPES::BuilderSignatureKey::sign_fee_with_vid_commitment(
2044 &priv_key,
2045 FEE_AMOUNT,
2046 &null_block_metadata,
2047 &commitment::<V>(num_storage_nodes)?,
2048 ) {
2049 Ok(sig) => Some(BuilderFee {
2050 fee_amount: FEE_AMOUNT,
2051 fee_account: pub_key,
2052 fee_signature: sig,
2053 }),
2054 Err(_) => None,
2055 }
2056 }
2057 }
2058}
2059
2060#[derive(Debug, Eq, PartialEq, Clone)]
2062pub struct PackedBundle<TYPES: NodeType> {
2063 pub encoded_transactions: Arc<[u8]>,
2065
2066 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2068
2069 pub view_number: TYPES::View,
2071
2072 pub epoch_number: Option<TYPES::Epoch>,
2074
2075 pub sequencing_fees: Vec1<BuilderFee<TYPES>>,
2077}
2078
2079impl<TYPES: NodeType> PackedBundle<TYPES> {
2080 pub fn new(
2082 encoded_transactions: Arc<[u8]>,
2083 metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2084 view_number: TYPES::View,
2085 epoch_number: Option<TYPES::Epoch>,
2086 sequencing_fees: Vec1<BuilderFee<TYPES>>,
2087 ) -> Self {
2088 Self {
2089 encoded_transactions,
2090 metadata,
2091 view_number,
2092 epoch_number,
2093 sequencing_fees,
2094 }
2095 }
2096}
2097
2098#[cfg(test)]
2099mod test {
2100 use super::*;
2101
2102 #[test]
2103 fn test_vid_commitment_display() {
2104 let vc = VidCommitment::V0(ADVZCommitment::default());
2105 assert_eq!(
2106 format!("{vc}"),
2107 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2108 );
2109 assert_eq!(
2110 format!("{vc:?}"),
2111 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2112 );
2113
2114 let vc = VidCommitment::V1(AvidMCommitment {
2115 commit: Default::default(),
2116 });
2117 assert_eq!(
2118 format!("{vc}"),
2119 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2120 );
2121 assert_eq!(
2122 format!("{vc:?}"),
2123 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2124 );
2125 }
2126}