1use std::{fmt, hash::Hash, ops::Deref, sync::Arc};
5
6use bytes::Bytes;
7use consensus_config::{
8 AuthorityIndex, DefaultHashFunction, Epoch, ProtocolKeyPair, ProtocolKeySignature,
9 ProtocolPublicKey,
10};
11use consensus_types::block::{BlockDigest, BlockRef, BlockTimestampMs, Round, TransactionIndex};
12use enum_dispatch::enum_dispatch;
13use fastcrypto::hash::HashFunction;
14use itertools::Itertools as _;
15use serde::{Deserialize, Serialize};
16use shared_crypto::intent::{Intent, IntentMessage, IntentScope};
17
18use crate::{
19 commit::CommitVote,
20 context::Context,
21 ensure,
22 error::{ConsensusError, ConsensusResult},
23};
24
25pub(crate) const GENESIS_ROUND: Round = 0;
26
27#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Default, Debug)]
29pub struct Transaction {
30 data: Bytes,
31}
32
33impl Transaction {
34 pub fn new(data: Vec<u8>) -> Self {
35 Self { data: data.into() }
36 }
37
38 pub fn data(&self) -> &[u8] {
39 &self.data
40 }
41
42 pub fn into_data(self) -> Bytes {
43 self.data
44 }
45}
46#[derive(Clone, Deserialize, Serialize)]
50pub(crate) struct BlockTransactionVotes {
51 pub(crate) block_ref: BlockRef,
52 pub(crate) rejects: Vec<TransactionIndex>,
53}
54
55#[allow(private_interfaces)]
60#[derive(Clone, Deserialize, Serialize)]
61#[enum_dispatch(BlockAPI)]
62pub enum Block {
63 V1(BlockV1),
64 V2(BlockV2),
65}
66
67#[allow(private_interfaces)]
68#[enum_dispatch]
69pub trait BlockAPI {
70 fn epoch(&self) -> Epoch;
71 fn round(&self) -> Round;
72 fn author(&self) -> AuthorityIndex;
73 fn slot(&self) -> Slot;
74 fn timestamp_ms(&self) -> BlockTimestampMs;
75 fn ancestors(&self) -> &[BlockRef];
76 fn transactions(&self) -> &[Transaction];
77 fn transactions_data(&self) -> Vec<&[u8]>;
78 fn commit_votes(&self) -> &[CommitVote];
79 fn transaction_votes(&self) -> &[BlockTransactionVotes];
80 fn misbehavior_reports(&self) -> &[MisbehaviorReport];
81}
82
83#[derive(Clone, Default, Deserialize, Serialize)]
84pub(crate) struct BlockV1 {
85 epoch: Epoch,
86 round: Round,
87 author: AuthorityIndex,
88 timestamp_ms: BlockTimestampMs,
89 ancestors: Vec<BlockRef>,
90 transactions: Vec<Transaction>,
91 commit_votes: Vec<CommitVote>,
92 misbehavior_reports: Vec<MisbehaviorReport>,
93}
94
95impl BlockV1 {
96 pub(crate) fn new(
97 epoch: Epoch,
98 round: Round,
99 author: AuthorityIndex,
100 timestamp_ms: BlockTimestampMs,
101 ancestors: Vec<BlockRef>,
102 transactions: Vec<Transaction>,
103 commit_votes: Vec<CommitVote>,
104 misbehavior_reports: Vec<MisbehaviorReport>,
105 ) -> BlockV1 {
106 Self {
107 epoch,
108 round,
109 author,
110 timestamp_ms,
111 ancestors,
112 transactions,
113 commit_votes,
114 misbehavior_reports,
115 }
116 }
117
118 fn genesis_block(context: &Context, author: AuthorityIndex) -> Self {
119 Self {
120 epoch: context.committee.epoch(),
121 round: GENESIS_ROUND,
122 author,
123 timestamp_ms: context.epoch_start_timestamp_ms,
124 ancestors: vec![],
125 transactions: vec![],
126 commit_votes: vec![],
127 misbehavior_reports: vec![],
128 }
129 }
130}
131
132impl BlockAPI for BlockV1 {
133 fn epoch(&self) -> Epoch {
134 self.epoch
135 }
136
137 fn round(&self) -> Round {
138 self.round
139 }
140
141 fn author(&self) -> AuthorityIndex {
142 self.author
143 }
144
145 fn slot(&self) -> Slot {
146 Slot::new(self.round, self.author)
147 }
148
149 fn timestamp_ms(&self) -> BlockTimestampMs {
150 self.timestamp_ms
151 }
152
153 fn ancestors(&self) -> &[BlockRef] {
154 &self.ancestors
155 }
156
157 fn transactions(&self) -> &[Transaction] {
158 &self.transactions
159 }
160
161 fn transactions_data(&self) -> Vec<&[u8]> {
162 self.transactions.iter().map(|t| t.data()).collect()
163 }
164
165 fn commit_votes(&self) -> &[CommitVote] {
166 &self.commit_votes
167 }
168
169 fn transaction_votes(&self) -> &[BlockTransactionVotes] {
170 &[]
171 }
172
173 fn misbehavior_reports(&self) -> &[MisbehaviorReport] {
174 &self.misbehavior_reports
175 }
176}
177
178#[derive(Clone, Default, Deserialize, Serialize)]
179pub(crate) struct BlockV2 {
180 epoch: Epoch,
181 round: Round,
182 author: AuthorityIndex,
183 timestamp_ms: BlockTimestampMs,
184 ancestors: Vec<BlockRef>,
185 transactions: Vec<Transaction>,
186 transaction_votes: Vec<BlockTransactionVotes>,
187 commit_votes: Vec<CommitVote>,
188 misbehavior_reports: Vec<MisbehaviorReport>,
189}
190
191#[allow(unused)]
192impl BlockV2 {
193 pub(crate) fn new(
194 epoch: Epoch,
195 round: Round,
196 author: AuthorityIndex,
197 timestamp_ms: BlockTimestampMs,
198 ancestors: Vec<BlockRef>,
199 transactions: Vec<Transaction>,
200 commit_votes: Vec<CommitVote>,
201 transaction_votes: Vec<BlockTransactionVotes>,
202 misbehavior_reports: Vec<MisbehaviorReport>,
203 ) -> BlockV2 {
204 Self {
205 epoch,
206 round,
207 author,
208 timestamp_ms,
209 ancestors,
210 transactions,
211 commit_votes,
212 transaction_votes,
213 misbehavior_reports,
214 }
215 }
216
217 fn genesis_block(context: &Context, author: AuthorityIndex) -> Self {
218 Self {
219 epoch: context.committee.epoch(),
220 round: GENESIS_ROUND,
221 author,
222 timestamp_ms: context.epoch_start_timestamp_ms,
223 ancestors: vec![],
224 transactions: vec![],
225 commit_votes: vec![],
226 transaction_votes: vec![],
227 misbehavior_reports: vec![],
228 }
229 }
230}
231
232impl BlockAPI for BlockV2 {
233 fn epoch(&self) -> Epoch {
234 self.epoch
235 }
236
237 fn round(&self) -> Round {
238 self.round
239 }
240
241 fn author(&self) -> AuthorityIndex {
242 self.author
243 }
244
245 fn slot(&self) -> Slot {
246 Slot::new(self.round, self.author)
247 }
248
249 fn timestamp_ms(&self) -> BlockTimestampMs {
250 self.timestamp_ms
251 }
252
253 fn ancestors(&self) -> &[BlockRef] {
254 &self.ancestors
255 }
256
257 fn transactions(&self) -> &[Transaction] {
258 &self.transactions
259 }
260
261 fn transactions_data(&self) -> Vec<&[u8]> {
262 self.transactions.iter().map(|t| t.data()).collect()
263 }
264
265 fn transaction_votes(&self) -> &[BlockTransactionVotes] {
266 &self.transaction_votes
267 }
268
269 fn commit_votes(&self) -> &[CommitVote] {
270 &self.commit_votes
271 }
272
273 fn misbehavior_reports(&self) -> &[MisbehaviorReport] {
274 &self.misbehavior_reports
275 }
276}
277
278#[derive(Clone, Copy, PartialEq, PartialOrd, Default, Hash)]
281pub struct Slot {
282 pub round: Round,
283 pub authority: AuthorityIndex,
284}
285
286impl Slot {
287 pub fn new(round: Round, authority: AuthorityIndex) -> Self {
288 Self { round, authority }
289 }
290
291 pub fn new_for_test(round: Round, authority: u32) -> Self {
292 Self {
293 round,
294 authority: AuthorityIndex::new_for_test(authority),
295 }
296 }
297}
298
299impl From<BlockRef> for Slot {
300 fn from(value: BlockRef) -> Self {
301 Slot::new(value.round, value.author)
302 }
303}
304
305impl fmt::Display for Slot {
307 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308 write!(f, "{}{}", self.authority, self.round)
309 }
310}
311
312impl fmt::Debug for Slot {
313 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
314 write!(f, "{}", self)
315 }
316}
317
318#[derive(Deserialize, Serialize)]
323pub(crate) struct SignedBlock {
324 inner: Block,
325 signature: Bytes,
326}
327
328impl SignedBlock {
329 pub(crate) fn new_genesis(block: Block) -> Self {
331 Self {
332 inner: block,
333 signature: Bytes::default(),
334 }
335 }
336
337 pub(crate) fn new(block: Block, protocol_keypair: &ProtocolKeyPair) -> ConsensusResult<Self> {
338 let signature = compute_block_signature(&block, protocol_keypair)?;
339 Ok(Self {
340 inner: block,
341 signature: Bytes::copy_from_slice(signature.to_bytes()),
342 })
343 }
344
345 pub(crate) fn signature(&self) -> &Bytes {
346 &self.signature
347 }
348
349 pub(crate) fn verify_signature(&self, context: &Context) -> ConsensusResult<()> {
352 let block = &self.inner;
353 let committee = &context.committee;
354 ensure!(
355 committee.is_valid_index(block.author()),
356 ConsensusError::InvalidAuthorityIndex {
357 index: block.author(),
358 max: committee.size() - 1
359 }
360 );
361 let authority = committee.authority(block.author());
362 verify_block_signature(block, self.signature(), &authority.protocol_key)
363 }
364
365 pub(crate) fn serialize(&self) -> Result<Bytes, bcs::Error> {
367 let bytes = bcs::to_bytes(self)?;
368 Ok(bytes.into())
369 }
370
371 #[cfg(test)]
373 pub(crate) fn clear_signature(&mut self) {
374 self.signature = Bytes::default();
375 }
376}
377
378#[derive(Serialize, Deserialize)]
382struct InnerBlockDigest([u8; consensus_config::DIGEST_LENGTH]);
383
384fn compute_inner_block_digest(block: &Block) -> ConsensusResult<InnerBlockDigest> {
386 let mut hasher = DefaultHashFunction::new();
387 hasher.update(bcs::to_bytes(block).map_err(ConsensusError::SerializationFailure)?);
388 Ok(InnerBlockDigest(hasher.finalize().into()))
389}
390
391fn to_consensus_block_intent(digest: InnerBlockDigest) -> IntentMessage<InnerBlockDigest> {
393 IntentMessage::new(Intent::consensus_app(IntentScope::ConsensusBlock), digest)
394}
395
396fn compute_block_signature(
401 block: &Block,
402 protocol_keypair: &ProtocolKeyPair,
403) -> ConsensusResult<ProtocolKeySignature> {
404 let digest = compute_inner_block_digest(block)?;
405 let message = bcs::to_bytes(&to_consensus_block_intent(digest))
406 .map_err(ConsensusError::SerializationFailure)?;
407 Ok(protocol_keypair.sign(&message))
408}
409
410fn verify_block_signature(
411 block: &Block,
412 signature: &[u8],
413 protocol_pubkey: &ProtocolPublicKey,
414) -> ConsensusResult<()> {
415 let digest = compute_inner_block_digest(block)?;
416 let message = bcs::to_bytes(&to_consensus_block_intent(digest))
417 .map_err(ConsensusError::SerializationFailure)?;
418 let sig =
419 ProtocolKeySignature::from_bytes(signature).map_err(ConsensusError::MalformedSignature)?;
420 protocol_pubkey
421 .verify(&message, &sig)
422 .map_err(ConsensusError::SignatureVerificationFailure)
423}
424
425impl Deref for SignedBlock {
427 type Target = Block;
428
429 fn deref(&self) -> &Self::Target {
430 &self.inner
431 }
432}
433
434#[derive(Clone)]
437pub struct VerifiedBlock {
438 block: Arc<SignedBlock>,
439
440 digest: BlockDigest,
442 serialized: Bytes,
443}
444
445impl VerifiedBlock {
446 pub(crate) fn new_verified(signed_block: SignedBlock, serialized: Bytes) -> Self {
448 let digest = Self::compute_digest(&serialized);
449 VerifiedBlock {
450 block: Arc::new(signed_block),
451 digest,
452 serialized,
453 }
454 }
455
456 pub fn new_for_test(block: Block) -> Self {
458 let signed_block = SignedBlock {
460 inner: block,
461 signature: Default::default(),
462 };
463 let serialized: Bytes = bcs::to_bytes(&signed_block)
464 .expect("Serialization should not fail")
465 .into();
466 let digest = Self::compute_digest(&serialized);
467 VerifiedBlock {
468 block: Arc::new(signed_block),
469 digest,
470 serialized,
471 }
472 }
473
474 pub fn reference(&self) -> BlockRef {
476 BlockRef {
477 round: self.round(),
478 author: self.author(),
479 digest: self.digest(),
480 }
481 }
482
483 pub(crate) fn digest(&self) -> BlockDigest {
484 self.digest
485 }
486
487 pub(crate) fn serialized(&self) -> &Bytes {
489 &self.serialized
490 }
491
492 pub(crate) fn compute_digest(serialized: &[u8]) -> BlockDigest {
494 let mut hasher = DefaultHashFunction::new();
495 hasher.update(serialized);
496 BlockDigest(hasher.finalize().into())
497 }
498}
499
500impl Deref for VerifiedBlock {
502 type Target = Block;
503
504 fn deref(&self) -> &Self::Target {
505 &self.block.inner
506 }
507}
508
509impl PartialEq for VerifiedBlock {
510 fn eq(&self, other: &Self) -> bool {
511 self.digest() == other.digest()
512 }
513}
514
515impl fmt::Display for VerifiedBlock {
516 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
517 write!(f, "{}", self.reference())
518 }
519}
520
521impl fmt::Debug for VerifiedBlock {
523 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
524 write!(
525 f,
526 "{:?}([{}];{}ms;{}t;{}c)",
527 self.reference(),
528 self.ancestors().iter().map(|a| a.to_string()).join(", "),
529 self.timestamp_ms(),
530 self.transactions().len(),
531 self.commit_votes().len(),
532 )
533 }
534}
535
536#[derive(Clone, Debug)]
540pub(crate) struct ExtendedBlock {
541 pub block: VerifiedBlock,
542 pub excluded_ancestors: Vec<BlockRef>,
543}
544
545pub(crate) fn genesis_blocks(context: &Context) -> Vec<VerifiedBlock> {
548 context
549 .committee
550 .authorities()
551 .map(|(authority_index, _)| {
552 let block = if context.protocol_config.mysticeti_fastpath() {
553 Block::V2(BlockV2::genesis_block(context, authority_index))
554 } else {
555 Block::V1(BlockV1::genesis_block(context, authority_index))
556 };
557 let signed_block = SignedBlock::new_genesis(block);
558 let serialized = signed_block
559 .serialize()
560 .expect("Genesis block serialization failed.");
561 VerifiedBlock::new_verified(signed_block, serialized)
563 })
564 .collect::<Vec<VerifiedBlock>>()
565}
566
567#[derive(Clone)]
569pub struct CertifiedBlock {
570 pub block: VerifiedBlock,
572 pub rejected: Vec<TransactionIndex>,
574}
575
576impl CertifiedBlock {
577 pub fn new(block: VerifiedBlock, rejected: Vec<TransactionIndex>) -> Self {
578 Self { block, rejected }
579 }
580}
581
582pub struct CertifiedBlocksOutput {
584 pub blocks: Vec<CertifiedBlock>,
585}
586
587#[derive(Clone)]
590pub struct TestBlock {
591 block: BlockV2,
592}
593
594impl TestBlock {
595 pub fn new(round: Round, author: u32) -> Self {
596 Self {
597 block: BlockV2 {
598 round,
599 author: AuthorityIndex::new_for_test(author),
600 ..Default::default()
601 },
602 }
603 }
604
605 pub fn set_epoch(mut self, epoch: Epoch) -> Self {
606 self.block.epoch = epoch;
607 self
608 }
609
610 pub fn set_round(mut self, round: Round) -> Self {
611 self.block.round = round;
612 self
613 }
614
615 pub fn set_author(mut self, author: AuthorityIndex) -> Self {
616 self.block.author = author;
617 self
618 }
619
620 pub fn set_timestamp_ms(mut self, timestamp_ms: BlockTimestampMs) -> Self {
621 self.block.timestamp_ms = timestamp_ms;
622 self
623 }
624
625 pub fn set_ancestors(mut self, mut ancestors: Vec<BlockRef>) -> Self {
629 ancestors.sort_by(|a, b| {
630 if a.author == self.block.author {
631 return std::cmp::Ordering::Less;
632 }
633 if b.author == self.block.author {
634 return std::cmp::Ordering::Greater;
635 }
636 a.author.cmp(&b.author)
637 });
638 self.block.ancestors = ancestors;
639 self
640 }
641
642 pub fn set_ancestors_raw(mut self, ancestors: Vec<BlockRef>) -> Self {
644 self.block.ancestors = ancestors;
645 self
646 }
647
648 pub fn set_transactions(mut self, transactions: Vec<Transaction>) -> Self {
649 self.block.transactions = transactions;
650 self
651 }
652
653 pub(crate) fn set_transaction_votes(mut self, votes: Vec<BlockTransactionVotes>) -> Self {
654 self.block.transaction_votes = votes;
655 self
656 }
657
658 #[cfg(test)]
659 pub(crate) fn set_commit_votes(mut self, commit_votes: Vec<CommitVote>) -> Self {
660 self.block.commit_votes = commit_votes;
661 self
662 }
663
664 pub fn build(self) -> Block {
665 Block::V2(self.block)
666 }
667}
668
669#[derive(Clone, Serialize, Deserialize, Debug)]
671pub struct MisbehaviorReport {
672 pub target: AuthorityIndex,
673 pub proof: MisbehaviorProof,
674}
675
676#[derive(Clone, Serialize, Deserialize, Debug)]
678pub enum MisbehaviorProof {
679 InvalidBlock(BlockRef),
680}
681
682#[cfg(test)]
686mod tests {
687 use std::sync::Arc;
688
689 use fastcrypto::error::FastCryptoError;
690
691 use crate::{
692 block::{BlockAPI, SignedBlock, TestBlock, genesis_blocks},
693 context::Context,
694 error::ConsensusError,
695 };
696
697 #[tokio::test]
698 async fn test_sign_and_verify() {
699 let (context, key_pairs) = Context::new_for_test(4);
700 let context = Arc::new(context);
701
702 let block = TestBlock::new(10, 2).build();
704
705 let author_two_key = &key_pairs[2].1;
707 let signed_block = SignedBlock::new(block, author_two_key).expect("Shouldn't fail signing");
708
709 let result = signed_block.verify_signature(&context);
711 assert!(result.is_ok());
712
713 let block = TestBlock::new(10, 2).build();
715 let author_one_key = &key_pairs[1].1;
716 let signed_block = SignedBlock::new(block, author_one_key).expect("Shouldn't fail signing");
717
718 let result = signed_block.verify_signature(&context);
720 match result.err().unwrap() {
721 ConsensusError::SignatureVerificationFailure(err) => {
722 assert_eq!(err, FastCryptoError::InvalidSignature);
723 }
724 err => panic!("Unexpected error: {err:?}"),
725 }
726 }
727
728 #[tokio::test]
729 async fn test_genesis_blocks() {
730 let (context, _) = Context::new_for_test(4);
731 const TIMESTAMP_MS: u64 = 1000;
732 let context = Arc::new(context.with_epoch_start_timestamp_ms(TIMESTAMP_MS));
733 let blocks = genesis_blocks(&context);
734 for (i, block) in blocks.into_iter().enumerate() {
735 assert_eq!(block.author().value(), i);
736 assert_eq!(block.round(), 0);
737 assert_eq!(block.timestamp_ms(), TIMESTAMP_MS);
738 }
739 }
740}