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 schemars::JsonSchema;
18use serde::{Deserialize, Serialize};
19use shared_crypto::intent::IntentScope;
20
21use crate::{
22 base_types::{
23 AuthorityName, ConciseableName, ObjectID, ObjectRef, SequenceNumber, TransactionDigest,
24 },
25 crypto::{AuthoritySignature, DefaultHash},
26 digests::{ConsensusCommitDigest, Digest},
27 message_envelope::{Envelope, Message, VerifiedEnvelope},
28 messages_checkpoint::{CheckpointSequenceNumber, CheckpointSignatureMessage},
29 supported_protocol_versions::{
30 Chain, SupportedProtocolVersions, SupportedProtocolVersionsWithHashes,
31 },
32 transaction::CertifiedTransaction,
33};
34
35pub type TimestampMs = u64;
37
38#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, JsonSchema)]
41pub enum ConsensusDeterminedVersionAssignments {
42 CancelledTransactions(Vec<(TransactionDigest, Vec<(ObjectID, SequenceNumber)>)>),
44}
45
46#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
47pub struct ConsensusCommitPrologueV1 {
48 pub epoch: u64,
50 pub round: u64,
52 pub sub_dag_index: Option<u64>,
55 pub commit_timestamp_ms: TimestampMs,
57 pub consensus_commit_digest: ConsensusCommitDigest,
59 pub consensus_determined_version_assignments: ConsensusDeterminedVersionAssignments,
61}
62
63static MAX_TOTAL_JWK_SIZE: usize = 4096;
67
68pub fn check_total_jwk_size(id: &JwkId, jwk: &JWK) -> bool {
69 id.iss.len() + id.kid.len() + jwk.kty.len() + jwk.alg.len() + jwk.e.len() + jwk.n.len()
70 <= MAX_TOTAL_JWK_SIZE
71}
72
73#[derive(Serialize, Deserialize, Clone, Debug)]
74pub struct ConsensusTransaction {
75 pub tracking_id: [u8; 8],
79 pub kind: ConsensusTransactionKind,
80}
81
82#[derive(Serialize, Deserialize, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
83pub enum ConsensusTransactionKey {
84 Certificate(TransactionDigest),
85 CheckpointSignature(AuthorityName, CheckpointSequenceNumber),
86 EndOfPublish(AuthorityName),
87 CapabilityNotification(AuthorityName, u64 ),
88 NewJWKFetched(Box<(AuthorityName, JwkId, JWK)>),
91 RandomnessDkgMessage(AuthorityName),
92 RandomnessDkgConfirmation(AuthorityName),
93}
94
95impl Debug for ConsensusTransactionKey {
96 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
97 match self {
98 Self::Certificate(digest) => write!(f, "Certificate({digest:?})"),
99 Self::CheckpointSignature(name, seq) => {
100 write!(f, "CheckpointSignature({:?}, {:?})", name.concise(), seq)
101 }
102 Self::EndOfPublish(name) => write!(f, "EndOfPublish({:?})", name.concise()),
103 Self::CapabilityNotification(name, generation) => write!(
104 f,
105 "CapabilityNotification({:?}, {:?})",
106 name.concise(),
107 generation
108 ),
109 Self::NewJWKFetched(key) => {
110 let (authority, id, jwk) = &**key;
111 write!(
112 f,
113 "NewJWKFetched({:?}, {:?}, {:?})",
114 authority.concise(),
115 id,
116 jwk
117 )
118 }
119 Self::RandomnessDkgMessage(name) => {
120 write!(f, "RandomnessDkgMessage({:?})", name.concise())
121 }
122 Self::RandomnessDkgConfirmation(name) => {
123 write!(f, "RandomnessDkgConfirmation({:?})", name.concise())
124 }
125 }
126 }
127}
128
129pub type SignedAuthorityCapabilitiesV1 = Envelope<AuthorityCapabilitiesV1, AuthoritySignature>;
130
131pub type VerifiedAuthorityCapabilitiesV1 =
132 VerifiedEnvelope<AuthorityCapabilitiesV1, AuthoritySignature>;
133
134#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
135pub struct AuthorityCapabilitiesDigest(Digest);
136
137impl AuthorityCapabilitiesDigest {
138 pub const fn new(digest: [u8; 32]) -> Self {
139 Self(Digest::new(digest))
140 }
141}
142
143impl Debug for AuthorityCapabilitiesDigest {
144 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
145 f.debug_tuple("AuthorityCapabilitiesDigest")
146 .field(&self.0)
147 .finish()
148 }
149}
150
151#[derive(Serialize, Deserialize, Clone, Hash)]
154pub struct AuthorityCapabilitiesV1 {
155 pub authority: AuthorityName,
158 pub generation: u64,
165
166 pub supported_protocol_versions: SupportedProtocolVersionsWithHashes,
169
170 pub available_system_packages: Vec<ObjectRef>,
174}
175
176impl Message for AuthorityCapabilitiesV1 {
177 type DigestType = AuthorityCapabilitiesDigest;
178 const SCOPE: IntentScope = IntentScope::AuthorityCapabilities;
179
180 fn digest(&self) -> Self::DigestType {
181 let mut hasher = DefaultHash::new();
183 let serialized = bcs::to_bytes(&self).expect("BCS should not fail");
184 hasher.update(&serialized);
185 AuthorityCapabilitiesDigest::new(<[u8; 32]>::from(hasher.finalize()))
186 }
187}
188
189impl Debug for AuthorityCapabilitiesV1 {
190 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
191 f.debug_struct("AuthorityCapabilities")
192 .field("authority", &self.authority.concise())
193 .field("generation", &self.generation)
194 .field(
195 "supported_protocol_versions",
196 &self.supported_protocol_versions,
197 )
198 .field("available_system_packages", &self.available_system_packages)
199 .finish()
200 }
201}
202
203impl AuthorityCapabilitiesV1 {
204 pub fn new(
205 authority: AuthorityName,
206 chain: Chain,
207 supported_protocol_versions: SupportedProtocolVersions,
208 available_system_packages: Vec<ObjectRef>,
209 ) -> Self {
210 let generation = SystemTime::now()
211 .duration_since(UNIX_EPOCH)
212 .expect("IOTA did not exist prior to 1970")
213 .as_millis()
214 .try_into()
215 .expect("This build of iota is not supported in the year 500,000,000");
216 Self {
217 authority,
218 generation,
219 supported_protocol_versions:
220 SupportedProtocolVersionsWithHashes::from_supported_versions(
221 supported_protocol_versions,
222 chain,
223 ),
224 available_system_packages,
225 }
226 }
227}
228
229impl SignedAuthorityCapabilitiesV1 {
230 pub fn cache_digest(&self, epoch: u64) -> AuthorityCapabilitiesDigest {
231 let data_with_epoch = (self.data(), epoch);
233
234 let mut hasher = DefaultHash::new();
236 let serialized = bcs::to_bytes(&data_with_epoch).expect("BCS should not fail");
237 hasher.update(&serialized);
238 AuthorityCapabilitiesDigest::new(<[u8; 32]>::from(hasher.finalize()))
239 }
240}
241
242#[derive(Serialize, Deserialize, Clone, Debug)]
243pub enum ConsensusTransactionKind {
244 CertifiedTransaction(Box<CertifiedTransaction>),
245 CheckpointSignature(Box<CheckpointSignatureMessage>),
246 EndOfPublish(AuthorityName),
247
248 CapabilityNotificationV1(AuthorityCapabilitiesV1),
249 SignedCapabilityNotificationV1(SignedAuthorityCapabilitiesV1),
250
251 NewJWKFetched(AuthorityName, JwkId, JWK),
252
253 RandomnessDkgMessage(AuthorityName, Vec<u8>),
257 RandomnessDkgConfirmation(AuthorityName, Vec<u8>),
261}
262
263impl ConsensusTransactionKind {
264 pub fn is_dkg(&self) -> bool {
265 matches!(
266 self,
267 ConsensusTransactionKind::RandomnessDkgMessage(_, _)
268 | ConsensusTransactionKind::RandomnessDkgConfirmation(_, _)
269 )
270 }
271}
272
273#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
274pub enum VersionedDkgMessage {
275 V1(dkg_v1::Message<bls12381::G2Element, bls12381::G2Element>),
276}
277
278#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
279pub enum VersionedDkgConfirmation {
280 V1(dkg_v1::Confirmation<bls12381::G2Element>),
281}
282
283impl Debug for VersionedDkgMessage {
284 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
285 match self {
286 VersionedDkgMessage::V1(msg) => write!(
287 f,
288 "DKG V1 Message with sender={}, vss_pk.degree={}, encrypted_shares.len()={}",
289 msg.sender,
290 msg.vss_pk.degree(),
291 msg.encrypted_shares.len(),
292 ),
293 }
294 }
295}
296
297impl VersionedDkgMessage {
298 pub fn sender(&self) -> u16 {
299 match self {
300 VersionedDkgMessage::V1(msg) => msg.sender,
301 }
302 }
303
304 pub fn create(
305 dkg_version: u64,
306 party: Arc<dkg_v1::Party<bls12381::G2Element, bls12381::G2Element>>,
307 ) -> FastCryptoResult<VersionedDkgMessage> {
308 assert_eq!(dkg_version, 1, "BUG: invalid DKG version");
309 let msg = party.create_message(&mut rand::thread_rng())?;
310 Ok(VersionedDkgMessage::V1(msg))
311 }
312
313 pub fn unwrap_v1(self) -> dkg_v1::Message<bls12381::G2Element, bls12381::G2Element> {
314 match self {
315 VersionedDkgMessage::V1(msg) => msg,
316 }
317 }
318
319 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
320 matches!((self, dkg_version), (VersionedDkgMessage::V1(_), 1))
321 }
322}
323
324impl VersionedDkgConfirmation {
325 pub fn sender(&self) -> u16 {
326 match self {
327 VersionedDkgConfirmation::V1(msg) => msg.sender,
328 }
329 }
330
331 pub fn num_of_complaints(&self) -> usize {
332 match self {
333 VersionedDkgConfirmation::V1(msg) => msg.complaints.len(),
334 }
335 }
336
337 pub fn unwrap_v1(&self) -> &dkg_v1::Confirmation<bls12381::G2Element> {
338 match self {
339 VersionedDkgConfirmation::V1(msg) => msg,
340 }
341 }
342
343 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
344 matches!((self, dkg_version), (VersionedDkgConfirmation::V1(_), 1))
345 }
346}
347
348impl ConsensusTransaction {
349 pub fn new_certificate_message(
350 authority: &AuthorityName,
351 certificate: CertifiedTransaction,
352 ) -> Self {
353 let mut hasher = DefaultHasher::new();
354 let tx_digest = certificate.digest();
355 tx_digest.hash(&mut hasher);
356 authority.hash(&mut hasher);
357 let tracking_id = hasher.finish().to_le_bytes();
358 Self {
359 tracking_id,
360 kind: ConsensusTransactionKind::CertifiedTransaction(Box::new(certificate)),
361 }
362 }
363
364 pub fn new_checkpoint_signature_message(data: CheckpointSignatureMessage) -> Self {
365 let mut hasher = DefaultHasher::new();
366 data.summary.auth_sig().signature.hash(&mut hasher);
367 let tracking_id = hasher.finish().to_le_bytes();
368 Self {
369 tracking_id,
370 kind: ConsensusTransactionKind::CheckpointSignature(Box::new(data)),
371 }
372 }
373
374 pub fn new_end_of_publish(authority: AuthorityName) -> Self {
375 let mut hasher = DefaultHasher::new();
376 authority.hash(&mut hasher);
377 let tracking_id = hasher.finish().to_le_bytes();
378 Self {
379 tracking_id,
380 kind: ConsensusTransactionKind::EndOfPublish(authority),
381 }
382 }
383
384 pub fn new_capability_notification_v1(capabilities: AuthorityCapabilitiesV1) -> Self {
385 let mut hasher = DefaultHasher::new();
386 capabilities.hash(&mut hasher);
387 let tracking_id = hasher.finish().to_le_bytes();
388 Self {
389 tracking_id,
390 kind: ConsensusTransactionKind::CapabilityNotificationV1(capabilities),
391 }
392 }
393
394 pub fn new_signed_capability_notification_v1(
395 signed_capabilities: SignedAuthorityCapabilitiesV1,
396 ) -> Self {
397 let mut hasher = DefaultHasher::new();
398 signed_capabilities.data().hash(&mut hasher);
399 signed_capabilities.auth_sig().hash(&mut hasher);
400 let tracking_id = hasher.finish().to_le_bytes();
401 Self {
402 tracking_id,
403 kind: ConsensusTransactionKind::SignedCapabilityNotificationV1(signed_capabilities),
404 }
405 }
406
407 pub fn new_mysticeti_certificate(
408 round: u64,
409 offset: u64,
410 certificate: CertifiedTransaction,
411 ) -> Self {
412 let mut hasher = DefaultHasher::new();
413 let tx_digest = certificate.digest();
414 tx_digest.hash(&mut hasher);
415 round.hash(&mut hasher);
416 offset.hash(&mut hasher);
417 let tracking_id = hasher.finish().to_le_bytes();
418 Self {
419 tracking_id,
420 kind: ConsensusTransactionKind::CertifiedTransaction(Box::new(certificate)),
421 }
422 }
423
424 pub fn new_jwk_fetched(authority: AuthorityName, id: JwkId, jwk: JWK) -> Self {
425 let mut hasher = DefaultHasher::new();
426 id.hash(&mut hasher);
427 let tracking_id = hasher.finish().to_le_bytes();
428 Self {
429 tracking_id,
430 kind: ConsensusTransactionKind::NewJWKFetched(authority, id, jwk),
431 }
432 }
433
434 pub fn new_randomness_dkg_message(
435 authority: AuthorityName,
436 versioned_message: &VersionedDkgMessage,
437 ) -> Self {
438 let message =
439 bcs::to_bytes(versioned_message).expect("message serialization should not fail");
440 let mut hasher = DefaultHasher::new();
441 message.hash(&mut hasher);
442 let tracking_id = hasher.finish().to_le_bytes();
443 Self {
444 tracking_id,
445 kind: ConsensusTransactionKind::RandomnessDkgMessage(authority, message),
446 }
447 }
448 pub fn new_randomness_dkg_confirmation(
449 authority: AuthorityName,
450 versioned_confirmation: &VersionedDkgConfirmation,
451 ) -> Self {
452 let confirmation =
453 bcs::to_bytes(versioned_confirmation).expect("message serialization should not fail");
454 let mut hasher = DefaultHasher::new();
455 confirmation.hash(&mut hasher);
456 let tracking_id = hasher.finish().to_le_bytes();
457 Self {
458 tracking_id,
459 kind: ConsensusTransactionKind::RandomnessDkgConfirmation(authority, confirmation),
460 }
461 }
462
463 pub fn get_tracking_id(&self) -> u64 {
464 (&self.tracking_id[..])
465 .read_u64::<BigEndian>()
466 .unwrap_or_default()
467 }
468
469 pub fn key(&self) -> ConsensusTransactionKey {
470 match &self.kind {
471 ConsensusTransactionKind::CertifiedTransaction(cert) => {
472 ConsensusTransactionKey::Certificate(*cert.digest())
473 }
474 ConsensusTransactionKind::CheckpointSignature(data) => {
475 ConsensusTransactionKey::CheckpointSignature(
476 data.summary.auth_sig().authority,
477 data.summary.sequence_number,
478 )
479 }
480 ConsensusTransactionKind::EndOfPublish(authority) => {
481 ConsensusTransactionKey::EndOfPublish(*authority)
482 }
483 ConsensusTransactionKind::CapabilityNotificationV1(cap) => {
484 ConsensusTransactionKey::CapabilityNotification(cap.authority, cap.generation)
485 }
486 ConsensusTransactionKind::SignedCapabilityNotificationV1(signed_cap) => {
487 ConsensusTransactionKey::CapabilityNotification(
488 signed_cap.authority,
489 signed_cap.generation,
490 )
491 }
492
493 ConsensusTransactionKind::NewJWKFetched(authority, id, key) => {
494 ConsensusTransactionKey::NewJWKFetched(Box::new((
495 *authority,
496 id.clone(),
497 key.clone(),
498 )))
499 }
500 ConsensusTransactionKind::RandomnessDkgMessage(authority, _) => {
501 ConsensusTransactionKey::RandomnessDkgMessage(*authority)
502 }
503 ConsensusTransactionKind::RandomnessDkgConfirmation(authority, _) => {
504 ConsensusTransactionKey::RandomnessDkgConfirmation(*authority)
505 }
506 }
507 }
508
509 pub fn is_user_certificate(&self) -> bool {
510 matches!(self.kind, ConsensusTransactionKind::CertifiedTransaction(_))
511 }
512
513 pub fn is_end_of_publish(&self) -> bool {
514 matches!(self.kind, ConsensusTransactionKind::EndOfPublish(_))
515 }
516}
517
518#[test]
519fn test_jwk_compatibility() {
520 let jwk = JWK {
525 kty: "a".to_string(),
526 e: "b".to_string(),
527 n: "c".to_string(),
528 alg: "d".to_string(),
529 };
530
531 let expected_jwk_bytes = vec![1, 97, 1, 98, 1, 99, 1, 100];
532 let jwk_bcs = bcs::to_bytes(&jwk).unwrap();
533 assert_eq!(jwk_bcs, expected_jwk_bytes);
534
535 let id = JwkId {
536 iss: "abc".to_string(),
537 kid: "def".to_string(),
538 };
539
540 let expected_id_bytes = vec![3, 97, 98, 99, 3, 100, 101, 102];
541 let id_bcs = bcs::to_bytes(&id).unwrap();
542 assert_eq!(id_bcs, expected_id_bytes);
543}