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 UserTransaction(Box<CertifiedTransaction>),
193 CheckpointSignature(Box<CheckpointSignatureMessage>),
194 EndOfPublish(AuthorityName),
195
196 CapabilityNotificationV1(AuthorityCapabilitiesV1),
197
198 NewJWKFetched(AuthorityName, JwkId, JWK),
199 RandomnessDkgMessage(AuthorityName, Vec<u8>),
203 RandomnessDkgConfirmation(AuthorityName, Vec<u8>),
207}
208
209impl ConsensusTransactionKind {
210 pub fn is_dkg(&self) -> bool {
211 matches!(
212 self,
213 ConsensusTransactionKind::RandomnessDkgMessage(_, _)
214 | ConsensusTransactionKind::RandomnessDkgConfirmation(_, _)
215 )
216 }
217}
218
219#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
220pub enum VersionedDkgMessage {
221 V1(dkg_v1::Message<bls12381::G2Element, bls12381::G2Element>),
222}
223
224#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
225pub enum VersionedDkgConfirmation {
226 V1(dkg::Confirmation<bls12381::G2Element>),
227}
228
229impl Debug for VersionedDkgMessage {
230 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
231 match self {
232 VersionedDkgMessage::V1(msg) => write!(
233 f,
234 "DKG V1 Message with sender={}, vss_pk.degree={}, encrypted_shares.len()={}",
235 msg.sender,
236 msg.vss_pk.degree(),
237 msg.encrypted_shares.len(),
238 ),
239 }
240 }
241}
242
243impl VersionedDkgMessage {
244 pub fn sender(&self) -> u16 {
245 match self {
246 VersionedDkgMessage::V1(msg) => msg.sender,
247 }
248 }
249
250 pub fn create(
251 dkg_version: u64,
252 party: Arc<dkg::Party<bls12381::G2Element, bls12381::G2Element>>,
253 ) -> FastCryptoResult<VersionedDkgMessage> {
254 assert_eq!(dkg_version, 1, "BUG: invalid DKG version");
255 let msg = party.create_message_v1(&mut rand::thread_rng())?;
256 Ok(VersionedDkgMessage::V1(msg))
257 }
258
259 pub fn unwrap_v1(self) -> dkg_v1::Message<bls12381::G2Element, bls12381::G2Element> {
260 match self {
261 VersionedDkgMessage::V1(msg) => msg,
262 }
263 }
264
265 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
266 matches!((self, dkg_version), (VersionedDkgMessage::V1(_), 1))
267 }
268}
269
270impl VersionedDkgConfirmation {
271 pub fn sender(&self) -> u16 {
272 match self {
273 VersionedDkgConfirmation::V1(msg) => msg.sender,
274 }
275 }
276
277 pub fn num_of_complaints(&self) -> usize {
278 match self {
279 VersionedDkgConfirmation::V1(msg) => msg.complaints.len(),
280 }
281 }
282
283 pub fn unwrap_v1(&self) -> &dkg::Confirmation<bls12381::G2Element> {
284 match self {
285 VersionedDkgConfirmation::V1(msg) => msg,
286 }
287 }
288
289 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
290 matches!((self, dkg_version), (VersionedDkgConfirmation::V1(_), 1))
291 }
292}
293
294impl ConsensusTransaction {
295 pub fn new_certificate_message(
296 authority: &AuthorityName,
297 certificate: CertifiedTransaction,
298 ) -> Self {
299 let mut hasher = DefaultHasher::new();
300 let tx_digest = certificate.digest();
301 tx_digest.hash(&mut hasher);
302 authority.hash(&mut hasher);
303 let tracking_id = hasher.finish().to_le_bytes();
304 Self {
305 tracking_id,
306 kind: ConsensusTransactionKind::UserTransaction(Box::new(certificate)),
307 }
308 }
309
310 pub fn new_checkpoint_signature_message(data: CheckpointSignatureMessage) -> Self {
311 let mut hasher = DefaultHasher::new();
312 data.summary.auth_sig().signature.hash(&mut hasher);
313 let tracking_id = hasher.finish().to_le_bytes();
314 Self {
315 tracking_id,
316 kind: ConsensusTransactionKind::CheckpointSignature(Box::new(data)),
317 }
318 }
319
320 pub fn new_end_of_publish(authority: AuthorityName) -> Self {
321 let mut hasher = DefaultHasher::new();
322 authority.hash(&mut hasher);
323 let tracking_id = hasher.finish().to_le_bytes();
324 Self {
325 tracking_id,
326 kind: ConsensusTransactionKind::EndOfPublish(authority),
327 }
328 }
329
330 pub fn new_capability_notification_v1(capabilities: AuthorityCapabilitiesV1) -> Self {
331 let mut hasher = DefaultHasher::new();
332 capabilities.hash(&mut hasher);
333 let tracking_id = hasher.finish().to_le_bytes();
334 Self {
335 tracking_id,
336 kind: ConsensusTransactionKind::CapabilityNotificationV1(capabilities),
337 }
338 }
339
340 pub fn new_mysticeti_certificate(
341 round: u64,
342 offset: u64,
343 certificate: CertifiedTransaction,
344 ) -> Self {
345 let mut hasher = DefaultHasher::new();
346 let tx_digest = certificate.digest();
347 tx_digest.hash(&mut hasher);
348 round.hash(&mut hasher);
349 offset.hash(&mut hasher);
350 let tracking_id = hasher.finish().to_le_bytes();
351 Self {
352 tracking_id,
353 kind: ConsensusTransactionKind::UserTransaction(Box::new(certificate)),
354 }
355 }
356
357 pub fn new_jwk_fetched(authority: AuthorityName, id: JwkId, jwk: JWK) -> Self {
358 let mut hasher = DefaultHasher::new();
359 id.hash(&mut hasher);
360 let tracking_id = hasher.finish().to_le_bytes();
361 Self {
362 tracking_id,
363 kind: ConsensusTransactionKind::NewJWKFetched(authority, id, jwk),
364 }
365 }
366
367 pub fn new_randomness_dkg_message(
368 authority: AuthorityName,
369 versioned_message: &VersionedDkgMessage,
370 ) -> Self {
371 let message =
372 bcs::to_bytes(versioned_message).expect("message serialization should not fail");
373 let mut hasher = DefaultHasher::new();
374 message.hash(&mut hasher);
375 let tracking_id = hasher.finish().to_le_bytes();
376 Self {
377 tracking_id,
378 kind: ConsensusTransactionKind::RandomnessDkgMessage(authority, message),
379 }
380 }
381 pub fn new_randomness_dkg_confirmation(
382 authority: AuthorityName,
383 versioned_confirmation: &VersionedDkgConfirmation,
384 ) -> Self {
385 let confirmation =
386 bcs::to_bytes(versioned_confirmation).expect("message serialization should not fail");
387 let mut hasher = DefaultHasher::new();
388 confirmation.hash(&mut hasher);
389 let tracking_id = hasher.finish().to_le_bytes();
390 Self {
391 tracking_id,
392 kind: ConsensusTransactionKind::RandomnessDkgConfirmation(authority, confirmation),
393 }
394 }
395
396 pub fn get_tracking_id(&self) -> u64 {
397 (&self.tracking_id[..])
398 .read_u64::<BigEndian>()
399 .unwrap_or_default()
400 }
401
402 pub fn key(&self) -> ConsensusTransactionKey {
403 match &self.kind {
404 ConsensusTransactionKind::UserTransaction(cert) => {
405 ConsensusTransactionKey::Certificate(*cert.digest())
406 }
407 ConsensusTransactionKind::CheckpointSignature(data) => {
408 ConsensusTransactionKey::CheckpointSignature(
409 data.summary.auth_sig().authority,
410 data.summary.sequence_number,
411 )
412 }
413 ConsensusTransactionKind::EndOfPublish(authority) => {
414 ConsensusTransactionKey::EndOfPublish(*authority)
415 }
416 ConsensusTransactionKind::CapabilityNotificationV1(cap) => {
417 ConsensusTransactionKey::CapabilityNotification(cap.authority, cap.generation)
418 }
419 ConsensusTransactionKind::NewJWKFetched(authority, id, key) => {
420 ConsensusTransactionKey::NewJWKFetched(Box::new((
421 *authority,
422 id.clone(),
423 key.clone(),
424 )))
425 }
426 ConsensusTransactionKind::RandomnessDkgMessage(authority, _) => {
427 ConsensusTransactionKey::RandomnessDkgMessage(*authority)
428 }
429 ConsensusTransactionKind::RandomnessDkgConfirmation(authority, _) => {
430 ConsensusTransactionKey::RandomnessDkgConfirmation(*authority)
431 }
432 }
433 }
434
435 pub fn is_user_certificate(&self) -> bool {
436 matches!(self.kind, ConsensusTransactionKind::UserTransaction(_))
437 }
438
439 pub fn is_end_of_publish(&self) -> bool {
440 matches!(self.kind, ConsensusTransactionKind::EndOfPublish(_))
441 }
442}
443
444#[test]
445fn test_jwk_compatibility() {
446 let jwk = JWK {
451 kty: "a".to_string(),
452 e: "b".to_string(),
453 n: "c".to_string(),
454 alg: "d".to_string(),
455 };
456
457 let expected_jwk_bytes = vec![1, 97, 1, 98, 1, 99, 1, 100];
458 let jwk_bcs = bcs::to_bytes(&jwk).unwrap();
459 assert_eq!(jwk_bcs, expected_jwk_bytes);
460
461 let id = JwkId {
462 iss: "abc".to_string(),
463 kid: "def".to_string(),
464 };
465
466 let expected_id_bytes = vec![3, 97, 98, 99, 3, 100, 101, 102];
467 let id_bcs = bcs::to_bytes(&id).unwrap();
468 assert_eq!(id_bcs, expected_id_bytes);
469}