1use crate::base_types::{AuthorityName, ConsensusObjectSequenceKey, ObjectRef, TransactionDigest};
5use crate::base_types::{ConciseableName, ObjectID, SequenceNumber};
6use crate::committee::EpochId;
7use crate::digests::{AdditionalConsensusStateDigest, ConsensusCommitDigest};
8use crate::error::{SuiError, SuiErrorKind};
9use crate::execution::ExecutionTimeObservationKey;
10use crate::messages_checkpoint::{
11 CheckpointDigest, CheckpointSequenceNumber, CheckpointSignatureMessage,
12};
13use crate::supported_protocol_versions::{
14 Chain, SupportedProtocolVersions, SupportedProtocolVersionsWithHashes,
15};
16use crate::transaction::{CertifiedTransaction, Transaction, TransactionWithAliases};
17use byteorder::{BigEndian, ReadBytesExt};
18use bytes::Bytes;
19use consensus_types::block::{BlockRef, PING_TRANSACTION_INDEX, TransactionIndex};
20use fastcrypto::error::FastCryptoResult;
21use fastcrypto::groups::bls12381;
22use fastcrypto_tbls::dkg_v1;
23use fastcrypto_zkp::bn254::zk_login::{JWK, JwkId};
24use schemars::JsonSchema;
25use serde::{Deserialize, Serialize};
26use std::collections::hash_map::DefaultHasher;
27use std::fmt::{Debug, Formatter};
28use std::hash::{Hash, Hasher};
29use std::sync::Arc;
30use std::time::{Duration, SystemTime, UNIX_EPOCH};
31
32pub type AuthorityIndex = u32;
35
36pub type Round = u64;
39
40pub type TimestampMs = u64;
43
44#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
46pub struct ConsensusPosition {
47 pub epoch: EpochId,
49 pub block: BlockRef,
51 pub index: TransactionIndex,
53}
54
55impl ConsensusPosition {
56 pub fn into_raw(self) -> Result<Bytes, SuiError> {
57 bcs::to_bytes(&self)
58 .map_err(|e| {
59 SuiErrorKind::GrpcMessageSerializeError {
60 type_info: "ConsensusPosition".to_string(),
61 error: e.to_string(),
62 }
63 .into()
64 })
65 .map(Bytes::from)
66 }
67
68 pub fn ping(epoch: EpochId, block: BlockRef) -> Self {
71 Self {
72 epoch,
73 block,
74 index: PING_TRANSACTION_INDEX,
75 }
76 }
77}
78
79impl TryFrom<&[u8]> for ConsensusPosition {
80 type Error = SuiError;
81
82 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
83 bcs::from_bytes(bytes).map_err(|e| {
84 SuiErrorKind::GrpcMessageDeserializeError {
85 type_info: "ConsensusPosition".to_string(),
86 error: e.to_string(),
87 }
88 .into()
89 })
90 }
91}
92
93impl std::fmt::Display for ConsensusPosition {
94 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
95 write!(f, "P(E{}, {}, {})", self.epoch, self.block, self.index)
96 }
97}
98
99impl std::fmt::Debug for ConsensusPosition {
100 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
101 write!(f, "P(E{}, {:?}, {})", self.epoch, self.block, self.index)
102 }
103}
104
105#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
108pub struct ConsensusCommitPrologue {
109 pub epoch: u64,
111 pub round: u64,
113 pub commit_timestamp_ms: TimestampMs,
115}
116
117#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
118pub struct ConsensusCommitPrologueV2 {
119 pub epoch: u64,
121 pub round: u64,
123 pub commit_timestamp_ms: TimestampMs,
125 pub consensus_commit_digest: ConsensusCommitDigest,
127}
128
129#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, JsonSchema)]
130pub enum ConsensusDeterminedVersionAssignments {
131 CancelledTransactions(Vec<(TransactionDigest, Vec<(ObjectID, SequenceNumber)>)>),
133 CancelledTransactionsV2(
134 Vec<(
135 TransactionDigest,
136 Vec<(ConsensusObjectSequenceKey, SequenceNumber)>,
137 )>,
138 ),
139}
140
141impl ConsensusDeterminedVersionAssignments {
142 pub fn empty_for_testing() -> Self {
143 Self::CancelledTransactions(Vec::new())
144 }
145}
146
147#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
148pub struct ConsensusCommitPrologueV3 {
149 pub epoch: u64,
151 pub round: u64,
153 pub sub_dag_index: Option<u64>,
156 pub commit_timestamp_ms: TimestampMs,
158 pub consensus_commit_digest: ConsensusCommitDigest,
160 pub consensus_determined_version_assignments: ConsensusDeterminedVersionAssignments,
162}
163
164#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
165pub struct ConsensusCommitPrologueV4 {
166 pub epoch: u64,
168 pub round: u64,
170 pub sub_dag_index: Option<u64>,
173 pub commit_timestamp_ms: TimestampMs,
175 pub consensus_commit_digest: ConsensusCommitDigest,
177 pub consensus_determined_version_assignments: ConsensusDeterminedVersionAssignments,
179 pub additional_state_digest: AdditionalConsensusStateDigest,
182}
183
184static MAX_TOTAL_JWK_SIZE: usize = 4096;
187
188pub fn check_total_jwk_size(id: &JwkId, jwk: &JWK) -> bool {
189 id.iss.len() + id.kid.len() + jwk.kty.len() + jwk.alg.len() + jwk.e.len() + jwk.n.len()
190 <= MAX_TOTAL_JWK_SIZE
191}
192
193#[derive(Serialize, Deserialize, Clone, Debug)]
194pub struct ConsensusTransaction {
195 pub tracking_id: [u8; 8],
198 pub kind: ConsensusTransactionKind,
199}
200
201impl ConsensusTransaction {
202 pub fn local_display(&self) -> String {
204 match &self.kind {
205 ConsensusTransactionKind::CertifiedTransaction(cert) => {
206 format!("Certified({})", cert.digest())
207 }
208 ConsensusTransactionKind::CheckpointSignature(data) => {
209 format!(
210 "CkptSig({}, {})",
211 data.summary.sequence_number,
212 data.summary.digest()
213 )
214 }
215 ConsensusTransactionKind::CheckpointSignatureV2(data) => {
216 format!(
217 "CkptSigV2({}, {})",
218 data.summary.sequence_number,
219 data.summary.digest()
220 )
221 }
222 ConsensusTransactionKind::EndOfPublish(..) => "EOP".to_string(),
223 ConsensusTransactionKind::CapabilityNotification(..) => "Cap".to_string(),
224 ConsensusTransactionKind::CapabilityNotificationV2(..) => "CapV2".to_string(),
225 ConsensusTransactionKind::NewJWKFetched(..) => "NewJWKFetched".to_string(),
226 ConsensusTransactionKind::RandomnessStateUpdate(..) => "RandStateUpdate".to_string(),
227 ConsensusTransactionKind::RandomnessDkgMessage(..) => "RandDkg".to_string(),
228 ConsensusTransactionKind::RandomnessDkgConfirmation(..) => "RandDkgConf".to_string(),
229 ConsensusTransactionKind::ExecutionTimeObservation(..) => "ExecTimeOb".to_string(),
230 ConsensusTransactionKind::UserTransaction(tx) => {
231 format!("User({})", tx.digest())
232 }
233 ConsensusTransactionKind::UserTransactionV2(tx) => {
234 format!("UserV2({})", tx.tx().digest())
235 }
236 }
237 }
238}
239
240#[derive(Serialize, Deserialize, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
242pub enum ConsensusTransactionKey {
243 Certificate(TransactionDigest),
244 CheckpointSignature(AuthorityName, CheckpointSequenceNumber),
246 EndOfPublish(AuthorityName),
247 CapabilityNotification(AuthorityName, u64 ),
248 NewJWKFetched(Box<(AuthorityName, JwkId, JWK)>),
251 RandomnessDkgMessage(AuthorityName),
252 RandomnessDkgConfirmation(AuthorityName),
253 ExecutionTimeObservation(AuthorityName, u64 ),
254 CheckpointSignatureV2(AuthorityName, CheckpointSequenceNumber, CheckpointDigest),
256}
257
258impl Debug for ConsensusTransactionKey {
259 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
260 match self {
261 Self::Certificate(digest) => write!(f, "Certificate({:?})", digest),
262 Self::CheckpointSignature(name, seq) => {
263 write!(f, "CheckpointSignature({:?}, {:?})", name.concise(), seq)
264 }
265 Self::CheckpointSignatureV2(name, seq, digest) => write!(
266 f,
267 "CheckpointSignatureV2({:?}, {:?}, {:?})",
268 name.concise(),
269 seq,
270 digest
271 ),
272 Self::EndOfPublish(name) => write!(f, "EndOfPublish({:?})", name.concise()),
273 Self::CapabilityNotification(name, generation) => write!(
274 f,
275 "CapabilityNotification({:?}, {:?})",
276 name.concise(),
277 generation
278 ),
279 Self::NewJWKFetched(key) => {
280 let (authority, id, jwk) = &**key;
281 write!(
282 f,
283 "NewJWKFetched({:?}, {:?}, {:?})",
284 authority.concise(),
285 id,
286 jwk
287 )
288 }
289 Self::RandomnessDkgMessage(name) => {
290 write!(f, "RandomnessDkgMessage({:?})", name.concise())
291 }
292 Self::RandomnessDkgConfirmation(name) => {
293 write!(f, "RandomnessDkgConfirmation({:?})", name.concise())
294 }
295 Self::ExecutionTimeObservation(name, generation) => {
296 write!(
297 f,
298 "ExecutionTimeObservation({:?}, {generation:?})",
299 name.concise()
300 )
301 }
302 }
303 }
304}
305
306#[derive(Serialize, Deserialize, Clone, Hash)]
309pub struct AuthorityCapabilitiesV1 {
310 pub authority: AuthorityName,
312 pub generation: u64,
318
319 pub supported_protocol_versions: SupportedProtocolVersions,
321
322 pub available_system_packages: Vec<ObjectRef>,
325}
326
327impl Debug for AuthorityCapabilitiesV1 {
328 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
329 f.debug_struct("AuthorityCapabilities")
330 .field("authority", &self.authority.concise())
331 .field("generation", &self.generation)
332 .field(
333 "supported_protocol_versions",
334 &self.supported_protocol_versions,
335 )
336 .field("available_system_packages", &self.available_system_packages)
337 .finish()
338 }
339}
340
341impl AuthorityCapabilitiesV1 {
342 pub fn new(
343 authority: AuthorityName,
344 supported_protocol_versions: SupportedProtocolVersions,
345 available_system_packages: Vec<ObjectRef>,
346 ) -> Self {
347 let generation = SystemTime::now()
348 .duration_since(UNIX_EPOCH)
349 .expect("Sui did not exist prior to 1970")
350 .as_millis()
351 .try_into()
352 .expect("This build of sui is not supported in the year 500,000,000");
353 Self {
354 authority,
355 generation,
356 supported_protocol_versions,
357 available_system_packages,
358 }
359 }
360}
361
362#[derive(Serialize, Deserialize, Clone, Hash)]
365pub struct AuthorityCapabilitiesV2 {
366 pub authority: AuthorityName,
368 pub generation: u64,
374
375 pub supported_protocol_versions: SupportedProtocolVersionsWithHashes,
377
378 pub available_system_packages: Vec<ObjectRef>,
381}
382
383impl Debug for AuthorityCapabilitiesV2 {
384 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
385 f.debug_struct("AuthorityCapabilities")
386 .field("authority", &self.authority.concise())
387 .field("generation", &self.generation)
388 .field(
389 "supported_protocol_versions",
390 &self.supported_protocol_versions,
391 )
392 .field("available_system_packages", &self.available_system_packages)
393 .finish()
394 }
395}
396
397impl AuthorityCapabilitiesV2 {
398 pub fn new(
399 authority: AuthorityName,
400 chain: Chain,
401 supported_protocol_versions: SupportedProtocolVersions,
402 available_system_packages: Vec<ObjectRef>,
403 ) -> Self {
404 let generation = SystemTime::now()
405 .duration_since(UNIX_EPOCH)
406 .expect("Sui did not exist prior to 1970")
407 .as_millis()
408 .try_into()
409 .expect("This build of sui is not supported in the year 500,000,000");
410 Self {
411 authority,
412 generation,
413 supported_protocol_versions:
414 SupportedProtocolVersionsWithHashes::from_supported_versions(
415 supported_protocol_versions,
416 chain,
417 ),
418 available_system_packages,
419 }
420 }
421}
422
423#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
426pub struct ExecutionTimeObservation {
427 pub authority: AuthorityName,
429 pub generation: u64,
432
433 pub estimates: Vec<(ExecutionTimeObservationKey, Duration)>,
435}
436
437impl ExecutionTimeObservation {
438 pub fn new(
439 authority: AuthorityName,
440 generation: u64,
441 estimates: Vec<(ExecutionTimeObservationKey, Duration)>,
442 ) -> Self {
443 Self {
444 authority,
445 generation,
446 estimates,
447 }
448 }
449}
450
451#[derive(Serialize, Deserialize, Clone, Debug)]
452pub enum ConsensusTransactionKind {
453 CertifiedTransaction(Box<CertifiedTransaction>),
454 CheckpointSignature(Box<CheckpointSignatureMessage>),
456 EndOfPublish(AuthorityName),
457
458 CapabilityNotification(AuthorityCapabilitiesV1),
459
460 NewJWKFetched(AuthorityName, JwkId, JWK),
461 RandomnessStateUpdate(u64, Vec<u8>), RandomnessDkgMessage(AuthorityName, Vec<u8>),
466 RandomnessDkgConfirmation(AuthorityName, Vec<u8>),
470
471 CapabilityNotificationV2(AuthorityCapabilitiesV2),
472
473 UserTransaction(Box<Transaction>),
474
475 ExecutionTimeObservation(ExecutionTimeObservation),
476 CheckpointSignatureV2(Box<CheckpointSignatureMessage>),
478
479 UserTransactionV2(Box<TransactionWithAliases>),
482}
483
484impl ConsensusTransactionKind {
485 pub fn as_user_transaction(&self) -> Option<&Transaction> {
486 match self {
487 ConsensusTransactionKind::UserTransaction(tx) => Some(tx),
488 ConsensusTransactionKind::UserTransactionV2(tx) => Some(tx.tx()),
489 _ => None,
490 }
491 }
492
493 pub fn into_user_transaction(self) -> Option<Transaction> {
494 match self {
495 ConsensusTransactionKind::UserTransaction(tx) => Some(*tx),
496 ConsensusTransactionKind::UserTransactionV2(tx) => Some(tx.into_tx()),
497 _ => None,
498 }
499 }
500}
501
502#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
503#[allow(clippy::large_enum_variant)]
504pub enum VersionedDkgMessage {
505 V0(), V1(dkg_v1::Message<bls12381::G2Element, bls12381::G2Element>),
507}
508
509#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
510pub enum VersionedDkgConfirmation {
511 V0(), V1(dkg_v1::Confirmation<bls12381::G2Element>),
513}
514
515impl Debug for VersionedDkgMessage {
516 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
517 match self {
518 VersionedDkgMessage::V0() => write!(f, "Deprecated VersionedDkgMessage version 0"),
519 VersionedDkgMessage::V1(msg) => write!(
520 f,
521 "DKG V1 Message with sender={}, vss_pk.degree={}, encrypted_shares.len()={}",
522 msg.sender,
523 msg.vss_pk.degree(),
524 msg.encrypted_shares.len(),
525 ),
526 }
527 }
528}
529
530impl VersionedDkgMessage {
531 pub fn sender(&self) -> u16 {
532 match self {
533 VersionedDkgMessage::V0() => panic!("BUG: invalid VersionedDkgMessage version"),
534 VersionedDkgMessage::V1(msg) => msg.sender,
535 }
536 }
537
538 pub fn create(
539 dkg_version: u64,
540 party: Arc<dkg_v1::Party<bls12381::G2Element, bls12381::G2Element>>,
541 ) -> FastCryptoResult<VersionedDkgMessage> {
542 assert_eq!(dkg_version, 1, "BUG: invalid DKG version");
543 let msg = party.create_message(&mut rand::thread_rng())?;
544 Ok(VersionedDkgMessage::V1(msg))
545 }
546
547 pub fn unwrap_v1(self) -> dkg_v1::Message<bls12381::G2Element, bls12381::G2Element> {
548 match self {
549 VersionedDkgMessage::V1(msg) => msg,
550 _ => panic!("BUG: expected V1 message"),
551 }
552 }
553
554 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
555 matches!((self, dkg_version), (VersionedDkgMessage::V1(_), 1))
556 }
557}
558
559impl VersionedDkgConfirmation {
560 pub fn sender(&self) -> u16 {
561 match self {
562 VersionedDkgConfirmation::V0() => {
563 panic!("BUG: invalid VersionedDkgConfirmation version")
564 }
565 VersionedDkgConfirmation::V1(msg) => msg.sender,
566 }
567 }
568
569 pub fn num_of_complaints(&self) -> usize {
570 match self {
571 VersionedDkgConfirmation::V0() => {
572 panic!("BUG: invalid VersionedDkgConfirmation version")
573 }
574 VersionedDkgConfirmation::V1(msg) => msg.complaints.len(),
575 }
576 }
577
578 pub fn unwrap_v1(&self) -> &dkg_v1::Confirmation<bls12381::G2Element> {
579 match self {
580 VersionedDkgConfirmation::V1(msg) => msg,
581 _ => panic!("BUG: expected V1 confirmation"),
582 }
583 }
584
585 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
586 matches!((self, dkg_version), (VersionedDkgConfirmation::V1(_), 1))
587 }
588}
589
590impl ConsensusTransaction {
591 pub fn new_certificate_message(
592 authority: &AuthorityName,
593 certificate: CertifiedTransaction,
594 ) -> Self {
595 let mut hasher = DefaultHasher::new();
596 let tx_digest = certificate.digest();
597 tx_digest.hash(&mut hasher);
598 authority.hash(&mut hasher);
599 let tracking_id = hasher.finish().to_le_bytes();
600 Self {
601 tracking_id,
602 kind: ConsensusTransactionKind::CertifiedTransaction(Box::new(certificate)),
603 }
604 }
605
606 pub fn new_user_transaction_message(authority: &AuthorityName, tx: Transaction) -> Self {
607 let mut hasher = DefaultHasher::new();
608 let tx_digest = tx.digest();
609 tx_digest.hash(&mut hasher);
610 authority.hash(&mut hasher);
611 let tracking_id = hasher.finish().to_le_bytes();
612 Self {
613 tracking_id,
614 kind: ConsensusTransactionKind::UserTransaction(Box::new(tx)),
615 }
616 }
617
618 pub fn new_user_transaction_v2_message(
619 authority: &AuthorityName,
620 tx: TransactionWithAliases,
621 ) -> Self {
622 let mut hasher = DefaultHasher::new();
623 let tx_digest = tx.tx().digest();
624 tx_digest.hash(&mut hasher);
625 authority.hash(&mut hasher);
626 let tracking_id = hasher.finish().to_le_bytes();
627 Self {
628 tracking_id,
629 kind: ConsensusTransactionKind::UserTransactionV2(Box::new(tx)),
630 }
631 }
632
633 pub fn new_checkpoint_signature_message(data: CheckpointSignatureMessage) -> Self {
634 let mut hasher = DefaultHasher::new();
635 data.summary.auth_sig().signature.hash(&mut hasher);
636 let tracking_id = hasher.finish().to_le_bytes();
637 Self {
638 tracking_id,
639 kind: ConsensusTransactionKind::CheckpointSignature(Box::new(data)),
640 }
641 }
642
643 pub fn new_checkpoint_signature_message_v2(data: CheckpointSignatureMessage) -> Self {
644 let mut hasher = DefaultHasher::new();
645 data.summary.auth_sig().signature.hash(&mut hasher);
646 let tracking_id = hasher.finish().to_le_bytes();
647 Self {
648 tracking_id,
649 kind: ConsensusTransactionKind::CheckpointSignatureV2(Box::new(data)),
650 }
651 }
652
653 pub fn new_end_of_publish(authority: AuthorityName) -> Self {
654 let mut hasher = DefaultHasher::new();
655 authority.hash(&mut hasher);
656 let tracking_id = hasher.finish().to_le_bytes();
657 Self {
658 tracking_id,
659 kind: ConsensusTransactionKind::EndOfPublish(authority),
660 }
661 }
662
663 pub fn new_capability_notification(capabilities: AuthorityCapabilitiesV1) -> Self {
664 let mut hasher = DefaultHasher::new();
665 capabilities.hash(&mut hasher);
666 let tracking_id = hasher.finish().to_le_bytes();
667 Self {
668 tracking_id,
669 kind: ConsensusTransactionKind::CapabilityNotification(capabilities),
670 }
671 }
672
673 pub fn new_capability_notification_v2(capabilities: AuthorityCapabilitiesV2) -> Self {
674 let mut hasher = DefaultHasher::new();
675 capabilities.hash(&mut hasher);
676 let tracking_id = hasher.finish().to_le_bytes();
677 Self {
678 tracking_id,
679 kind: ConsensusTransactionKind::CapabilityNotificationV2(capabilities),
680 }
681 }
682
683 pub fn new_mysticeti_certificate(
684 round: u64,
685 offset: u64,
686 certificate: CertifiedTransaction,
687 ) -> Self {
688 let mut hasher = DefaultHasher::new();
689 let tx_digest = certificate.digest();
690 tx_digest.hash(&mut hasher);
691 round.hash(&mut hasher);
692 offset.hash(&mut hasher);
693 let tracking_id = hasher.finish().to_le_bytes();
694 Self {
695 tracking_id,
696 kind: ConsensusTransactionKind::CertifiedTransaction(Box::new(certificate)),
697 }
698 }
699
700 pub fn new_jwk_fetched(authority: AuthorityName, id: JwkId, jwk: JWK) -> Self {
701 let mut hasher = DefaultHasher::new();
702 id.hash(&mut hasher);
703 let tracking_id = hasher.finish().to_le_bytes();
704 Self {
705 tracking_id,
706 kind: ConsensusTransactionKind::NewJWKFetched(authority, id, jwk),
707 }
708 }
709
710 pub fn new_randomness_dkg_message(
711 authority: AuthorityName,
712 versioned_message: &VersionedDkgMessage,
713 ) -> Self {
714 let message =
715 bcs::to_bytes(versioned_message).expect("message serialization should not fail");
716 let mut hasher = DefaultHasher::new();
717 message.hash(&mut hasher);
718 let tracking_id = hasher.finish().to_le_bytes();
719 Self {
720 tracking_id,
721 kind: ConsensusTransactionKind::RandomnessDkgMessage(authority, message),
722 }
723 }
724 pub fn new_randomness_dkg_confirmation(
725 authority: AuthorityName,
726 versioned_confirmation: &VersionedDkgConfirmation,
727 ) -> Self {
728 let confirmation =
729 bcs::to_bytes(versioned_confirmation).expect("message serialization should not fail");
730 let mut hasher = DefaultHasher::new();
731 confirmation.hash(&mut hasher);
732 let tracking_id = hasher.finish().to_le_bytes();
733 Self {
734 tracking_id,
735 kind: ConsensusTransactionKind::RandomnessDkgConfirmation(authority, confirmation),
736 }
737 }
738
739 pub fn new_execution_time_observation(observation: ExecutionTimeObservation) -> Self {
740 let mut hasher = DefaultHasher::new();
741 observation.hash(&mut hasher);
742 let tracking_id = hasher.finish().to_le_bytes();
743 Self {
744 tracking_id,
745 kind: ConsensusTransactionKind::ExecutionTimeObservation(observation),
746 }
747 }
748
749 pub fn get_tracking_id(&self) -> u64 {
750 (&self.tracking_id[..])
751 .read_u64::<BigEndian>()
752 .unwrap_or_default()
753 }
754
755 pub fn key(&self) -> ConsensusTransactionKey {
756 match &self.kind {
757 ConsensusTransactionKind::CertifiedTransaction(cert) => {
758 ConsensusTransactionKey::Certificate(*cert.digest())
759 }
760 ConsensusTransactionKind::CheckpointSignature(data) => {
761 ConsensusTransactionKey::CheckpointSignature(
762 data.summary.auth_sig().authority,
763 data.summary.sequence_number,
764 )
765 }
766 ConsensusTransactionKind::CheckpointSignatureV2(data) => {
767 ConsensusTransactionKey::CheckpointSignatureV2(
768 data.summary.auth_sig().authority,
769 data.summary.sequence_number,
770 *data.summary.digest(),
771 )
772 }
773 ConsensusTransactionKind::EndOfPublish(authority) => {
774 ConsensusTransactionKey::EndOfPublish(*authority)
775 }
776 ConsensusTransactionKind::CapabilityNotification(cap) => {
777 ConsensusTransactionKey::CapabilityNotification(cap.authority, cap.generation)
778 }
779 ConsensusTransactionKind::CapabilityNotificationV2(cap) => {
780 ConsensusTransactionKey::CapabilityNotification(cap.authority, cap.generation)
781 }
782 ConsensusTransactionKind::NewJWKFetched(authority, id, key) => {
783 ConsensusTransactionKey::NewJWKFetched(Box::new((
784 *authority,
785 id.clone(),
786 key.clone(),
787 )))
788 }
789 ConsensusTransactionKind::RandomnessStateUpdate(_, _) => {
790 unreachable!(
791 "there should never be a RandomnessStateUpdate with SequencedConsensusTransactionKind::External"
792 )
793 }
794 ConsensusTransactionKind::RandomnessDkgMessage(authority, _) => {
795 ConsensusTransactionKey::RandomnessDkgMessage(*authority)
796 }
797 ConsensusTransactionKind::RandomnessDkgConfirmation(authority, _) => {
798 ConsensusTransactionKey::RandomnessDkgConfirmation(*authority)
799 }
800 ConsensusTransactionKind::UserTransaction(tx) => {
801 ConsensusTransactionKey::Certificate(*tx.digest())
805 }
806 ConsensusTransactionKind::UserTransactionV2(tx) => {
807 ConsensusTransactionKey::Certificate(*tx.tx().digest())
811 }
812 ConsensusTransactionKind::ExecutionTimeObservation(msg) => {
813 ConsensusTransactionKey::ExecutionTimeObservation(msg.authority, msg.generation)
814 }
815 }
816 }
817
818 pub fn is_dkg(&self) -> bool {
819 matches!(
820 self.kind,
821 ConsensusTransactionKind::RandomnessDkgMessage(_, _)
822 | ConsensusTransactionKind::RandomnessDkgConfirmation(_, _)
823 )
824 }
825
826 pub fn is_mfp_transaction(&self) -> bool {
827 matches!(
828 self.kind,
829 ConsensusTransactionKind::UserTransaction(_)
830 | ConsensusTransactionKind::UserTransactionV2(_)
831 )
832 }
833
834 pub fn is_user_transaction(&self) -> bool {
835 matches!(
836 self.kind,
837 ConsensusTransactionKind::UserTransaction(_)
838 | ConsensusTransactionKind::UserTransactionV2(_)
839 | ConsensusTransactionKind::CertifiedTransaction(_)
840 )
841 }
842
843 pub fn is_end_of_publish(&self) -> bool {
844 matches!(self.kind, ConsensusTransactionKind::EndOfPublish(_))
845 }
846}
847
848#[test]
849fn test_jwk_compatibility() {
850 let jwk = JWK {
855 kty: "a".to_string(),
856 e: "b".to_string(),
857 n: "c".to_string(),
858 alg: "d".to_string(),
859 };
860
861 let expected_jwk_bytes = vec![1, 97, 1, 98, 1, 99, 1, 100];
862 let jwk_bcs = bcs::to_bytes(&jwk).unwrap();
863 assert_eq!(jwk_bcs, expected_jwk_bytes);
864
865 let id = JwkId {
866 iss: "abc".to_string(),
867 kid: "def".to_string(),
868 };
869
870 let expected_id_bytes = vec![3, 97, 98, 99, 3, 100, 101, 102];
871 let id_bcs = bcs::to_bytes(&id).unwrap();
872 assert_eq!(id_bcs, expected_id_bytes);
873}