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 iota_protocol_config::ProtocolConfig;
17use iota_sdk_types::crypto::IntentScope;
18use once_cell::sync::OnceCell;
19use schemars::JsonSchema;
20use serde::{Deserialize, Serialize};
21use tracing::warn;
22
23use crate::{
24 base_types::{
25 AuthorityName, ConciseableName, ObjectID, ObjectRef, SequenceNumber, TransactionDigest,
26 },
27 crypto::{AuthoritySignature, DefaultHash, default_hash},
28 digests::{ConsensusCommitDigest, Digest, MisbehaviorReportDigest},
29 message_envelope::{Envelope, Message, VerifiedEnvelope},
30 messages_checkpoint::{CheckpointSequenceNumber, CheckpointSignatureMessage},
31 supported_protocol_versions::{
32 Chain, SupportedProtocolVersions, SupportedProtocolVersionsWithHashes,
33 },
34 transaction::CertifiedTransaction,
35};
36
37pub type TimestampMs = u64;
39
40#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, JsonSchema)]
43pub enum ConsensusDeterminedVersionAssignments {
44 CancelledTransactions(Vec<(TransactionDigest, Vec<(ObjectID, SequenceNumber)>)>),
46}
47
48#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
49pub struct ConsensusCommitPrologueV1 {
50 pub epoch: u64,
52 pub round: u64,
54 pub sub_dag_index: Option<u64>,
57 pub commit_timestamp_ms: TimestampMs,
59 pub consensus_commit_digest: ConsensusCommitDigest,
61 pub consensus_determined_version_assignments: ConsensusDeterminedVersionAssignments,
63}
64
65#[derive(Serialize, Deserialize, Clone, Debug)]
66pub struct ConsensusTransaction {
67 pub tracking_id: [u8; 8],
71 pub kind: ConsensusTransactionKind,
72}
73
74#[derive(Serialize, Deserialize, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
75pub enum ConsensusTransactionKey {
76 Certificate(TransactionDigest),
77 CheckpointSignature(AuthorityName, CheckpointSequenceNumber),
78 EndOfPublish(AuthorityName),
79 CapabilityNotification(AuthorityName, u64 ),
80 #[deprecated(note = "Authenticator state (JWK) is deprecated and was never enabled on IOTA")]
81 NewJWKFetchedDeprecated,
82 RandomnessDkgMessage(AuthorityName),
83 RandomnessDkgConfirmation(AuthorityName),
84 MisbehaviorReport(
85 AuthorityName,
86 MisbehaviorReportDigest,
87 CheckpointSequenceNumber,
88 ),
89 }
92
93impl Debug for ConsensusTransactionKey {
94 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
95 match self {
96 Self::Certificate(digest) => write!(f, "Certificate({digest:?})"),
97 Self::CheckpointSignature(name, seq) => {
98 write!(f, "CheckpointSignature({:?}, {:?})", name.concise(), seq)
99 }
100 Self::EndOfPublish(name) => write!(f, "EndOfPublish({:?})", name.concise()),
101 Self::CapabilityNotification(name, generation) => write!(
102 f,
103 "CapabilityNotification({:?}, {:?})",
104 name.concise(),
105 generation
106 ),
107 #[allow(deprecated)]
108 Self::NewJWKFetchedDeprecated => {
109 write!(
110 f,
111 "NewJWKFetched(deprecated: Authenticator state (JWK) is deprecated and was never enabled on IOTA)"
112 )
113 }
114 Self::RandomnessDkgMessage(name) => {
115 write!(f, "RandomnessDkgMessage({:?})", name.concise())
116 }
117 Self::RandomnessDkgConfirmation(name) => {
118 write!(f, "RandomnessDkgConfirmation({:?})", name.concise())
119 }
120 Self::MisbehaviorReport(name, digest, checkpoint_seq) => {
121 write!(
122 f,
123 "MisbehaviorReport({:?}, {:?}, {:?})",
124 name.concise(),
125 digest,
126 checkpoint_seq
127 )
128 }
129 }
130 }
131}
132
133pub type SignedAuthorityCapabilitiesV1 = Envelope<AuthorityCapabilitiesV1, AuthoritySignature>;
134
135pub type VerifiedAuthorityCapabilitiesV1 =
136 VerifiedEnvelope<AuthorityCapabilitiesV1, AuthoritySignature>;
137
138#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
139pub struct AuthorityCapabilitiesDigest(Digest);
140
141impl AuthorityCapabilitiesDigest {
142 pub const fn new(digest: [u8; 32]) -> Self {
143 Self(Digest::new(digest))
144 }
145}
146
147impl Debug for AuthorityCapabilitiesDigest {
148 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
149 f.debug_tuple("AuthorityCapabilitiesDigest")
150 .field(&self.0)
151 .finish()
152 }
153}
154
155#[derive(Serialize, Deserialize, Clone, Hash)]
158pub struct AuthorityCapabilitiesV1 {
159 pub authority: AuthorityName,
162 pub generation: u64,
169
170 pub supported_protocol_versions: SupportedProtocolVersionsWithHashes,
173
174 pub available_system_packages: Vec<ObjectRef>,
178}
179
180impl Message for AuthorityCapabilitiesV1 {
181 type DigestType = AuthorityCapabilitiesDigest;
182 const SCOPE: IntentScope = IntentScope::AuthorityCapabilities;
183
184 fn digest(&self) -> Self::DigestType {
185 let mut hasher = DefaultHash::new();
187 let serialized = bcs::to_bytes(&self).expect("BCS should not fail");
188 hasher.update(&serialized);
189 AuthorityCapabilitiesDigest::new(<[u8; 32]>::from(hasher.finalize()))
190 }
191}
192
193impl Debug for AuthorityCapabilitiesV1 {
194 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
195 f.debug_struct("AuthorityCapabilities")
196 .field("authority", &self.authority.concise())
197 .field("generation", &self.generation)
198 .field(
199 "supported_protocol_versions",
200 &self.supported_protocol_versions,
201 )
202 .field("available_system_packages", &self.available_system_packages)
203 .finish()
204 }
205}
206
207impl AuthorityCapabilitiesV1 {
208 pub fn new(
209 authority: AuthorityName,
210 chain: Chain,
211 supported_protocol_versions: SupportedProtocolVersions,
212 available_system_packages: Vec<ObjectRef>,
213 ) -> Self {
214 let generation = SystemTime::now()
215 .duration_since(UNIX_EPOCH)
216 .expect("IOTA did not exist prior to 1970")
217 .as_millis()
218 .try_into()
219 .expect("This build of iota is not supported in the year 500,000,000");
220 Self {
221 authority,
222 generation,
223 supported_protocol_versions:
224 SupportedProtocolVersionsWithHashes::from_supported_versions(
225 supported_protocol_versions,
226 chain,
227 ),
228 available_system_packages,
229 }
230 }
231}
232
233impl SignedAuthorityCapabilitiesV1 {
234 pub fn cache_digest(&self, epoch: u64) -> AuthorityCapabilitiesDigest {
235 let data_with_epoch = (self.data(), epoch);
237
238 let mut hasher = DefaultHash::new();
240 let serialized = bcs::to_bytes(&data_with_epoch).expect("BCS should not fail");
241 hasher.update(&serialized);
242 AuthorityCapabilitiesDigest::new(<[u8; 32]>::from(hasher.finalize()))
243 }
244}
245
246#[derive(Serialize, Deserialize, Clone, Debug)]
247pub enum ConsensusTransactionKind {
248 CertifiedTransaction(Box<CertifiedTransaction>),
249 CheckpointSignature(Box<CheckpointSignatureMessage>),
250 EndOfPublish(AuthorityName),
251
252 CapabilityNotificationV1(AuthorityCapabilitiesV1),
253 SignedCapabilityNotificationV1(SignedAuthorityCapabilitiesV1),
254
255 #[deprecated(note = "Authenticator state (JWK) is deprecated and was never enabled on IOTA")]
256 NewJWKFetchedDeprecated,
257
258 RandomnessDkgMessage(AuthorityName, Vec<u8>),
262 RandomnessDkgConfirmation(AuthorityName, Vec<u8>),
266 MisbehaviorReport(
267 AuthorityName,
268 VersionedMisbehaviorReport,
269 CheckpointSequenceNumber,
270 ),
271 }
274
275impl ConsensusTransactionKind {
276 pub fn is_dkg(&self) -> bool {
277 matches!(
278 self,
279 ConsensusTransactionKind::RandomnessDkgMessage(_, _)
280 | ConsensusTransactionKind::RandomnessDkgConfirmation(_, _)
281 )
282 }
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
286pub enum VersionedMisbehaviorReport {
287 V1(
288 MisbehaviorsV1<Vec<u64>>,
289 #[serde(skip)] OnceCell<MisbehaviorReportDigest>,
290 ),
291}
292
293impl VersionedMisbehaviorReport {
294 pub fn new_v1(misbehaviors: MisbehaviorsV1<Vec<u64>>) -> Self {
295 VersionedMisbehaviorReport::V1(misbehaviors, OnceCell::new())
296 }
297
298 pub fn verify(&self, committee_size: usize) -> bool {
299 match self {
300 VersionedMisbehaviorReport::V1(report, _) => report.verify(committee_size),
301 }
302 }
303 pub fn iterate_over_metrics(&self) -> std::vec::IntoIter<&Vec<u64>> {
305 match self {
306 VersionedMisbehaviorReport::V1(report, _) => report.iter(),
307 }
308 }
309 pub fn digest(&self) -> &MisbehaviorReportDigest {
312 match self {
313 VersionedMisbehaviorReport::V1(_, digest) => {
314 digest.get_or_init(|| MisbehaviorReportDigest::new(default_hash(self)))
315 }
316 }
317 }
318 pub fn summary(&self) -> u64 {
321 let summary = match self {
322 VersionedMisbehaviorReport::V1(report, _) => report
323 .iter()
324 .flatten()
325 .fold(0u64, |acc, metric| acc.saturating_add(*metric)),
326 };
327 if summary == u64::MAX {
328 warn!("MisbehaviorReport summary reached its maximum value.");
329 }
330 summary
331 }
332
333 pub fn is_valid_version(&self, protocol_config: &ProtocolConfig) -> bool {
334 let scorer_version = protocol_config.scorer_version_as_option();
335 match (self, scorer_version) {
336 (VersionedMisbehaviorReport::V1(_, _), None) => true,
337 (VersionedMisbehaviorReport::V1(_, _), Some(1)) => true,
338 (VersionedMisbehaviorReport::V1(_, _), _) => false,
339 }
340 }
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
348pub struct MisbehaviorsV1<T> {
349 pub faulty_blocks_provable: T,
350 pub faulty_blocks_unprovable: T,
351 pub missing_proposals: T,
352 pub equivocations: T,
353}
354
355impl MisbehaviorsV1<Vec<u64>> {
356 pub fn verify(&self, committee_size: usize) -> bool {
357 if (self.faulty_blocks_provable.len() != committee_size)
365 | (self.faulty_blocks_unprovable.len() != committee_size)
366 | (self.equivocations.len() != committee_size)
367 | (self.missing_proposals.len() != committee_size)
368 {
369 return false;
370 }
371 true
372 }
373}
374impl<T> MisbehaviorsV1<T> {
375 pub fn iter(&self) -> std::vec::IntoIter<&T> {
376 vec![
377 &self.faulty_blocks_provable,
378 &self.faulty_blocks_unprovable,
379 &self.missing_proposals,
380 &self.equivocations,
381 ]
382 .into_iter()
383 }
384 pub fn iter_major_misbehaviors(&self) -> std::vec::IntoIter<&T> {
387 vec![&self.equivocations].into_iter()
388 }
389 pub fn iter_minor_misbehaviors(&self) -> std::vec::IntoIter<&T> {
392 vec![
393 &self.faulty_blocks_provable,
394 &self.faulty_blocks_unprovable,
395 &self.missing_proposals,
396 ]
397 .into_iter()
398 }
399}
400
401impl<T> FromIterator<T> for MisbehaviorsV1<T> {
402 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
403 let mut iterator = iter.into_iter();
404 Self {
405 faulty_blocks_provable: iterator.next().expect("Not enough elements in iterator"),
406 faulty_blocks_unprovable: iterator.next().expect("Not enough elements in iterator"),
407 missing_proposals: iterator.next().expect("Not enough elements in iterator"),
408 equivocations: iterator.next().expect("Not enough elements in iterator"),
409 }
410 }
411}
412
413#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
414pub enum VersionedDkgMessage {
415 V1(dkg_v1::Message<bls12381::G2Element, bls12381::G2Element>),
416}
417
418#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
419pub enum VersionedDkgConfirmation {
420 V1(dkg_v1::Confirmation<bls12381::G2Element>),
421}
422
423impl Debug for VersionedDkgMessage {
424 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
425 match self {
426 VersionedDkgMessage::V1(msg) => write!(
427 f,
428 "DKG V1 Message with sender={}, vss_pk.degree={}, encrypted_shares.len()={}",
429 msg.sender,
430 msg.vss_pk.degree(),
431 msg.encrypted_shares.len(),
432 ),
433 }
434 }
435}
436
437impl VersionedDkgMessage {
438 pub fn sender(&self) -> u16 {
439 match self {
440 VersionedDkgMessage::V1(msg) => msg.sender,
441 }
442 }
443
444 pub fn create(
445 dkg_version: u64,
446 party: Arc<dkg_v1::Party<bls12381::G2Element, bls12381::G2Element>>,
447 ) -> FastCryptoResult<VersionedDkgMessage> {
448 assert_eq!(dkg_version, 1, "BUG: invalid DKG version");
449 let msg = party.create_message(&mut rand::thread_rng())?;
450 Ok(VersionedDkgMessage::V1(msg))
451 }
452
453 pub fn unwrap_v1(self) -> dkg_v1::Message<bls12381::G2Element, bls12381::G2Element> {
454 match self {
455 VersionedDkgMessage::V1(msg) => msg,
456 }
457 }
458
459 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
460 matches!((self, dkg_version), (VersionedDkgMessage::V1(_), 1))
461 }
462}
463
464impl VersionedDkgConfirmation {
465 pub fn sender(&self) -> u16 {
466 match self {
467 VersionedDkgConfirmation::V1(msg) => msg.sender,
468 }
469 }
470
471 pub fn num_of_complaints(&self) -> usize {
472 match self {
473 VersionedDkgConfirmation::V1(msg) => msg.complaints.len(),
474 }
475 }
476
477 pub fn unwrap_v1(&self) -> &dkg_v1::Confirmation<bls12381::G2Element> {
478 match self {
479 VersionedDkgConfirmation::V1(msg) => msg,
480 }
481 }
482
483 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
484 matches!((self, dkg_version), (VersionedDkgConfirmation::V1(_), 1))
485 }
486}
487
488impl ConsensusTransaction {
489 pub fn new_certificate_message(
490 authority: &AuthorityName,
491 certificate: CertifiedTransaction,
492 ) -> Self {
493 let mut hasher = DefaultHasher::new();
494 let tx_digest = certificate.digest();
495 tx_digest.hash(&mut hasher);
496 authority.hash(&mut hasher);
497 let tracking_id = hasher.finish().to_le_bytes();
498 Self {
499 tracking_id,
500 kind: ConsensusTransactionKind::CertifiedTransaction(Box::new(certificate)),
501 }
502 }
503
504 pub fn new_checkpoint_signature_message(data: CheckpointSignatureMessage) -> Self {
505 let mut hasher = DefaultHasher::new();
506 data.summary.auth_sig().signature.hash(&mut hasher);
507 let tracking_id = hasher.finish().to_le_bytes();
508 Self {
509 tracking_id,
510 kind: ConsensusTransactionKind::CheckpointSignature(Box::new(data)),
511 }
512 }
513
514 pub fn new_end_of_publish(authority: AuthorityName) -> Self {
515 let mut hasher = DefaultHasher::new();
516 authority.hash(&mut hasher);
517 let tracking_id = hasher.finish().to_le_bytes();
518 Self {
519 tracking_id,
520 kind: ConsensusTransactionKind::EndOfPublish(authority),
521 }
522 }
523
524 pub fn new_capability_notification_v1(capabilities: AuthorityCapabilitiesV1) -> Self {
525 let mut hasher = DefaultHasher::new();
526 capabilities.hash(&mut hasher);
527 let tracking_id = hasher.finish().to_le_bytes();
528 Self {
529 tracking_id,
530 kind: ConsensusTransactionKind::CapabilityNotificationV1(capabilities),
531 }
532 }
533
534 pub fn new_signed_capability_notification_v1(
535 signed_capabilities: SignedAuthorityCapabilitiesV1,
536 ) -> Self {
537 let mut hasher = DefaultHasher::new();
538 signed_capabilities.data().hash(&mut hasher);
539 signed_capabilities.auth_sig().hash(&mut hasher);
540 let tracking_id = hasher.finish().to_le_bytes();
541 Self {
542 tracking_id,
543 kind: ConsensusTransactionKind::SignedCapabilityNotificationV1(signed_capabilities),
544 }
545 }
546
547 pub fn new_mysticeti_certificate(
548 round: u64,
549 offset: u64,
550 certificate: CertifiedTransaction,
551 ) -> Self {
552 let mut hasher = DefaultHasher::new();
553 let tx_digest = certificate.digest();
554 tx_digest.hash(&mut hasher);
555 round.hash(&mut hasher);
556 offset.hash(&mut hasher);
557 let tracking_id = hasher.finish().to_le_bytes();
558 Self {
559 tracking_id,
560 kind: ConsensusTransactionKind::CertifiedTransaction(Box::new(certificate)),
561 }
562 }
563
564 pub fn new_randomness_dkg_message(
565 authority: AuthorityName,
566 versioned_message: &VersionedDkgMessage,
567 ) -> Self {
568 let message =
569 bcs::to_bytes(versioned_message).expect("message serialization should not fail");
570 let mut hasher = DefaultHasher::new();
571 message.hash(&mut hasher);
572 let tracking_id = hasher.finish().to_le_bytes();
573 Self {
574 tracking_id,
575 kind: ConsensusTransactionKind::RandomnessDkgMessage(authority, message),
576 }
577 }
578 pub fn new_randomness_dkg_confirmation(
579 authority: AuthorityName,
580 versioned_confirmation: &VersionedDkgConfirmation,
581 ) -> Self {
582 let confirmation =
583 bcs::to_bytes(versioned_confirmation).expect("message serialization should not fail");
584 let mut hasher = DefaultHasher::new();
585 confirmation.hash(&mut hasher);
586 let tracking_id = hasher.finish().to_le_bytes();
587 Self {
588 tracking_id,
589 kind: ConsensusTransactionKind::RandomnessDkgConfirmation(authority, confirmation),
590 }
591 }
592
593 pub fn new_misbehavior_report(
594 authority: AuthorityName,
595 report: &VersionedMisbehaviorReport,
596 checkpoint_seq: CheckpointSequenceNumber,
597 ) -> Self {
598 let serialized_report =
599 bcs::to_bytes(report).expect("report serialization should not fail");
600 let mut hasher = DefaultHasher::new();
601 serialized_report.hash(&mut hasher);
602 let tracking_id = hasher.finish().to_le_bytes();
603 Self {
604 tracking_id,
605 kind: ConsensusTransactionKind::MisbehaviorReport(
606 authority,
607 report.clone(),
608 checkpoint_seq,
609 ),
610 }
611 }
612
613 pub fn get_tracking_id(&self) -> u64 {
614 (&self.tracking_id[..])
615 .read_u64::<BigEndian>()
616 .unwrap_or_default()
617 }
618
619 pub fn key(&self) -> ConsensusTransactionKey {
620 match &self.kind {
621 ConsensusTransactionKind::CertifiedTransaction(cert) => {
622 ConsensusTransactionKey::Certificate(*cert.digest())
623 }
624 ConsensusTransactionKind::CheckpointSignature(data) => {
625 ConsensusTransactionKey::CheckpointSignature(
626 data.summary.auth_sig().authority,
627 data.summary.sequence_number,
628 )
629 }
630 ConsensusTransactionKind::EndOfPublish(authority) => {
631 ConsensusTransactionKey::EndOfPublish(*authority)
632 }
633 ConsensusTransactionKind::CapabilityNotificationV1(cap) => {
634 ConsensusTransactionKey::CapabilityNotification(cap.authority, cap.generation)
635 }
636 ConsensusTransactionKind::SignedCapabilityNotificationV1(signed_cap) => {
637 ConsensusTransactionKey::CapabilityNotification(
638 signed_cap.authority,
639 signed_cap.generation,
640 )
641 }
642
643 #[allow(deprecated)]
644 ConsensusTransactionKind::NewJWKFetchedDeprecated => {
645 ConsensusTransactionKey::NewJWKFetchedDeprecated
646 }
647 ConsensusTransactionKind::RandomnessDkgMessage(authority, _) => {
648 ConsensusTransactionKey::RandomnessDkgMessage(*authority)
649 }
650 ConsensusTransactionKind::RandomnessDkgConfirmation(authority, _) => {
651 ConsensusTransactionKey::RandomnessDkgConfirmation(*authority)
652 }
653 ConsensusTransactionKind::MisbehaviorReport(authority, report, checkpoint_seq) => {
654 ConsensusTransactionKey::MisbehaviorReport(
655 *authority,
656 *report.digest(),
657 *checkpoint_seq,
658 )
659 }
660 }
661 }
662
663 pub fn is_user_certificate(&self) -> bool {
664 matches!(self.kind, ConsensusTransactionKind::CertifiedTransaction(_))
665 }
666
667 pub fn is_end_of_publish(&self) -> bool {
668 matches!(self.kind, ConsensusTransactionKind::EndOfPublish(_))
669 }
670}