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_advz::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 next_epoch_justify_qc(&self) -> Option<NextEpochQuorumCertificate2<TYPES>> {
1339 self.next_epoch_justify_qc.clone()
1340 }
1341 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1343 self.upgrade_certificate.clone()
1344 }
1345 pub fn parent_commitment(&self) -> Commitment<Self> {
1347 self.parent_commitment
1348 }
1349 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1351 &self.block_header
1352 }
1353
1354 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1356 &mut self.block_header
1357 }
1358 pub fn fill_block_payload<V: Versions>(
1365 &mut self,
1366 block_payload: TYPES::BlockPayload,
1367 num_storage_nodes: usize,
1368 version: Version,
1369 ) -> std::result::Result<(), BlockError> {
1370 let encoded_txns = block_payload.encode();
1371 let commitment = vid_commitment::<V>(
1372 &encoded_txns,
1373 &self.block_header.metadata().encode(),
1374 num_storage_nodes,
1375 version,
1376 );
1377 if commitment != self.block_header.payload_commitment() {
1378 return Err(BlockError::InconsistentPayloadCommitment);
1379 }
1380 self.block_payload = Some(block_payload);
1381 Ok(())
1382 }
1383
1384 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
1386 self.block_payload.take()
1387 }
1388
1389 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
1392 self.block_payload = Some(block_payload);
1393 }
1394
1395 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
1397 self.block_payload.clone()
1398 }
1399
1400 pub fn payload_commitment(&self) -> VidCommitment {
1402 self.block_header().payload_commitment()
1403 }
1404
1405 pub async fn extends_upgrade(
1413 &self,
1414 parent: &Self,
1415 decided_upgrade_certificate: &Arc<RwLock<Option<UpgradeCertificate<TYPES>>>>,
1416 ) -> Result<()> {
1417 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
1418 (None | Some(_), None) => {},
1422 (None, Some(parent_cert)) => {
1426 let decided_upgrade_certificate_read = decided_upgrade_certificate.read().await;
1427 ensure!(
1428 self.view_number() > parent_cert.data.new_version_first_view
1429 || (self.view_number() > parent_cert.data.decide_by
1430 && decided_upgrade_certificate_read.is_none()),
1431 "The new leaf is missing an upgrade certificate that was present in its \
1432 parent, and should still be live."
1433 );
1434 },
1435 (Some(cert), Some(parent_cert)) => {
1439 ensure!(
1440 cert == parent_cert,
1441 "The new leaf does not extend the parent leaf, because it has attached a \
1442 different upgrade certificate."
1443 );
1444 },
1445 }
1446
1447 Ok(())
1451 }
1452
1453 pub fn to_leaf_unsafe(self) -> Leaf<TYPES> {
1455 let bytes: [u8; 32] = self.parent_commitment.into();
1456
1457 Leaf {
1458 view_number: self.view_number,
1459 justify_qc: self.justify_qc.to_qc(),
1460 parent_commitment: Commitment::from_raw(bytes),
1461 block_header: self.block_header,
1462 upgrade_certificate: self.upgrade_certificate,
1463 block_payload: self.block_payload,
1464 }
1465 }
1466}
1467
1468impl<TYPES: NodeType> Committable for Leaf2<TYPES> {
1469 fn commit(&self) -> committable::Commitment<Self> {
1470 let Leaf2 {
1471 view_number,
1472 justify_qc,
1473 next_epoch_justify_qc,
1474 parent_commitment,
1475 block_header,
1476 upgrade_certificate,
1477 block_payload: _,
1478 view_change_evidence,
1479 next_drb_result,
1480 with_epoch,
1481 } = self;
1482
1483 let mut cb = RawCommitmentBuilder::new("leaf commitment")
1484 .u64_field("view number", **view_number)
1485 .field("parent leaf commitment", *parent_commitment)
1486 .field("block header", block_header.commit())
1487 .field("justify qc", justify_qc.commit())
1488 .optional("upgrade certificate", upgrade_certificate);
1489
1490 if *with_epoch {
1491 cb = cb
1492 .constant_str("with_epoch")
1493 .optional("next_epoch_justify_qc", next_epoch_justify_qc);
1494
1495 if let Some(next_drb_result) = next_drb_result {
1496 cb = cb
1497 .constant_str("next_drb_result")
1498 .fixed_size_bytes(next_drb_result);
1499 }
1500
1501 match view_change_evidence {
1502 Some(ViewChangeEvidence2::Timeout(cert)) => {
1503 cb = cb.field("timeout cert", cert.commit());
1504 },
1505 Some(ViewChangeEvidence2::ViewSync(cert)) => {
1506 cb = cb.field("viewsync cert", cert.commit());
1507 },
1508 None => {},
1509 }
1510 }
1511
1512 cb.finalize()
1513 }
1514}
1515
1516impl<TYPES: NodeType> Leaf<TYPES> {
1517 #[allow(clippy::unused_async)]
1518 pub async fn commit<V: Versions>(
1521 &self,
1522 _upgrade_lock: &UpgradeLock<TYPES, V>,
1523 ) -> Commitment<Self> {
1524 <Self as Committable>::commit(self)
1525 }
1526}
1527
1528impl<TYPES: NodeType> PartialEq for Leaf<TYPES> {
1529 fn eq(&self, other: &Self) -> bool {
1530 self.view_number == other.view_number
1531 && self.justify_qc == other.justify_qc
1532 && self.parent_commitment == other.parent_commitment
1533 && self.block_header == other.block_header
1534 }
1535}
1536
1537impl<TYPES: NodeType> PartialEq for Leaf2<TYPES> {
1538 fn eq(&self, other: &Self) -> bool {
1539 let Leaf2 {
1540 view_number,
1541 justify_qc,
1542 next_epoch_justify_qc,
1543 parent_commitment,
1544 block_header,
1545 upgrade_certificate,
1546 block_payload: _,
1547 view_change_evidence,
1548 next_drb_result,
1549 with_epoch,
1550 } = self;
1551
1552 *view_number == other.view_number
1553 && *justify_qc == other.justify_qc
1554 && *next_epoch_justify_qc == other.next_epoch_justify_qc
1555 && *parent_commitment == other.parent_commitment
1556 && *block_header == other.block_header
1557 && *upgrade_certificate == other.upgrade_certificate
1558 && *view_change_evidence == other.view_change_evidence
1559 && *next_drb_result == other.next_drb_result
1560 && *with_epoch == other.with_epoch
1561 }
1562}
1563
1564impl<TYPES: NodeType> Hash for Leaf<TYPES> {
1565 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1566 self.view_number.hash(state);
1567 self.justify_qc.hash(state);
1568 self.parent_commitment.hash(state);
1569 self.block_header.hash(state);
1570 }
1571}
1572
1573impl<TYPES: NodeType> Hash for Leaf2<TYPES> {
1574 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1575 self.commit().hash(state);
1576 self.view_number.hash(state);
1577 self.justify_qc.hash(state);
1578 self.parent_commitment.hash(state);
1579 self.block_header.hash(state);
1580 }
1581}
1582
1583impl<TYPES: NodeType> Display for Leaf<TYPES> {
1584 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1585 write!(
1586 f,
1587 "view: {:?}, height: {:?}, justify: {}",
1588 self.view_number,
1589 self.height(),
1590 self.justify_qc
1591 )
1592 }
1593}
1594
1595impl<TYPES: NodeType> QuorumCertificate<TYPES> {
1596 #[must_use]
1597 pub async fn genesis<V: Versions>(
1599 validated_state: &TYPES::ValidatedState,
1600 instance_state: &TYPES::InstanceState,
1601 ) -> Self {
1602 let upgrade_lock = UpgradeLock::<TYPES, V>::new();
1604
1605 let genesis_view = <TYPES::View as ConsensusTime>::genesis();
1606
1607 let data = QuorumData {
1608 leaf_commit: Leaf::genesis::<V>(validated_state, instance_state)
1609 .await
1610 .commit(&upgrade_lock)
1611 .await,
1612 };
1613
1614 let versioned_data =
1615 VersionedVoteData::<_, _, V>::new_infallible(data.clone(), genesis_view, &upgrade_lock)
1616 .await;
1617
1618 let bytes: [u8; 32] = versioned_data.commit().into();
1619
1620 Self::new(
1621 data,
1622 Commitment::from_raw(bytes),
1623 genesis_view,
1624 None,
1625 PhantomData,
1626 )
1627 }
1628}
1629
1630impl<TYPES: NodeType> QuorumCertificate2<TYPES> {
1631 #[must_use]
1632 pub async fn genesis<V: Versions>(
1634 validated_state: &TYPES::ValidatedState,
1635 instance_state: &TYPES::InstanceState,
1636 ) -> Self {
1637 let upgrade_lock = UpgradeLock::<TYPES, V>::new();
1639
1640 let genesis_view = <TYPES::View as ConsensusTime>::genesis();
1641
1642 let genesis_leaf = Leaf2::genesis::<V>(validated_state, instance_state).await;
1643 let block_number = if upgrade_lock.epochs_enabled(genesis_view).await {
1644 Some(genesis_leaf.height())
1645 } else {
1646 None
1647 };
1648 let data = QuorumData2 {
1649 leaf_commit: genesis_leaf.commit(),
1650 epoch: genesis_epoch_from_version::<V, TYPES>(), block_number,
1652 };
1653
1654 let versioned_data =
1655 VersionedVoteData::<_, _, V>::new_infallible(data.clone(), genesis_view, &upgrade_lock)
1656 .await;
1657
1658 let bytes: [u8; 32] = versioned_data.commit().into();
1659
1660 Self::new(
1661 data,
1662 Commitment::from_raw(bytes),
1663 genesis_view,
1664 None,
1665 PhantomData,
1666 )
1667 }
1668}
1669
1670impl<TYPES: NodeType> Leaf<TYPES> {
1671 #[must_use]
1678 pub async fn genesis<V: Versions>(
1679 validated_state: &TYPES::ValidatedState,
1680 instance_state: &TYPES::InstanceState,
1681 ) -> Self {
1682 let (payload, metadata) =
1683 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1684 .await
1685 .unwrap();
1686
1687 let genesis_view = TYPES::View::genesis();
1688
1689 let block_header =
1690 TYPES::BlockHeader::genesis::<V>(instance_state, payload.clone(), &metadata);
1691
1692 let null_quorum_data = QuorumData {
1693 leaf_commit: Commitment::<Leaf<TYPES>>::default_commitment_no_preimage(),
1694 };
1695
1696 let justify_qc = QuorumCertificate::new(
1697 null_quorum_data.clone(),
1698 null_quorum_data.commit(),
1699 genesis_view,
1700 None,
1701 PhantomData,
1702 );
1703
1704 Self {
1705 view_number: genesis_view,
1706 justify_qc,
1707 parent_commitment: null_quorum_data.leaf_commit,
1708 upgrade_certificate: None,
1709 block_header: block_header.clone(),
1710 block_payload: Some(payload),
1711 }
1712 }
1713
1714 pub fn view_number(&self) -> TYPES::View {
1716 self.view_number
1717 }
1718 pub fn height(&self) -> u64 {
1722 self.block_header.block_number()
1723 }
1724 pub fn justify_qc(&self) -> QuorumCertificate<TYPES> {
1726 self.justify_qc.clone()
1727 }
1728 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1730 self.upgrade_certificate.clone()
1731 }
1732 pub fn parent_commitment(&self) -> Commitment<Self> {
1734 self.parent_commitment
1735 }
1736 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1738 &self.block_header
1739 }
1740
1741 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1743 &mut self.block_header
1744 }
1745 pub fn fill_block_payload<V: Versions>(
1752 &mut self,
1753 block_payload: TYPES::BlockPayload,
1754 num_storage_nodes: usize,
1755 version: Version,
1756 ) -> std::result::Result<(), BlockError> {
1757 let encoded_txns = block_payload.encode();
1758 let commitment = vid_commitment::<V>(
1759 &encoded_txns,
1760 &self.block_header.metadata().encode(),
1761 num_storage_nodes,
1762 version,
1763 );
1764 if commitment != self.block_header.payload_commitment() {
1765 return Err(BlockError::InconsistentPayloadCommitment);
1766 }
1767 self.block_payload = Some(block_payload);
1768 Ok(())
1769 }
1770
1771 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
1773 self.block_payload.take()
1774 }
1775
1776 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
1779 self.block_payload = Some(block_payload);
1780 }
1781
1782 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
1784 self.block_payload.clone()
1785 }
1786
1787 pub fn payload_commitment(&self) -> VidCommitment {
1789 self.block_header().payload_commitment()
1790 }
1791
1792 pub async fn extends_upgrade(
1800 &self,
1801 parent: &Self,
1802 decided_upgrade_certificate: &Arc<RwLock<Option<UpgradeCertificate<TYPES>>>>,
1803 ) -> Result<()> {
1804 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
1805 (None | Some(_), None) => {},
1809 (None, Some(parent_cert)) => {
1813 let decided_upgrade_certificate_read = decided_upgrade_certificate.read().await;
1814 ensure!(
1815 self.view_number() > parent_cert.data.new_version_first_view
1816 || (self.view_number() > parent_cert.data.decide_by
1817 && decided_upgrade_certificate_read.is_none()),
1818 "The new leaf is missing an upgrade certificate that was present in its \
1819 parent, and should still be live."
1820 );
1821 },
1822 (Some(cert), Some(parent_cert)) => {
1826 ensure!(
1827 cert == parent_cert,
1828 "The new leaf does not extend the parent leaf, because it has attached a \
1829 different upgrade certificate."
1830 );
1831 },
1832 }
1833
1834 Ok(())
1838 }
1839}
1840
1841impl<TYPES: NodeType> TestableLeaf for Leaf<TYPES>
1842where
1843 TYPES::ValidatedState: TestableState<TYPES>,
1844 TYPES::BlockPayload: TestableBlock<TYPES>,
1845{
1846 type NodeType = TYPES;
1847
1848 fn create_random_transaction(
1849 &self,
1850 rng: &mut dyn rand::RngCore,
1851 padding: u64,
1852 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
1853 {
1854 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
1855 }
1856}
1857impl<TYPES: NodeType> TestableLeaf for Leaf2<TYPES>
1858where
1859 TYPES::ValidatedState: TestableState<TYPES>,
1860 TYPES::BlockPayload: TestableBlock<TYPES>,
1861{
1862 type NodeType = TYPES;
1863
1864 fn create_random_transaction(
1865 &self,
1866 rng: &mut dyn rand::RngCore,
1867 padding: u64,
1868 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
1869 {
1870 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
1871 }
1872}
1873#[must_use]
1875pub fn fake_commitment<S: Committable>() -> Commitment<S> {
1876 RawCommitmentBuilder::new("Dummy commitment for arbitrary genesis").finalize()
1877}
1878
1879#[must_use]
1881pub fn random_commitment<S: Committable>(rng: &mut dyn rand::RngCore) -> Commitment<S> {
1882 let random_array: Vec<u8> = (0u8..100u8).map(|_| rng.gen_range(0..255)).collect();
1883 RawCommitmentBuilder::new("Random Commitment")
1884 .constant_str("Random Field")
1885 .var_size_bytes(&random_array)
1886 .finalize()
1887}
1888
1889pub fn serialize_signature2<TYPES: NodeType>(
1893 signatures: &<TYPES::SignatureKey as SignatureKey>::QcType,
1894) -> Vec<u8> {
1895 let mut signatures_bytes = vec![];
1896 signatures_bytes.extend("Yes".as_bytes());
1897
1898 let (sig, proof) = TYPES::SignatureKey::sig_proof(signatures);
1899 let proof_bytes = bincode_opts()
1900 .serialize(&proof.as_bitslice())
1901 .expect("This serialization shouldn't be able to fail");
1902 signatures_bytes.extend("bitvec proof".as_bytes());
1903 signatures_bytes.extend(proof_bytes.as_slice());
1904 let sig_bytes = bincode_opts()
1905 .serialize(&sig)
1906 .expect("This serialization shouldn't be able to fail");
1907 signatures_bytes.extend("aggregated signature".as_bytes());
1908 signatures_bytes.extend(sig_bytes.as_slice());
1909 signatures_bytes
1910}
1911
1912impl<TYPES: NodeType> Committable for Leaf<TYPES> {
1913 fn commit(&self) -> committable::Commitment<Self> {
1914 RawCommitmentBuilder::new("leaf commitment")
1915 .u64_field("view number", *self.view_number)
1916 .field("parent leaf commitment", self.parent_commitment)
1917 .field("block header", self.block_header.commit())
1918 .field("justify qc", self.justify_qc.commit())
1919 .optional("upgrade certificate", &self.upgrade_certificate)
1920 .finalize()
1921 }
1922}
1923
1924impl<TYPES: NodeType> Leaf2<TYPES> {
1925 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposalWrapper<TYPES>) -> Self {
1927 let QuorumProposalWrapper {
1930 proposal:
1931 QuorumProposal2 {
1932 view_number,
1933 epoch,
1934 justify_qc,
1935 next_epoch_justify_qc,
1936 block_header,
1937 upgrade_certificate,
1938 view_change_evidence,
1939 next_drb_result,
1940 state_cert: _,
1941 },
1942 } = quorum_proposal;
1943
1944 Self {
1945 view_number: *view_number,
1946 justify_qc: justify_qc.clone(),
1947 next_epoch_justify_qc: next_epoch_justify_qc.clone(),
1948 parent_commitment: justify_qc.data().leaf_commit,
1949 block_header: block_header.clone(),
1950 upgrade_certificate: upgrade_certificate.clone(),
1951 block_payload: None,
1952 view_change_evidence: view_change_evidence.clone(),
1953 next_drb_result: *next_drb_result,
1954 with_epoch: epoch.is_some(),
1955 }
1956 }
1957}
1958
1959impl<TYPES: NodeType> Leaf<TYPES> {
1960 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposal<TYPES>) -> Self {
1962 let QuorumProposal {
1965 view_number,
1966 justify_qc,
1967 block_header,
1968 upgrade_certificate,
1969 proposal_certificate: _,
1970 } = quorum_proposal;
1971
1972 Self {
1973 view_number: *view_number,
1974 justify_qc: justify_qc.clone(),
1975 parent_commitment: justify_qc.data().leaf_commit,
1976 block_header: block_header.clone(),
1977 upgrade_certificate: upgrade_certificate.clone(),
1978 block_payload: None,
1979 }
1980 }
1981}
1982
1983pub mod null_block {
1984 #![allow(missing_docs)]
1985
1986 use jf_advz::VidScheme;
1987 use vbs::version::StaticVersionType;
1988
1989 use crate::{
1990 data::VidCommitment,
1991 traits::{
1992 block_contents::BuilderFee,
1993 node_implementation::{NodeType, Versions},
1994 signature_key::BuilderSignatureKey,
1995 BlockPayload,
1996 },
1997 vid::advz::advz_scheme,
1998 };
1999
2000 #[must_use]
2009 pub fn commitment<V: Versions>(num_storage_nodes: usize) -> Option<VidCommitment> {
2010 let vid_result = advz_scheme(num_storage_nodes).commit_only(Vec::new());
2011
2012 match vid_result {
2013 Ok(r) => Some(VidCommitment::V0(r)),
2014 Err(_) => None,
2015 }
2016 }
2017
2018 #[must_use]
2020 pub fn builder_fee<TYPES: NodeType, V: Versions>(
2021 num_storage_nodes: usize,
2022 version: vbs::version::Version,
2023 ) -> Option<BuilderFee<TYPES>> {
2024 const FEE_AMOUNT: u64 = 0;
2026
2027 let (pub_key, priv_key) =
2028 <TYPES::BuilderSignatureKey as BuilderSignatureKey>::generated_from_seed_indexed(
2029 [0_u8; 32], 0,
2030 );
2031
2032 if version >= V::Epochs::VERSION {
2033 let (_null_block, null_block_metadata) =
2034 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2035
2036 match TYPES::BuilderSignatureKey::sign_fee(&priv_key, FEE_AMOUNT, &null_block_metadata)
2037 {
2038 Ok(sig) => Some(BuilderFee {
2039 fee_amount: FEE_AMOUNT,
2040 fee_account: pub_key,
2041 fee_signature: sig,
2042 }),
2043 Err(_) => None,
2044 }
2045 } else {
2046 let (_null_block, null_block_metadata) =
2047 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
2048
2049 match TYPES::BuilderSignatureKey::sign_fee_with_vid_commitment(
2050 &priv_key,
2051 FEE_AMOUNT,
2052 &null_block_metadata,
2053 &commitment::<V>(num_storage_nodes)?,
2054 ) {
2055 Ok(sig) => Some(BuilderFee {
2056 fee_amount: FEE_AMOUNT,
2057 fee_account: pub_key,
2058 fee_signature: sig,
2059 }),
2060 Err(_) => None,
2061 }
2062 }
2063 }
2064}
2065
2066#[derive(Debug, Eq, PartialEq, Clone)]
2068pub struct PackedBundle<TYPES: NodeType> {
2069 pub encoded_transactions: Arc<[u8]>,
2071
2072 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2074
2075 pub view_number: TYPES::View,
2077
2078 pub epoch_number: Option<TYPES::Epoch>,
2080
2081 pub sequencing_fees: Vec1<BuilderFee<TYPES>>,
2083}
2084
2085impl<TYPES: NodeType> PackedBundle<TYPES> {
2086 pub fn new(
2088 encoded_transactions: Arc<[u8]>,
2089 metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
2090 view_number: TYPES::View,
2091 epoch_number: Option<TYPES::Epoch>,
2092 sequencing_fees: Vec1<BuilderFee<TYPES>>,
2093 ) -> Self {
2094 Self {
2095 encoded_transactions,
2096 metadata,
2097 view_number,
2098 epoch_number,
2099 sequencing_fees,
2100 }
2101 }
2102}
2103
2104#[cfg(test)]
2105mod test {
2106 use super::*;
2107
2108 #[test]
2109 fn test_vid_commitment_display() {
2110 let vc = VidCommitment::V0(ADVZCommitment::default());
2111 assert_eq!(
2112 format!("{vc}"),
2113 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2114 );
2115 assert_eq!(
2116 format!("{vc:?}"),
2117 "HASH~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI"
2118 );
2119
2120 let vc = VidCommitment::V1(AvidMCommitment {
2121 commit: Default::default(),
2122 });
2123 assert_eq!(
2124 format!("{vc}"),
2125 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2126 );
2127 assert_eq!(
2128 format!("{vc:?}"),
2129 "AvidMCommit~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADr"
2130 );
2131 }
2132}