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