1use std::{
6 fmt,
7 hash::{Hash, Hasher},
8 ops::Deref,
9 sync::Arc,
10};
11
12use bytes::Bytes;
13use consensus_config::{
14 AuthorityIndex, DIGEST_LENGTH, DefaultHashFunction, Epoch, ProtocolKeyPair,
15 ProtocolKeySignature, ProtocolPublicKey,
16};
17use enum_dispatch::enum_dispatch;
18use fastcrypto::hash::{Digest, HashFunction};
19use serde::{Deserialize, Serialize};
20use shared_crypto::intent::{Intent, IntentMessage, IntentScope};
21
22use crate::{
23 commit::CommitVote,
24 context::Context,
25 ensure,
26 error::{ConsensusError, ConsensusResult},
27};
28
29pub type Round = u32;
31
32pub(crate) const GENESIS_ROUND: Round = 0;
33
34pub type BlockTimestampMs = u64;
36
37#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Default, Debug)]
39pub struct Transaction {
40 data: Bytes,
41}
42
43impl Transaction {
44 pub fn new(data: Vec<u8>) -> Self {
45 Self { data: data.into() }
46 }
47
48 pub fn data(&self) -> &[u8] {
49 &self.data
50 }
51
52 pub fn into_data(self) -> Bytes {
53 self.data
54 }
55}
56
57#[derive(Clone, Deserialize, Serialize)]
62#[enum_dispatch(BlockAPI)]
63pub enum Block {
64 V1(BlockV1),
65}
66
67#[enum_dispatch]
68pub trait BlockAPI {
69 fn epoch(&self) -> Epoch;
70 fn round(&self) -> Round;
71 fn author(&self) -> AuthorityIndex;
72 fn slot(&self) -> Slot;
73 fn timestamp_ms(&self) -> BlockTimestampMs;
74 fn ancestors(&self) -> &[BlockRef];
75 fn transactions(&self) -> &[Transaction];
76 fn commit_votes(&self) -> &[CommitVote];
77 fn misbehavior_reports(&self) -> &[MisbehaviorReport];
78}
79
80#[derive(Clone, Default, Deserialize, Serialize)]
81pub struct BlockV1 {
82 epoch: Epoch,
83 round: Round,
84 author: AuthorityIndex,
85 timestamp_ms: BlockTimestampMs,
87 ancestors: Vec<BlockRef>,
88 transactions: Vec<Transaction>,
89 commit_votes: Vec<CommitVote>,
90 misbehavior_reports: Vec<MisbehaviorReport>,
91}
92
93impl BlockV1 {
94 pub(crate) fn new(
95 epoch: Epoch,
96 round: Round,
97 author: AuthorityIndex,
98 timestamp_ms: BlockTimestampMs,
99 ancestors: Vec<BlockRef>,
100 transactions: Vec<Transaction>,
101 commit_votes: Vec<CommitVote>,
102 misbehavior_reports: Vec<MisbehaviorReport>,
103 ) -> BlockV1 {
104 Self {
105 epoch,
106 round,
107 author,
108 timestamp_ms,
109 ancestors,
110 transactions,
111 commit_votes,
112 misbehavior_reports,
113 }
114 }
115
116 fn genesis_block(epoch: Epoch, author: AuthorityIndex) -> Self {
117 Self {
118 epoch,
119 round: GENESIS_ROUND,
120 author,
121 timestamp_ms: 0,
122 ancestors: vec![],
123 transactions: vec![],
124 commit_votes: vec![],
125 misbehavior_reports: vec![],
126 }
127 }
128}
129
130impl BlockAPI for BlockV1 {
131 fn epoch(&self) -> Epoch {
132 self.epoch
133 }
134
135 fn round(&self) -> Round {
136 self.round
137 }
138
139 fn author(&self) -> AuthorityIndex {
140 self.author
141 }
142
143 fn slot(&self) -> Slot {
144 Slot::new(self.round, self.author)
145 }
146
147 fn timestamp_ms(&self) -> BlockTimestampMs {
148 self.timestamp_ms
149 }
150
151 fn ancestors(&self) -> &[BlockRef] {
152 &self.ancestors
153 }
154
155 fn transactions(&self) -> &[Transaction] {
156 &self.transactions
157 }
158
159 fn commit_votes(&self) -> &[CommitVote] {
160 &self.commit_votes
161 }
162
163 fn misbehavior_reports(&self) -> &[MisbehaviorReport] {
164 &self.misbehavior_reports
165 }
166}
167
168#[derive(Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd, Ord)]
172pub struct BlockRef {
173 pub round: Round,
174 pub author: AuthorityIndex,
175 pub digest: BlockDigest,
176}
177
178impl BlockRef {
179 pub const MIN: Self = Self {
180 round: 0,
181 author: AuthorityIndex::MIN,
182 digest: BlockDigest::MIN,
183 };
184
185 pub const MAX: Self = Self {
186 round: u32::MAX,
187 author: AuthorityIndex::MAX,
188 digest: BlockDigest::MAX,
189 };
190
191 pub fn new(round: Round, author: AuthorityIndex, digest: BlockDigest) -> Self {
192 Self {
193 round,
194 author,
195 digest,
196 }
197 }
198}
199
200impl fmt::Display for BlockRef {
201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
202 write!(f, "B{}({},{})", self.round, self.author, self.digest)
203 }
204}
205
206impl fmt::Debug for BlockRef {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
208 fmt::Display::fmt(self, f)
209 }
210}
211
212impl Hash for BlockRef {
213 fn hash<H: Hasher>(&self, state: &mut H) {
214 state.write(&self.digest.0[..8]);
215 }
216}
217
218#[derive(Clone, Copy, Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd, Ord)]
225pub struct BlockDigest([u8; consensus_config::DIGEST_LENGTH]);
226
227impl BlockDigest {
228 pub const MIN: Self = Self([u8::MIN; consensus_config::DIGEST_LENGTH]);
230 pub const MAX: Self = Self([u8::MAX; consensus_config::DIGEST_LENGTH]);
231}
232
233impl Hash for BlockDigest {
234 fn hash<H: Hasher>(&self, state: &mut H) {
235 state.write(&self.0[..8]);
236 }
237}
238
239impl From<BlockDigest> for Digest<{ DIGEST_LENGTH }> {
240 fn from(hd: BlockDigest) -> Self {
241 Digest::new(hd.0)
242 }
243}
244
245impl fmt::Display for BlockDigest {
246 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
247 write!(
248 f,
249 "{}",
250 base64::Engine::encode(&base64::engine::general_purpose::STANDARD, self.0)
251 .get(0..4)
252 .ok_or(fmt::Error)?
253 )
254 }
255}
256
257impl fmt::Debug for BlockDigest {
258 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
259 write!(
260 f,
261 "{}",
262 base64::Engine::encode(&base64::engine::general_purpose::STANDARD, self.0)
263 )
264 }
265}
266
267impl AsRef<[u8]> for BlockDigest {
268 fn as_ref(&self) -> &[u8] {
269 &self.0
270 }
271}
272
273#[derive(Clone, Copy, PartialEq, PartialOrd, Default, Hash)]
276pub struct Slot {
277 pub round: Round,
278 pub authority: AuthorityIndex,
279}
280
281impl Slot {
282 pub fn new(round: Round, authority: AuthorityIndex) -> Self {
283 Self { round, authority }
284 }
285
286 #[cfg(test)]
287 pub fn new_for_test(round: Round, authority: u32) -> Self {
288 Self {
289 round,
290 authority: AuthorityIndex::new_for_test(authority),
291 }
292 }
293}
294
295impl From<BlockRef> for Slot {
296 fn from(value: BlockRef) -> Self {
297 Slot::new(value.round, value.author)
298 }
299}
300
301impl fmt::Display for Slot {
302 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303 write!(f, "S{}{}", self.round, self.authority)
304 }
305}
306
307impl fmt::Debug for Slot {
308 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
309 fmt::Display::fmt(&self, f)
310 }
311}
312
313#[derive(Deserialize, Serialize)]
319pub(crate) struct SignedBlock {
320 inner: Block,
321 signature: Bytes,
322}
323
324impl SignedBlock {
325 pub(crate) fn new_genesis(block: Block) -> Self {
327 Self {
328 inner: block,
329 signature: Bytes::default(),
330 }
331 }
332
333 pub(crate) fn new(block: Block, protocol_keypair: &ProtocolKeyPair) -> ConsensusResult<Self> {
334 let signature = compute_block_signature(&block, protocol_keypair)?;
335 Ok(Self {
336 inner: block,
337 signature: Bytes::copy_from_slice(signature.to_bytes()),
338 })
339 }
340
341 pub(crate) fn signature(&self) -> &Bytes {
342 &self.signature
343 }
344
345 pub(crate) fn verify_signature(&self, context: &Context) -> ConsensusResult<()> {
348 let block = &self.inner;
349 let committee = &context.committee;
350 ensure!(
351 committee.is_valid_index(block.author()),
352 ConsensusError::InvalidAuthorityIndex {
353 index: block.author(),
354 max: committee.size() - 1
355 }
356 );
357 let authority = committee.authority(block.author());
358 verify_block_signature(block, self.signature(), &authority.protocol_key)
359 }
360
361 pub(crate) fn serialize(&self) -> Result<Bytes, bcs::Error> {
363 let bytes = bcs::to_bytes(self)?;
364 Ok(bytes.into())
365 }
366
367 #[cfg(test)]
369 pub(crate) fn clear_signature(&mut self) {
370 self.signature = Bytes::default();
371 }
372}
373
374#[derive(Serialize, Deserialize)]
379struct InnerBlockDigest([u8; consensus_config::DIGEST_LENGTH]);
380
381fn compute_inner_block_digest(block: &Block) -> ConsensusResult<InnerBlockDigest> {
383 let mut hasher = DefaultHashFunction::new();
384 hasher.update(bcs::to_bytes(block).map_err(ConsensusError::SerializationFailure)?);
385 Ok(InnerBlockDigest(hasher.finalize().into()))
386}
387
388fn to_consensus_block_intent(digest: InnerBlockDigest) -> IntentMessage<InnerBlockDigest> {
390 IntentMessage::new(Intent::consensus_app(IntentScope::ConsensusBlock), digest)
391}
392
393fn compute_block_signature(
398 block: &Block,
399 protocol_keypair: &ProtocolKeyPair,
400) -> ConsensusResult<ProtocolKeySignature> {
401 let digest = compute_inner_block_digest(block)?;
402 let message = bcs::to_bytes(&to_consensus_block_intent(digest))
403 .map_err(ConsensusError::SerializationFailure)?;
404 Ok(protocol_keypair.sign(&message))
405}
406fn verify_block_signature(
407 block: &Block,
408 signature: &[u8],
409 protocol_pubkey: &ProtocolPublicKey,
410) -> ConsensusResult<()> {
411 let digest = compute_inner_block_digest(block)?;
412 let message = bcs::to_bytes(&to_consensus_block_intent(digest))
413 .map_err(ConsensusError::SerializationFailure)?;
414 let sig =
415 ProtocolKeySignature::from_bytes(signature).map_err(ConsensusError::MalformedSignature)?;
416 protocol_pubkey
417 .verify(&message, &sig)
418 .map_err(ConsensusError::SignatureVerificationFailure)
419}
420
421impl Deref for SignedBlock {
424 type Target = Block;
425
426 fn deref(&self) -> &Self::Target {
427 &self.inner
428 }
429}
430
431#[derive(Clone)]
434pub struct VerifiedBlock {
435 block: Arc<SignedBlock>,
436
437 digest: BlockDigest,
439 serialized: Bytes,
440}
441
442impl VerifiedBlock {
443 pub(crate) fn new_verified(signed_block: SignedBlock, serialized: Bytes) -> Self {
446 let digest = Self::compute_digest(&serialized);
447 VerifiedBlock {
448 block: Arc::new(signed_block),
449 digest,
450 serialized,
451 }
452 }
453
454 pub fn new_for_test(block: Block) -> Self {
456 let signed_block = SignedBlock {
457 inner: block,
458 signature: Default::default(),
459 };
460 let serialized: Bytes = bcs::to_bytes(&signed_block)
461 .expect("Serialization should not fail")
462 .into();
463 let digest = Self::compute_digest(&serialized);
464 VerifiedBlock {
465 block: Arc::new(signed_block),
466 digest,
467 serialized,
468 }
469 }
470
471 pub fn reference(&self) -> BlockRef {
473 BlockRef {
474 round: self.round(),
475 author: self.author(),
476 digest: self.digest(),
477 }
478 }
479
480 pub(crate) fn digest(&self) -> BlockDigest {
481 self.digest
482 }
483
484 pub(crate) fn serialized(&self) -> &Bytes {
486 &self.serialized
487 }
488
489 pub(crate) fn compute_digest(serialized: &[u8]) -> BlockDigest {
491 let mut hasher = DefaultHashFunction::new();
492 hasher.update(serialized);
493 BlockDigest(hasher.finalize().into())
494 }
495}
496
497impl Deref for VerifiedBlock {
500 type Target = Block;
501
502 fn deref(&self) -> &Self::Target {
503 &self.block.inner
504 }
505}
506
507impl PartialEq for VerifiedBlock {
508 fn eq(&self, other: &Self) -> bool {
509 self.digest() == other.digest()
510 }
511}
512
513impl fmt::Display for VerifiedBlock {
514 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
515 write!(f, "{}", self.reference())
516 }
517}
518
519impl fmt::Debug for VerifiedBlock {
520 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
521 write!(
522 f,
523 "{:?}({}ms;{:?};{}t;{}c)",
524 self.reference(),
525 self.timestamp_ms(),
526 self.ancestors(),
527 self.transactions().len(),
528 self.commit_votes().len(),
529 )
530 }
531}
532
533#[derive(Clone, Debug)]
538pub(crate) struct ExtendedBlock {
539 pub block: VerifiedBlock,
540 pub excluded_ancestors: Vec<BlockRef>,
541}
542
543pub(crate) fn genesis_blocks(context: Arc<Context>) -> Vec<VerifiedBlock> {
546 context
547 .committee
548 .authorities()
549 .map(|(authority_index, _)| {
550 let signed_block = SignedBlock::new_genesis(Block::V1(BlockV1::genesis_block(
551 context.committee.epoch(),
552 authority_index,
553 )));
554 let serialized = signed_block
555 .serialize()
556 .expect("Genesis block serialization failed.");
557 VerifiedBlock::new_verified(signed_block, serialized)
559 })
560 .collect::<Vec<VerifiedBlock>>()
561}
562
563#[derive(Clone)]
565pub struct TestBlock {
566 block: BlockV1,
567}
568
569impl TestBlock {
570 pub fn new(round: Round, author: u32) -> Self {
571 Self {
572 block: BlockV1 {
573 round,
574 author: AuthorityIndex::new_for_test(author),
575 ..Default::default()
576 },
577 }
578 }
579
580 pub fn set_epoch(mut self, epoch: Epoch) -> Self {
581 self.block.epoch = epoch;
582 self
583 }
584
585 pub fn set_round(mut self, round: Round) -> Self {
586 self.block.round = round;
587 self
588 }
589
590 pub fn set_author(mut self, author: AuthorityIndex) -> Self {
591 self.block.author = author;
592 self
593 }
594
595 pub fn set_timestamp_ms(mut self, timestamp_ms: BlockTimestampMs) -> Self {
596 self.block.timestamp_ms = timestamp_ms;
597 self
598 }
599
600 pub fn set_ancestors(mut self, ancestors: Vec<BlockRef>) -> Self {
601 self.block.ancestors = ancestors;
602 self
603 }
604
605 pub fn set_transactions(mut self, transactions: Vec<Transaction>) -> Self {
606 self.block.transactions = transactions;
607 self
608 }
609
610 pub fn set_commit_votes(mut self, commit_votes: Vec<CommitVote>) -> Self {
611 self.block.commit_votes = commit_votes;
612 self
613 }
614
615 pub fn build(self) -> Block {
616 Block::V1(self.block)
617 }
618}
619
620#[derive(Clone, Serialize, Deserialize, Debug)]
622pub struct MisbehaviorReport {
623 pub target: AuthorityIndex,
624 pub proof: MisbehaviorProof,
625}
626
627#[derive(Clone, Serialize, Deserialize, Debug)]
630pub enum MisbehaviorProof {
631 InvalidBlock(BlockRef),
632}
633
634#[cfg(test)]
638mod tests {
639 use std::sync::Arc;
640
641 use fastcrypto::error::FastCryptoError;
642
643 use crate::{
644 block::{SignedBlock, TestBlock},
645 context::Context,
646 error::ConsensusError,
647 };
648
649 #[tokio::test]
650 async fn test_sign_and_verify() {
651 let (context, key_pairs) = Context::new_for_test(4);
652 let context = Arc::new(context);
653
654 let block = TestBlock::new(10, 2).build();
656
657 let author_two_key = &key_pairs[2].1;
659 let signed_block = SignedBlock::new(block, author_two_key).expect("Shouldn't fail signing");
660
661 let result = signed_block.verify_signature(&context);
663 assert!(result.is_ok());
664
665 let block = TestBlock::new(10, 2).build();
667 let author_one_key = &key_pairs[1].1;
668 let signed_block = SignedBlock::new(block, author_one_key).expect("Shouldn't fail signing");
669
670 let result = signed_block.verify_signature(&context);
672 match result.err().unwrap() {
673 ConsensusError::SignatureVerificationFailure(err) => {
674 assert_eq!(err, FastCryptoError::InvalidSignature);
675 }
676 err => panic!("Unexpected error: {err:?}"),
677 }
678 }
679}