1use std::{
6 collections::hash_map::DefaultHasher,
7 fmt::{Debug, Formatter},
8 hash::{Hash, Hasher},
9 sync::Arc,
10 time::{SystemTime, UNIX_EPOCH},
11};
12
13use byteorder::{BigEndian, ReadBytesExt};
14use fastcrypto::{error::FastCryptoResult, groups::bls12381, hash::HashFunction};
15use fastcrypto_tbls::dkg_v1;
16use fastcrypto_zkp::bn254::zk_login::{JWK, JwkId};
17use iota_sdk_types::crypto::IntentScope;
18use once_cell::sync::OnceCell;
19use schemars::JsonSchema;
20use serde::{Deserialize, Serialize};
21
22use crate::{
23 base_types::{
24 AuthorityName, ConciseableName, ObjectID, ObjectRef, SequenceNumber, TransactionDigest,
25 },
26 crypto::{AuthoritySignature, DefaultHash, default_hash},
27 digests::{ConsensusCommitDigest, Digest, MisbehaviorReportDigest},
28 message_envelope::{Envelope, Message, VerifiedEnvelope},
29 messages_checkpoint::{CheckpointSequenceNumber, CheckpointSignatureMessage},
30 supported_protocol_versions::{
31 Chain, SupportedProtocolVersions, SupportedProtocolVersionsWithHashes,
32 },
33 transaction::CertifiedTransaction,
34};
35
36pub type TimestampMs = u64;
38
39#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, JsonSchema)]
42pub enum ConsensusDeterminedVersionAssignments {
43 CancelledTransactions(Vec<(TransactionDigest, Vec<(ObjectID, SequenceNumber)>)>),
45}
46
47#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
48pub struct ConsensusCommitPrologueV1 {
49 pub epoch: u64,
51 pub round: u64,
53 pub sub_dag_index: Option<u64>,
56 pub commit_timestamp_ms: TimestampMs,
58 pub consensus_commit_digest: ConsensusCommitDigest,
60 pub consensus_determined_version_assignments: ConsensusDeterminedVersionAssignments,
62}
63
64static MAX_TOTAL_JWK_SIZE: usize = 4096;
68
69pub fn check_total_jwk_size(id: &JwkId, jwk: &JWK) -> bool {
70 id.iss.len() + id.kid.len() + jwk.kty.len() + jwk.alg.len() + jwk.e.len() + jwk.n.len()
71 <= MAX_TOTAL_JWK_SIZE
72}
73
74#[derive(Serialize, Deserialize, Clone, Debug)]
75pub struct ConsensusTransaction {
76 pub tracking_id: [u8; 8],
80 pub kind: ConsensusTransactionKind,
81}
82
83#[derive(Serialize, Deserialize, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
84pub enum ConsensusTransactionKey {
85 Certificate(TransactionDigest),
86 CheckpointSignature(AuthorityName, CheckpointSequenceNumber),
87 EndOfPublish(AuthorityName),
88 CapabilityNotification(AuthorityName, u64 ),
89 NewJWKFetched(Box<(AuthorityName, JwkId, JWK)>),
92 RandomnessDkgMessage(AuthorityName),
93 RandomnessDkgConfirmation(AuthorityName),
94 MisbehaviorReport(
95 AuthorityName,
96 MisbehaviorReportDigest,
97 CheckpointSequenceNumber,
98 ),
99 }
102
103impl Debug for ConsensusTransactionKey {
104 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
105 match self {
106 Self::Certificate(digest) => write!(f, "Certificate({digest:?})"),
107 Self::CheckpointSignature(name, seq) => {
108 write!(f, "CheckpointSignature({:?}, {:?})", name.concise(), seq)
109 }
110 Self::EndOfPublish(name) => write!(f, "EndOfPublish({:?})", name.concise()),
111 Self::CapabilityNotification(name, generation) => write!(
112 f,
113 "CapabilityNotification({:?}, {:?})",
114 name.concise(),
115 generation
116 ),
117 Self::NewJWKFetched(key) => {
118 let (authority, id, jwk) = &**key;
119 write!(
120 f,
121 "NewJWKFetched({:?}, {:?}, {:?})",
122 authority.concise(),
123 id,
124 jwk
125 )
126 }
127 Self::RandomnessDkgMessage(name) => {
128 write!(f, "RandomnessDkgMessage({:?})", name.concise())
129 }
130 Self::RandomnessDkgConfirmation(name) => {
131 write!(f, "RandomnessDkgConfirmation({:?})", name.concise())
132 }
133 Self::MisbehaviorReport(name, digest, checkpoint_seq) => {
134 write!(
135 f,
136 "MisbehaviorReport({:?}, {:?}, {:?})",
137 name.concise(),
138 digest,
139 checkpoint_seq
140 )
141 }
142 }
143 }
144}
145
146pub type SignedAuthorityCapabilitiesV1 = Envelope<AuthorityCapabilitiesV1, AuthoritySignature>;
147
148pub type VerifiedAuthorityCapabilitiesV1 =
149 VerifiedEnvelope<AuthorityCapabilitiesV1, AuthoritySignature>;
150
151#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
152pub struct AuthorityCapabilitiesDigest(Digest);
153
154impl AuthorityCapabilitiesDigest {
155 pub const fn new(digest: [u8; 32]) -> Self {
156 Self(Digest::new(digest))
157 }
158}
159
160impl Debug for AuthorityCapabilitiesDigest {
161 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
162 f.debug_tuple("AuthorityCapabilitiesDigest")
163 .field(&self.0)
164 .finish()
165 }
166}
167
168#[derive(Serialize, Deserialize, Clone, Hash)]
171pub struct AuthorityCapabilitiesV1 {
172 pub authority: AuthorityName,
175 pub generation: u64,
182
183 pub supported_protocol_versions: SupportedProtocolVersionsWithHashes,
186
187 pub available_system_packages: Vec<ObjectRef>,
191}
192
193impl Message for AuthorityCapabilitiesV1 {
194 type DigestType = AuthorityCapabilitiesDigest;
195 const SCOPE: IntentScope = IntentScope::AuthorityCapabilities;
196
197 fn digest(&self) -> Self::DigestType {
198 let mut hasher = DefaultHash::new();
200 let serialized = bcs::to_bytes(&self).expect("BCS should not fail");
201 hasher.update(&serialized);
202 AuthorityCapabilitiesDigest::new(<[u8; 32]>::from(hasher.finalize()))
203 }
204}
205
206impl Debug for AuthorityCapabilitiesV1 {
207 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
208 f.debug_struct("AuthorityCapabilities")
209 .field("authority", &self.authority.concise())
210 .field("generation", &self.generation)
211 .field(
212 "supported_protocol_versions",
213 &self.supported_protocol_versions,
214 )
215 .field("available_system_packages", &self.available_system_packages)
216 .finish()
217 }
218}
219
220impl AuthorityCapabilitiesV1 {
221 pub fn new(
222 authority: AuthorityName,
223 chain: Chain,
224 supported_protocol_versions: SupportedProtocolVersions,
225 available_system_packages: Vec<ObjectRef>,
226 ) -> Self {
227 let generation = SystemTime::now()
228 .duration_since(UNIX_EPOCH)
229 .expect("IOTA did not exist prior to 1970")
230 .as_millis()
231 .try_into()
232 .expect("This build of iota is not supported in the year 500,000,000");
233 Self {
234 authority,
235 generation,
236 supported_protocol_versions:
237 SupportedProtocolVersionsWithHashes::from_supported_versions(
238 supported_protocol_versions,
239 chain,
240 ),
241 available_system_packages,
242 }
243 }
244}
245
246impl SignedAuthorityCapabilitiesV1 {
247 pub fn cache_digest(&self, epoch: u64) -> AuthorityCapabilitiesDigest {
248 let data_with_epoch = (self.data(), epoch);
250
251 let mut hasher = DefaultHash::new();
253 let serialized = bcs::to_bytes(&data_with_epoch).expect("BCS should not fail");
254 hasher.update(&serialized);
255 AuthorityCapabilitiesDigest::new(<[u8; 32]>::from(hasher.finalize()))
256 }
257}
258
259#[derive(Serialize, Deserialize, Clone, Debug)]
260pub enum ConsensusTransactionKind {
261 CertifiedTransaction(Box<CertifiedTransaction>),
262 CheckpointSignature(Box<CheckpointSignatureMessage>),
263 EndOfPublish(AuthorityName),
264
265 CapabilityNotificationV1(AuthorityCapabilitiesV1),
266 SignedCapabilityNotificationV1(SignedAuthorityCapabilitiesV1),
267
268 NewJWKFetched(AuthorityName, JwkId, JWK),
269
270 RandomnessDkgMessage(AuthorityName, Vec<u8>),
274 RandomnessDkgConfirmation(AuthorityName, Vec<u8>),
278 MisbehaviorReport(
279 AuthorityName,
280 VersionedMisbehaviorReport,
281 CheckpointSequenceNumber,
282 ),
283 }
286
287impl ConsensusTransactionKind {
288 pub fn is_dkg(&self) -> bool {
289 matches!(
290 self,
291 ConsensusTransactionKind::RandomnessDkgMessage(_, _)
292 | ConsensusTransactionKind::RandomnessDkgConfirmation(_, _)
293 )
294 }
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize)]
298pub enum VersionedMisbehaviorReport {
299 V1(
300 MisbehaviorsV1<Vec<u64>>,
301 #[serde(skip)] OnceCell<MisbehaviorReportDigest>,
302 ),
303}
304
305impl VersionedMisbehaviorReport {
306 pub fn new_v1(misbehaviors: MisbehaviorsV1<Vec<u64>>) -> Self {
307 VersionedMisbehaviorReport::V1(misbehaviors, OnceCell::new())
308 }
309
310 pub fn verify(&self, committee_size: usize) -> bool {
311 match self {
312 VersionedMisbehaviorReport::V1(report, _) => report.verify(committee_size),
313 }
314 }
315 pub fn iterate_over_metrics(&self) -> std::vec::IntoIter<&Vec<u64>> {
317 match self {
318 VersionedMisbehaviorReport::V1(report, _) => report.iter(),
319 }
320 }
321 pub fn digest(&self) -> &MisbehaviorReportDigest {
324 match self {
325 VersionedMisbehaviorReport::V1(_, digest) => {
326 digest.get_or_init(|| MisbehaviorReportDigest::new(default_hash(self)))
327 }
328 }
329 }
330}
331
332#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
337pub struct MisbehaviorsV1<T> {
338 pub faulty_blocks_provable: T,
339 pub faulty_blocks_unprovable: T,
340 pub missing_proposals: T,
341 pub equivocations: T,
342}
343
344impl MisbehaviorsV1<Vec<u64>> {
345 pub fn verify(&self, committee_size: usize) -> bool {
346 if (self.faulty_blocks_provable.len() != committee_size)
354 | (self.faulty_blocks_unprovable.len() != committee_size)
355 | (self.equivocations.len() != committee_size)
356 | (self.missing_proposals.len() != committee_size)
357 {
358 return false;
359 }
360 true
361 }
362}
363impl<T> MisbehaviorsV1<T> {
364 pub fn iter(&self) -> std::vec::IntoIter<&T> {
365 vec![
366 &self.faulty_blocks_provable,
367 &self.faulty_blocks_unprovable,
368 &self.missing_proposals,
369 &self.equivocations,
370 ]
371 .into_iter()
372 }
373 pub fn iter_major_misbehaviors(&self) -> std::vec::IntoIter<&T> {
376 vec![&self.equivocations].into_iter()
377 }
378 pub fn iter_minor_misbehaviors(&self) -> std::vec::IntoIter<&T> {
381 vec![
382 &self.faulty_blocks_provable,
383 &self.faulty_blocks_unprovable,
384 &self.missing_proposals,
385 ]
386 .into_iter()
387 }
388}
389
390impl<T> FromIterator<T> for MisbehaviorsV1<T> {
391 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
392 let mut iterator = iter.into_iter();
393 Self {
394 faulty_blocks_provable: iterator.next().expect("Not enough elements in iterator"),
395 faulty_blocks_unprovable: iterator.next().expect("Not enough elements in iterator"),
396 missing_proposals: iterator.next().expect("Not enough elements in iterator"),
397 equivocations: iterator.next().expect("Not enough elements in iterator"),
398 }
399 }
400}
401
402#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
403pub enum VersionedDkgMessage {
404 V1(dkg_v1::Message<bls12381::G2Element, bls12381::G2Element>),
405}
406
407#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
408pub enum VersionedDkgConfirmation {
409 V1(dkg_v1::Confirmation<bls12381::G2Element>),
410}
411
412impl Debug for VersionedDkgMessage {
413 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
414 match self {
415 VersionedDkgMessage::V1(msg) => write!(
416 f,
417 "DKG V1 Message with sender={}, vss_pk.degree={}, encrypted_shares.len()={}",
418 msg.sender,
419 msg.vss_pk.degree(),
420 msg.encrypted_shares.len(),
421 ),
422 }
423 }
424}
425
426impl VersionedDkgMessage {
427 pub fn sender(&self) -> u16 {
428 match self {
429 VersionedDkgMessage::V1(msg) => msg.sender,
430 }
431 }
432
433 pub fn create(
434 dkg_version: u64,
435 party: Arc<dkg_v1::Party<bls12381::G2Element, bls12381::G2Element>>,
436 ) -> FastCryptoResult<VersionedDkgMessage> {
437 assert_eq!(dkg_version, 1, "BUG: invalid DKG version");
438 let msg = party.create_message(&mut rand::thread_rng())?;
439 Ok(VersionedDkgMessage::V1(msg))
440 }
441
442 pub fn unwrap_v1(self) -> dkg_v1::Message<bls12381::G2Element, bls12381::G2Element> {
443 match self {
444 VersionedDkgMessage::V1(msg) => msg,
445 }
446 }
447
448 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
449 matches!((self, dkg_version), (VersionedDkgMessage::V1(_), 1))
450 }
451}
452
453impl VersionedDkgConfirmation {
454 pub fn sender(&self) -> u16 {
455 match self {
456 VersionedDkgConfirmation::V1(msg) => msg.sender,
457 }
458 }
459
460 pub fn num_of_complaints(&self) -> usize {
461 match self {
462 VersionedDkgConfirmation::V1(msg) => msg.complaints.len(),
463 }
464 }
465
466 pub fn unwrap_v1(&self) -> &dkg_v1::Confirmation<bls12381::G2Element> {
467 match self {
468 VersionedDkgConfirmation::V1(msg) => msg,
469 }
470 }
471
472 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
473 matches!((self, dkg_version), (VersionedDkgConfirmation::V1(_), 1))
474 }
475}
476
477impl ConsensusTransaction {
478 pub fn new_certificate_message(
479 authority: &AuthorityName,
480 certificate: CertifiedTransaction,
481 ) -> Self {
482 let mut hasher = DefaultHasher::new();
483 let tx_digest = certificate.digest();
484 tx_digest.hash(&mut hasher);
485 authority.hash(&mut hasher);
486 let tracking_id = hasher.finish().to_le_bytes();
487 Self {
488 tracking_id,
489 kind: ConsensusTransactionKind::CertifiedTransaction(Box::new(certificate)),
490 }
491 }
492
493 pub fn new_checkpoint_signature_message(data: CheckpointSignatureMessage) -> Self {
494 let mut hasher = DefaultHasher::new();
495 data.summary.auth_sig().signature.hash(&mut hasher);
496 let tracking_id = hasher.finish().to_le_bytes();
497 Self {
498 tracking_id,
499 kind: ConsensusTransactionKind::CheckpointSignature(Box::new(data)),
500 }
501 }
502
503 pub fn new_end_of_publish(authority: AuthorityName) -> Self {
504 let mut hasher = DefaultHasher::new();
505 authority.hash(&mut hasher);
506 let tracking_id = hasher.finish().to_le_bytes();
507 Self {
508 tracking_id,
509 kind: ConsensusTransactionKind::EndOfPublish(authority),
510 }
511 }
512
513 pub fn new_capability_notification_v1(capabilities: AuthorityCapabilitiesV1) -> Self {
514 let mut hasher = DefaultHasher::new();
515 capabilities.hash(&mut hasher);
516 let tracking_id = hasher.finish().to_le_bytes();
517 Self {
518 tracking_id,
519 kind: ConsensusTransactionKind::CapabilityNotificationV1(capabilities),
520 }
521 }
522
523 pub fn new_signed_capability_notification_v1(
524 signed_capabilities: SignedAuthorityCapabilitiesV1,
525 ) -> Self {
526 let mut hasher = DefaultHasher::new();
527 signed_capabilities.data().hash(&mut hasher);
528 signed_capabilities.auth_sig().hash(&mut hasher);
529 let tracking_id = hasher.finish().to_le_bytes();
530 Self {
531 tracking_id,
532 kind: ConsensusTransactionKind::SignedCapabilityNotificationV1(signed_capabilities),
533 }
534 }
535
536 pub fn new_mysticeti_certificate(
537 round: u64,
538 offset: u64,
539 certificate: CertifiedTransaction,
540 ) -> Self {
541 let mut hasher = DefaultHasher::new();
542 let tx_digest = certificate.digest();
543 tx_digest.hash(&mut hasher);
544 round.hash(&mut hasher);
545 offset.hash(&mut hasher);
546 let tracking_id = hasher.finish().to_le_bytes();
547 Self {
548 tracking_id,
549 kind: ConsensusTransactionKind::CertifiedTransaction(Box::new(certificate)),
550 }
551 }
552
553 pub fn new_jwk_fetched(authority: AuthorityName, id: JwkId, jwk: JWK) -> Self {
554 let mut hasher = DefaultHasher::new();
555 id.hash(&mut hasher);
556 let tracking_id = hasher.finish().to_le_bytes();
557 Self {
558 tracking_id,
559 kind: ConsensusTransactionKind::NewJWKFetched(authority, id, jwk),
560 }
561 }
562
563 pub fn new_randomness_dkg_message(
564 authority: AuthorityName,
565 versioned_message: &VersionedDkgMessage,
566 ) -> Self {
567 let message =
568 bcs::to_bytes(versioned_message).expect("message serialization should not fail");
569 let mut hasher = DefaultHasher::new();
570 message.hash(&mut hasher);
571 let tracking_id = hasher.finish().to_le_bytes();
572 Self {
573 tracking_id,
574 kind: ConsensusTransactionKind::RandomnessDkgMessage(authority, message),
575 }
576 }
577 pub fn new_randomness_dkg_confirmation(
578 authority: AuthorityName,
579 versioned_confirmation: &VersionedDkgConfirmation,
580 ) -> Self {
581 let confirmation =
582 bcs::to_bytes(versioned_confirmation).expect("message serialization should not fail");
583 let mut hasher = DefaultHasher::new();
584 confirmation.hash(&mut hasher);
585 let tracking_id = hasher.finish().to_le_bytes();
586 Self {
587 tracking_id,
588 kind: ConsensusTransactionKind::RandomnessDkgConfirmation(authority, confirmation),
589 }
590 }
591
592 pub fn new_misbehavior_report(
593 authority: AuthorityName,
594 report: &VersionedMisbehaviorReport,
595 checkpoint_seq: CheckpointSequenceNumber,
596 ) -> Self {
597 let serialized_report =
598 bcs::to_bytes(report).expect("report serialization should not fail");
599 let mut hasher = DefaultHasher::new();
600 serialized_report.hash(&mut hasher);
601 let tracking_id = hasher.finish().to_le_bytes();
602 Self {
603 tracking_id,
604 kind: ConsensusTransactionKind::MisbehaviorReport(
605 authority,
606 report.clone(),
607 checkpoint_seq,
608 ),
609 }
610 }
611
612 pub fn get_tracking_id(&self) -> u64 {
613 (&self.tracking_id[..])
614 .read_u64::<BigEndian>()
615 .unwrap_or_default()
616 }
617
618 pub fn key(&self) -> ConsensusTransactionKey {
619 match &self.kind {
620 ConsensusTransactionKind::CertifiedTransaction(cert) => {
621 ConsensusTransactionKey::Certificate(*cert.digest())
622 }
623 ConsensusTransactionKind::CheckpointSignature(data) => {
624 ConsensusTransactionKey::CheckpointSignature(
625 data.summary.auth_sig().authority,
626 data.summary.sequence_number,
627 )
628 }
629 ConsensusTransactionKind::EndOfPublish(authority) => {
630 ConsensusTransactionKey::EndOfPublish(*authority)
631 }
632 ConsensusTransactionKind::CapabilityNotificationV1(cap) => {
633 ConsensusTransactionKey::CapabilityNotification(cap.authority, cap.generation)
634 }
635 ConsensusTransactionKind::SignedCapabilityNotificationV1(signed_cap) => {
636 ConsensusTransactionKey::CapabilityNotification(
637 signed_cap.authority,
638 signed_cap.generation,
639 )
640 }
641
642 ConsensusTransactionKind::NewJWKFetched(authority, id, key) => {
643 ConsensusTransactionKey::NewJWKFetched(Box::new((
644 *authority,
645 id.clone(),
646 key.clone(),
647 )))
648 }
649 ConsensusTransactionKind::RandomnessDkgMessage(authority, _) => {
650 ConsensusTransactionKey::RandomnessDkgMessage(*authority)
651 }
652 ConsensusTransactionKind::RandomnessDkgConfirmation(authority, _) => {
653 ConsensusTransactionKey::RandomnessDkgConfirmation(*authority)
654 }
655 ConsensusTransactionKind::MisbehaviorReport(authority, report, checkpoint_seq) => {
656 ConsensusTransactionKey::MisbehaviorReport(
657 *authority,
658 *report.digest(),
659 *checkpoint_seq,
660 )
661 }
662 }
663 }
664
665 pub fn is_user_certificate(&self) -> bool {
666 matches!(self.kind, ConsensusTransactionKind::CertifiedTransaction(_))
667 }
668
669 pub fn is_end_of_publish(&self) -> bool {
670 matches!(self.kind, ConsensusTransactionKind::EndOfPublish(_))
671 }
672}
673
674#[test]
675fn test_jwk_compatibility() {
676 let jwk = JWK {
681 kty: "a".to_string(),
682 e: "b".to_string(),
683 n: "c".to_string(),
684 alg: "d".to_string(),
685 };
686
687 let expected_jwk_bytes = vec![1, 97, 1, 98, 1, 99, 1, 100];
688 let jwk_bcs = bcs::to_bytes(&jwk).unwrap();
689 assert_eq!(jwk_bcs, expected_jwk_bytes);
690
691 let id = JwkId {
692 iss: "abc".to_string(),
693 kid: "def".to_string(),
694 };
695
696 let expected_id_bytes = vec![3, 97, 98, 99, 3, 100, 101, 102];
697 let id_bcs = bcs::to_bytes(&id).unwrap();
698 assert_eq!(id_bcs, expected_id_bytes);
699}