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(MisbehaviorReportDigest),
95 }
98
99impl Debug for ConsensusTransactionKey {
100 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
101 match self {
102 Self::Certificate(digest) => write!(f, "Certificate({digest:?})"),
103 Self::CheckpointSignature(name, seq) => {
104 write!(f, "CheckpointSignature({:?}, {:?})", name.concise(), seq)
105 }
106 Self::EndOfPublish(name) => write!(f, "EndOfPublish({:?})", name.concise()),
107 Self::CapabilityNotification(name, generation) => write!(
108 f,
109 "CapabilityNotification({:?}, {:?})",
110 name.concise(),
111 generation
112 ),
113 Self::NewJWKFetched(key) => {
114 let (authority, id, jwk) = &**key;
115 write!(
116 f,
117 "NewJWKFetched({:?}, {:?}, {:?})",
118 authority.concise(),
119 id,
120 jwk
121 )
122 }
123 Self::RandomnessDkgMessage(name) => {
124 write!(f, "RandomnessDkgMessage({:?})", name.concise())
125 }
126 Self::RandomnessDkgConfirmation(name) => {
127 write!(f, "RandomnessDkgConfirmation({:?})", name.concise())
128 }
129 Self::MisbehaviorReport(digest) => {
130 write!(f, "MisbehaviorReport({digest:?})")
131 }
132 }
133 }
134}
135
136pub type SignedAuthorityCapabilitiesV1 = Envelope<AuthorityCapabilitiesV1, AuthoritySignature>;
137
138pub type VerifiedAuthorityCapabilitiesV1 =
139 VerifiedEnvelope<AuthorityCapabilitiesV1, AuthoritySignature>;
140
141#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
142pub struct AuthorityCapabilitiesDigest(Digest);
143
144impl AuthorityCapabilitiesDigest {
145 pub const fn new(digest: [u8; 32]) -> Self {
146 Self(Digest::new(digest))
147 }
148}
149
150impl Debug for AuthorityCapabilitiesDigest {
151 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
152 f.debug_tuple("AuthorityCapabilitiesDigest")
153 .field(&self.0)
154 .finish()
155 }
156}
157
158#[derive(Serialize, Deserialize, Clone, Hash)]
161pub struct AuthorityCapabilitiesV1 {
162 pub authority: AuthorityName,
165 pub generation: u64,
172
173 pub supported_protocol_versions: SupportedProtocolVersionsWithHashes,
176
177 pub available_system_packages: Vec<ObjectRef>,
181}
182
183impl Message for AuthorityCapabilitiesV1 {
184 type DigestType = AuthorityCapabilitiesDigest;
185 const SCOPE: IntentScope = IntentScope::AuthorityCapabilities;
186
187 fn digest(&self) -> Self::DigestType {
188 let mut hasher = DefaultHash::new();
190 let serialized = bcs::to_bytes(&self).expect("BCS should not fail");
191 hasher.update(&serialized);
192 AuthorityCapabilitiesDigest::new(<[u8; 32]>::from(hasher.finalize()))
193 }
194}
195
196impl Debug for AuthorityCapabilitiesV1 {
197 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
198 f.debug_struct("AuthorityCapabilities")
199 .field("authority", &self.authority.concise())
200 .field("generation", &self.generation)
201 .field(
202 "supported_protocol_versions",
203 &self.supported_protocol_versions,
204 )
205 .field("available_system_packages", &self.available_system_packages)
206 .finish()
207 }
208}
209
210impl AuthorityCapabilitiesV1 {
211 pub fn new(
212 authority: AuthorityName,
213 chain: Chain,
214 supported_protocol_versions: SupportedProtocolVersions,
215 available_system_packages: Vec<ObjectRef>,
216 ) -> Self {
217 let generation = SystemTime::now()
218 .duration_since(UNIX_EPOCH)
219 .expect("IOTA did not exist prior to 1970")
220 .as_millis()
221 .try_into()
222 .expect("This build of iota is not supported in the year 500,000,000");
223 Self {
224 authority,
225 generation,
226 supported_protocol_versions:
227 SupportedProtocolVersionsWithHashes::from_supported_versions(
228 supported_protocol_versions,
229 chain,
230 ),
231 available_system_packages,
232 }
233 }
234}
235
236impl SignedAuthorityCapabilitiesV1 {
237 pub fn cache_digest(&self, epoch: u64) -> AuthorityCapabilitiesDigest {
238 let data_with_epoch = (self.data(), epoch);
240
241 let mut hasher = DefaultHash::new();
243 let serialized = bcs::to_bytes(&data_with_epoch).expect("BCS should not fail");
244 hasher.update(&serialized);
245 AuthorityCapabilitiesDigest::new(<[u8; 32]>::from(hasher.finalize()))
246 }
247}
248
249#[derive(Serialize, Deserialize, Clone, Debug)]
250pub enum ConsensusTransactionKind {
251 CertifiedTransaction(Box<CertifiedTransaction>),
252 CheckpointSignature(Box<CheckpointSignatureMessage>),
253 EndOfPublish(AuthorityName),
254
255 CapabilityNotificationV1(AuthorityCapabilitiesV1),
256 SignedCapabilityNotificationV1(SignedAuthorityCapabilitiesV1),
257
258 NewJWKFetched(AuthorityName, JwkId, JWK),
259
260 RandomnessDkgMessage(AuthorityName, Vec<u8>),
264 RandomnessDkgConfirmation(AuthorityName, Vec<u8>),
268 MisbehaviorReport(
269 AuthorityName,
270 VersionedMisbehaviorReport,
271 u64, ),
273 }
276
277impl ConsensusTransactionKind {
278 pub fn is_dkg(&self) -> bool {
279 matches!(
280 self,
281 ConsensusTransactionKind::RandomnessDkgMessage(_, _)
282 | ConsensusTransactionKind::RandomnessDkgConfirmation(_, _)
283 )
284 }
285}
286
287#[derive(Debug, Clone, Serialize, Deserialize)]
288pub enum VersionedMisbehaviorReport {
289 V1(
290 MisbehaviorsV1<Vec<u64>>,
291 #[serde(skip)] OnceCell<MisbehaviorReportDigest>,
292 ),
293}
294
295impl VersionedMisbehaviorReport {
296 pub fn new_v1(misbehaviors: MisbehaviorsV1<Vec<u64>>) -> Self {
297 VersionedMisbehaviorReport::V1(misbehaviors, OnceCell::new())
298 }
299
300 pub fn verify(&self, committee_size: usize) -> bool {
301 match self {
302 VersionedMisbehaviorReport::V1(report, _) => report.verify(committee_size),
303 }
304 }
305 pub fn iterate_over_metrics(&self) -> std::vec::IntoIter<&Vec<u64>> {
307 match self {
308 VersionedMisbehaviorReport::V1(report, _) => report.iter(),
309 }
310 }
311 pub fn digest(&self) -> &MisbehaviorReportDigest {
314 match self {
315 VersionedMisbehaviorReport::V1(_, digest) => {
316 digest.get_or_init(|| MisbehaviorReportDigest::new(default_hash(self)))
317 }
318 }
319 }
320}
321
322#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
327pub struct MisbehaviorsV1<T> {
328 pub faulty_blocks_provable: T,
329 pub faulty_blocks_unprovable: T,
330 pub missing_proposals: T,
331 pub equivocations: T,
332}
333
334impl MisbehaviorsV1<Vec<u64>> {
335 pub fn verify(&self, committee_size: usize) -> bool {
336 if (self.faulty_blocks_provable.len() != committee_size)
344 | (self.faulty_blocks_unprovable.len() != committee_size)
345 | (self.equivocations.len() != committee_size)
346 | (self.missing_proposals.len() != committee_size)
347 {
348 return false;
349 }
350 true
351 }
352}
353impl<T> MisbehaviorsV1<T> {
354 pub fn iter(&self) -> std::vec::IntoIter<&T> {
355 vec![
356 &self.faulty_blocks_provable,
357 &self.faulty_blocks_unprovable,
358 &self.missing_proposals,
359 &self.equivocations,
360 ]
361 .into_iter()
362 }
363 pub fn iter_major_misbehaviors(&self) -> std::vec::IntoIter<&T> {
366 vec![&self.equivocations].into_iter()
367 }
368 pub fn iter_minor_misbehaviors(&self) -> std::vec::IntoIter<&T> {
371 vec![
372 &self.faulty_blocks_provable,
373 &self.faulty_blocks_unprovable,
374 &self.missing_proposals,
375 ]
376 .into_iter()
377 }
378}
379
380impl<T> FromIterator<T> for MisbehaviorsV1<T> {
381 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
382 let mut iterator = iter.into_iter();
383 Self {
384 faulty_blocks_provable: iterator.next().expect("Not enough elements in iterator"),
385 faulty_blocks_unprovable: iterator.next().expect("Not enough elements in iterator"),
386 missing_proposals: iterator.next().expect("Not enough elements in iterator"),
387 equivocations: iterator.next().expect("Not enough elements in iterator"),
388 }
389 }
390}
391
392#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
393pub enum VersionedDkgMessage {
394 V1(dkg_v1::Message<bls12381::G2Element, bls12381::G2Element>),
395}
396
397#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
398pub enum VersionedDkgConfirmation {
399 V1(dkg_v1::Confirmation<bls12381::G2Element>),
400}
401
402impl Debug for VersionedDkgMessage {
403 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
404 match self {
405 VersionedDkgMessage::V1(msg) => write!(
406 f,
407 "DKG V1 Message with sender={}, vss_pk.degree={}, encrypted_shares.len()={}",
408 msg.sender,
409 msg.vss_pk.degree(),
410 msg.encrypted_shares.len(),
411 ),
412 }
413 }
414}
415
416impl VersionedDkgMessage {
417 pub fn sender(&self) -> u16 {
418 match self {
419 VersionedDkgMessage::V1(msg) => msg.sender,
420 }
421 }
422
423 pub fn create(
424 dkg_version: u64,
425 party: Arc<dkg_v1::Party<bls12381::G2Element, bls12381::G2Element>>,
426 ) -> FastCryptoResult<VersionedDkgMessage> {
427 assert_eq!(dkg_version, 1, "BUG: invalid DKG version");
428 let msg = party.create_message(&mut rand::thread_rng())?;
429 Ok(VersionedDkgMessage::V1(msg))
430 }
431
432 pub fn unwrap_v1(self) -> dkg_v1::Message<bls12381::G2Element, bls12381::G2Element> {
433 match self {
434 VersionedDkgMessage::V1(msg) => msg,
435 }
436 }
437
438 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
439 matches!((self, dkg_version), (VersionedDkgMessage::V1(_), 1))
440 }
441}
442
443impl VersionedDkgConfirmation {
444 pub fn sender(&self) -> u16 {
445 match self {
446 VersionedDkgConfirmation::V1(msg) => msg.sender,
447 }
448 }
449
450 pub fn num_of_complaints(&self) -> usize {
451 match self {
452 VersionedDkgConfirmation::V1(msg) => msg.complaints.len(),
453 }
454 }
455
456 pub fn unwrap_v1(&self) -> &dkg_v1::Confirmation<bls12381::G2Element> {
457 match self {
458 VersionedDkgConfirmation::V1(msg) => msg,
459 }
460 }
461
462 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
463 matches!((self, dkg_version), (VersionedDkgConfirmation::V1(_), 1))
464 }
465}
466
467impl ConsensusTransaction {
468 pub fn new_certificate_message(
469 authority: &AuthorityName,
470 certificate: CertifiedTransaction,
471 ) -> Self {
472 let mut hasher = DefaultHasher::new();
473 let tx_digest = certificate.digest();
474 tx_digest.hash(&mut hasher);
475 authority.hash(&mut hasher);
476 let tracking_id = hasher.finish().to_le_bytes();
477 Self {
478 tracking_id,
479 kind: ConsensusTransactionKind::CertifiedTransaction(Box::new(certificate)),
480 }
481 }
482
483 pub fn new_checkpoint_signature_message(data: CheckpointSignatureMessage) -> Self {
484 let mut hasher = DefaultHasher::new();
485 data.summary.auth_sig().signature.hash(&mut hasher);
486 let tracking_id = hasher.finish().to_le_bytes();
487 Self {
488 tracking_id,
489 kind: ConsensusTransactionKind::CheckpointSignature(Box::new(data)),
490 }
491 }
492
493 pub fn new_end_of_publish(authority: AuthorityName) -> Self {
494 let mut hasher = DefaultHasher::new();
495 authority.hash(&mut hasher);
496 let tracking_id = hasher.finish().to_le_bytes();
497 Self {
498 tracking_id,
499 kind: ConsensusTransactionKind::EndOfPublish(authority),
500 }
501 }
502
503 pub fn new_capability_notification_v1(capabilities: AuthorityCapabilitiesV1) -> Self {
504 let mut hasher = DefaultHasher::new();
505 capabilities.hash(&mut hasher);
506 let tracking_id = hasher.finish().to_le_bytes();
507 Self {
508 tracking_id,
509 kind: ConsensusTransactionKind::CapabilityNotificationV1(capabilities),
510 }
511 }
512
513 pub fn new_signed_capability_notification_v1(
514 signed_capabilities: SignedAuthorityCapabilitiesV1,
515 ) -> Self {
516 let mut hasher = DefaultHasher::new();
517 signed_capabilities.data().hash(&mut hasher);
518 signed_capabilities.auth_sig().hash(&mut hasher);
519 let tracking_id = hasher.finish().to_le_bytes();
520 Self {
521 tracking_id,
522 kind: ConsensusTransactionKind::SignedCapabilityNotificationV1(signed_capabilities),
523 }
524 }
525
526 pub fn new_mysticeti_certificate(
527 round: u64,
528 offset: u64,
529 certificate: CertifiedTransaction,
530 ) -> Self {
531 let mut hasher = DefaultHasher::new();
532 let tx_digest = certificate.digest();
533 tx_digest.hash(&mut hasher);
534 round.hash(&mut hasher);
535 offset.hash(&mut hasher);
536 let tracking_id = hasher.finish().to_le_bytes();
537 Self {
538 tracking_id,
539 kind: ConsensusTransactionKind::CertifiedTransaction(Box::new(certificate)),
540 }
541 }
542
543 pub fn new_jwk_fetched(authority: AuthorityName, id: JwkId, jwk: JWK) -> Self {
544 let mut hasher = DefaultHasher::new();
545 id.hash(&mut hasher);
546 let tracking_id = hasher.finish().to_le_bytes();
547 Self {
548 tracking_id,
549 kind: ConsensusTransactionKind::NewJWKFetched(authority, id, jwk),
550 }
551 }
552
553 pub fn new_randomness_dkg_message(
554 authority: AuthorityName,
555 versioned_message: &VersionedDkgMessage,
556 ) -> Self {
557 let message =
558 bcs::to_bytes(versioned_message).expect("message serialization should not fail");
559 let mut hasher = DefaultHasher::new();
560 message.hash(&mut hasher);
561 let tracking_id = hasher.finish().to_le_bytes();
562 Self {
563 tracking_id,
564 kind: ConsensusTransactionKind::RandomnessDkgMessage(authority, message),
565 }
566 }
567 pub fn new_randomness_dkg_confirmation(
568 authority: AuthorityName,
569 versioned_confirmation: &VersionedDkgConfirmation,
570 ) -> Self {
571 let confirmation =
572 bcs::to_bytes(versioned_confirmation).expect("message serialization should not fail");
573 let mut hasher = DefaultHasher::new();
574 confirmation.hash(&mut hasher);
575 let tracking_id = hasher.finish().to_le_bytes();
576 Self {
577 tracking_id,
578 kind: ConsensusTransactionKind::RandomnessDkgConfirmation(authority, confirmation),
579 }
580 }
581
582 pub fn new_misbehavior_report(
583 authority: AuthorityName,
584 report: &VersionedMisbehaviorReport,
585 checkpoint_seq: u64,
586 ) -> Self {
587 let serialized_report =
588 bcs::to_bytes(report).expect("report serialization should not fail");
589 let mut hasher = DefaultHasher::new();
590 serialized_report.hash(&mut hasher);
591 let tracking_id = hasher.finish().to_le_bytes();
592 Self {
593 tracking_id,
594 kind: ConsensusTransactionKind::MisbehaviorReport(
595 authority,
596 report.clone(),
597 checkpoint_seq,
598 ),
599 }
600 }
601
602 pub fn get_tracking_id(&self) -> u64 {
603 (&self.tracking_id[..])
604 .read_u64::<BigEndian>()
605 .unwrap_or_default()
606 }
607
608 pub fn key(&self) -> ConsensusTransactionKey {
609 match &self.kind {
610 ConsensusTransactionKind::CertifiedTransaction(cert) => {
611 ConsensusTransactionKey::Certificate(*cert.digest())
612 }
613 ConsensusTransactionKind::CheckpointSignature(data) => {
614 ConsensusTransactionKey::CheckpointSignature(
615 data.summary.auth_sig().authority,
616 data.summary.sequence_number,
617 )
618 }
619 ConsensusTransactionKind::EndOfPublish(authority) => {
620 ConsensusTransactionKey::EndOfPublish(*authority)
621 }
622 ConsensusTransactionKind::CapabilityNotificationV1(cap) => {
623 ConsensusTransactionKey::CapabilityNotification(cap.authority, cap.generation)
624 }
625 ConsensusTransactionKind::SignedCapabilityNotificationV1(signed_cap) => {
626 ConsensusTransactionKey::CapabilityNotification(
627 signed_cap.authority,
628 signed_cap.generation,
629 )
630 }
631
632 ConsensusTransactionKind::NewJWKFetched(authority, id, key) => {
633 ConsensusTransactionKey::NewJWKFetched(Box::new((
634 *authority,
635 id.clone(),
636 key.clone(),
637 )))
638 }
639 ConsensusTransactionKind::RandomnessDkgMessage(authority, _) => {
640 ConsensusTransactionKey::RandomnessDkgMessage(*authority)
641 }
642 ConsensusTransactionKind::RandomnessDkgConfirmation(authority, _) => {
643 ConsensusTransactionKey::RandomnessDkgConfirmation(*authority)
644 }
645 ConsensusTransactionKind::MisbehaviorReport(_, report, _) => {
646 ConsensusTransactionKey::MisbehaviorReport(*report.digest())
647 }
648 }
649 }
650
651 pub fn is_user_certificate(&self) -> bool {
652 matches!(self.kind, ConsensusTransactionKind::CertifiedTransaction(_))
653 }
654
655 pub fn is_end_of_publish(&self) -> bool {
656 matches!(self.kind, ConsensusTransactionKind::EndOfPublish(_))
657 }
658}
659
660#[test]
661fn test_jwk_compatibility() {
662 let jwk = JWK {
667 kty: "a".to_string(),
668 e: "b".to_string(),
669 n: "c".to_string(),
670 alg: "d".to_string(),
671 };
672
673 let expected_jwk_bytes = vec![1, 97, 1, 98, 1, 99, 1, 100];
674 let jwk_bcs = bcs::to_bytes(&jwk).unwrap();
675 assert_eq!(jwk_bcs, expected_jwk_bytes);
676
677 let id = JwkId {
678 iss: "abc".to_string(),
679 kid: "def".to_string(),
680 };
681
682 let expected_id_bytes = vec![3, 97, 98, 99, 3, 100, 101, 102];
683 let id_bcs = bcs::to_bytes(&id).unwrap();
684 assert_eq!(id_bcs, expected_id_bytes);
685}