1use mysten_common::ZipDebugEqIteratorExt;
5use mysten_common::debug_fatal;
6
7use crate::authority::AuthorityPerEpochStore;
8use crate::authority::authority_per_epoch_store::CancelConsensusCertificateReason;
9use crate::execution_cache::ObjectCacheRead;
10use either::Either;
11use std::collections::BTreeMap;
12use std::collections::HashMap;
13use std::collections::HashSet;
14use sui_types::SUI_ACCUMULATOR_ROOT_OBJECT_ID;
15use sui_types::SUI_CLOCK_OBJECT_ID;
16use sui_types::SUI_CLOCK_OBJECT_SHARED_VERSION;
17use sui_types::SUI_FORWARDING_ADDRESS_REGISTRY_OBJECT_ID;
18use sui_types::base_types::ConsensusObjectSequenceKey;
19use sui_types::base_types::ConsensusObjectVersion;
20use sui_types::base_types::ObjectID;
21use sui_types::base_types::SystemObjectVersions;
22use sui_types::base_types::TransactionDigest;
23use sui_types::committee::EpochId;
24use sui_types::crypto::RandomnessRound;
25use sui_types::effects::{TransactionEffects, TransactionEffectsAPI};
26use sui_types::executable_transaction::VerifiedExecutableTransaction;
27use sui_types::executable_transaction::VerifiedExecutableTransactionWithAliases;
28use sui_types::storage::{
29 ObjectKey, transaction_non_shared_input_object_keys, transaction_receiving_object_keys,
30};
31use sui_types::transaction::SharedObjectMutability;
32use sui_types::transaction::{SharedInputObject, TransactionDataAPI, TransactionKey};
33use sui_types::{
34 IMPLICITLY_READ_SYSTEM_OBJECTS, SUI_RANDOMNESS_STATE_OBJECT_ID, base_types::SequenceNumber,
35 error::SuiResult,
36};
37use tracing::trace;
38
39pub struct SharedObjVerManager {}
40
41#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct AssignedVersions {
44 pub shared_object_versions: Vec<(ConsensusObjectSequenceKey, SequenceNumber)>,
45 pub system_object_versions: SystemObjectVersions,
56}
57
58impl AssignedVersions {
59 pub fn new(
60 shared_object_versions: Vec<(ConsensusObjectSequenceKey, SequenceNumber)>,
61 system_object_versions: SystemObjectVersions,
62 ) -> Self {
63 debug_assert!(
64 shared_object_versions
65 .iter()
66 .filter(|((id, _), version)| {
67 id.is_implicitly_read_system_object() && !version.is_cancelled()
68 })
69 .all(|((id, _), version)| {
70 system_object_versions
71 .get(id)
72 .is_none_or(|system_version| system_version.version == *version)
73 }),
74 "declared versions {shared_object_versions:?} disagree with {system_object_versions:?}"
75 );
76 Self {
77 shared_object_versions,
78 system_object_versions,
79 }
80 }
81
82 pub fn empty() -> Self {
83 Self::new(vec![], SystemObjectVersions::empty())
84 }
85
86 pub fn with_accumulator_version_for_testing(mut self, version: ConsensusObjectVersion) -> Self {
90 self.system_object_versions = SystemObjectVersions::new(
91 Some(version),
92 self.system_object_versions
93 .get(&sui_types::SUI_FORWARDING_ADDRESS_REGISTRY_OBJECT_ID),
94 );
95 self
96 }
97
98 #[cfg(test)]
101 pub fn new_for_testing(
102 shared_object_versions: Vec<(ConsensusObjectSequenceKey, SequenceNumber)>,
103 accumulator_version: Option<SequenceNumber>,
104 ) -> Self {
105 Self::new(
106 shared_object_versions,
107 SystemObjectVersions::new(
108 accumulator_version.map(|v| ConsensusObjectVersion {
109 initial_shared_version: sui_types::object::OBJECT_START_VERSION,
110 version: v,
111 }),
112 None,
113 ),
114 )
115 }
116
117 pub fn accumulator_version(&self) -> Option<SequenceNumber> {
119 self.system_object_versions
120 .get(&SUI_ACCUMULATOR_ROOT_OBJECT_ID)
121 .map(|v| v.version)
122 }
123
124 pub fn iter(&self) -> impl Iterator<Item = &(ConsensusObjectSequenceKey, SequenceNumber)> {
125 self.shared_object_versions.iter()
126 }
127
128 pub fn as_slice(&self) -> &[(ConsensusObjectSequenceKey, SequenceNumber)] {
129 &self.shared_object_versions
130 }
131}
132
133#[derive(Default, Debug, PartialEq, Eq)]
134pub struct AssignedTxAndVersions(pub Vec<(TransactionKey, AssignedVersions)>);
135
136impl AssignedTxAndVersions {
137 pub fn new(assigned_versions: Vec<(TransactionKey, AssignedVersions)>) -> Self {
138 Self(assigned_versions)
139 }
140
141 pub fn into_map(self) -> HashMap<TransactionKey, AssignedVersions> {
142 self.0.into_iter().collect()
143 }
144}
145
146#[derive(Clone)]
149pub enum Schedulable<T = VerifiedExecutableTransaction> {
150 Transaction(T),
151 RandomnessStateUpdate(EpochId, RandomnessRound),
152 AccumulatorSettlement(EpochId, u64 ),
153 ConsensusCommitPrologue(EpochId, u64 , u32 ),
154}
155
156impl From<VerifiedExecutableTransaction> for Schedulable<VerifiedExecutableTransaction> {
157 fn from(tx: VerifiedExecutableTransaction) -> Self {
158 Schedulable::Transaction(tx)
159 }
160}
161
162impl From<Schedulable<VerifiedExecutableTransactionWithAliases>>
163 for Schedulable<VerifiedExecutableTransaction>
164{
165 fn from(schedulable: Schedulable<VerifiedExecutableTransactionWithAliases>) -> Self {
166 match schedulable {
167 Schedulable::Transaction(tx) => Schedulable::Transaction(tx.into_tx()),
168 Schedulable::RandomnessStateUpdate(epoch, round) => {
169 Schedulable::RandomnessStateUpdate(epoch, round)
170 }
171 Schedulable::AccumulatorSettlement(epoch, checkpoint_height) => {
172 Schedulable::AccumulatorSettlement(epoch, checkpoint_height)
173 }
174 Schedulable::ConsensusCommitPrologue(epoch, round, sub_dag_index) => {
175 Schedulable::ConsensusCommitPrologue(epoch, round, sub_dag_index)
176 }
177 }
178 }
179}
180
181pub trait AsTx {
184 fn as_tx(&self) -> &VerifiedExecutableTransaction;
185}
186
187impl AsTx for VerifiedExecutableTransaction {
188 fn as_tx(&self) -> &VerifiedExecutableTransaction {
189 self
190 }
191}
192
193impl AsTx for &'_ VerifiedExecutableTransaction {
194 fn as_tx(&self) -> &VerifiedExecutableTransaction {
195 self
196 }
197}
198
199impl AsTx for VerifiedExecutableTransactionWithAliases {
200 fn as_tx(&self) -> &VerifiedExecutableTransaction {
201 self.tx()
202 }
203}
204
205impl AsTx for &'_ VerifiedExecutableTransactionWithAliases {
206 fn as_tx(&self) -> &VerifiedExecutableTransaction {
207 self.tx()
208 }
209}
210
211impl Schedulable<&'_ VerifiedExecutableTransaction> {
212 pub fn to_owned_schedulable(&self) -> Schedulable<VerifiedExecutableTransaction> {
214 match self {
215 Schedulable::Transaction(tx) => Schedulable::Transaction((*tx).clone()),
216 Schedulable::RandomnessStateUpdate(epoch, round) => {
217 Schedulable::RandomnessStateUpdate(*epoch, *round)
218 }
219 Schedulable::AccumulatorSettlement(epoch, checkpoint_height) => {
220 Schedulable::AccumulatorSettlement(*epoch, *checkpoint_height)
221 }
222 Schedulable::ConsensusCommitPrologue(epoch, round, sub_dag_index) => {
223 Schedulable::ConsensusCommitPrologue(*epoch, *round, *sub_dag_index)
224 }
225 }
226 }
227}
228
229impl<T> Schedulable<T> {
230 pub fn as_tx(&self) -> Option<&VerifiedExecutableTransaction>
231 where
232 T: AsTx,
233 {
234 match self {
235 Schedulable::Transaction(tx) => Some(tx.as_tx()),
236 Schedulable::RandomnessStateUpdate(_, _) => None,
237 Schedulable::AccumulatorSettlement(_, _) => None,
238 Schedulable::ConsensusCommitPrologue(_, _, _) => None,
239 }
240 }
241
242 pub fn shared_input_objects(
243 &self,
244 epoch_store: &AuthorityPerEpochStore,
245 ) -> impl Iterator<Item = SharedInputObject> + '_
246 where
247 T: AsTx,
248 {
249 match self {
250 Schedulable::Transaction(tx) => Either::Left(tx.as_tx().shared_input_objects()),
251 Schedulable::RandomnessStateUpdate(_, _) => {
252 Either::Right(std::iter::once(SharedInputObject {
253 id: SUI_RANDOMNESS_STATE_OBJECT_ID,
254 initial_shared_version: epoch_store
255 .epoch_start_config()
256 .randomness_obj_initial_shared_version()
257 .expect("randomness obj initial shared version should be set"),
258 mutability: SharedObjectMutability::Mutable,
259 }))
260 }
261 Schedulable::AccumulatorSettlement(_, _) => {
262 Either::Right(std::iter::once(SharedInputObject {
263 id: SUI_ACCUMULATOR_ROOT_OBJECT_ID,
264 initial_shared_version: epoch_store
265 .epoch_start_config()
266 .accumulator_root_obj_initial_shared_version()
267 .expect("accumulator root obj initial shared version should be set"),
268 mutability: SharedObjectMutability::Mutable,
269 }))
270 }
271 Schedulable::ConsensusCommitPrologue(_, _, _) => {
272 Either::Right(std::iter::once(SharedInputObject {
273 id: SUI_CLOCK_OBJECT_ID,
274 initial_shared_version: SUI_CLOCK_OBJECT_SHARED_VERSION,
275 mutability: SharedObjectMutability::Mutable,
276 }))
277 }
278 }
279 }
280
281 pub fn non_shared_input_object_keys(&self) -> Vec<ObjectKey>
282 where
283 T: AsTx,
284 {
285 match self {
286 Schedulable::Transaction(tx) => transaction_non_shared_input_object_keys(tx.as_tx())
287 .expect("Transaction input should have been verified"),
288 Schedulable::RandomnessStateUpdate(_, _) => vec![],
289 Schedulable::AccumulatorSettlement(_, _) => vec![],
290 Schedulable::ConsensusCommitPrologue(_, _, _) => vec![],
291 }
292 }
293
294 pub fn receiving_object_keys(&self) -> Vec<ObjectKey>
295 where
296 T: AsTx,
297 {
298 match self {
299 Schedulable::Transaction(tx) => transaction_receiving_object_keys(tx.as_tx()),
300 Schedulable::RandomnessStateUpdate(_, _) => vec![],
301 Schedulable::AccumulatorSettlement(_, _) => vec![],
302 Schedulable::ConsensusCommitPrologue(_, _, _) => vec![],
303 }
304 }
305
306 pub fn key(&self) -> TransactionKey
307 where
308 T: AsTx,
309 {
310 match self {
311 Schedulable::Transaction(tx) => tx.as_tx().key(),
312 Schedulable::RandomnessStateUpdate(epoch, round) => {
313 TransactionKey::RandomnessRound(*epoch, *round)
314 }
315 Schedulable::AccumulatorSettlement(epoch, checkpoint_height) => {
316 TransactionKey::AccumulatorSettlement(*epoch, *checkpoint_height)
317 }
318 Schedulable::ConsensusCommitPrologue(epoch, round, sub_dag_index) => {
319 TransactionKey::ConsensusCommitPrologue(*epoch, *round, *sub_dag_index)
320 }
321 }
322 }
323}
324
325#[must_use]
326#[derive(Default, Eq, PartialEq, Debug)]
327pub struct ConsensusSharedObjVerAssignment {
328 pub shared_input_next_versions: HashMap<ConsensusObjectSequenceKey, SequenceNumber>,
329 pub assigned_versions: AssignedTxAndVersions,
330}
331
332impl SharedObjVerManager {
333 pub fn assign_versions_from_consensus<'a, T>(
334 epoch_store: &AuthorityPerEpochStore,
335 cache_reader: &dyn ObjectCacheRead,
336 assignables: impl Iterator<Item = &'a Schedulable<T>> + Clone,
337 cancelled_txns: &BTreeMap<TransactionDigest, CancelConsensusCertificateReason>,
338 ) -> SuiResult<ConsensusSharedObjVerAssignment>
339 where
340 T: AsTx + 'a,
341 {
342 let mut shared_input_next_versions = get_or_init_versions(
343 assignables
344 .clone()
345 .flat_map(|a| a.shared_input_objects(epoch_store)),
346 epoch_store,
347 cache_reader,
348 )?;
349 let mut assigned_versions = Vec::new();
350 for assignable in assignables {
351 assert!(
352 !matches!(assignable, Schedulable::AccumulatorSettlement(_, _))
353 || epoch_store.accumulators_enabled(),
354 "AccumulatorSettlement should not be scheduled when accumulators are disabled"
355 );
356
357 let cert_assigned_versions = Self::assign_versions_for_certificate(
358 epoch_store,
359 assignable,
360 &mut shared_input_next_versions,
361 cancelled_txns,
362 );
363 assigned_versions.push((assignable.key(), cert_assigned_versions));
364 }
365
366 Ok(ConsensusSharedObjVerAssignment {
367 shared_input_next_versions,
368 assigned_versions: AssignedTxAndVersions::new(assigned_versions),
369 })
370 }
371
372 pub fn assign_versions_from_effects(
373 certs_and_effects: &[(
374 &VerifiedExecutableTransaction,
375 &TransactionEffects,
376 Option<SequenceNumber>,
378 )],
379 epoch_store: &AuthorityPerEpochStore,
380 cache_reader: &dyn ObjectCacheRead,
381 ) -> AssignedTxAndVersions {
382 let _ = get_or_init_versions(
390 certs_and_effects.iter().flat_map(|(cert, _, _)| {
391 cert.transaction_data().shared_input_objects().into_iter()
392 }),
393 epoch_store,
394 cache_reader,
395 );
396 let mut assigned_versions = Vec::new();
397 for (cert, effects, accumulator_version) in certs_and_effects {
398 let initial_version_map: BTreeMap<_, _> = cert
399 .transaction_data()
400 .shared_input_objects()
401 .into_iter()
402 .map(|input| input.into_id_and_version())
403 .collect();
404 let accessed_versions: BTreeMap<ObjectID, SequenceNumber> = effects
406 .accessed_consensus_objects()
407 .into_iter()
408 .map(|iso| iso.id_and_version())
409 .collect();
410 let cert_assigned_versions: Vec<_> = accessed_versions
411 .iter()
412 .filter_map(|(id, version)| {
413 let v = initial_version_map
414 .get(id)
415 .map(|initial_version| ((*id, *initial_version), *version));
416 if v.is_none() {
417 debug_assert!(
418 IMPLICITLY_READ_SYSTEM_OBJECTS.contains(id),
419 "accessed consensus object is neither a declared input nor a known implicitly read system object: \
420 accessed={accessed_versions:?} declared={initial_version_map:?}"
421 );
422 }
423 v
424 })
425 .collect();
426 if let (Some(effects_version), Some(sequenced_version)) = (
427 accessed_versions.get(&SUI_ACCUMULATOR_ROOT_OBJECT_ID),
428 accumulator_version,
429 ) && !effects_version.is_cancelled()
430 && effects_version != sequenced_version
431 {
432 debug_fatal!(
433 "accumulator root version from effects {:?} disagrees \
434 with the reconstructed accumulator version {:?} for tx {:?}",
435 effects_version,
436 sequenced_version,
437 cert.digest()
438 );
439 }
440 let mut system_object_versions: BTreeMap<_, _> =
441 implicitly_read_system_objects(epoch_store)
442 .into_iter()
443 .filter_map(|(id, initial_shared_version)| {
444 let version = *accessed_versions.get(&id)?;
445 (!version.is_cancelled()).then_some((
448 id,
449 ConsensusObjectVersion {
450 initial_shared_version,
451 version,
452 },
453 ))
454 })
455 .collect();
456 if let Some(version) = *accumulator_version {
464 let initial_shared_version = epoch_store
465 .epoch_start_config()
466 .accumulator_root_obj_initial_shared_version()
467 .expect(
468 "initial shared version must be known for an implicitly read system object",
469 );
470 system_object_versions.insert(
471 SUI_ACCUMULATOR_ROOT_OBJECT_ID,
472 ConsensusObjectVersion {
473 initial_shared_version,
474 version,
475 },
476 );
477 }
478 let system_object_versions = SystemObjectVersions::from_map(system_object_versions);
479 let tx_key = cert.key();
480 trace!(
481 ?tx_key,
482 ?cert_assigned_versions,
483 ?system_object_versions,
484 "assigned consensus object versions from effects"
485 );
486 assigned_versions.push((
487 tx_key,
488 AssignedVersions::new(cert_assigned_versions, system_object_versions),
489 ));
490 }
491 AssignedTxAndVersions::new(assigned_versions)
492 }
493
494 pub fn assign_versions_for_certificate(
495 epoch_store: &AuthorityPerEpochStore,
496 assignable: &Schedulable<impl AsTx>,
497 shared_input_next_versions: &mut HashMap<ConsensusObjectSequenceKey, SequenceNumber>,
498 cancelled_txns: &BTreeMap<TransactionDigest, CancelConsensusCertificateReason>,
499 ) -> AssignedVersions {
500 let shared_input_objects: Vec<_> = assignable.shared_input_objects(epoch_store).collect();
501
502 let system_object_versions = SystemObjectVersions::from_map(
503 implicitly_read_system_objects(epoch_store)
504 .into_iter()
505 .map(|(id, initial_shared_version)| {
506 let version = *shared_input_next_versions
507 .get(&(id, initial_shared_version))
508 .expect(
509 "implicitly read system objects must be in shared_input_next_versions",
510 );
511 (
512 id,
513 ConsensusObjectVersion {
514 initial_shared_version,
515 version,
516 },
517 )
518 })
519 .collect(),
520 );
521
522 if shared_input_objects.is_empty() {
523 return AssignedVersions::new(vec![], system_object_versions);
525 }
526
527 let tx_key = assignable.key();
528
529 let cancellation_info = tx_key
531 .as_digest()
532 .and_then(|tx_digest| cancelled_txns.get(tx_digest));
533 let congested_objects_info: Option<HashSet<_>> =
534 if let Some(CancelConsensusCertificateReason::CongestionOnObjects(congested_objects)) =
535 &cancellation_info
536 {
537 Some(congested_objects.iter().cloned().collect())
538 } else {
539 None
540 };
541 let txn_cancelled = cancellation_info.is_some();
542
543 let mut input_object_keys = assignable.non_shared_input_object_keys();
544 let mut assigned_versions = Vec::with_capacity(shared_input_objects.len());
545 let mut is_exclusively_accessed_input = Vec::with_capacity(shared_input_objects.len());
546 let receiving_object_keys = assignable.receiving_object_keys();
548 input_object_keys.extend(receiving_object_keys);
549
550 if txn_cancelled {
551 for SharedInputObject {
554 id,
555 initial_shared_version,
556 ..
557 } in shared_input_objects.iter()
558 {
559 let assigned_version = match cancellation_info {
560 Some(CancelConsensusCertificateReason::CongestionOnObjects(_)) => {
561 if congested_objects_info
562 .as_ref()
563 .is_some_and(|info| info.contains(id))
564 {
565 SequenceNumber::CONGESTED
566 } else {
567 SequenceNumber::CANCELLED_READ
568 }
569 }
570 Some(CancelConsensusCertificateReason::DkgFailed) => {
571 if id == &SUI_RANDOMNESS_STATE_OBJECT_ID {
572 SequenceNumber::RANDOMNESS_UNAVAILABLE
573 } else {
574 SequenceNumber::CANCELLED_READ
575 }
576 }
577 None => unreachable!("cancelled transaction should have cancellation info"),
578 };
579 assigned_versions.push(((*id, *initial_shared_version), assigned_version));
580 is_exclusively_accessed_input.push(false);
581 }
582 } else {
583 for (
584 SharedInputObject {
585 id,
586 initial_shared_version,
587 mutability,
588 },
589 assigned_version,
590 ) in shared_input_objects.iter().map(|obj| {
591 (
592 obj,
593 *shared_input_next_versions
594 .get(&obj.id_and_version())
595 .unwrap(),
596 )
597 }) {
598 assigned_versions.push(((*id, *initial_shared_version), assigned_version));
599 input_object_keys.push(ObjectKey(*id, assigned_version));
600 is_exclusively_accessed_input.push(mutability.is_exclusive());
601 }
602 }
603
604 let next_version =
605 SequenceNumber::lamport_increment(input_object_keys.iter().map(|obj| obj.1));
606 assert!(
607 next_version.is_valid(),
608 "Assigned version must be valid. Got {:?}",
609 next_version
610 );
611
612 if !txn_cancelled {
613 assigned_versions
615 .iter()
616 .zip_debug_eq(is_exclusively_accessed_input)
617 .filter_map(|((id, _), mutable)| {
618 if mutable {
619 Some((*id, next_version))
620 } else {
621 None
622 }
623 })
624 .for_each(|(id, version)| {
625 assert!(
626 version.is_valid(),
627 "Assigned version must be a valid version."
628 );
629 shared_input_next_versions
630 .insert(id, version)
631 .expect("Object must exist in shared_input_next_versions.");
632 });
633 }
634
635 trace!(
636 ?tx_key,
637 ?assigned_versions,
638 ?next_version,
639 ?txn_cancelled,
640 "locking shared objects"
641 );
642
643 AssignedVersions::new(assigned_versions, system_object_versions)
644 }
645}
646
647fn implicitly_read_system_objects(
648 epoch_store: &AuthorityPerEpochStore,
649) -> Vec<ConsensusObjectSequenceKey> {
650 let epoch_start_config = epoch_store.epoch_start_config();
651 let mut objects = Vec::new();
652 if epoch_store.accumulators_enabled() {
653 objects.push((
654 SUI_ACCUMULATOR_ROOT_OBJECT_ID,
655 epoch_start_config
656 .accumulator_root_obj_initial_shared_version()
657 .expect("accumulator root obj initial shared version should be set"),
658 ));
659 }
660 if epoch_store.protocol_config().enable_forwarding_addresses()
661 && let Some(initial_shared_version) =
662 epoch_start_config.forwarding_address_registry_obj_initial_shared_version()
663 {
664 objects.push((
665 SUI_FORWARDING_ADDRESS_REGISTRY_OBJECT_ID,
666 initial_shared_version,
667 ));
668 }
669 objects
670}
671
672fn get_or_init_versions<'a>(
673 shared_input_objects: impl Iterator<Item = SharedInputObject> + 'a,
674 epoch_store: &AuthorityPerEpochStore,
675 cache_reader: &dyn ObjectCacheRead,
676) -> SuiResult<HashMap<ConsensusObjectSequenceKey, SequenceNumber>> {
677 let mut shared_input_objects: Vec<_> = shared_input_objects
678 .map(|so| so.into_id_and_version())
679 .collect();
680
681 shared_input_objects.extend(implicitly_read_system_objects(epoch_store));
682
683 shared_input_objects.sort();
684 shared_input_objects.dedup();
685
686 epoch_store.get_or_init_next_object_versions(&shared_input_objects, cache_reader)
687}
688
689#[cfg(test)]
690mod tests {
691 use super::*;
692
693 use crate::authority::AuthorityState;
694 use crate::authority::shared_object_version_manager::{
695 ConsensusSharedObjVerAssignment, SharedObjVerManager,
696 };
697 use crate::authority::test_authority_builder::TestAuthorityBuilder;
698 use std::collections::{BTreeMap, HashMap};
699 use std::sync::Arc;
700 use sui_protocol_config::ProtocolConfig;
701 use sui_test_transaction_builder::TestTransactionBuilder;
702 use sui_types::base_types::{ObjectID, SequenceNumber, SuiAddress};
703 use sui_types::crypto::{RandomnessRound, get_account_key_pair};
704 use sui_types::digests::ObjectDigest;
705 use sui_types::effects::TestEffectsBuilder;
706 use sui_types::executable_transaction::{
707 CertificateProof, ExecutableTransaction, VerifiedExecutableTransaction,
708 };
709
710 use sui_types::object::Object;
711 use sui_types::transaction::{ObjectArg, SenderSignedData, VerifiedTransaction};
712
713 use sui_types::gas_coin::GAS;
714 use sui_types::transaction::FundsWithdrawalArg;
715 use sui_types::{SUI_ACCUMULATOR_ROOT_OBJECT_ID, SUI_RANDOMNESS_STATE_OBJECT_ID};
716
717 fn assigned_versions_for_testing(
718 shared_object_versions: Vec<(ConsensusObjectSequenceKey, SequenceNumber)>,
719 accumulator_version: Option<SequenceNumber>,
720 forwarding_address_registry_version: Option<SequenceNumber>,
721 ) -> AssignedVersions {
722 let at_start_version = |v| ConsensusObjectVersion {
723 initial_shared_version: sui_types::object::OBJECT_START_VERSION,
724 version: v,
725 };
726 AssignedVersions::new(
727 shared_object_versions,
728 SystemObjectVersions::new(
729 accumulator_version.map(at_start_version),
730 forwarding_address_registry_version.map(at_start_version),
731 ),
732 )
733 }
734
735 #[tokio::test]
736 async fn test_assign_versions_from_consensus_basic() {
737 let shared_object = Object::shared_for_testing();
738 let id = shared_object.id();
739 let init_shared_version = shared_object.owner.start_version().unwrap();
740 let authority = TestAuthorityBuilder::new()
741 .with_starting_objects(std::slice::from_ref(&shared_object))
742 .build()
743 .await;
744 let certs = [
745 generate_shared_objs_tx_with_gas_version(&[(id, init_shared_version, true)], 3),
746 generate_shared_objs_tx_with_gas_version(&[(id, init_shared_version, false)], 5),
747 generate_shared_objs_tx_with_gas_version(&[(id, init_shared_version, true)], 9),
748 generate_shared_objs_tx_with_gas_version(&[(id, init_shared_version, true)], 11),
749 ];
750 let epoch_store = authority.epoch_store_for_testing();
751 let assignables = certs
752 .iter()
753 .map(Schedulable::Transaction)
754 .collect::<Vec<_>>();
755 let ConsensusSharedObjVerAssignment {
756 shared_input_next_versions,
757 assigned_versions,
758 } = SharedObjVerManager::assign_versions_from_consensus(
759 &epoch_store,
760 authority.get_object_cache_reader().as_ref(),
761 assignables.iter(),
762 &BTreeMap::new(),
763 )
764 .unwrap();
765 assert_eq!(
767 epoch_store
768 .get_next_object_version(&id, init_shared_version)
769 .unwrap(),
770 init_shared_version
771 );
772 assert_eq!(
775 *shared_input_next_versions
776 .get(&(id, init_shared_version))
777 .unwrap(),
778 SequenceNumber::from_u64(12)
779 );
780 let expected_accumulator_version = SequenceNumber::from_u64(1);
785 let expected_registry_version = SequenceNumber::from_u64(1);
786 assert_eq!(
787 assigned_versions.0,
788 vec![
789 (
790 certs[0].key(),
791 assigned_versions_for_testing(
792 vec![((id, init_shared_version), init_shared_version)],
793 Some(expected_accumulator_version),
794 Some(expected_registry_version)
795 )
796 ),
797 (
798 certs[1].key(),
799 assigned_versions_for_testing(
800 vec![((id, init_shared_version), SequenceNumber::from_u64(4))],
801 Some(expected_accumulator_version),
802 Some(expected_registry_version)
803 )
804 ),
805 (
806 certs[2].key(),
807 assigned_versions_for_testing(
808 vec![((id, init_shared_version), SequenceNumber::from_u64(4))],
809 Some(expected_accumulator_version),
810 Some(expected_registry_version)
811 )
812 ),
813 (
814 certs[3].key(),
815 assigned_versions_for_testing(
816 vec![((id, init_shared_version), SequenceNumber::from_u64(10))],
817 Some(expected_accumulator_version),
818 Some(expected_registry_version)
819 )
820 ),
821 ]
822 );
823 }
824
825 #[tokio::test]
826 async fn test_forwarding_registry_version_follows_consensus_order() {
827 let authority = TestAuthorityBuilder::new().build().await;
828 let epoch_store = authority.epoch_store_for_testing();
829 let registry_initial_version = epoch_store
830 .epoch_start_config()
831 .forwarding_address_registry_obj_initial_shared_version()
832 .unwrap();
833 let registry_key = (
834 SUI_FORWARDING_ADDRESS_REGISTRY_OBJECT_ID,
835 registry_initial_version,
836 );
837 let certs = [
838 generate_shared_objs_tx_with_gas_version(&[], 3),
839 generate_shared_objs_tx_with_gas_version(
840 &[(
841 SUI_FORWARDING_ADDRESS_REGISTRY_OBJECT_ID,
842 registry_initial_version,
843 true,
844 )],
845 5,
846 ),
847 generate_shared_objs_tx_with_gas_version(&[], 1),
848 ];
849 let assignables = certs
850 .iter()
851 .map(Schedulable::Transaction)
852 .collect::<Vec<_>>();
853 let ConsensusSharedObjVerAssignment {
854 shared_input_next_versions,
855 assigned_versions,
856 } = SharedObjVerManager::assign_versions_from_consensus(
857 &epoch_store,
858 authority.get_object_cache_reader().as_ref(),
859 assignables.iter(),
860 &BTreeMap::new(),
861 )
862 .unwrap();
863 let registry_version = |version| ConsensusObjectVersion {
864 initial_shared_version: registry_initial_version,
865 version,
866 };
867 assert_eq!(
870 assigned_versions
871 .0
872 .iter()
873 .map(|(_, versions)| {
874 (
875 versions.shared_object_versions.clone(),
876 versions
877 .system_object_versions
878 .get(&SUI_FORWARDING_ADDRESS_REGISTRY_OBJECT_ID)
879 .unwrap(),
880 )
881 })
882 .collect::<Vec<_>>(),
883 vec![
884 (vec![], registry_version(registry_initial_version)),
885 (
886 vec![(registry_key, registry_initial_version)],
887 registry_version(registry_initial_version),
888 ),
889 (vec![], registry_version(SequenceNumber::from_u64(6))),
890 ]
891 );
892 assert_eq!(
893 shared_input_next_versions.get(®istry_key),
894 Some(&SequenceNumber::from_u64(6))
895 );
896 }
897
898 #[tokio::test]
899 async fn test_forwarding_registry_declared_by_cancelled_transaction() {
900 let authority = TestAuthorityBuilder::new().build().await;
901 let epoch_store = authority.epoch_store_for_testing();
902 let registry_initial_version = epoch_store
903 .epoch_start_config()
904 .forwarding_address_registry_obj_initial_shared_version()
905 .unwrap();
906 let registry_key = (
907 SUI_FORWARDING_ADDRESS_REGISTRY_OBJECT_ID,
908 registry_initial_version,
909 );
910 let certs = [
911 generate_shared_objs_tx_with_gas_version(
912 &[(
913 SUI_FORWARDING_ADDRESS_REGISTRY_OBJECT_ID,
914 registry_initial_version,
915 true,
916 )],
917 5,
918 ),
919 generate_shared_objs_tx_with_gas_version(&[], 3),
920 ];
921 let cancelled_txns = BTreeMap::from([(
922 *certs[0].digest(),
923 CancelConsensusCertificateReason::CongestionOnObjects(vec![
924 SUI_FORWARDING_ADDRESS_REGISTRY_OBJECT_ID,
925 ]),
926 )]);
927 let assignables = certs
928 .iter()
929 .map(Schedulable::Transaction)
930 .collect::<Vec<_>>();
931 let ConsensusSharedObjVerAssignment {
932 shared_input_next_versions,
933 assigned_versions,
934 } = SharedObjVerManager::assign_versions_from_consensus(
935 &epoch_store,
936 authority.get_object_cache_reader().as_ref(),
937 assignables.iter(),
938 &cancelled_txns,
939 )
940 .unwrap();
941 let expected_version = SequenceNumber::from_u64(1);
944 assert_eq!(
945 assigned_versions.0,
946 vec![
947 (
948 certs[0].key(),
949 assigned_versions_for_testing(
950 vec![(registry_key, SequenceNumber::CONGESTED)],
951 Some(expected_version),
952 Some(expected_version)
953 )
954 ),
955 (
956 certs[1].key(),
957 assigned_versions_for_testing(
958 vec![],
959 Some(expected_version),
960 Some(expected_version)
961 )
962 ),
963 ]
964 );
965 assert_eq!(
966 shared_input_next_versions.get(®istry_key),
967 Some(®istry_initial_version)
968 );
969 }
970
971 #[tokio::test]
972 async fn test_forwarding_registry_version_from_effects() {
973 let authority = TestAuthorityBuilder::new().build().await;
974 let epoch_store = authority.epoch_store_for_testing();
975 let registry_initial_version = epoch_store
976 .epoch_start_config()
977 .forwarding_address_registry_obj_initial_shared_version()
978 .unwrap();
979 let registry_version = SequenceNumber::from_u64(4);
980 let certs = [
981 generate_shared_objs_tx_with_gas_version(&[], 3),
982 generate_shared_objs_tx_with_gas_version(
983 &[(
984 SUI_FORWARDING_ADDRESS_REGISTRY_OBJECT_ID,
985 registry_initial_version,
986 false,
987 )],
988 5,
989 ),
990 ];
991 let effects = certs
992 .iter()
993 .map(|cert| {
994 TestEffectsBuilder::new(cert.data())
995 .with_shared_input_versions(BTreeMap::from([(
996 SUI_FORWARDING_ADDRESS_REGISTRY_OBJECT_ID,
997 registry_version,
998 )]))
999 .build()
1000 })
1001 .collect::<Vec<_>>();
1002 let assigned_versions = SharedObjVerManager::assign_versions_from_effects(
1003 certs
1004 .iter()
1005 .zip_debug_eq(effects.iter())
1006 .map(|(cert, effect)| (cert, effect, None))
1007 .collect::<Vec<_>>()
1008 .as_slice(),
1009 &epoch_store,
1010 authority.get_object_cache_reader().as_ref(),
1011 );
1012 let system_object_versions = SystemObjectVersions::new(
1013 None,
1014 Some(ConsensusObjectVersion {
1015 initial_shared_version: registry_initial_version,
1016 version: registry_version,
1017 }),
1018 );
1019 assert_eq!(
1020 assigned_versions.0,
1021 vec![
1022 (
1023 certs[0].key(),
1024 AssignedVersions::new(vec![], system_object_versions)
1025 ),
1026 (
1027 certs[1].key(),
1028 AssignedVersions::new(
1029 vec![(
1030 (
1031 SUI_FORWARDING_ADDRESS_REGISTRY_OBJECT_ID,
1032 registry_initial_version
1033 ),
1034 registry_version
1035 )],
1036 system_object_versions
1037 )
1038 ),
1039 ]
1040 );
1041 }
1042
1043 #[tokio::test]
1044 async fn test_assign_versions_from_consensus_with_randomness() {
1045 let authority = TestAuthorityBuilder::new().build().await;
1046 let epoch_store = authority.epoch_store_for_testing();
1047 let randomness_obj_version = epoch_store
1048 .epoch_start_config()
1049 .randomness_obj_initial_shared_version()
1050 .unwrap();
1051 let certs = [
1052 VerifiedExecutableTransaction::new_system(
1053 VerifiedTransaction::new_randomness_state_update(
1054 epoch_store.epoch(),
1055 RandomnessRound::new(1),
1056 vec![],
1057 randomness_obj_version,
1058 ),
1059 epoch_store.epoch(),
1060 ),
1061 generate_shared_objs_tx_with_gas_version(
1062 &[(
1063 SUI_RANDOMNESS_STATE_OBJECT_ID,
1064 randomness_obj_version,
1065 false,
1067 )],
1068 3,
1069 ),
1070 generate_shared_objs_tx_with_gas_version(
1071 &[(
1072 SUI_RANDOMNESS_STATE_OBJECT_ID,
1073 randomness_obj_version,
1074 false,
1075 )],
1076 5,
1077 ),
1078 ];
1079 let assignables = certs
1080 .iter()
1081 .map(Schedulable::Transaction)
1082 .collect::<Vec<_>>();
1083 let ConsensusSharedObjVerAssignment {
1084 shared_input_next_versions,
1085 assigned_versions,
1086 } = SharedObjVerManager::assign_versions_from_consensus(
1087 &epoch_store,
1088 authority.get_object_cache_reader().as_ref(),
1089 assignables.iter(),
1090 &BTreeMap::new(),
1091 )
1092 .unwrap();
1093 assert_eq!(
1095 epoch_store
1096 .get_next_object_version(&SUI_RANDOMNESS_STATE_OBJECT_ID, randomness_obj_version)
1097 .unwrap(),
1098 randomness_obj_version
1099 );
1100 let next_randomness_obj_version = randomness_obj_version.next();
1101 assert_eq!(
1102 *shared_input_next_versions
1103 .get(&(SUI_RANDOMNESS_STATE_OBJECT_ID, randomness_obj_version))
1104 .unwrap(),
1105 next_randomness_obj_version
1107 );
1108 let expected_accumulator_version = SequenceNumber::from_u64(1);
1109 let expected_registry_version = SequenceNumber::from_u64(1);
1110 assert_eq!(
1111 assigned_versions.0,
1112 vec![
1113 (
1114 certs[0].key(),
1115 assigned_versions_for_testing(
1116 vec![(
1117 (SUI_RANDOMNESS_STATE_OBJECT_ID, randomness_obj_version),
1118 randomness_obj_version
1119 )],
1120 Some(expected_accumulator_version),
1121 Some(expected_registry_version)
1122 )
1123 ),
1124 (
1125 certs[1].key(),
1126 assigned_versions_for_testing(
1128 vec![(
1129 (SUI_RANDOMNESS_STATE_OBJECT_ID, randomness_obj_version),
1130 next_randomness_obj_version
1131 )],
1132 Some(expected_accumulator_version),
1133 Some(expected_registry_version)
1134 )
1135 ),
1136 (
1137 certs[2].key(),
1138 assigned_versions_for_testing(
1140 vec![(
1141 (SUI_RANDOMNESS_STATE_OBJECT_ID, randomness_obj_version),
1142 next_randomness_obj_version
1143 )],
1144 Some(expected_accumulator_version),
1145 Some(expected_registry_version)
1146 )
1147 ),
1148 ]
1149 );
1150 }
1151
1152 #[tokio::test]
1154 async fn test_assign_versions_from_consensus_with_cancellation() {
1155 let shared_object_1 = Object::shared_for_testing();
1156 let shared_object_2 = Object::shared_for_testing();
1157 let id1 = shared_object_1.id();
1158 let id2 = shared_object_2.id();
1159 let init_shared_version_1 = shared_object_1.owner.start_version().unwrap();
1160 let init_shared_version_2 = shared_object_2.owner.start_version().unwrap();
1161 let authority = TestAuthorityBuilder::new()
1162 .with_starting_objects(&[shared_object_1.clone(), shared_object_2.clone()])
1163 .build()
1164 .await;
1165 let randomness_obj_version = authority
1166 .epoch_store_for_testing()
1167 .epoch_start_config()
1168 .randomness_obj_initial_shared_version()
1169 .unwrap();
1170
1171 let certs = [
1186 generate_shared_objs_tx_with_gas_version(
1187 &[
1188 (id1, init_shared_version_1, true),
1189 (id2, init_shared_version_2, true),
1190 ],
1191 3,
1192 ),
1193 generate_shared_objs_tx_with_gas_version(
1194 &[
1195 (id1, init_shared_version_1, true),
1196 (id2, init_shared_version_2, true),
1197 ],
1198 5,
1199 ),
1200 generate_shared_objs_tx_with_gas_version(&[(id1, init_shared_version_1, true)], 1),
1201 generate_shared_objs_tx_with_gas_version(
1202 &[
1203 (id1, init_shared_version_1, true),
1204 (id2, init_shared_version_2, true),
1205 ],
1206 9,
1207 ),
1208 generate_shared_objs_tx_with_gas_version(
1209 &[
1210 (
1211 SUI_RANDOMNESS_STATE_OBJECT_ID,
1212 randomness_obj_version,
1213 false,
1214 ),
1215 (id2, init_shared_version_2, true),
1216 ],
1217 11,
1218 ),
1219 ];
1220 let epoch_store = authority.epoch_store_for_testing();
1221
1222 let cancelled_txns: BTreeMap<TransactionDigest, CancelConsensusCertificateReason> = [
1224 (
1225 *certs[1].digest(),
1226 CancelConsensusCertificateReason::CongestionOnObjects(vec![id1]),
1227 ),
1228 (
1229 *certs[3].digest(),
1230 CancelConsensusCertificateReason::CongestionOnObjects(vec![id2]),
1231 ),
1232 (
1233 *certs[4].digest(),
1234 CancelConsensusCertificateReason::DkgFailed,
1235 ),
1236 ]
1237 .into_iter()
1238 .collect();
1239
1240 let assignables = certs
1241 .iter()
1242 .map(Schedulable::Transaction)
1243 .collect::<Vec<_>>();
1244
1245 let ConsensusSharedObjVerAssignment {
1247 mut shared_input_next_versions,
1248 assigned_versions,
1249 } = SharedObjVerManager::assign_versions_from_consensus(
1250 &epoch_store,
1251 authority.get_object_cache_reader().as_ref(),
1252 assignables.iter(),
1253 &cancelled_txns,
1254 )
1255 .unwrap();
1256
1257 shared_input_next_versions
1260 .remove(&(SUI_ACCUMULATOR_ROOT_OBJECT_ID, SequenceNumber::from_u64(1)));
1261 shared_input_next_versions.remove(&(
1262 SUI_FORWARDING_ADDRESS_REGISTRY_OBJECT_ID,
1263 SequenceNumber::from_u64(1),
1264 ));
1265 assert_eq!(
1266 shared_input_next_versions,
1267 HashMap::from([
1268 ((id1, init_shared_version_1), SequenceNumber::from_u64(5)), ((id2, init_shared_version_2), SequenceNumber::from_u64(4)), (
1271 (SUI_RANDOMNESS_STATE_OBJECT_ID, randomness_obj_version),
1272 SequenceNumber::from_u64(1)
1273 ), ])
1275 );
1276
1277 let expected_accumulator_version = SequenceNumber::from_u64(1);
1279 let expected_registry_version = SequenceNumber::from_u64(1);
1280 assert_eq!(
1281 assigned_versions.0,
1282 vec![
1283 (
1284 certs[0].key(),
1285 assigned_versions_for_testing(
1286 vec![
1287 ((id1, init_shared_version_1), init_shared_version_1),
1288 ((id2, init_shared_version_2), init_shared_version_2)
1289 ],
1290 Some(expected_accumulator_version),
1291 Some(expected_registry_version)
1292 )
1293 ),
1294 (
1295 certs[1].key(),
1296 assigned_versions_for_testing(
1297 vec![
1298 ((id1, init_shared_version_1), SequenceNumber::CONGESTED),
1299 ((id2, init_shared_version_2), SequenceNumber::CANCELLED_READ),
1300 ],
1301 Some(expected_accumulator_version),
1302 Some(expected_registry_version)
1303 )
1304 ),
1305 (
1306 certs[2].key(),
1307 assigned_versions_for_testing(
1308 vec![((id1, init_shared_version_1), SequenceNumber::from_u64(4))],
1309 Some(expected_accumulator_version),
1310 Some(expected_registry_version)
1311 )
1312 ),
1313 (
1314 certs[3].key(),
1315 assigned_versions_for_testing(
1316 vec![
1317 ((id1, init_shared_version_1), SequenceNumber::CANCELLED_READ),
1318 ((id2, init_shared_version_2), SequenceNumber::CONGESTED)
1319 ],
1320 Some(expected_accumulator_version),
1321 Some(expected_registry_version)
1322 )
1323 ),
1324 (
1325 certs[4].key(),
1326 assigned_versions_for_testing(
1327 vec![
1328 (
1329 (SUI_RANDOMNESS_STATE_OBJECT_ID, randomness_obj_version),
1330 SequenceNumber::RANDOMNESS_UNAVAILABLE
1331 ),
1332 ((id2, init_shared_version_2), SequenceNumber::CANCELLED_READ)
1333 ],
1334 Some(expected_accumulator_version),
1335 Some(expected_registry_version)
1336 )
1337 ),
1338 ]
1339 );
1340 }
1341
1342 #[tokio::test]
1343 async fn test_assign_versions_from_effects() {
1344 let shared_object = Object::shared_for_testing();
1345 let id = shared_object.id();
1346 let init_shared_version = shared_object.owner.start_version().unwrap();
1347 let authority = TestAuthorityBuilder::new()
1348 .with_starting_objects(std::slice::from_ref(&shared_object))
1349 .build()
1350 .await;
1351 let certs = [
1352 generate_shared_objs_tx_with_gas_version(&[(id, init_shared_version, true)], 3),
1353 generate_shared_objs_tx_with_gas_version(&[(id, init_shared_version, false)], 5),
1354 generate_shared_objs_tx_with_gas_version(&[(id, init_shared_version, true)], 9),
1355 generate_shared_objs_tx_with_gas_version(&[(id, init_shared_version, true)], 11),
1356 ];
1357 let effects = [
1358 TestEffectsBuilder::new(certs[0].data()).build(),
1359 TestEffectsBuilder::new(certs[1].data())
1360 .with_shared_input_versions(BTreeMap::from([(id, SequenceNumber::from_u64(4))]))
1361 .build(),
1362 TestEffectsBuilder::new(certs[2].data())
1363 .with_shared_input_versions(BTreeMap::from([(id, SequenceNumber::from_u64(4))]))
1364 .build(),
1365 TestEffectsBuilder::new(certs[3].data())
1366 .with_shared_input_versions(BTreeMap::from([(id, SequenceNumber::from_u64(10))]))
1367 .build(),
1368 ];
1369 let epoch_store = authority.epoch_store_for_testing();
1370 let assigned_versions = SharedObjVerManager::assign_versions_from_effects(
1371 certs
1372 .iter()
1373 .zip_debug_eq(effects.iter())
1374 .map(|(cert, effect)| (cert, effect, None))
1375 .collect::<Vec<_>>()
1376 .as_slice(),
1377 &epoch_store,
1378 authority.get_object_cache_reader().as_ref(),
1379 );
1380 assert_eq!(
1382 epoch_store
1383 .get_next_object_version(&id, init_shared_version)
1384 .unwrap(),
1385 init_shared_version
1386 );
1387 assert_eq!(
1388 assigned_versions.0,
1389 vec![
1390 (
1391 certs[0].key(),
1392 assigned_versions_for_testing(
1393 vec![((id, init_shared_version), init_shared_version)],
1394 None,
1395 None
1396 )
1397 ),
1398 (
1399 certs[1].key(),
1400 assigned_versions_for_testing(
1401 vec![((id, init_shared_version), SequenceNumber::from_u64(4))],
1402 None,
1403 None
1404 )
1405 ),
1406 (
1407 certs[2].key(),
1408 assigned_versions_for_testing(
1409 vec![((id, init_shared_version), SequenceNumber::from_u64(4))],
1410 None,
1411 None
1412 )
1413 ),
1414 (
1415 certs[3].key(),
1416 assigned_versions_for_testing(
1417 vec![((id, init_shared_version), SequenceNumber::from_u64(10))],
1418 None,
1419 None
1420 )
1421 ),
1422 ]
1423 );
1424 }
1425
1426 fn generate_shared_objs_tx_with_gas_version(
1430 shared_objects: &[(ObjectID, SequenceNumber, bool)],
1431 gas_object_version: u64,
1432 ) -> VerifiedExecutableTransaction {
1433 let mut tx_builder = TestTransactionBuilder::new(
1434 SuiAddress::ZERO,
1435 (
1436 ObjectID::random(),
1437 SequenceNumber::from_u64(gas_object_version),
1438 ObjectDigest::random(),
1439 ),
1440 0,
1441 );
1442 let tx_data = {
1443 let builder = tx_builder.ptb_builder_mut();
1444 for (shared_object_id, shared_object_init_version, shared_object_mutable) in
1445 shared_objects
1446 {
1447 builder
1448 .obj(ObjectArg::SharedObject {
1449 id: *shared_object_id,
1450 initial_shared_version: *shared_object_init_version,
1451 mutability: if *shared_object_mutable {
1452 SharedObjectMutability::Mutable
1453 } else {
1454 SharedObjectMutability::Immutable
1455 },
1456 })
1457 .unwrap();
1458 }
1459 tx_builder.build()
1460 };
1461 let tx = SenderSignedData::new(tx_data, vec![]);
1462 VerifiedExecutableTransaction::new_unchecked(ExecutableTransaction::new_from_data_and_sig(
1463 tx,
1464 CertificateProof::new_system(0),
1465 ))
1466 }
1467
1468 struct WithdrawTestContext {
1469 authority: Arc<AuthorityState>,
1470 assignables: Vec<Schedulable<VerifiedExecutableTransaction>>,
1471 shared_objects: Vec<Object>,
1472 }
1473
1474 impl WithdrawTestContext {
1475 pub async fn new() -> Self {
1476 let shared_objects = vec![Object::shared_for_testing()];
1478 let mut config = ProtocolConfig::get_for_max_version_UNSAFE();
1479 config.set_enable_accumulators_for_testing(true);
1480 config.set_enable_forwarding_addresses_for_testing(false);
1481 let authority = TestAuthorityBuilder::new()
1482 .with_starting_objects(&shared_objects)
1483 .with_protocol_config(config)
1484 .build()
1485 .await;
1486 Self {
1487 authority,
1488 assignables: vec![],
1489 shared_objects,
1490 }
1491 }
1492
1493 pub fn add_withdraw_transaction(&mut self) -> TransactionKey {
1494 let (sender, keypair) = get_account_key_pair();
1496 let gas_object = Object::with_owner_for_testing(sender);
1497 let gas_object_ref = gas_object.compute_object_reference();
1498 let gas_price = (self.assignables.len() + 1) as u64;
1500 let mut tx_builder = TestTransactionBuilder::new(sender, gas_object_ref, gas_price);
1501 let tx_data = {
1502 let ptb_builder = tx_builder.ptb_builder_mut();
1503 ptb_builder
1504 .funds_withdrawal(FundsWithdrawalArg::balance_from_sender(
1505 200,
1506 GAS::type_tag(),
1507 ))
1508 .unwrap();
1509 tx_builder.build()
1510 };
1511 let cert = VerifiedExecutableTransaction::new_for_testing(tx_data, &keypair);
1512 let key = cert.key();
1513 self.assignables.push(Schedulable::Transaction(cert));
1514 key
1515 }
1516
1517 pub fn add_settlement_transaction(&mut self) -> TransactionKey {
1518 let height = (self.assignables.len() + 1) as u64;
1519 let settlement = Schedulable::AccumulatorSettlement(0, height);
1520 let key = settlement.key();
1521 self.assignables.push(settlement);
1522 key
1523 }
1524
1525 pub fn add_withdraw_with_shared_object_transaction(&mut self) -> TransactionKey {
1526 let (sender, keypair) = get_account_key_pair();
1528 let gas_object = Object::with_owner_for_testing(sender);
1529 let gas_object_ref = gas_object.compute_object_reference();
1530 let gas_price = (self.assignables.len() + 1) as u64;
1532 let mut tx_builder = TestTransactionBuilder::new(sender, gas_object_ref, gas_price);
1533 let tx_data = {
1534 let ptb_builder = tx_builder.ptb_builder_mut();
1535 if let Some(shared_obj) = self.shared_objects.first() {
1537 let id = shared_obj.id();
1538 let init_version = shared_obj.owner.start_version().unwrap();
1539 ptb_builder
1540 .obj(ObjectArg::SharedObject {
1541 id,
1542 initial_shared_version: init_version,
1543 mutability: SharedObjectMutability::Mutable,
1544 })
1545 .unwrap();
1546 }
1547 ptb_builder
1549 .funds_withdrawal(FundsWithdrawalArg::balance_from_sender(
1550 200,
1551 GAS::type_tag(),
1552 ))
1553 .unwrap();
1554 tx_builder.build()
1555 };
1556 let cert = VerifiedExecutableTransaction::new_for_testing(tx_data, &keypair);
1557 let key = cert.key();
1558 self.assignables.push(Schedulable::Transaction(cert));
1559 key
1560 }
1561
1562 pub fn assign_versions_from_consensus(&self) -> ConsensusSharedObjVerAssignment {
1563 let epoch_store = self.authority.epoch_store_for_testing();
1564 SharedObjVerManager::assign_versions_from_consensus(
1565 &epoch_store,
1566 self.authority.get_object_cache_reader().as_ref(),
1567 self.assignables.iter(),
1568 &BTreeMap::new(),
1569 )
1570 .unwrap()
1571 }
1572 }
1573
1574 #[tokio::test]
1575 async fn test_assign_versions_from_consensus_with_withdraws_simple() {
1576 let mut ctx = WithdrawTestContext::new().await;
1579
1580 let acc_version = ctx
1581 .authority
1582 .get_object(&SUI_ACCUMULATOR_ROOT_OBJECT_ID)
1583 .unwrap()
1584 .version();
1585
1586 let withdraw_key = ctx.add_withdraw_transaction();
1587 let settlement_key = ctx.add_settlement_transaction();
1588
1589 let assigned_versions = ctx.assign_versions_from_consensus();
1590 assert_eq!(
1591 assigned_versions,
1592 ConsensusSharedObjVerAssignment {
1593 assigned_versions: AssignedTxAndVersions::new(vec![
1594 (
1595 withdraw_key,
1596 assigned_versions_for_testing(vec![], Some(acc_version), None)
1597 ),
1598 (
1599 settlement_key,
1600 assigned_versions_for_testing(
1601 vec![((SUI_ACCUMULATOR_ROOT_OBJECT_ID, acc_version), acc_version)],
1602 Some(acc_version),
1603 None
1604 )
1605 ),
1606 ]),
1607 shared_input_next_versions: HashMap::from([(
1608 (SUI_ACCUMULATOR_ROOT_OBJECT_ID, acc_version),
1609 acc_version.next()
1610 )]),
1611 }
1612 );
1613 }
1614
1615 #[tokio::test]
1616 async fn test_assign_versions_from_consensus_with_multiple_withdraws_and_settlements() {
1617 let mut ctx = WithdrawTestContext::new().await;
1619
1620 let acc_version = ctx
1621 .authority
1622 .get_object(&SUI_ACCUMULATOR_ROOT_OBJECT_ID)
1623 .unwrap()
1624 .version();
1625
1626 let withdraw_key1 = ctx.add_withdraw_transaction();
1628 let settlement_key1 = ctx.add_settlement_transaction();
1629
1630 let withdraw_key2 = ctx.add_withdraw_transaction();
1632 let settlement_key2 = ctx.add_settlement_transaction();
1633
1634 let withdraw_key3 = ctx.add_withdraw_transaction();
1636 let settlement_key3 = ctx.add_settlement_transaction();
1637
1638 let assigned_versions = ctx.assign_versions_from_consensus();
1639 assert_eq!(
1640 assigned_versions,
1641 ConsensusSharedObjVerAssignment {
1642 assigned_versions: AssignedTxAndVersions::new(vec![
1643 (
1644 withdraw_key1,
1645 assigned_versions_for_testing(vec![], Some(acc_version), None)
1646 ),
1647 (
1648 settlement_key1,
1649 assigned_versions_for_testing(
1650 vec![((SUI_ACCUMULATOR_ROOT_OBJECT_ID, acc_version), acc_version)],
1651 Some(acc_version),
1652 None
1653 )
1654 ),
1655 (
1656 withdraw_key2,
1657 assigned_versions_for_testing(vec![], Some(acc_version.next()), None)
1658 ),
1659 (
1660 settlement_key2,
1661 assigned_versions_for_testing(
1662 vec![(
1663 (SUI_ACCUMULATOR_ROOT_OBJECT_ID, acc_version),
1664 acc_version.next()
1665 )],
1666 Some(acc_version.next()),
1667 None
1668 )
1669 ),
1670 (
1671 withdraw_key3,
1672 assigned_versions_for_testing(
1673 vec![],
1674 Some(acc_version.next().next()),
1675 None
1676 )
1677 ),
1678 (
1679 settlement_key3,
1680 assigned_versions_for_testing(
1681 vec![(
1682 (SUI_ACCUMULATOR_ROOT_OBJECT_ID, acc_version),
1683 acc_version.next().next()
1684 )],
1685 Some(acc_version.next().next()),
1686 None
1687 )
1688 ),
1689 ]),
1690 shared_input_next_versions: HashMap::from([(
1691 (SUI_ACCUMULATOR_ROOT_OBJECT_ID, acc_version),
1692 acc_version.next().next().next()
1693 )]),
1694 }
1695 );
1696 }
1697
1698 #[tokio::test]
1699 async fn test_assign_versions_from_consensus_with_withdraw_and_shared_object() {
1700 let mut ctx = WithdrawTestContext::new().await;
1702
1703 let shared_obj_id = ctx.shared_objects[0].id();
1705 let shared_obj_version = ctx.shared_objects[0].owner.start_version().unwrap();
1706
1707 let acc_version = ctx
1708 .authority
1709 .get_object(&SUI_ACCUMULATOR_ROOT_OBJECT_ID)
1710 .unwrap()
1711 .version();
1712
1713 let withdraw_with_shared_key = ctx.add_withdraw_with_shared_object_transaction();
1714 let settlement_key = ctx.add_settlement_transaction();
1715
1716 let assigned_versions = ctx.assign_versions_from_consensus();
1717 assert_eq!(
1718 assigned_versions,
1719 ConsensusSharedObjVerAssignment {
1720 assigned_versions: AssignedTxAndVersions::new(vec![
1721 (
1722 withdraw_with_shared_key,
1723 assigned_versions_for_testing(
1724 vec![((shared_obj_id, shared_obj_version), shared_obj_version)],
1725 Some(acc_version),
1726 None
1727 )
1728 ),
1729 (
1730 settlement_key,
1731 assigned_versions_for_testing(
1732 vec![((SUI_ACCUMULATOR_ROOT_OBJECT_ID, acc_version), acc_version)],
1733 Some(acc_version),
1734 None
1735 )
1736 ),
1737 ]),
1738 shared_input_next_versions: HashMap::from([
1739 (
1740 (SUI_ACCUMULATOR_ROOT_OBJECT_ID, acc_version),
1741 acc_version.next()
1742 ),
1743 (
1744 (shared_obj_id, shared_obj_version),
1745 shared_obj_version.next()
1746 ),
1747 ]),
1748 }
1749 );
1750 }
1751}