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, PlainTransactionWithClaims, Transaction};
17use crate::transaction_deny_rules::TransactionDenyRules;
18use byteorder::{BigEndian, ReadBytesExt};
19use bytes::Bytes;
20use consensus_types::block::{BlockRef, PING_TRANSACTION_INDEX, TransactionIndex};
21use fastcrypto::error::FastCryptoResult;
22use fastcrypto::groups::bls12381;
23use fastcrypto_tbls::dkg_v1;
24use fastcrypto_zkp::bn254::zk_login::{JWK, JwkId};
25use mysten_common::debug_fatal;
26use schemars::JsonSchema;
27use serde::{Deserialize, Serialize};
28use std::collections::hash_map::DefaultHasher;
29use std::fmt::{Debug, Formatter};
30use std::hash::{Hash, Hasher};
31use std::time::{Duration, SystemTime, UNIX_EPOCH};
32
33pub type AuthorityIndex = u32;
36
37pub type Round = u64;
40
41pub type TimestampMs = u64;
44
45#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
47pub struct ConsensusPosition {
48 pub epoch: EpochId,
50 pub block: BlockRef,
52 pub index: TransactionIndex,
54}
55
56impl ConsensusPosition {
57 pub fn into_raw(self) -> Result<Bytes, SuiError> {
58 bcs::to_bytes(&self)
59 .map_err(|e| {
60 SuiErrorKind::GrpcMessageSerializeError {
61 type_info: "ConsensusPosition".to_string(),
62 error: e.to_string(),
63 }
64 .into()
65 })
66 .map(Bytes::from)
67 }
68
69 pub fn ping(epoch: EpochId, block: BlockRef) -> Self {
72 Self {
73 epoch,
74 block,
75 index: PING_TRANSACTION_INDEX,
76 }
77 }
78}
79
80impl TryFrom<&[u8]> for ConsensusPosition {
81 type Error = SuiError;
82
83 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
84 bcs::from_bytes(bytes).map_err(|e| {
85 SuiErrorKind::GrpcMessageDeserializeError {
86 type_info: "ConsensusPosition".to_string(),
87 error: e.to_string(),
88 }
89 .into()
90 })
91 }
92}
93
94impl std::fmt::Display for ConsensusPosition {
95 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
96 write!(f, "P(E{}, {}, {})", self.epoch, self.block, self.index)
97 }
98}
99
100impl std::fmt::Debug for ConsensusPosition {
101 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
102 write!(f, "P(E{}, {:?}, {})", self.epoch, self.block, self.index)
103 }
104}
105
106#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
109pub struct ConsensusCommitPrologue {
110 pub epoch: u64,
112 pub round: u64,
114 pub commit_timestamp_ms: TimestampMs,
116}
117
118#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
119pub struct ConsensusCommitPrologueV2 {
120 pub epoch: u64,
122 pub round: u64,
124 pub commit_timestamp_ms: TimestampMs,
126 pub consensus_commit_digest: ConsensusCommitDigest,
128}
129
130#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, JsonSchema)]
131pub enum ConsensusDeterminedVersionAssignments {
132 CancelledTransactions(Vec<(TransactionDigest, Vec<(ObjectID, SequenceNumber)>)>),
134 CancelledTransactionsV2(
135 Vec<(
136 TransactionDigest,
137 Vec<(ConsensusObjectSequenceKey, SequenceNumber)>,
138 )>,
139 ),
140}
141
142impl ConsensusDeterminedVersionAssignments {
143 pub fn empty_for_testing() -> Self {
144 Self::CancelledTransactions(Vec::new())
145 }
146}
147
148#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
149pub struct ConsensusCommitPrologueV3 {
150 pub epoch: u64,
152 pub round: u64,
154 pub sub_dag_index: Option<u64>,
157 pub commit_timestamp_ms: TimestampMs,
159 pub consensus_commit_digest: ConsensusCommitDigest,
161 pub consensus_determined_version_assignments: ConsensusDeterminedVersionAssignments,
163}
164
165#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
166pub struct ConsensusCommitPrologueV4 {
167 pub epoch: u64,
169 pub round: u64,
171 pub sub_dag_index: Option<u64>,
174 pub commit_timestamp_ms: TimestampMs,
176 pub consensus_commit_digest: ConsensusCommitDigest,
178 pub consensus_determined_version_assignments: ConsensusDeterminedVersionAssignments,
180 pub additional_state_digest: AdditionalConsensusStateDigest,
183}
184
185static MAX_TOTAL_JWK_SIZE: usize = 4096;
188
189pub fn check_total_jwk_size(id: &JwkId, jwk: &JWK) -> bool {
190 id.iss.len() + id.kid.len() + jwk.kty.len() + jwk.alg.len() + jwk.e.len() + jwk.n.len()
191 <= MAX_TOTAL_JWK_SIZE
192}
193
194#[derive(Serialize, Deserialize, Clone, Debug)]
195pub struct ConsensusTransaction {
196 pub tracking_id: [u8; 8],
199 pub kind: ConsensusTransactionKind,
200}
201
202impl ConsensusTransaction {
203 pub fn local_display(&self) -> String {
205 match &self.kind {
206 ConsensusTransactionKind::CertifiedTransaction(cert) => {
207 format!("Certified({})", cert.digest())
208 }
209 ConsensusTransactionKind::CheckpointSignature(data) => {
210 format!(
211 "CkptSig({}, {})",
212 data.summary.sequence_number,
213 data.summary.digest()
214 )
215 }
216 ConsensusTransactionKind::CheckpointSignatureV2(data) => {
217 format!(
218 "CkptSigV2({}, {})",
219 data.summary.sequence_number,
220 data.summary.digest()
221 )
222 }
223 ConsensusTransactionKind::EndOfPublish(..) => "EOP".to_string(),
224 ConsensusTransactionKind::CapabilityNotification(..) => "Cap".to_string(),
225 ConsensusTransactionKind::CapabilityNotificationV2(..) => "CapV2".to_string(),
226 ConsensusTransactionKind::NewJWKFetched(..) => "NewJWKFetched".to_string(),
227 ConsensusTransactionKind::RandomnessStateUpdate(..) => "RandStateUpdate".to_string(),
228 ConsensusTransactionKind::RandomnessDkgMessage(..) => "RandDkg".to_string(),
229 ConsensusTransactionKind::RandomnessDkgConfirmation(..) => "RandDkgConf".to_string(),
230 ConsensusTransactionKind::ExecutionTimeObservation(..) => "ExecTimeOb".to_string(),
231 ConsensusTransactionKind::UserTransaction(tx) => {
232 format!("User({})", tx.digest())
233 }
234 ConsensusTransactionKind::UserTransactionV2(tx) => {
235 format!("UserV2({})", tx.tx().digest())
236 }
237 ConsensusTransactionKind::UpdateTransactionDenyConfig(msg) => {
238 format!(
239 "UpdateDenyConfig({}, gen={})",
240 msg.authority().concise(),
241 msg.generation()
242 )
243 }
244 }
245 }
246}
247
248#[derive(Serialize, Deserialize, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
250pub enum ConsensusTransactionKey {
251 Certificate(TransactionDigest),
252 CheckpointSignature(AuthorityName, CheckpointSequenceNumber),
254 EndOfPublish(AuthorityName),
255 CapabilityNotification(AuthorityName, u64 ),
256 NewJWKFetched(Box<(AuthorityName, JwkId, JWK)>),
259 RandomnessDkgMessage(AuthorityName),
260 RandomnessDkgConfirmation(AuthorityName),
261 ExecutionTimeObservation(AuthorityName, u64 ),
262 CheckpointSignatureV2(AuthorityName, CheckpointSequenceNumber, CheckpointDigest),
264 RandomnessStateUpdate,
266 UpdateTransactionDenyConfig(AuthorityName, u64),
268}
269
270impl Debug for ConsensusTransactionKey {
271 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
272 match self {
273 Self::Certificate(digest) => write!(f, "Certificate({:?})", digest),
274 Self::CheckpointSignature(name, seq) => {
275 write!(f, "CheckpointSignature({:?}, {:?})", name.concise(), seq)
276 }
277 Self::CheckpointSignatureV2(name, seq, digest) => write!(
278 f,
279 "CheckpointSignatureV2({:?}, {:?}, {:?})",
280 name.concise(),
281 seq,
282 digest
283 ),
284 Self::EndOfPublish(name) => write!(f, "EndOfPublish({:?})", name.concise()),
285 Self::CapabilityNotification(name, generation) => write!(
286 f,
287 "CapabilityNotification({:?}, {:?})",
288 name.concise(),
289 generation
290 ),
291 Self::NewJWKFetched(key) => {
292 let (authority, id, jwk) = &**key;
293 write!(
294 f,
295 "NewJWKFetched({:?}, {:?}, {:?})",
296 authority.concise(),
297 id,
298 jwk
299 )
300 }
301 Self::RandomnessDkgMessage(name) => {
302 write!(f, "RandomnessDkgMessage({:?})", name.concise())
303 }
304 Self::RandomnessDkgConfirmation(name) => {
305 write!(f, "RandomnessDkgConfirmation({:?})", name.concise())
306 }
307 Self::ExecutionTimeObservation(name, generation) => {
308 write!(
309 f,
310 "ExecutionTimeObservation({:?}, {generation:?})",
311 name.concise()
312 )
313 }
314 Self::RandomnessStateUpdate => {
315 write!(f, "RandomnessStateUpdate")
316 }
317 Self::UpdateTransactionDenyConfig(name, generation) => write!(
318 f,
319 "UpdateTransactionDenyConfig({:?}, {generation:?})",
320 name.concise()
321 ),
322 }
323 }
324}
325
326#[derive(Serialize, Deserialize, Clone, Hash, Debug, PartialEq, Eq)]
327pub enum SharedTransactionDenyConfig {
328 V1(SharedTransactionDenyConfigV1),
329}
330
331impl SharedTransactionDenyConfig {
332 pub const MAX_GENERATION_FUTURE_DRIFT_MS: u64 = 60_000;
335
336 pub fn authority(&self) -> AuthorityName {
337 match self {
338 Self::V1(inner) => inner.authority,
339 }
340 }
341
342 pub fn generation(&self) -> u64 {
343 match self {
344 Self::V1(inner) => inner.generation,
345 }
346 }
347
348 pub fn rules(&self) -> Option<&TransactionDenyRules> {
349 match self {
350 Self::V1(inner) => inner.rules.as_ref(),
351 }
352 }
353}
354
355#[derive(Serialize, Deserialize, Clone, Hash, Debug, PartialEq, Eq)]
356pub struct SharedTransactionDenyConfigV1 {
357 pub authority: AuthorityName,
359 pub generation: u64,
363 pub rules: Option<TransactionDenyRules>,
365}
366
367#[derive(Serialize, Deserialize, Clone, Hash)]
371pub struct AuthorityCapabilitiesV1 {
372 pub authority: AuthorityName,
374 pub generation: u64,
380
381 pub supported_protocol_versions: SupportedProtocolVersions,
383
384 pub available_system_packages: Vec<ObjectRef>,
387}
388
389impl Debug for AuthorityCapabilitiesV1 {
390 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
391 f.debug_struct("AuthorityCapabilities")
392 .field("authority", &self.authority.concise())
393 .field("generation", &self.generation)
394 .field(
395 "supported_protocol_versions",
396 &self.supported_protocol_versions,
397 )
398 .field("available_system_packages", &self.available_system_packages)
399 .finish()
400 }
401}
402
403#[derive(Serialize, Deserialize, Clone, Hash)]
406pub struct AuthorityCapabilitiesV2 {
407 pub authority: AuthorityName,
409 pub generation: u64,
415
416 pub supported_protocol_versions: SupportedProtocolVersionsWithHashes,
418
419 pub available_system_packages: Vec<ObjectRef>,
422}
423
424impl Debug for AuthorityCapabilitiesV2 {
425 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
426 f.debug_struct("AuthorityCapabilities")
427 .field("authority", &self.authority.concise())
428 .field("generation", &self.generation)
429 .field(
430 "supported_protocol_versions",
431 &self.supported_protocol_versions,
432 )
433 .field("available_system_packages", &self.available_system_packages)
434 .finish()
435 }
436}
437
438impl AuthorityCapabilitiesV2 {
439 pub fn new(
440 authority: AuthorityName,
441 chain: Chain,
442 supported_protocol_versions: SupportedProtocolVersions,
443 available_system_packages: Vec<ObjectRef>,
444 ) -> Self {
445 let generation = SystemTime::now()
446 .duration_since(UNIX_EPOCH)
447 .expect("Sui did not exist prior to 1970")
448 .as_millis()
449 .try_into()
450 .expect("This build of sui is not supported in the year 500,000,000");
451 Self {
452 authority,
453 generation,
454 supported_protocol_versions:
455 SupportedProtocolVersionsWithHashes::from_supported_versions(
456 supported_protocol_versions,
457 chain,
458 ),
459 available_system_packages,
460 }
461 }
462}
463
464#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
467pub struct ExecutionTimeObservation {
468 pub authority: AuthorityName,
470 pub generation: u64,
473
474 pub estimates: Vec<(ExecutionTimeObservationKey, Duration)>,
476}
477
478impl ExecutionTimeObservation {
479 pub fn new(
480 authority: AuthorityName,
481 generation: u64,
482 estimates: Vec<(ExecutionTimeObservationKey, Duration)>,
483 ) -> Self {
484 Self {
485 authority,
486 generation,
487 estimates,
488 }
489 }
490}
491
492#[derive(Serialize, Deserialize, Clone, Debug)]
493pub enum ConsensusTransactionKind {
494 CertifiedTransaction(Box<CertifiedTransaction>),
495 CheckpointSignature(Box<CheckpointSignatureMessage>), EndOfPublish(AuthorityName),
497
498 CapabilityNotification(AuthorityCapabilitiesV1), NewJWKFetched(AuthorityName, JwkId, JWK),
501 RandomnessStateUpdate(u64, Vec<u8>), RandomnessDkgMessage(AuthorityName, Vec<u8>),
506 RandomnessDkgConfirmation(AuthorityName, Vec<u8>),
510
511 CapabilityNotificationV2(AuthorityCapabilitiesV2),
512
513 UserTransaction(Box<Transaction>),
514
515 ExecutionTimeObservation(ExecutionTimeObservation),
516 CheckpointSignatureV2(Box<CheckpointSignatureMessage>),
518
519 UserTransactionV2(Box<PlainTransactionWithClaims>),
523
524 UpdateTransactionDenyConfig(Box<SharedTransactionDenyConfig>),
527}
528
529impl ConsensusTransactionKind {
530 pub fn as_user_transaction(&self) -> Option<&Transaction> {
531 match self {
532 ConsensusTransactionKind::UserTransactionV2(tx) => Some(tx.tx()),
533 _ => None,
534 }
535 }
536
537 pub fn into_user_transaction(self) -> Option<Transaction> {
538 match self {
539 ConsensusTransactionKind::UserTransactionV2(tx) => Some(tx.into_tx()),
540 _ => None,
541 }
542 }
543}
544
545#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
546#[allow(clippy::large_enum_variant)]
547pub enum VersionedDkgMessage {
548 V0(), V1(dkg_v1::Message<bls12381::G2Element, bls12381::G2Element>),
550}
551
552#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
553pub enum VersionedDkgConfirmation {
554 V0(), V1(dkg_v1::Confirmation<bls12381::G2Element>),
556}
557
558impl Debug for VersionedDkgMessage {
559 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
560 match self {
561 VersionedDkgMessage::V0() => write!(f, "Deprecated VersionedDkgMessage version 0"),
562 VersionedDkgMessage::V1(msg) => write!(
563 f,
564 "DKG V1 Message with sender={}, vss_pk.degree={}, encrypted_shares.len()={}",
565 msg.sender,
566 msg.vss_pk.degree(),
567 msg.encrypted_shares.len(),
568 ),
569 }
570 }
571}
572
573impl VersionedDkgMessage {
574 pub fn sender(&self) -> u16 {
575 match self {
576 VersionedDkgMessage::V0() => panic!("BUG: invalid VersionedDkgMessage version"),
577 VersionedDkgMessage::V1(msg) => msg.sender,
578 }
579 }
580
581 pub fn create(
582 dkg_version: u64,
583 party: &dkg_v1::Party<bls12381::G2Element, bls12381::G2Element>,
584 ) -> FastCryptoResult<VersionedDkgMessage> {
585 assert_eq!(dkg_version, 1, "BUG: invalid DKG version");
586 let msg = party.create_message(&mut rand::thread_rng())?;
587 Ok(VersionedDkgMessage::V1(msg))
588 }
589
590 pub fn unwrap_v1(self) -> dkg_v1::Message<bls12381::G2Element, bls12381::G2Element> {
591 match self {
592 VersionedDkgMessage::V1(msg) => msg,
593 _ => panic!("BUG: expected V1 message"),
594 }
595 }
596
597 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
598 matches!((self, dkg_version), (VersionedDkgMessage::V1(_), 1))
599 }
600}
601
602impl VersionedDkgConfirmation {
603 pub fn sender(&self) -> u16 {
604 match self {
605 VersionedDkgConfirmation::V0() => {
606 panic!("BUG: invalid VersionedDkgConfirmation version")
607 }
608 VersionedDkgConfirmation::V1(msg) => msg.sender,
609 }
610 }
611
612 pub fn num_of_complaints(&self) -> usize {
613 match self {
614 VersionedDkgConfirmation::V0() => {
615 panic!("BUG: invalid VersionedDkgConfirmation version")
616 }
617 VersionedDkgConfirmation::V1(msg) => msg.complaints.len(),
618 }
619 }
620
621 pub fn as_v1(&self) -> Option<&dkg_v1::Confirmation<bls12381::G2Element>> {
622 match self {
623 VersionedDkgConfirmation::V1(msg) => Some(msg),
624 _ => None,
625 }
626 }
627
628 pub fn is_valid_version(&self, dkg_version: u64) -> bool {
629 matches!((self, dkg_version), (VersionedDkgConfirmation::V1(_), 1))
630 }
631}
632
633impl ConsensusTransaction {
634 pub fn new_user_transaction_v2_message(
635 authority: &AuthorityName,
636 tx: PlainTransactionWithClaims,
637 ) -> Self {
638 let mut hasher = DefaultHasher::new();
639 let tx_digest = tx.tx().digest();
640 tx_digest.hash(&mut hasher);
641 authority.hash(&mut hasher);
642 let tracking_id = hasher.finish().to_le_bytes();
643 Self {
644 tracking_id,
645 kind: ConsensusTransactionKind::UserTransactionV2(Box::new(tx)),
646 }
647 }
648
649 pub fn new_checkpoint_signature_message_v2(data: CheckpointSignatureMessage) -> Self {
650 let mut hasher = DefaultHasher::new();
651 data.summary.auth_sig().signature.hash(&mut hasher);
652 let tracking_id = hasher.finish().to_le_bytes();
653 Self {
654 tracking_id,
655 kind: ConsensusTransactionKind::CheckpointSignatureV2(Box::new(data)),
656 }
657 }
658
659 pub fn new_end_of_publish(authority: AuthorityName) -> Self {
660 let mut hasher = DefaultHasher::new();
661 authority.hash(&mut hasher);
662 let tracking_id = hasher.finish().to_le_bytes();
663 Self {
664 tracking_id,
665 kind: ConsensusTransactionKind::EndOfPublish(authority),
666 }
667 }
668
669 pub fn new_capability_notification_v2(capabilities: AuthorityCapabilitiesV2) -> Self {
670 let mut hasher = DefaultHasher::new();
671 capabilities.hash(&mut hasher);
672 let tracking_id = hasher.finish().to_le_bytes();
673 Self {
674 tracking_id,
675 kind: ConsensusTransactionKind::CapabilityNotificationV2(capabilities),
676 }
677 }
678
679 pub fn new_jwk_fetched(authority: AuthorityName, id: JwkId, jwk: JWK) -> Self {
680 let mut hasher = DefaultHasher::new();
681 id.hash(&mut hasher);
682 let tracking_id = hasher.finish().to_le_bytes();
683 Self {
684 tracking_id,
685 kind: ConsensusTransactionKind::NewJWKFetched(authority, id, jwk),
686 }
687 }
688
689 pub fn new_randomness_dkg_message(
690 authority: AuthorityName,
691 versioned_message: &VersionedDkgMessage,
692 ) -> Self {
693 let message =
694 bcs::to_bytes(versioned_message).expect("message serialization should not fail");
695 let mut hasher = DefaultHasher::new();
696 message.hash(&mut hasher);
697 let tracking_id = hasher.finish().to_le_bytes();
698 Self {
699 tracking_id,
700 kind: ConsensusTransactionKind::RandomnessDkgMessage(authority, message),
701 }
702 }
703 pub fn new_randomness_dkg_confirmation(
704 authority: AuthorityName,
705 versioned_confirmation: &VersionedDkgConfirmation,
706 ) -> Self {
707 let confirmation =
708 bcs::to_bytes(versioned_confirmation).expect("message serialization should not fail");
709 let mut hasher = DefaultHasher::new();
710 confirmation.hash(&mut hasher);
711 let tracking_id = hasher.finish().to_le_bytes();
712 Self {
713 tracking_id,
714 kind: ConsensusTransactionKind::RandomnessDkgConfirmation(authority, confirmation),
715 }
716 }
717
718 pub fn new_execution_time_observation(observation: ExecutionTimeObservation) -> Self {
719 let mut hasher = DefaultHasher::new();
720 observation.hash(&mut hasher);
721 let tracking_id = hasher.finish().to_le_bytes();
722 Self {
723 tracking_id,
724 kind: ConsensusTransactionKind::ExecutionTimeObservation(observation),
725 }
726 }
727
728 pub fn new_update_transaction_deny_config(msg: SharedTransactionDenyConfig) -> Self {
729 let mut hasher = DefaultHasher::new();
730 msg.hash(&mut hasher);
731 let tracking_id = hasher.finish().to_le_bytes();
732 Self {
733 tracking_id,
734 kind: ConsensusTransactionKind::UpdateTransactionDenyConfig(Box::new(msg)),
735 }
736 }
737
738 pub fn get_tracking_id(&self) -> u64 {
739 (&self.tracking_id[..])
740 .read_u64::<BigEndian>()
741 .unwrap_or_default()
742 }
743
744 pub fn key(&self) -> ConsensusTransactionKey {
745 match &self.kind {
746 ConsensusTransactionKind::CertifiedTransaction(cert) => {
747 ConsensusTransactionKey::Certificate(*cert.digest())
748 }
749 ConsensusTransactionKind::CheckpointSignature(data) => {
750 ConsensusTransactionKey::CheckpointSignature(
751 data.summary.auth_sig().authority,
752 data.summary.sequence_number,
753 )
754 }
755 ConsensusTransactionKind::CheckpointSignatureV2(data) => {
756 ConsensusTransactionKey::CheckpointSignatureV2(
757 data.summary.auth_sig().authority,
758 data.summary.sequence_number,
759 *data.summary.digest(),
760 )
761 }
762 ConsensusTransactionKind::EndOfPublish(authority) => {
763 ConsensusTransactionKey::EndOfPublish(*authority)
764 }
765 ConsensusTransactionKind::CapabilityNotification(cap) => {
766 ConsensusTransactionKey::CapabilityNotification(cap.authority, cap.generation)
767 }
768 ConsensusTransactionKind::CapabilityNotificationV2(cap) => {
769 ConsensusTransactionKey::CapabilityNotification(cap.authority, cap.generation)
770 }
771 ConsensusTransactionKind::NewJWKFetched(authority, id, key) => {
772 ConsensusTransactionKey::NewJWKFetched(Box::new((
773 *authority,
774 id.clone(),
775 key.clone(),
776 )))
777 }
778 ConsensusTransactionKind::RandomnessStateUpdate(_, _) => {
779 debug_fatal!(
780 "there should never be a RandomnessStateUpdate with SequencedConsensusTransactionKind::External"
781 );
782 ConsensusTransactionKey::RandomnessStateUpdate
783 }
784 ConsensusTransactionKind::RandomnessDkgMessage(authority, _) => {
785 ConsensusTransactionKey::RandomnessDkgMessage(*authority)
786 }
787 ConsensusTransactionKind::RandomnessDkgConfirmation(authority, _) => {
788 ConsensusTransactionKey::RandomnessDkgConfirmation(*authority)
789 }
790 ConsensusTransactionKind::UserTransaction(tx) => {
791 ConsensusTransactionKey::Certificate(*tx.digest())
795 }
796 ConsensusTransactionKind::UserTransactionV2(tx) => {
797 ConsensusTransactionKey::Certificate(*tx.tx().digest())
801 }
802 ConsensusTransactionKind::ExecutionTimeObservation(msg) => {
803 ConsensusTransactionKey::ExecutionTimeObservation(msg.authority, msg.generation)
804 }
805 ConsensusTransactionKind::UpdateTransactionDenyConfig(msg) => {
806 ConsensusTransactionKey::UpdateTransactionDenyConfig(
807 msg.authority(),
808 msg.generation(),
809 )
810 }
811 }
812 }
813
814 pub fn is_dkg(&self) -> bool {
815 matches!(
816 self.kind,
817 ConsensusTransactionKind::RandomnessDkgMessage(_, _)
818 | ConsensusTransactionKind::RandomnessDkgConfirmation(_, _)
819 )
820 }
821
822 pub fn is_user_transaction(&self) -> bool {
823 matches!(self.kind, ConsensusTransactionKind::UserTransactionV2(_))
825 }
826
827 pub fn is_end_of_publish(&self) -> bool {
828 matches!(self.kind, ConsensusTransactionKind::EndOfPublish(_))
829 }
830}
831
832#[test]
833fn test_shared_transaction_deny_config_bcs_roundtrip() {
834 use crate::base_types::{ObjectID, SuiAddress};
835 use crate::transaction_deny_rules::TransactionDenyRules;
836 use std::collections::BTreeSet;
837
838 let authority = AuthorityName::new([7u8; 96]);
839 let mut rules = TransactionDenyRules::default();
840 rules.object_deny_list.insert(ObjectID::new([1u8; 32]));
841 rules.object_deny_list.insert(ObjectID::new([2u8; 32]));
842 rules
843 .address_deny_list
844 .insert(SuiAddress::from_bytes([3u8; 32]).unwrap());
845 rules.user_transaction_disabled = true;
846 let mut providers: BTreeSet<String> = BTreeSet::new();
847 providers.insert("Google".to_string());
848 rules.zklogin_disabled_providers = providers;
849
850 let msg = SharedTransactionDenyConfig::V1(SharedTransactionDenyConfigV1 {
851 authority,
852 generation: 12345,
853 rules: Some(rules),
854 });
855 let consensus_tx = ConsensusTransaction::new_update_transaction_deny_config(msg.clone());
856
857 let bytes = bcs::to_bytes(&consensus_tx).unwrap();
860 let decoded: ConsensusTransaction = bcs::from_bytes(&bytes).unwrap();
861 assert_eq!(decoded.tracking_id, consensus_tx.tracking_id);
862 let decoded_msg = match decoded.kind {
863 ConsensusTransactionKind::UpdateTransactionDenyConfig(m) => *m,
864 other => panic!("unexpected kind: {other:?}"),
865 };
866 assert_eq!(decoded_msg, msg);
867
868 let key = consensus_tx.key();
871 match key {
872 ConsensusTransactionKey::UpdateTransactionDenyConfig(name, generation) => {
873 assert_eq!(name, authority);
874 assert_eq!(generation, 12345);
875 }
876 other => panic!("unexpected key: {other:?}"),
877 }
878}
879
880#[test]
881fn test_shared_transaction_deny_config_withdrawal_bcs_roundtrip() {
882 let authority = AuthorityName::new([9u8; 96]);
883 let msg = SharedTransactionDenyConfig::V1(SharedTransactionDenyConfigV1 {
884 authority,
885 generation: 99,
886 rules: None,
887 });
888 let consensus_tx = ConsensusTransaction::new_update_transaction_deny_config(msg.clone());
889 let bytes = bcs::to_bytes(&consensus_tx).unwrap();
890 let decoded: ConsensusTransaction = bcs::from_bytes(&bytes).unwrap();
891 let decoded_msg = match decoded.kind {
892 ConsensusTransactionKind::UpdateTransactionDenyConfig(m) => *m,
893 other => panic!("unexpected kind: {other:?}"),
894 };
895 assert_eq!(decoded_msg, msg);
896 assert!(decoded_msg.rules().is_none());
897}
898
899#[test]
900fn test_jwk_compatibility() {
901 let jwk = JWK {
906 kty: "a".to_string(),
907 e: "b".to_string(),
908 n: "c".to_string(),
909 alg: "d".to_string(),
910 };
911
912 let expected_jwk_bytes = vec![1, 97, 1, 98, 1, 99, 1, 100];
913 let jwk_bcs = bcs::to_bytes(&jwk).unwrap();
914 assert_eq!(jwk_bcs, expected_jwk_bytes);
915
916 let id = JwkId {
917 iss: "abc".to_string(),
918 kid: "def".to_string(),
919 };
920
921 let expected_id_bytes = vec![3, 97, 98, 99, 3, 100, 101, 102];
922 let id_bcs = bcs::to_bytes(&id).unwrap();
923 assert_eq!(id_bcs, expected_id_bytes);
924}