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};
15use fastcrypto_tbls::dkg_v1;
16use fastcrypto_zkp::bn254::zk_login::{JWK, JwkId};
17use schemars::JsonSchema;
18use serde::{Deserialize, Serialize};
19
20use crate::{
21 base_types::{
22 AuthorityName, ConciseableName, ObjectID, ObjectRef, SequenceNumber, TransactionDigest,
23 },
24 digests::ConsensusCommitDigest,
25 messages_checkpoint::{CheckpointSequenceNumber, CheckpointSignatureMessage},
26 supported_protocol_versions::{
27 Chain, SupportedProtocolVersions, SupportedProtocolVersionsWithHashes,
28 },
29 transaction::CertifiedTransaction,
30};
31
32pub type TimestampMs = u64;
34
35#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, JsonSchema)]
38pub enum ConsensusDeterminedVersionAssignments {
39 CancelledTransactions(Vec<(TransactionDigest, Vec<(ObjectID, SequenceNumber)>)>),
41}
42
43#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
44pub struct ConsensusCommitPrologueV1 {
45 pub epoch: u64,
47 pub round: u64,
49 pub sub_dag_index: Option<u64>,
52 pub commit_timestamp_ms: TimestampMs,
54 pub consensus_commit_digest: ConsensusCommitDigest,
56 pub consensus_determined_version_assignments: ConsensusDeterminedVersionAssignments,
58}
59
60static MAX_TOTAL_JWK_SIZE: usize = 4096;
64
65pub fn check_total_jwk_size(id: &JwkId, jwk: &JWK) -> bool {
66 id.iss.len() + id.kid.len() + jwk.kty.len() + jwk.alg.len() + jwk.e.len() + jwk.n.len()
67 <= MAX_TOTAL_JWK_SIZE
68}
69
70#[derive(Serialize, Deserialize, Clone, Debug)]
71pub struct ConsensusTransaction {
72 pub tracking_id: [u8; 8],
76 pub kind: ConsensusTransactionKind,
77}
78
79#[derive(Serialize, Deserialize, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
80pub enum ConsensusTransactionKey {
81 Certificate(TransactionDigest),
82 CheckpointSignature(AuthorityName, CheckpointSequenceNumber),
83 EndOfPublish(AuthorityName),
84 CapabilityNotification(AuthorityName, u64 ),
85 NewJWKFetched(Box<(AuthorityName, JwkId, JWK)>),
88 RandomnessDkgMessage(AuthorityName),
89 RandomnessDkgConfirmation(AuthorityName),
90}
91
92impl Debug for ConsensusTransactionKey {
93 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
94 match self {
95 Self::Certificate(digest) => write!(f, "Certificate({digest:?})"),
96 Self::CheckpointSignature(name, seq) => {
97 write!(f, "CheckpointSignature({:?}, {:?})", name.concise(), seq)
98 }
99 Self::EndOfPublish(name) => write!(f, "EndOfPublish({:?})", name.concise()),
100 Self::CapabilityNotification(name, generation) => write!(
101 f,
102 "CapabilityNotification({:?}, {:?})",
103 name.concise(),
104 generation
105 ),
106 Self::NewJWKFetched(key) => {
107 let (authority, id, jwk) = &**key;
108 write!(
109 f,
110 "NewJWKFetched({:?}, {:?}, {:?})",
111 authority.concise(),
112 id,
113 jwk
114 )
115 }
116 Self::RandomnessDkgMessage(name) => {
117 write!(f, "RandomnessDkgMessage({:?})", name.concise())
118 }
119 Self::RandomnessDkgConfirmation(name) => {
120 write!(f, "RandomnessDkgConfirmation({:?})", name.concise())
121 }
122 }
123 }
124}
125
126#[derive(Serialize, Deserialize, Clone, Hash)]
129pub struct AuthorityCapabilitiesV1 {
130 pub authority: AuthorityName,
133 pub generation: u64,
140
141 pub supported_protocol_versions: SupportedProtocolVersionsWithHashes,
144
145 pub available_system_packages: Vec<ObjectRef>,
149}
150
151impl Debug for AuthorityCapabilitiesV1 {
152 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
153 f.debug_struct("AuthorityCapabilities")
154 .field("authority", &self.authority.concise())
155 .field("generation", &self.generation)
156 .field(
157 "supported_protocol_versions",
158 &self.supported_protocol_versions,
159 )
160 .field("available_system_packages", &self.available_system_packages)
161 .finish()
162 }
163}
164
165impl AuthorityCapabilitiesV1 {
166 pub fn new(
167 authority: AuthorityName,
168 chain: Chain,
169 supported_protocol_versions: SupportedProtocolVersions,
170 available_system_packages: Vec<ObjectRef>,
171 ) -> Self {
172 let generation = SystemTime::now()
173 .duration_since(UNIX_EPOCH)
174 .expect("IOTA did not exist prior to 1970")
175 .as_millis()
176 .try_into()
177 .expect("This build of iota is not supported in the year 500,000,000");
178 Self {
179 authority,
180 generation,
181 supported_protocol_versions:
182 SupportedProtocolVersionsWithHashes::from_supported_versions(
183 supported_protocol_versions,
184 chain,
185 ),
186 available_system_packages,
187 }
188 }
189}
190
191#[derive(Serialize, Deserialize, Clone, Debug)]
192pub enum ConsensusTransactionKind {
193 CertifiedTransaction(Box<CertifiedTransaction>),
194 CheckpointSignature(Box<CheckpointSignatureMessage>),
195 EndOfPublish(AuthorityName),
196
197 CapabilityNotificationV1(AuthorityCapabilitiesV1),
198
199 NewJWKFetched(AuthorityName, JwkId, JWK),
200
201 RandomnessDkgMessage(AuthorityName, Vec<u8>),
205 RandomnessDkgConfirmation(AuthorityName, Vec<u8>),
209}
210
211impl ConsensusTransactionKind {
212 pub fn is_dkg(&self) -> bool {
213 matches!(
214 self,
215 ConsensusTransactionKind::RandomnessDkgMessage(_, _)
216 | ConsensusTransactionKind::RandomnessDkgConfirmation(_, _)
217 )
218 }
219}
220
221#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
222pub enum VersionedDkgMessage {
223 V1(dkg_v1::Message<bls12381::G2Element, bls12381::G2Element>),
224}
225
226#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
227pub enum VersionedDkgConfirmation {
228 V1(dkg_v1::Confirmation<bls12381::G2Element>),
229}
230
231impl Debug for VersionedDkgMessage {
232 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
233 match self {
234 VersionedDkgMessage::V1(msg) => write!(
235 f,
236 "DKG V1 Message with sender={}, vss_pk.degree={}, encrypted_shares.len()={}",
237 msg.sender,
238 msg.vss_pk.degree(),
239 msg.encrypted_shares.len(),
240 ),
241 }
242 }
243}
244
245impl VersionedDkgMessage {
246 pub fn sender(&self) -> u16 {
247 match self {
248 VersionedDkgMessage::V1(msg) => msg.sender,
249 }
250 }
251
252 pub fn create(
253 dkg_version: u64,
254 party: Arc<dkg_v1::Party<bls12381::G2Element, bls12381::G2Element>>,
255 ) -> FastCryptoResult<VersionedDkgMessage> {
256 assert_eq!(dkg_version, 1, "BUG: invalid DKG version");
257 let msg = party.create_message(&mut rand::thread_rng())?;
258 Ok(VersionedDkgMessage::V1(msg))
259 }
260
261 pub fn unwrap_v1(self) -> dkg_v1::Message<bls12381::G2Element, bls12381::G2Element> {
262 match self {
263 VersionedDkgMessage::V1(msg) => msg,
264 }
265 }
266
267 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
268 matches!((self, dkg_version), (VersionedDkgMessage::V1(_), 1))
269 }
270}
271
272impl VersionedDkgConfirmation {
273 pub fn sender(&self) -> u16 {
274 match self {
275 VersionedDkgConfirmation::V1(msg) => msg.sender,
276 }
277 }
278
279 pub fn num_of_complaints(&self) -> usize {
280 match self {
281 VersionedDkgConfirmation::V1(msg) => msg.complaints.len(),
282 }
283 }
284
285 pub fn unwrap_v1(&self) -> &dkg_v1::Confirmation<bls12381::G2Element> {
286 match self {
287 VersionedDkgConfirmation::V1(msg) => msg,
288 }
289 }
290
291 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
292 matches!((self, dkg_version), (VersionedDkgConfirmation::V1(_), 1))
293 }
294}
295
296impl ConsensusTransaction {
297 pub fn new_certificate_message(
298 authority: &AuthorityName,
299 certificate: CertifiedTransaction,
300 ) -> Self {
301 let mut hasher = DefaultHasher::new();
302 let tx_digest = certificate.digest();
303 tx_digest.hash(&mut hasher);
304 authority.hash(&mut hasher);
305 let tracking_id = hasher.finish().to_le_bytes();
306 Self {
307 tracking_id,
308 kind: ConsensusTransactionKind::CertifiedTransaction(Box::new(certificate)),
309 }
310 }
311
312 pub fn new_checkpoint_signature_message(data: CheckpointSignatureMessage) -> Self {
313 let mut hasher = DefaultHasher::new();
314 data.summary.auth_sig().signature.hash(&mut hasher);
315 let tracking_id = hasher.finish().to_le_bytes();
316 Self {
317 tracking_id,
318 kind: ConsensusTransactionKind::CheckpointSignature(Box::new(data)),
319 }
320 }
321
322 pub fn new_end_of_publish(authority: AuthorityName) -> Self {
323 let mut hasher = DefaultHasher::new();
324 authority.hash(&mut hasher);
325 let tracking_id = hasher.finish().to_le_bytes();
326 Self {
327 tracking_id,
328 kind: ConsensusTransactionKind::EndOfPublish(authority),
329 }
330 }
331
332 pub fn new_capability_notification_v1(capabilities: AuthorityCapabilitiesV1) -> Self {
333 let mut hasher = DefaultHasher::new();
334 capabilities.hash(&mut hasher);
335 let tracking_id = hasher.finish().to_le_bytes();
336 Self {
337 tracking_id,
338 kind: ConsensusTransactionKind::CapabilityNotificationV1(capabilities),
339 }
340 }
341
342 pub fn new_mysticeti_certificate(
343 round: u64,
344 offset: u64,
345 certificate: CertifiedTransaction,
346 ) -> Self {
347 let mut hasher = DefaultHasher::new();
348 let tx_digest = certificate.digest();
349 tx_digest.hash(&mut hasher);
350 round.hash(&mut hasher);
351 offset.hash(&mut hasher);
352 let tracking_id = hasher.finish().to_le_bytes();
353 Self {
354 tracking_id,
355 kind: ConsensusTransactionKind::CertifiedTransaction(Box::new(certificate)),
356 }
357 }
358
359 pub fn new_jwk_fetched(authority: AuthorityName, id: JwkId, jwk: JWK) -> Self {
360 let mut hasher = DefaultHasher::new();
361 id.hash(&mut hasher);
362 let tracking_id = hasher.finish().to_le_bytes();
363 Self {
364 tracking_id,
365 kind: ConsensusTransactionKind::NewJWKFetched(authority, id, jwk),
366 }
367 }
368
369 pub fn new_randomness_dkg_message(
370 authority: AuthorityName,
371 versioned_message: &VersionedDkgMessage,
372 ) -> Self {
373 let message =
374 bcs::to_bytes(versioned_message).expect("message serialization should not fail");
375 let mut hasher = DefaultHasher::new();
376 message.hash(&mut hasher);
377 let tracking_id = hasher.finish().to_le_bytes();
378 Self {
379 tracking_id,
380 kind: ConsensusTransactionKind::RandomnessDkgMessage(authority, message),
381 }
382 }
383 pub fn new_randomness_dkg_confirmation(
384 authority: AuthorityName,
385 versioned_confirmation: &VersionedDkgConfirmation,
386 ) -> Self {
387 let confirmation =
388 bcs::to_bytes(versioned_confirmation).expect("message serialization should not fail");
389 let mut hasher = DefaultHasher::new();
390 confirmation.hash(&mut hasher);
391 let tracking_id = hasher.finish().to_le_bytes();
392 Self {
393 tracking_id,
394 kind: ConsensusTransactionKind::RandomnessDkgConfirmation(authority, confirmation),
395 }
396 }
397
398 pub fn get_tracking_id(&self) -> u64 {
399 (&self.tracking_id[..])
400 .read_u64::<BigEndian>()
401 .unwrap_or_default()
402 }
403
404 pub fn key(&self) -> ConsensusTransactionKey {
405 match &self.kind {
406 ConsensusTransactionKind::CertifiedTransaction(cert) => {
407 ConsensusTransactionKey::Certificate(*cert.digest())
408 }
409 ConsensusTransactionKind::CheckpointSignature(data) => {
410 ConsensusTransactionKey::CheckpointSignature(
411 data.summary.auth_sig().authority,
412 data.summary.sequence_number,
413 )
414 }
415 ConsensusTransactionKind::EndOfPublish(authority) => {
416 ConsensusTransactionKey::EndOfPublish(*authority)
417 }
418 ConsensusTransactionKind::CapabilityNotificationV1(cap) => {
419 ConsensusTransactionKey::CapabilityNotification(cap.authority, cap.generation)
420 }
421 ConsensusTransactionKind::NewJWKFetched(authority, id, key) => {
422 ConsensusTransactionKey::NewJWKFetched(Box::new((
423 *authority,
424 id.clone(),
425 key.clone(),
426 )))
427 }
428 ConsensusTransactionKind::RandomnessDkgMessage(authority, _) => {
429 ConsensusTransactionKey::RandomnessDkgMessage(*authority)
430 }
431 ConsensusTransactionKind::RandomnessDkgConfirmation(authority, _) => {
432 ConsensusTransactionKey::RandomnessDkgConfirmation(*authority)
433 }
434 }
435 }
436
437 pub fn is_user_certificate(&self) -> bool {
438 matches!(self.kind, ConsensusTransactionKind::CertifiedTransaction(_))
439 }
440
441 pub fn is_end_of_publish(&self) -> bool {
442 matches!(self.kind, ConsensusTransactionKind::EndOfPublish(_))
443 }
444}
445
446#[test]
447fn test_jwk_compatibility() {
448 let jwk = JWK {
453 kty: "a".to_string(),
454 e: "b".to_string(),
455 n: "c".to_string(),
456 alg: "d".to_string(),
457 };
458
459 let expected_jwk_bytes = vec![1, 97, 1, 98, 1, 99, 1, 100];
460 let jwk_bcs = bcs::to_bytes(&jwk).unwrap();
461 assert_eq!(jwk_bcs, expected_jwk_bytes);
462
463 let id = JwkId {
464 iss: "abc".to_string(),
465 kid: "def".to_string(),
466 };
467
468 let expected_id_bytes = vec![3, 97, 98, 99, 3, 100, 101, 102];
469 let id_bcs = bcs::to_bytes(&id).unwrap();
470 assert_eq!(id_bcs, expected_id_bytes);
471}