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