1use std::{
13 fmt::{Debug, Display},
14 hash::Hash,
15 marker::PhantomData,
16 sync::Arc,
17};
18
19use async_lock::RwLock;
20use bincode::Options;
21use committable::{Commitment, CommitmentBoundsArkless, Committable, RawCommitmentBuilder};
22use hotshot_utils::anytrace::*;
23use jf_vid::VidScheme;
24use rand::Rng;
25use serde::{Deserialize, Serialize};
26use tagged_base64::TaggedBase64;
27use thiserror::Error;
28use vbs::version::{StaticVersionType, Version};
29use vec1::Vec1;
30use vid_disperse::{ADVZDisperse, ADVZDisperseShare, AvidMDisperse, VidDisperseShare2};
31
32use crate::{
33 drb::DrbResult,
34 epoch_membership::EpochMembershipCoordinator,
35 impl_has_epoch, impl_has_none_epoch,
36 message::{convert_proposal, Proposal, UpgradeLock},
37 simple_certificate::{
38 LightClientStateUpdateCertificate, NextEpochQuorumCertificate2, QuorumCertificate,
39 QuorumCertificate2, TimeoutCertificate, TimeoutCertificate2, UpgradeCertificate,
40 ViewSyncFinalizeCertificate, ViewSyncFinalizeCertificate2,
41 },
42 simple_vote::{HasEpoch, QuorumData, QuorumData2, UpgradeProposalData, VersionedVoteData},
43 traits::{
44 block_contents::{
45 BlockHeader, BuilderFee, EncodeBytes, TestableBlock, GENESIS_VID_NUM_STORAGE_NODES,
46 },
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) => {
67 impl ConsensusTime for $t {
68 fn genesis() -> Self {
70 Self(0)
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);
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);
144
145impl EpochNumber {
146 #[allow(dead_code)]
148 fn genesis() -> Self {
149 Self(1)
150 }
151}
152
153#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
155#[serde(bound = "TYPES: NodeType")]
156pub struct DaProposal<TYPES: NodeType> {
157 pub encoded_transactions: Arc<[u8]>,
159 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
161 pub view_number: TYPES::View,
163}
164
165#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
167#[serde(bound = "TYPES: NodeType")]
168pub struct DaProposal2<TYPES: NodeType> {
169 pub encoded_transactions: Arc<[u8]>,
171 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
173 pub view_number: TYPES::View,
175 pub epoch: Option<TYPES::Epoch>,
177 pub epoch_transition_indicator: EpochTransitionIndicator,
180}
181
182impl<TYPES: NodeType> From<DaProposal<TYPES>> for DaProposal2<TYPES> {
183 fn from(da_proposal: DaProposal<TYPES>) -> Self {
184 Self {
185 encoded_transactions: da_proposal.encoded_transactions,
186 metadata: da_proposal.metadata,
187 view_number: da_proposal.view_number,
188 epoch: None,
189 epoch_transition_indicator: EpochTransitionIndicator::NotInTransition,
190 }
191 }
192}
193
194impl<TYPES: NodeType> From<DaProposal2<TYPES>> for DaProposal<TYPES> {
195 fn from(da_proposal2: DaProposal2<TYPES>) -> Self {
196 Self {
197 encoded_transactions: da_proposal2.encoded_transactions,
198 metadata: da_proposal2.metadata,
199 view_number: da_proposal2.view_number,
200 }
201 }
202}
203
204#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
206#[serde(bound = "TYPES: NodeType")]
207pub struct UpgradeProposal<TYPES>
208where
209 TYPES: NodeType,
210{
211 pub upgrade_proposal: UpgradeProposalData<TYPES>,
213 pub view_number: TYPES::View,
215}
216
217#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, Ord, PartialOrd)]
219#[serde(
220 try_from = "tagged_base64::TaggedBase64",
221 into = "tagged_base64::TaggedBase64"
222)]
223pub enum VidCommitment {
224 V0(ADVZCommitment),
225 V1(AvidMCommitment),
226}
227
228impl Default for VidCommitment {
229 fn default() -> Self {
230 Self::V0(Default::default())
231 }
232}
233
234impl Display for VidCommitment {
235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 std::write!(f, "{}", TaggedBase64::from(self))
237 }
238}
239
240impl From<VidCommitment> for TaggedBase64 {
241 fn from(val: VidCommitment) -> Self {
242 match val {
243 VidCommitment::V0(comm) => comm.into(),
244 VidCommitment::V1(comm) => comm.into(),
245 }
246 }
247}
248
249impl From<&VidCommitment> for TaggedBase64 {
250 fn from(val: &VidCommitment) -> Self {
251 match val {
252 VidCommitment::V0(comm) => comm.into(),
253 VidCommitment::V1(comm) => comm.into(),
254 }
255 }
256}
257
258impl TryFrom<TaggedBase64> for VidCommitment {
259 type Error = tagged_base64::Tb64Error;
260
261 fn try_from(value: TaggedBase64) -> std::result::Result<Self, Self::Error> {
262 ADVZCommitment::try_from(&value)
263 .map(Self::V0)
264 .or(AvidMCommitment::try_from(value).map(Self::V1))
265 }
266}
267
268impl<'a> TryFrom<&'a TaggedBase64> for VidCommitment {
269 type Error = tagged_base64::Tb64Error;
270
271 fn try_from(value: &'a TaggedBase64) -> std::result::Result<Self, Self::Error> {
272 ADVZCommitment::try_from(value)
273 .map(Self::V0)
274 .or(AvidMCommitment::try_from(value).map(Self::V1))
275 }
276}
277
278impl std::str::FromStr for VidCommitment {
279 type Err = tagged_base64::Tb64Error;
280 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
281 use core::convert::TryFrom;
282 Self::try_from(TaggedBase64::from_str(s)?)
283 .map_err(|_| tagged_base64::Tb64Error::InvalidData)
284 }
285}
286
287impl From<AvidMCommitment> for VidCommitment {
295 fn from(comm: AvidMCommitment) -> Self {
296 Self::V1(comm)
297 }
298}
299
300impl AsRef<[u8]> for VidCommitment {
301 fn as_ref(&self) -> &[u8] {
302 match self {
303 Self::V0(comm) => comm.as_ref(),
304 Self::V1(comm) => comm.as_ref(),
305 }
306 }
307}
308
309impl AsRef<[u8; 32]> for VidCommitment {
310 fn as_ref(&self) -> &[u8; 32] {
311 match self {
312 Self::V0(comm) => comm.as_ref().as_ref(),
313 Self::V1(comm) => comm.as_ref(),
314 }
315 }
316}
317
318impl VidCommitment {
319 pub fn unwrap_v0(self) -> ADVZCommitment {
321 match self {
322 VidCommitment::V0(comm) => comm,
323 _ => panic!("Unexpected version for this commitment"),
324 }
325 }
326 pub fn unwrap_v1(self) -> AvidMCommitment {
328 match self {
329 VidCommitment::V1(comm) => comm,
330 _ => panic!("Unexpected version for this commitment"),
331 }
332 }
333}
334
335#[must_use]
340#[allow(clippy::panic)]
341pub fn vid_commitment<V: Versions>(
342 encoded_transactions: &[u8],
343 metadata: &[u8],
344 total_weight: usize,
345 version: Version,
346) -> VidCommitment {
347 if version < V::Epochs::VERSION {
348 let encoded_tx_len = encoded_transactions.len();
349 advz_scheme(total_weight).commit_only(encoded_transactions).map(VidCommitment::V0).unwrap_or_else(|err| panic!("VidScheme::commit_only failure:(total_weight,payload_byte_len)=({total_weight},{encoded_tx_len}) error: {err}"))
350 } else {
351 let param = init_avidm_param(total_weight).unwrap();
352 let encoded_tx_len = encoded_transactions.len();
353 AvidMScheme::commit(
354 ¶m,
355 encoded_transactions,
356 ns_table::parse_ns_table(encoded_tx_len, metadata),
357 )
358 .map(VidCommitment::V1)
359 .unwrap()
360 }
361}
362
363#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
365pub enum VidShare {
366 V0(ADVZShare),
367 V1(AvidMShare),
368}
369
370impl From<AvidMShare> for VidShare {
378 fn from(share: AvidMShare) -> Self {
379 Self::V1(share)
380 }
381}
382
383pub mod ns_table;
384pub mod vid_disperse;
385
386#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
392#[serde(bound = "TYPES: NodeType")]
393pub enum VidDisperse<TYPES: NodeType> {
394 V0(vid_disperse::ADVZDisperse<TYPES>),
396 V1(vid_disperse::AvidMDisperse<TYPES>),
398}
399
400impl<TYPES: NodeType> From<vid_disperse::ADVZDisperse<TYPES>> for VidDisperse<TYPES> {
401 fn from(disperse: vid_disperse::ADVZDisperse<TYPES>) -> Self {
402 Self::V0(disperse)
403 }
404}
405
406impl<TYPES: NodeType> From<vid_disperse::AvidMDisperse<TYPES>> for VidDisperse<TYPES> {
407 fn from(disperse: vid_disperse::AvidMDisperse<TYPES>) -> Self {
408 Self::V1(disperse)
409 }
410}
411
412impl<TYPES: NodeType> HasViewNumber<TYPES> for VidDisperse<TYPES> {
413 fn view_number(&self) -> TYPES::View {
414 match self {
415 Self::V0(disperse) => disperse.view_number(),
416 Self::V1(disperse) => disperse.view_number(),
417 }
418 }
419}
420
421impl<TYPES: NodeType> HasEpoch<TYPES> for VidDisperse<TYPES> {
422 fn epoch(&self) -> Option<TYPES::Epoch> {
423 match self {
424 Self::V0(disperse) => disperse.epoch(),
425 Self::V1(disperse) => disperse.epoch(),
426 }
427 }
428}
429
430impl<TYPES: NodeType> VidDisperse<TYPES> {
431 #[allow(clippy::panic)]
437 pub async fn calculate_vid_disperse<V: Versions>(
438 payload: &TYPES::BlockPayload,
439 membership: &EpochMembershipCoordinator<TYPES>,
440 view: TYPES::View,
441 target_epoch: Option<TYPES::Epoch>,
442 data_epoch: Option<TYPES::Epoch>,
443 metadata: &<TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
444 upgrade_lock: &UpgradeLock<TYPES, V>,
445 ) -> Result<Self> {
446 let version = upgrade_lock.version_infallible(view).await;
447 if version < V::Epochs::VERSION {
448 ADVZDisperse::calculate_vid_disperse(
449 payload,
450 membership,
451 view,
452 target_epoch,
453 data_epoch,
454 )
455 .await
456 .map(|disperse| Self::V0(disperse))
457 } else {
458 AvidMDisperse::calculate_vid_disperse(
459 payload,
460 membership,
461 view,
462 target_epoch,
463 data_epoch,
464 metadata,
465 )
466 .await
467 .map(|disperse| Self::V1(disperse))
468 }
469 }
470
471 pub fn payload_commitment(&self) -> VidCommitment {
473 match self {
474 Self::V0(disperse) => VidCommitment::V0(disperse.payload_commitment),
475 Self::V1(disperse) => disperse.payload_commitment.into(),
476 }
477 }
478
479 pub fn payload_commitment_ref(&self) -> &[u8] {
481 match self {
482 Self::V0(disperse) => disperse.payload_commitment.as_ref(),
483 Self::V1(disperse) => disperse.payload_commitment.as_ref(),
484 }
485 }
486
487 pub fn set_view_number(&mut self, view_number: <TYPES as NodeType>::View) {
489 match self {
490 Self::V0(share) => share.view_number = view_number,
491 Self::V1(share) => share.view_number = view_number,
492 }
493 }
494}
495
496#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
498#[serde(bound = "TYPES: NodeType")]
499pub enum VidDisperseShare<TYPES: NodeType> {
500 V0(vid_disperse::ADVZDisperseShare<TYPES>),
502 V1(vid_disperse::VidDisperseShare2<TYPES>),
504}
505
506impl<TYPES: NodeType> VidDisperseShare<TYPES> {
507 pub fn from_vid_disperse(vid_disperse: VidDisperse<TYPES>) -> Vec<Self> {
509 match vid_disperse {
510 VidDisperse::V0(vid_disperse) => {
511 ADVZDisperseShare::<TYPES>::from_advz_disperse(vid_disperse)
512 .into_iter()
513 .map(|share| Self::V0(share))
514 .collect()
515 },
516 VidDisperse::V1(vid_disperse) => {
517 VidDisperseShare2::<TYPES>::from_vid_disperse(vid_disperse)
518 .into_iter()
519 .map(|share| Self::V1(share))
520 .collect()
521 },
522 }
523 }
524
525 pub fn to_proposal(
527 self,
528 private_key: &<TYPES::SignatureKey as SignatureKey>::PrivateKey,
529 ) -> Option<Proposal<TYPES, Self>> {
530 let payload_commitment_ref: &[u8] = match &self {
531 Self::V0(share) => share.payload_commitment.as_ref(),
532 Self::V1(share) => share.payload_commitment.as_ref(),
533 };
534 let Ok(signature) = TYPES::SignatureKey::sign(private_key, payload_commitment_ref) else {
535 tracing::error!("VID: failed to sign dispersal share payload");
536 return None;
537 };
538 Some(Proposal {
539 signature,
540 _pd: PhantomData,
541 data: self,
542 })
543 }
544
545 pub fn to_vid_share_proposals(
547 vid_disperse_proposal: Proposal<TYPES, VidDisperse<TYPES>>,
548 ) -> Vec<Proposal<TYPES, Self>> {
549 match vid_disperse_proposal.data {
550 VidDisperse::V0(disperse) => ADVZDisperseShare::to_vid_share_proposals(
551 disperse,
552 &vid_disperse_proposal.signature,
553 )
554 .into_iter()
555 .map(|proposal| convert_proposal(proposal))
556 .collect(),
557 VidDisperse::V1(disperse) => VidDisperseShare2::to_vid_share_proposals(
558 disperse,
559 &vid_disperse_proposal.signature,
560 )
561 .into_iter()
562 .map(|proposal| convert_proposal(proposal))
563 .collect(),
564 }
565 }
566
567 pub fn recipient_key(&self) -> &TYPES::SignatureKey {
569 match self {
570 Self::V0(share) => &share.recipient_key,
571 Self::V1(share) => &share.recipient_key,
572 }
573 }
574
575 pub fn payload_byte_len(&self) -> u32 {
577 match self {
578 Self::V0(share) => share.payload_byte_len(),
579 Self::V1(share) => share.payload_byte_len(),
580 }
581 }
582
583 pub fn payload_commitment_ref(&self) -> &[u8] {
585 match self {
586 Self::V0(share) => share.payload_commitment.as_ref(),
587 Self::V1(share) => share.payload_commitment.as_ref(),
588 }
589 }
590
591 pub fn payload_commitment(&self) -> VidCommitment {
593 match self {
594 Self::V0(share) => VidCommitment::V0(share.payload_commitment),
595 Self::V1(share) => share.payload_commitment.into(),
596 }
597 }
598
599 pub fn target_epoch(&self) -> Option<<TYPES as NodeType>::Epoch> {
601 match self {
602 Self::V0(_) => None,
603 Self::V1(share) => share.target_epoch,
604 }
605 }
606
607 #[allow(clippy::result_unit_err)]
611 pub fn verify_share(&self, total_nodes: usize) -> std::result::Result<(), ()> {
612 match self {
613 Self::V0(share) => share.verify_share(total_nodes),
614 Self::V1(share) => share.verify_share(total_nodes),
615 }
616 }
617
618 pub fn set_view_number(&mut self, view_number: <TYPES as NodeType>::View) {
620 match self {
621 Self::V0(share) => share.view_number = view_number,
622 Self::V1(share) => share.view_number = view_number,
623 }
624 }
625}
626
627impl<TYPES: NodeType> HasViewNumber<TYPES> for VidDisperseShare<TYPES> {
628 fn view_number(&self) -> TYPES::View {
629 match self {
630 Self::V0(disperse) => disperse.view_number(),
631 Self::V1(disperse) => disperse.view_number(),
632 }
633 }
634}
635
636impl<TYPES: NodeType> HasEpoch<TYPES> for VidDisperseShare<TYPES> {
637 fn epoch(&self) -> Option<TYPES::Epoch> {
638 match self {
639 Self::V0(_) => None,
640 Self::V1(share) => share.epoch(),
641 }
642 }
643}
644
645impl<TYPES: NodeType> From<vid_disperse::ADVZDisperseShare<TYPES>> for VidDisperseShare<TYPES> {
646 fn from(share: vid_disperse::ADVZDisperseShare<TYPES>) -> Self {
647 Self::V0(share)
648 }
649}
650
651impl<TYPES: NodeType> From<vid_disperse::VidDisperseShare2<TYPES>> for VidDisperseShare<TYPES> {
652 fn from(share: vid_disperse::VidDisperseShare2<TYPES>) -> Self {
653 Self::V1(share)
654 }
655}
656
657#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
660#[serde(bound(deserialize = ""))]
661pub enum ViewChangeEvidence<TYPES: NodeType> {
662 Timeout(TimeoutCertificate<TYPES>),
664 ViewSync(ViewSyncFinalizeCertificate<TYPES>),
666}
667
668impl<TYPES: NodeType> ViewChangeEvidence<TYPES> {
669 pub fn is_valid_for_view(&self, view: &TYPES::View) -> bool {
671 match self {
672 ViewChangeEvidence::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
673 ViewChangeEvidence::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
674 }
675 }
676
677 pub fn to_evidence2(self) -> ViewChangeEvidence2<TYPES> {
679 match self {
680 ViewChangeEvidence::Timeout(timeout_cert) => {
681 ViewChangeEvidence2::Timeout(timeout_cert.to_tc2())
682 },
683 ViewChangeEvidence::ViewSync(view_sync_cert) => {
684 ViewChangeEvidence2::ViewSync(view_sync_cert.to_vsc2())
685 },
686 }
687 }
688}
689
690#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
693#[serde(bound(deserialize = ""))]
694pub enum ViewChangeEvidence2<TYPES: NodeType> {
695 Timeout(TimeoutCertificate2<TYPES>),
697 ViewSync(ViewSyncFinalizeCertificate2<TYPES>),
699}
700
701impl<TYPES: NodeType> ViewChangeEvidence2<TYPES> {
702 pub fn is_valid_for_view(&self, view: &TYPES::View) -> bool {
704 match self {
705 ViewChangeEvidence2::Timeout(timeout_cert) => timeout_cert.data().view == *view - 1,
706 ViewChangeEvidence2::ViewSync(view_sync_cert) => view_sync_cert.view_number == *view,
707 }
708 }
709
710 pub fn to_evidence(self) -> ViewChangeEvidence<TYPES> {
712 match self {
713 ViewChangeEvidence2::Timeout(timeout_cert) => {
714 ViewChangeEvidence::Timeout(timeout_cert.to_tc())
715 },
716 ViewChangeEvidence2::ViewSync(view_sync_cert) => {
717 ViewChangeEvidence::ViewSync(view_sync_cert.to_vsc())
718 },
719 }
720 }
721}
722
723#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
725#[serde(bound(deserialize = ""))]
726pub struct QuorumProposal<TYPES: NodeType> {
727 pub block_header: TYPES::BlockHeader,
729
730 pub view_number: TYPES::View,
732
733 pub justify_qc: QuorumCertificate<TYPES>,
735
736 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
738
739 pub proposal_certificate: Option<ViewChangeEvidence<TYPES>>,
744}
745
746#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
748#[serde(bound(deserialize = ""))]
749pub struct QuorumProposal2<TYPES: NodeType> {
750 pub block_header: TYPES::BlockHeader,
752
753 pub view_number: TYPES::View,
755
756 pub epoch: Option<TYPES::Epoch>,
758
759 pub justify_qc: QuorumCertificate2<TYPES>,
761
762 pub next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
764
765 pub upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
767
768 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
770
771 #[serde(with = "serde_bytes")]
776 pub next_drb_result: Option<DrbResult>,
777
778 pub state_cert: Option<LightClientStateUpdateCertificate<TYPES>>,
781}
782
783#[derive(derive_more::Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
785#[serde(bound(deserialize = ""))]
786pub struct QuorumProposalWrapper<TYPES: NodeType> {
787 pub proposal: QuorumProposal2<TYPES>,
789}
790
791impl<TYPES: NodeType> QuorumProposal2<TYPES> {
792 pub async fn validate_epoch<V: Versions>(
796 &self,
797 upgrade_lock: &UpgradeLock<TYPES, V>,
798 epoch_height: u64,
799 ) -> Result<()> {
800 let calculated_epoch = option_epoch_from_block_number::<TYPES>(
801 upgrade_lock.epochs_enabled(self.view_number()).await,
802 self.block_header.block_number(),
803 epoch_height,
804 );
805 ensure!(
806 calculated_epoch == self.epoch(),
807 "Quorum proposal invalid: inconsistent epoch."
808 );
809 Ok(())
810 }
811}
812
813impl<TYPES: NodeType> QuorumProposalWrapper<TYPES> {
814 pub fn block_header(&self) -> &TYPES::BlockHeader {
816 &self.proposal.block_header
817 }
818
819 pub fn view_number(&self) -> TYPES::View {
821 self.proposal.view_number
822 }
823
824 pub fn justify_qc(&self) -> &QuorumCertificate2<TYPES> {
826 &self.proposal.justify_qc
827 }
828
829 pub fn next_epoch_justify_qc(&self) -> &Option<NextEpochQuorumCertificate2<TYPES>> {
831 &self.proposal.next_epoch_justify_qc
832 }
833
834 pub fn upgrade_certificate(&self) -> &Option<UpgradeCertificate<TYPES>> {
836 &self.proposal.upgrade_certificate
837 }
838
839 pub fn view_change_evidence(&self) -> &Option<ViewChangeEvidence2<TYPES>> {
841 &self.proposal.view_change_evidence
842 }
843
844 pub fn next_drb_result(&self) -> &Option<DrbResult> {
846 &self.proposal.next_drb_result
847 }
848
849 pub async fn validate_epoch<V: Versions>(
853 &self,
854 upgrade_lock: &UpgradeLock<TYPES, V>,
855 epoch_height: u64,
856 ) -> Result<()> {
857 self.proposal
858 .validate_epoch(upgrade_lock, epoch_height)
859 .await
860 }
861
862 pub fn state_cert(&self) -> &Option<LightClientStateUpdateCertificate<TYPES>> {
864 &self.proposal.state_cert
865 }
866}
867
868impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposalWrapper<TYPES> {
869 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
870 Self {
871 proposal: quorum_proposal.into(),
872 }
873 }
874}
875
876impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposalWrapper<TYPES> {
877 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
878 Self {
879 proposal: quorum_proposal2,
880 }
881 }
882}
883
884impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal<TYPES> {
885 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
886 quorum_proposal_wrapper.proposal.into()
887 }
888}
889
890impl<TYPES: NodeType> From<QuorumProposalWrapper<TYPES>> for QuorumProposal2<TYPES> {
891 fn from(quorum_proposal_wrapper: QuorumProposalWrapper<TYPES>) -> Self {
892 quorum_proposal_wrapper.proposal
893 }
894}
895
896impl<TYPES: NodeType> From<QuorumProposal<TYPES>> for QuorumProposal2<TYPES> {
897 fn from(quorum_proposal: QuorumProposal<TYPES>) -> Self {
898 Self {
899 block_header: quorum_proposal.block_header,
900 view_number: quorum_proposal.view_number,
901 epoch: None,
902 justify_qc: quorum_proposal.justify_qc.to_qc2(),
903 next_epoch_justify_qc: None,
904 upgrade_certificate: quorum_proposal.upgrade_certificate,
905 view_change_evidence: quorum_proposal
906 .proposal_certificate
907 .map(ViewChangeEvidence::to_evidence2),
908 next_drb_result: None,
909 state_cert: None,
910 }
911 }
912}
913
914impl<TYPES: NodeType> From<QuorumProposal2<TYPES>> for QuorumProposal<TYPES> {
915 fn from(quorum_proposal2: QuorumProposal2<TYPES>) -> Self {
916 Self {
917 block_header: quorum_proposal2.block_header,
918 view_number: quorum_proposal2.view_number,
919 justify_qc: quorum_proposal2.justify_qc.to_qc(),
920 upgrade_certificate: quorum_proposal2.upgrade_certificate,
921 proposal_certificate: quorum_proposal2
922 .view_change_evidence
923 .map(ViewChangeEvidence2::to_evidence),
924 }
925 }
926}
927
928impl<TYPES: NodeType> From<Leaf<TYPES>> for Leaf2<TYPES> {
929 fn from(leaf: Leaf<TYPES>) -> Self {
930 let bytes: [u8; 32] = leaf.parent_commitment.into();
931
932 Self {
933 view_number: leaf.view_number,
934 justify_qc: leaf.justify_qc.to_qc2(),
935 next_epoch_justify_qc: None,
936 parent_commitment: Commitment::from_raw(bytes),
937 block_header: leaf.block_header,
938 upgrade_certificate: leaf.upgrade_certificate,
939 block_payload: leaf.block_payload,
940 view_change_evidence: None,
941 next_drb_result: None,
942 with_epoch: false,
943 }
944 }
945}
946
947impl<TYPES: NodeType> HasViewNumber<TYPES> for DaProposal<TYPES> {
948 fn view_number(&self) -> TYPES::View {
949 self.view_number
950 }
951}
952
953impl<TYPES: NodeType> HasViewNumber<TYPES> for DaProposal2<TYPES> {
954 fn view_number(&self) -> TYPES::View {
955 self.view_number
956 }
957}
958
959impl<TYPES: NodeType> HasViewNumber<TYPES> for QuorumProposal<TYPES> {
960 fn view_number(&self) -> TYPES::View {
961 self.view_number
962 }
963}
964
965impl<TYPES: NodeType> HasViewNumber<TYPES> for QuorumProposal2<TYPES> {
966 fn view_number(&self) -> TYPES::View {
967 self.view_number
968 }
969}
970
971impl<TYPES: NodeType> HasViewNumber<TYPES> for QuorumProposalWrapper<TYPES> {
972 fn view_number(&self) -> TYPES::View {
973 self.proposal.view_number
974 }
975}
976
977impl<TYPES: NodeType> HasViewNumber<TYPES> for UpgradeProposal<TYPES> {
978 fn view_number(&self) -> TYPES::View {
979 self.view_number
980 }
981}
982
983impl_has_epoch!(QuorumProposal2<TYPES>, DaProposal2<TYPES>);
984
985impl_has_none_epoch!(
986 QuorumProposal<TYPES>,
987 DaProposal<TYPES>,
988 UpgradeProposal<TYPES>,
989 ADVZDisperseShare<TYPES>
990);
991
992impl<TYPES: NodeType> HasEpoch<TYPES> for QuorumProposalWrapper<TYPES> {
993 #[allow(clippy::panic)]
995 fn epoch(&self) -> Option<TYPES::Epoch> {
996 self.proposal.epoch()
997 }
998}
999
1000#[derive(Error, Debug, Serialize, Deserialize)]
1002pub enum BlockError {
1003 #[error("Invalid block header: {0}")]
1005 InvalidBlockHeader(String),
1006
1007 #[error("Inconsistent payload commitment")]
1009 InconsistentPayloadCommitment,
1010
1011 #[error("Failed to apply block header: {0}")]
1013 FailedHeaderApply(String),
1014}
1015
1016pub trait TestableLeaf {
1018 type NodeType: NodeType;
1020
1021 fn create_random_transaction(
1023 &self,
1024 rng: &mut dyn rand::RngCore,
1025 padding: u64,
1026 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction;
1027}
1028
1029#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1033#[serde(bound(deserialize = ""))]
1034pub struct Leaf<TYPES: NodeType> {
1035 view_number: TYPES::View,
1037
1038 justify_qc: QuorumCertificate<TYPES>,
1040
1041 parent_commitment: Commitment<Self>,
1044
1045 block_header: TYPES::BlockHeader,
1047
1048 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1050
1051 block_payload: Option<TYPES::BlockPayload>,
1055}
1056
1057#[derive(Serialize, Deserialize, Clone, Debug, Eq)]
1060#[serde(bound(deserialize = ""))]
1061pub struct Leaf2<TYPES: NodeType> {
1062 view_number: TYPES::View,
1064
1065 justify_qc: QuorumCertificate2<TYPES>,
1067
1068 next_epoch_justify_qc: Option<NextEpochQuorumCertificate2<TYPES>>,
1070
1071 parent_commitment: Commitment<Self>,
1074
1075 block_header: TYPES::BlockHeader,
1077
1078 upgrade_certificate: Option<UpgradeCertificate<TYPES>>,
1080
1081 block_payload: Option<TYPES::BlockPayload>,
1085
1086 pub view_change_evidence: Option<ViewChangeEvidence2<TYPES>>,
1088
1089 #[serde(with = "serde_bytes")]
1094 pub next_drb_result: Option<DrbResult>,
1095
1096 pub with_epoch: bool,
1098}
1099
1100impl<TYPES: NodeType> Leaf2<TYPES> {
1101 #[must_use]
1108 pub async fn genesis<V: Versions>(
1109 validated_state: &TYPES::ValidatedState,
1110 instance_state: &TYPES::InstanceState,
1111 ) -> Self {
1112 let epoch = genesis_epoch_from_version::<V, TYPES>();
1113
1114 let (payload, metadata) =
1115 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1116 .await
1117 .unwrap();
1118 let builder_commitment = payload.builder_commitment(&metadata);
1119 let payload_bytes = payload.encode();
1120
1121 let genesis_view = TYPES::View::genesis();
1122 let upgrade_lock = UpgradeLock::<TYPES, V>::new();
1123 let genesis_version = upgrade_lock.version_infallible(genesis_view).await;
1124 let payload_commitment = vid_commitment::<V>(
1125 &payload_bytes,
1126 &metadata.encode(),
1127 GENESIS_VID_NUM_STORAGE_NODES,
1128 genesis_version,
1129 );
1130
1131 let block_header = TYPES::BlockHeader::genesis(
1132 instance_state,
1133 payload_commitment,
1134 builder_commitment,
1135 metadata,
1136 );
1137
1138 let block_number = if V::Base::VERSION < V::Epochs::VERSION {
1139 None
1140 } else {
1141 Some(0u64)
1142 };
1143
1144 let null_quorum_data = QuorumData2 {
1145 leaf_commit: Commitment::<Leaf2<TYPES>>::default_commitment_no_preimage(),
1146 epoch,
1147 block_number,
1148 };
1149
1150 let justify_qc = QuorumCertificate2::new(
1151 null_quorum_data.clone(),
1152 null_quorum_data.commit(),
1153 genesis_view,
1154 None,
1155 PhantomData,
1156 );
1157
1158 Self {
1159 view_number: genesis_view,
1160 justify_qc,
1161 next_epoch_justify_qc: None,
1162 parent_commitment: null_quorum_data.leaf_commit,
1163 upgrade_certificate: None,
1164 block_header: block_header.clone(),
1165 block_payload: Some(payload),
1166 view_change_evidence: None,
1167 next_drb_result: None,
1168 with_epoch: epoch.is_some(),
1169 }
1170 }
1171 pub fn view_number(&self) -> TYPES::View {
1173 self.view_number
1174 }
1175 pub fn epoch(&self, epoch_height: u64) -> Option<TYPES::Epoch> {
1177 option_epoch_from_block_number::<TYPES>(
1178 self.with_epoch,
1179 self.block_header.block_number(),
1180 epoch_height,
1181 )
1182 }
1183 pub fn height(&self) -> u64 {
1187 self.block_header.block_number()
1188 }
1189 pub fn justify_qc(&self) -> QuorumCertificate2<TYPES> {
1191 self.justify_qc.clone()
1192 }
1193 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1195 self.upgrade_certificate.clone()
1196 }
1197 pub fn parent_commitment(&self) -> Commitment<Self> {
1199 self.parent_commitment
1200 }
1201 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1203 &self.block_header
1204 }
1205
1206 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1208 &mut self.block_header
1209 }
1210 pub fn fill_block_payload<V: Versions>(
1217 &mut self,
1218 block_payload: TYPES::BlockPayload,
1219 num_storage_nodes: usize,
1220 version: Version,
1221 ) -> std::result::Result<(), BlockError> {
1222 let encoded_txns = block_payload.encode();
1223 let commitment = vid_commitment::<V>(
1224 &encoded_txns,
1225 &self.block_header.metadata().encode(),
1226 num_storage_nodes,
1227 version,
1228 );
1229 if commitment != self.block_header.payload_commitment() {
1230 return Err(BlockError::InconsistentPayloadCommitment);
1231 }
1232 self.block_payload = Some(block_payload);
1233 Ok(())
1234 }
1235
1236 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
1238 self.block_payload.take()
1239 }
1240
1241 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
1244 self.block_payload = Some(block_payload);
1245 }
1246
1247 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
1249 self.block_payload.clone()
1250 }
1251
1252 pub fn payload_commitment(&self) -> VidCommitment {
1254 self.block_header().payload_commitment()
1255 }
1256
1257 pub async fn extends_upgrade(
1265 &self,
1266 parent: &Self,
1267 decided_upgrade_certificate: &Arc<RwLock<Option<UpgradeCertificate<TYPES>>>>,
1268 ) -> Result<()> {
1269 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
1270 (None | Some(_), None) => {},
1274 (None, Some(parent_cert)) => {
1278 let decided_upgrade_certificate_read = decided_upgrade_certificate.read().await;
1279 ensure!(self.view_number() > parent_cert.data.new_version_first_view
1280 || (self.view_number() > parent_cert.data.decide_by && decided_upgrade_certificate_read.is_none()),
1281 "The new leaf is missing an upgrade certificate that was present in its parent, and should still be live."
1282 );
1283 },
1284 (Some(cert), Some(parent_cert)) => {
1288 ensure!(cert == parent_cert, "The new leaf does not extend the parent leaf, because it has attached a different upgrade certificate.");
1289 },
1290 }
1291
1292 Ok(())
1296 }
1297
1298 pub fn to_leaf_unsafe(self) -> Leaf<TYPES> {
1300 let bytes: [u8; 32] = self.parent_commitment.into();
1301
1302 Leaf {
1303 view_number: self.view_number,
1304 justify_qc: self.justify_qc.to_qc(),
1305 parent_commitment: Commitment::from_raw(bytes),
1306 block_header: self.block_header,
1307 upgrade_certificate: self.upgrade_certificate,
1308 block_payload: self.block_payload,
1309 }
1310 }
1311}
1312
1313impl<TYPES: NodeType> Committable for Leaf2<TYPES> {
1314 fn commit(&self) -> committable::Commitment<Self> {
1315 let Leaf2 {
1316 view_number,
1317 justify_qc,
1318 next_epoch_justify_qc,
1319 parent_commitment,
1320 block_header,
1321 upgrade_certificate,
1322 block_payload: _,
1323 view_change_evidence,
1324 next_drb_result,
1325 with_epoch,
1326 } = self;
1327
1328 let mut cb = RawCommitmentBuilder::new("leaf commitment")
1329 .u64_field("view number", **view_number)
1330 .field("parent leaf commitment", *parent_commitment)
1331 .field("block header", block_header.commit())
1332 .field("justify qc", justify_qc.commit())
1333 .optional("upgrade certificate", upgrade_certificate);
1334
1335 if *with_epoch {
1336 cb = cb
1337 .constant_str("with_epoch")
1338 .optional("next_epoch_justify_qc", next_epoch_justify_qc);
1339
1340 if let Some(next_drb_result) = next_drb_result {
1341 cb = cb
1342 .constant_str("next_drb_result")
1343 .fixed_size_bytes(next_drb_result);
1344 }
1345
1346 match view_change_evidence {
1347 Some(ViewChangeEvidence2::Timeout(cert)) => {
1348 cb = cb.field("timeout cert", cert.commit());
1349 },
1350 Some(ViewChangeEvidence2::ViewSync(cert)) => {
1351 cb = cb.field("viewsync cert", cert.commit());
1352 },
1353 None => {},
1354 }
1355 }
1356
1357 cb.finalize()
1358 }
1359}
1360
1361impl<TYPES: NodeType> Leaf<TYPES> {
1362 #[allow(clippy::unused_async)]
1363 pub async fn commit<V: Versions>(
1366 &self,
1367 _upgrade_lock: &UpgradeLock<TYPES, V>,
1368 ) -> Commitment<Self> {
1369 <Self as Committable>::commit(self)
1370 }
1371}
1372
1373impl<TYPES: NodeType> PartialEq for Leaf<TYPES> {
1374 fn eq(&self, other: &Self) -> bool {
1375 self.view_number == other.view_number
1376 && self.justify_qc == other.justify_qc
1377 && self.parent_commitment == other.parent_commitment
1378 && self.block_header == other.block_header
1379 }
1380}
1381
1382impl<TYPES: NodeType> PartialEq for Leaf2<TYPES> {
1383 fn eq(&self, other: &Self) -> bool {
1384 let Leaf2 {
1385 view_number,
1386 justify_qc,
1387 next_epoch_justify_qc,
1388 parent_commitment,
1389 block_header,
1390 upgrade_certificate,
1391 block_payload: _,
1392 view_change_evidence,
1393 next_drb_result,
1394 with_epoch,
1395 } = self;
1396
1397 *view_number == other.view_number
1398 && *justify_qc == other.justify_qc
1399 && *next_epoch_justify_qc == other.next_epoch_justify_qc
1400 && *parent_commitment == other.parent_commitment
1401 && *block_header == other.block_header
1402 && *upgrade_certificate == other.upgrade_certificate
1403 && *view_change_evidence == other.view_change_evidence
1404 && *next_drb_result == other.next_drb_result
1405 && *with_epoch == other.with_epoch
1406 }
1407}
1408
1409impl<TYPES: NodeType> Hash for Leaf<TYPES> {
1410 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1411 self.view_number.hash(state);
1412 self.justify_qc.hash(state);
1413 self.parent_commitment.hash(state);
1414 self.block_header.hash(state);
1415 }
1416}
1417
1418impl<TYPES: NodeType> Hash for Leaf2<TYPES> {
1419 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1420 self.commit().hash(state);
1421 self.view_number.hash(state);
1422 self.justify_qc.hash(state);
1423 self.parent_commitment.hash(state);
1424 self.block_header.hash(state);
1425 }
1426}
1427
1428impl<TYPES: NodeType> Display for Leaf<TYPES> {
1429 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1430 write!(
1431 f,
1432 "view: {:?}, height: {:?}, justify: {}",
1433 self.view_number,
1434 self.height(),
1435 self.justify_qc
1436 )
1437 }
1438}
1439
1440impl<TYPES: NodeType> QuorumCertificate<TYPES> {
1441 #[must_use]
1442 pub async fn genesis<V: Versions>(
1444 validated_state: &TYPES::ValidatedState,
1445 instance_state: &TYPES::InstanceState,
1446 ) -> Self {
1447 let upgrade_lock = UpgradeLock::<TYPES, V>::new();
1449
1450 let genesis_view = <TYPES::View as ConsensusTime>::genesis();
1451
1452 let data = QuorumData {
1453 leaf_commit: Leaf::genesis::<V>(validated_state, instance_state)
1454 .await
1455 .commit(&upgrade_lock)
1456 .await,
1457 };
1458
1459 let versioned_data =
1460 VersionedVoteData::<_, _, V>::new_infallible(data.clone(), genesis_view, &upgrade_lock)
1461 .await;
1462
1463 let bytes: [u8; 32] = versioned_data.commit().into();
1464
1465 Self::new(
1466 data,
1467 Commitment::from_raw(bytes),
1468 genesis_view,
1469 None,
1470 PhantomData,
1471 )
1472 }
1473}
1474
1475impl<TYPES: NodeType> QuorumCertificate2<TYPES> {
1476 #[must_use]
1477 pub async fn genesis<V: Versions>(
1479 validated_state: &TYPES::ValidatedState,
1480 instance_state: &TYPES::InstanceState,
1481 ) -> Self {
1482 let upgrade_lock = UpgradeLock::<TYPES, V>::new();
1484
1485 let genesis_view = <TYPES::View as ConsensusTime>::genesis();
1486
1487 let genesis_leaf = Leaf2::genesis::<V>(validated_state, instance_state).await;
1488 let block_number = if upgrade_lock.epochs_enabled(genesis_view).await {
1489 Some(genesis_leaf.height())
1490 } else {
1491 None
1492 };
1493 let data = QuorumData2 {
1494 leaf_commit: genesis_leaf.commit(),
1495 epoch: genesis_epoch_from_version::<V, TYPES>(), block_number,
1497 };
1498
1499 let versioned_data =
1500 VersionedVoteData::<_, _, V>::new_infallible(data.clone(), genesis_view, &upgrade_lock)
1501 .await;
1502
1503 let bytes: [u8; 32] = versioned_data.commit().into();
1504
1505 Self::new(
1506 data,
1507 Commitment::from_raw(bytes),
1508 genesis_view,
1509 None,
1510 PhantomData,
1511 )
1512 }
1513}
1514
1515impl<TYPES: NodeType> Leaf<TYPES> {
1516 #[must_use]
1523 pub async fn genesis<V: Versions>(
1524 validated_state: &TYPES::ValidatedState,
1525 instance_state: &TYPES::InstanceState,
1526 ) -> Self {
1527 let (payload, metadata) =
1528 TYPES::BlockPayload::from_transactions([], validated_state, instance_state)
1529 .await
1530 .unwrap();
1531 let builder_commitment = payload.builder_commitment(&metadata);
1532 let payload_bytes = payload.encode();
1533
1534 let genesis_view = TYPES::View::genesis();
1535 let upgrade_lock = UpgradeLock::<TYPES, V>::new();
1536 let genesis_version = upgrade_lock.version_infallible(genesis_view).await;
1537 let payload_commitment = vid_commitment::<V>(
1538 &payload_bytes,
1539 &metadata.encode(),
1540 GENESIS_VID_NUM_STORAGE_NODES,
1541 genesis_version,
1542 );
1543
1544 let block_header = TYPES::BlockHeader::genesis(
1545 instance_state,
1546 payload_commitment,
1547 builder_commitment,
1548 metadata,
1549 );
1550
1551 let null_quorum_data = QuorumData {
1552 leaf_commit: Commitment::<Leaf<TYPES>>::default_commitment_no_preimage(),
1553 };
1554
1555 let justify_qc = QuorumCertificate::new(
1556 null_quorum_data.clone(),
1557 null_quorum_data.commit(),
1558 genesis_view,
1559 None,
1560 PhantomData,
1561 );
1562
1563 Self {
1564 view_number: genesis_view,
1565 justify_qc,
1566 parent_commitment: null_quorum_data.leaf_commit,
1567 upgrade_certificate: None,
1568 block_header: block_header.clone(),
1569 block_payload: Some(payload),
1570 }
1571 }
1572
1573 pub fn view_number(&self) -> TYPES::View {
1575 self.view_number
1576 }
1577 pub fn height(&self) -> u64 {
1581 self.block_header.block_number()
1582 }
1583 pub fn justify_qc(&self) -> QuorumCertificate<TYPES> {
1585 self.justify_qc.clone()
1586 }
1587 pub fn upgrade_certificate(&self) -> Option<UpgradeCertificate<TYPES>> {
1589 self.upgrade_certificate.clone()
1590 }
1591 pub fn parent_commitment(&self) -> Commitment<Self> {
1593 self.parent_commitment
1594 }
1595 pub fn block_header(&self) -> &<TYPES as NodeType>::BlockHeader {
1597 &self.block_header
1598 }
1599
1600 pub fn block_header_mut(&mut self) -> &mut <TYPES as NodeType>::BlockHeader {
1602 &mut self.block_header
1603 }
1604 pub fn fill_block_payload<V: Versions>(
1611 &mut self,
1612 block_payload: TYPES::BlockPayload,
1613 num_storage_nodes: usize,
1614 version: Version,
1615 ) -> std::result::Result<(), BlockError> {
1616 let encoded_txns = block_payload.encode();
1617 let commitment = vid_commitment::<V>(
1618 &encoded_txns,
1619 &self.block_header.metadata().encode(),
1620 num_storage_nodes,
1621 version,
1622 );
1623 if commitment != self.block_header.payload_commitment() {
1624 return Err(BlockError::InconsistentPayloadCommitment);
1625 }
1626 self.block_payload = Some(block_payload);
1627 Ok(())
1628 }
1629
1630 pub fn unfill_block_payload(&mut self) -> Option<TYPES::BlockPayload> {
1632 self.block_payload.take()
1633 }
1634
1635 pub fn fill_block_payload_unchecked(&mut self, block_payload: TYPES::BlockPayload) {
1638 self.block_payload = Some(block_payload);
1639 }
1640
1641 pub fn block_payload(&self) -> Option<TYPES::BlockPayload> {
1643 self.block_payload.clone()
1644 }
1645
1646 pub fn payload_commitment(&self) -> VidCommitment {
1648 self.block_header().payload_commitment()
1649 }
1650
1651 pub async fn extends_upgrade(
1659 &self,
1660 parent: &Self,
1661 decided_upgrade_certificate: &Arc<RwLock<Option<UpgradeCertificate<TYPES>>>>,
1662 ) -> Result<()> {
1663 match (self.upgrade_certificate(), parent.upgrade_certificate()) {
1664 (None | Some(_), None) => {},
1668 (None, Some(parent_cert)) => {
1672 let decided_upgrade_certificate_read = decided_upgrade_certificate.read().await;
1673 ensure!(self.view_number() > parent_cert.data.new_version_first_view
1674 || (self.view_number() > parent_cert.data.decide_by && decided_upgrade_certificate_read.is_none()),
1675 "The new leaf is missing an upgrade certificate that was present in its parent, and should still be live."
1676 );
1677 },
1678 (Some(cert), Some(parent_cert)) => {
1682 ensure!(cert == parent_cert, "The new leaf does not extend the parent leaf, because it has attached a different upgrade certificate.");
1683 },
1684 }
1685
1686 Ok(())
1690 }
1691}
1692
1693impl<TYPES: NodeType> TestableLeaf for Leaf<TYPES>
1694where
1695 TYPES::ValidatedState: TestableState<TYPES>,
1696 TYPES::BlockPayload: TestableBlock<TYPES>,
1697{
1698 type NodeType = TYPES;
1699
1700 fn create_random_transaction(
1701 &self,
1702 rng: &mut dyn rand::RngCore,
1703 padding: u64,
1704 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
1705 {
1706 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
1707 }
1708}
1709impl<TYPES: NodeType> TestableLeaf for Leaf2<TYPES>
1710where
1711 TYPES::ValidatedState: TestableState<TYPES>,
1712 TYPES::BlockPayload: TestableBlock<TYPES>,
1713{
1714 type NodeType = TYPES;
1715
1716 fn create_random_transaction(
1717 &self,
1718 rng: &mut dyn rand::RngCore,
1719 padding: u64,
1720 ) -> <<Self::NodeType as NodeType>::BlockPayload as BlockPayload<Self::NodeType>>::Transaction
1721 {
1722 TYPES::ValidatedState::create_random_transaction(None, rng, padding)
1723 }
1724}
1725#[must_use]
1727pub fn fake_commitment<S: Committable>() -> Commitment<S> {
1728 RawCommitmentBuilder::new("Dummy commitment for arbitrary genesis").finalize()
1729}
1730
1731#[must_use]
1733pub fn random_commitment<S: Committable>(rng: &mut dyn rand::RngCore) -> Commitment<S> {
1734 let random_array: Vec<u8> = (0u8..100u8).map(|_| rng.gen_range(0..255)).collect();
1735 RawCommitmentBuilder::new("Random Commitment")
1736 .constant_str("Random Field")
1737 .var_size_bytes(&random_array)
1738 .finalize()
1739}
1740
1741pub fn serialize_signature2<TYPES: NodeType>(
1745 signatures: &<TYPES::SignatureKey as SignatureKey>::QcType,
1746) -> Vec<u8> {
1747 let mut signatures_bytes = vec![];
1748 signatures_bytes.extend("Yes".as_bytes());
1749
1750 let (sig, proof) = TYPES::SignatureKey::sig_proof(signatures);
1751 let proof_bytes = bincode_opts()
1752 .serialize(&proof.as_bitslice())
1753 .expect("This serialization shouldn't be able to fail");
1754 signatures_bytes.extend("bitvec proof".as_bytes());
1755 signatures_bytes.extend(proof_bytes.as_slice());
1756 let sig_bytes = bincode_opts()
1757 .serialize(&sig)
1758 .expect("This serialization shouldn't be able to fail");
1759 signatures_bytes.extend("aggregated signature".as_bytes());
1760 signatures_bytes.extend(sig_bytes.as_slice());
1761 signatures_bytes
1762}
1763
1764impl<TYPES: NodeType> Committable for Leaf<TYPES> {
1765 fn commit(&self) -> committable::Commitment<Self> {
1766 RawCommitmentBuilder::new("leaf commitment")
1767 .u64_field("view number", *self.view_number)
1768 .field("parent leaf commitment", self.parent_commitment)
1769 .field("block header", self.block_header.commit())
1770 .field("justify qc", self.justify_qc.commit())
1771 .optional("upgrade certificate", &self.upgrade_certificate)
1772 .finalize()
1773 }
1774}
1775
1776impl<TYPES: NodeType> Leaf2<TYPES> {
1777 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposalWrapper<TYPES>) -> Self {
1779 let QuorumProposalWrapper {
1782 proposal:
1783 QuorumProposal2 {
1784 view_number,
1785 epoch,
1786 justify_qc,
1787 next_epoch_justify_qc,
1788 block_header,
1789 upgrade_certificate,
1790 view_change_evidence,
1791 next_drb_result,
1792 state_cert: _,
1793 },
1794 } = quorum_proposal;
1795
1796 Self {
1797 view_number: *view_number,
1798 justify_qc: justify_qc.clone(),
1799 next_epoch_justify_qc: next_epoch_justify_qc.clone(),
1800 parent_commitment: justify_qc.data().leaf_commit,
1801 block_header: block_header.clone(),
1802 upgrade_certificate: upgrade_certificate.clone(),
1803 block_payload: None,
1804 view_change_evidence: view_change_evidence.clone(),
1805 next_drb_result: *next_drb_result,
1806 with_epoch: epoch.is_some(),
1807 }
1808 }
1809}
1810
1811impl<TYPES: NodeType> Leaf<TYPES> {
1812 pub fn from_quorum_proposal(quorum_proposal: &QuorumProposal<TYPES>) -> Self {
1814 let QuorumProposal {
1817 view_number,
1818 justify_qc,
1819 block_header,
1820 upgrade_certificate,
1821 proposal_certificate: _,
1822 } = quorum_proposal;
1823
1824 Self {
1825 view_number: *view_number,
1826 justify_qc: justify_qc.clone(),
1827 parent_commitment: justify_qc.data().leaf_commit,
1828 block_header: block_header.clone(),
1829 upgrade_certificate: upgrade_certificate.clone(),
1830 block_payload: None,
1831 }
1832 }
1833}
1834
1835pub mod null_block {
1836 #![allow(missing_docs)]
1837
1838 use jf_vid::VidScheme;
1839 use vbs::version::StaticVersionType;
1840
1841 use crate::{
1842 data::VidCommitment,
1843 traits::{
1844 block_contents::BuilderFee,
1845 node_implementation::{NodeType, Versions},
1846 signature_key::BuilderSignatureKey,
1847 BlockPayload,
1848 },
1849 vid::advz::advz_scheme,
1850 };
1851
1852 #[must_use]
1861 pub fn commitment<V: Versions>(num_storage_nodes: usize) -> Option<VidCommitment> {
1862 let vid_result = advz_scheme(num_storage_nodes).commit_only(Vec::new());
1863
1864 match vid_result {
1865 Ok(r) => Some(VidCommitment::V0(r)),
1866 Err(_) => None,
1867 }
1868 }
1869
1870 #[must_use]
1872 pub fn builder_fee<TYPES: NodeType, V: Versions>(
1873 num_storage_nodes: usize,
1874 version: vbs::version::Version,
1875 view_number: u64,
1876 ) -> Option<BuilderFee<TYPES>> {
1877 const FEE_AMOUNT: u64 = 0;
1879
1880 let (pub_key, priv_key) =
1881 <TYPES::BuilderSignatureKey as BuilderSignatureKey>::generated_from_seed_indexed(
1882 [0_u8; 32], 0,
1883 );
1884
1885 if version >= V::Marketplace::VERSION {
1886 match TYPES::BuilderSignatureKey::sign_sequencing_fee_marketplace(
1887 &priv_key,
1888 FEE_AMOUNT,
1889 view_number,
1890 ) {
1891 Ok(sig) => Some(BuilderFee {
1892 fee_amount: FEE_AMOUNT,
1893 fee_account: pub_key,
1894 fee_signature: sig,
1895 }),
1896 Err(_) => None,
1897 }
1898 } else if version >= V::Epochs::VERSION {
1899 let (_null_block, null_block_metadata) =
1900 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
1901
1902 match TYPES::BuilderSignatureKey::sign_fee(&priv_key, FEE_AMOUNT, &null_block_metadata)
1903 {
1904 Ok(sig) => Some(BuilderFee {
1905 fee_amount: FEE_AMOUNT,
1906 fee_account: pub_key,
1907 fee_signature: sig,
1908 }),
1909 Err(_) => None,
1910 }
1911 } else {
1912 let (_null_block, null_block_metadata) =
1913 <TYPES::BlockPayload as BlockPayload<TYPES>>::empty();
1914
1915 match TYPES::BuilderSignatureKey::sign_fee_with_vid_commitment(
1916 &priv_key,
1917 FEE_AMOUNT,
1918 &null_block_metadata,
1919 &commitment::<V>(num_storage_nodes)?,
1920 ) {
1921 Ok(sig) => Some(BuilderFee {
1922 fee_amount: FEE_AMOUNT,
1923 fee_account: pub_key,
1924 fee_signature: sig,
1925 }),
1926 Err(_) => None,
1927 }
1928 }
1929 }
1930}
1931
1932#[derive(Debug, Eq, PartialEq, Clone)]
1934pub struct PackedBundle<TYPES: NodeType> {
1935 pub encoded_transactions: Arc<[u8]>,
1937
1938 pub metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
1940
1941 pub view_number: TYPES::View,
1943
1944 pub epoch_number: Option<TYPES::Epoch>,
1946
1947 pub sequencing_fees: Vec1<BuilderFee<TYPES>>,
1949
1950 pub auction_result: Option<TYPES::AuctionResult>,
1952}
1953
1954impl<TYPES: NodeType> PackedBundle<TYPES> {
1955 pub fn new(
1957 encoded_transactions: Arc<[u8]>,
1958 metadata: <TYPES::BlockPayload as BlockPayload<TYPES>>::Metadata,
1959 view_number: TYPES::View,
1960 epoch_number: Option<TYPES::Epoch>,
1961 sequencing_fees: Vec1<BuilderFee<TYPES>>,
1962 auction_result: Option<TYPES::AuctionResult>,
1963 ) -> Self {
1964 Self {
1965 encoded_transactions,
1966 metadata,
1967 view_number,
1968 epoch_number,
1969 sequencing_fees,
1970 auction_result,
1971 }
1972 }
1973}