1pub mod error;
6mod object_store_trait;
7mod read_store;
8mod shared_in_memory_store;
9mod write_store;
10
11use std::{
12 cell::RefCell,
13 collections::BTreeMap,
14 fmt::{Display, Formatter},
15 rc::Rc,
16 sync::Arc,
17};
18
19use iota_sdk_types::{
20 ObjectId, ObjectReference, SenderSignedTransaction, TransactionDigest, TransactionEffects,
21 Version, WriteKind, move_package::MovePackage,
22};
23use itertools::Itertools;
24use move_binary_format::CompiledModule;
25use move_core_types::language_storage::ModuleId;
26pub use object_store_trait::ObjectStore;
27pub use read_store::{
28 AccountOwnedObjectInfo, CoinInfo, DynamicFieldIteratorItem, DynamicFieldKey, EpochInfo,
29 EpochInfoV1Entry, EpochInfoV2, OwnedObjectCursor, OwnedObjectIteratorItem, PackageVersionInfo,
30 PackageVersionIteratorItem, PackageVersionKey, ReadStore, TransactionInfo,
31};
32use serde::{Deserialize, Serialize};
33use serde_with::serde_as;
34pub use shared_in_memory_store::{SharedInMemoryStore, SingleCheckpointSharedInMemoryStore};
35pub use write_store::WriteStore;
36
37use crate::{
38 auth_context::AuthContext,
39 base_types::VersionNumber,
40 committee::EpochId,
41 effects::{TransactionEffectsAPI, TransactionEffectsExt},
42 error::{ExecutionError, IotaError, IotaResult},
43 execution::{DynamicallyLoadedObjectMetadata, ExecutionResults},
44 iota_sdk_types_conversions::identifier_core_to_sdk,
45 object::Object,
46 storage::error::Error as StorageError,
47 transaction::{SenderSignedTransactionAPI, TransactionAPI},
48};
49
50#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
52pub enum InputKey {
53 VersionedObject { id: ObjectId, version: Version },
54 Package { id: ObjectId },
55}
56
57impl InputKey {
58 pub fn id(&self) -> ObjectId {
59 match self {
60 InputKey::VersionedObject { id, .. } => *id,
61 InputKey::Package { id } => *id,
62 }
63 }
64
65 pub fn version(&self) -> Option<Version> {
66 match self {
67 InputKey::VersionedObject { version, .. } => Some(*version),
68 InputKey::Package { .. } => None,
69 }
70 }
71
72 pub fn is_cancelled(&self) -> bool {
73 match self {
74 InputKey::VersionedObject { version, .. } => version.is_canceled(),
75 InputKey::Package { .. } => false,
76 }
77 }
78}
79
80impl From<&Object> for InputKey {
81 fn from(obj: &Object) -> Self {
82 if obj.is_package() {
83 InputKey::Package { id: obj.id() }
84 } else {
85 InputKey::VersionedObject {
86 id: obj.id(),
87 version: obj.version(),
88 }
89 }
90 }
91}
92
93#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
94pub enum DeleteKind {
95 Normal,
97 UnwrapThenDelete,
100 Wrap,
103}
104
105#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
106pub enum MarkerValue {
107 Received,
111 OwnedDeleted,
114 SharedDeleted(TransactionDigest),
117}
118
119#[derive(Debug)]
125pub enum DeleteKindWithOldVersion {
126 Normal(Version),
127 UnwrapThenDelete,
128 Wrap(Version),
129}
130
131impl DeleteKindWithOldVersion {
132 pub fn old_version(&self) -> Option<Version> {
133 match self {
134 DeleteKindWithOldVersion::Normal(version) | DeleteKindWithOldVersion::Wrap(version) => {
135 Some(*version)
136 }
137 DeleteKindWithOldVersion::UnwrapThenDelete => None,
138 }
139 }
140
141 pub fn to_delete_kind(&self) -> DeleteKind {
142 match self {
143 DeleteKindWithOldVersion::Normal(_) => DeleteKind::Normal,
144 DeleteKindWithOldVersion::UnwrapThenDelete => DeleteKind::UnwrapThenDelete,
145 DeleteKindWithOldVersion::Wrap(_) => DeleteKind::Wrap,
146 }
147 }
148}
149
150#[derive(Debug)]
151pub enum ObjectChange {
152 Write(Object, WriteKind),
153 Delete(DeleteKindWithOldVersion),
155}
156
157pub trait StorageView: Storage + ChildObjectResolver {}
158impl<T: Storage + ChildObjectResolver> StorageView for T {}
159
160pub trait ChildObjectResolver {
163 fn read_child_object(
165 &self,
166 parent: &ObjectId,
167 child: &ObjectId,
168 child_version_upper_bound: Version,
169 ) -> IotaResult<Option<Object>>;
170
171 fn get_object_received_at_version(
178 &self,
179 owner: &ObjectId,
180 receiving_object_id: &ObjectId,
181 receive_object_at_version: Version,
182 epoch_id: EpochId,
183 ) -> IotaResult<Option<Object>>;
184}
185
186pub struct DenyListResult {
187 pub result: Result<(), ExecutionError>,
191 pub num_non_gas_coin_owners: u64,
193}
194
195pub trait Storage {
198 fn reset(&mut self);
199
200 fn read_object(&self, id: &ObjectId) -> Option<&Object>;
201
202 fn record_execution_results(&mut self, results: ExecutionResults);
203
204 fn save_loaded_runtime_objects(
205 &mut self,
206 loaded_runtime_objects: BTreeMap<ObjectId, DynamicallyLoadedObjectMetadata>,
207 );
208
209 fn save_wrapped_object_containers(
210 &mut self,
211 wrapped_object_containers: BTreeMap<ObjectId, ObjectId>,
212 );
213
214 fn check_coin_deny_list(&self, written_objects: &BTreeMap<ObjectId, Object>) -> DenyListResult;
217
218 fn read_auth_context(&self) -> Option<Rc<RefCell<AuthContext>>>;
219}
220
221pub type PackageFetchResults<Package> = Result<Vec<Package>, Vec<ObjectId>>;
222
223#[derive(Clone, Debug)]
224pub struct PackageObject {
225 package_object: Object,
226}
227
228impl PackageObject {
229 pub fn new(package_object: Object) -> Self {
230 assert!(package_object.is_package());
231 Self { package_object }
232 }
233
234 pub fn object(&self) -> &Object {
235 &self.package_object
236 }
237
238 pub fn move_package(&self) -> &MovePackage {
239 self.package_object.data.as_opt_package().unwrap()
240 }
241}
242
243impl From<PackageObject> for Object {
244 fn from(package_object_arc: PackageObject) -> Self {
245 package_object_arc.package_object
246 }
247}
248
249pub trait BackingPackageStore {
250 fn get_package_object(&self, package_id: &ObjectId) -> IotaResult<Option<PackageObject>>;
251}
252
253impl<S: ?Sized + BackingPackageStore> BackingPackageStore for Box<S> {
254 fn get_package_object(&self, package_id: &ObjectId) -> IotaResult<Option<PackageObject>> {
255 BackingPackageStore::get_package_object(self.as_ref(), package_id)
256 }
257}
258
259impl<S: ?Sized + BackingPackageStore> BackingPackageStore for Arc<S> {
260 fn get_package_object(&self, package_id: &ObjectId) -> IotaResult<Option<PackageObject>> {
261 BackingPackageStore::get_package_object(self.as_ref(), package_id)
262 }
263}
264
265impl<S: ?Sized + BackingPackageStore> BackingPackageStore for &S {
266 fn get_package_object(&self, package_id: &ObjectId) -> IotaResult<Option<PackageObject>> {
267 BackingPackageStore::get_package_object(*self, package_id)
268 }
269}
270
271impl<S: ?Sized + BackingPackageStore> BackingPackageStore for &mut S {
272 fn get_package_object(&self, package_id: &ObjectId) -> IotaResult<Option<PackageObject>> {
273 BackingPackageStore::get_package_object(*self, package_id)
274 }
275}
276
277pub fn load_package_object_from_object_store(
278 store: &impl ObjectStore,
279 package_id: &ObjectId,
280) -> IotaResult<Option<PackageObject>> {
281 let package = store.try_get_object(package_id)?;
282 if let Some(obj) = &package {
283 fp_ensure!(
284 obj.is_package(),
285 IotaError::BadObjectType {
286 error: format!("Package expected, Move object found: {package_id}"),
287 }
288 );
289 }
290 Ok(package.map(PackageObject::new))
291}
292
293pub fn get_package_objects<'a>(
298 store: &impl BackingPackageStore,
299 package_ids: impl IntoIterator<Item = &'a ObjectId>,
300) -> IotaResult<PackageFetchResults<PackageObject>> {
301 let packages: Vec<Result<_, _>> = package_ids
302 .into_iter()
303 .map(|id| match store.get_package_object(id) {
304 Ok(None) => Ok(Err(*id)),
305 Ok(Some(o)) => Ok(Ok(o)),
306 Err(x) => Err(x),
307 })
308 .collect::<IotaResult<_>>()?;
309
310 let (fetched, failed_to_fetch): (Vec<_>, Vec<_>) = packages.into_iter().partition_result();
311 if !failed_to_fetch.is_empty() {
312 Ok(Err(failed_to_fetch))
313 } else {
314 Ok(Ok(fetched))
315 }
316}
317
318pub fn get_module(
319 store: impl BackingPackageStore,
320 module_id: &ModuleId,
321) -> Result<Option<Vec<u8>>, IotaError> {
322 Ok(store
323 .get_package_object(&ObjectId::new(module_id.address().into_bytes()))?
324 .and_then(|package| {
325 package
326 .move_package()
327 .serialized_module_map()
328 .get(&identifier_core_to_sdk(module_id.name()))
329 .cloned()
330 }))
331}
332
333pub fn get_module_by_id<S: BackingPackageStore>(
334 store: &S,
335 id: &ModuleId,
336) -> anyhow::Result<Option<CompiledModule>, IotaError> {
337 Ok(get_module(store, id)?
338 .map(|bytes| CompiledModule::deserialize_with_defaults(&bytes).unwrap()))
339}
340
341pub struct PostExecutionPackageResolver {
347 backing_store: Arc<dyn BackingPackageStore>,
348 new_packages: BTreeMap<ObjectId, PackageObject>,
349}
350
351impl PostExecutionPackageResolver {
352 pub fn new(
353 backing_store: Arc<dyn BackingPackageStore>,
354 output_objects: &Option<Vec<Object>>,
355 ) -> Self {
356 let new_packages = output_objects
357 .iter()
358 .flatten()
359 .filter_map(|o| {
360 if o.is_package() {
361 Some((o.id(), PackageObject::new(o.clone())))
362 } else {
363 None
364 }
365 })
366 .collect();
367 Self {
368 backing_store,
369 new_packages,
370 }
371 }
372}
373
374impl BackingPackageStore for PostExecutionPackageResolver {
375 fn get_package_object(&self, package_id: &ObjectId) -> IotaResult<Option<PackageObject>> {
376 if let Some(package) = self.new_packages.get(package_id) {
377 Ok(Some(package.clone()))
378 } else {
379 self.backing_store.get_package_object(package_id)
380 }
381 }
382}
383
384impl<S: ChildObjectResolver> ChildObjectResolver for std::sync::Arc<S> {
385 fn read_child_object(
386 &self,
387 parent: &ObjectId,
388 child: &ObjectId,
389 child_version_upper_bound: Version,
390 ) -> IotaResult<Option<Object>> {
391 ChildObjectResolver::read_child_object(
392 self.as_ref(),
393 parent,
394 child,
395 child_version_upper_bound,
396 )
397 }
398 fn get_object_received_at_version(
399 &self,
400 owner: &ObjectId,
401 receiving_object_id: &ObjectId,
402 receive_object_at_version: Version,
403 epoch_id: EpochId,
404 ) -> IotaResult<Option<Object>> {
405 ChildObjectResolver::get_object_received_at_version(
406 self.as_ref(),
407 owner,
408 receiving_object_id,
409 receive_object_at_version,
410 epoch_id,
411 )
412 }
413}
414
415impl<S: ChildObjectResolver> ChildObjectResolver for &S {
416 fn read_child_object(
417 &self,
418 parent: &ObjectId,
419 child: &ObjectId,
420 child_version_upper_bound: Version,
421 ) -> IotaResult<Option<Object>> {
422 ChildObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound)
423 }
424 fn get_object_received_at_version(
425 &self,
426 owner: &ObjectId,
427 receiving_object_id: &ObjectId,
428 receive_object_at_version: Version,
429 epoch_id: EpochId,
430 ) -> IotaResult<Option<Object>> {
431 ChildObjectResolver::get_object_received_at_version(
432 *self,
433 owner,
434 receiving_object_id,
435 receive_object_at_version,
436 epoch_id,
437 )
438 }
439}
440
441impl<S: ChildObjectResolver> ChildObjectResolver for &mut S {
442 fn read_child_object(
443 &self,
444 parent: &ObjectId,
445 child: &ObjectId,
446 child_version_upper_bound: Version,
447 ) -> IotaResult<Option<Object>> {
448 ChildObjectResolver::read_child_object(*self, parent, child, child_version_upper_bound)
449 }
450 fn get_object_received_at_version(
451 &self,
452 owner: &ObjectId,
453 receiving_object_id: &ObjectId,
454 receive_object_at_version: Version,
455 epoch_id: EpochId,
456 ) -> IotaResult<Option<Object>> {
457 ChildObjectResolver::get_object_received_at_version(
458 *self,
459 owner,
460 receiving_object_id,
461 receive_object_at_version,
462 epoch_id,
463 )
464 }
465}
466
467#[serde_as]
469#[derive(Eq, PartialEq, Clone, Copy, PartialOrd, Ord, Hash, Serialize, Deserialize, Debug)]
470pub struct ObjectKey(pub ObjectId, pub VersionNumber);
471
472impl ObjectKey {
473 pub const ZERO: ObjectKey = ObjectKey(ObjectId::ZERO, VersionNumber::MIN_VALID_INCL);
474
475 pub fn max_for_id(id: &ObjectId) -> Self {
476 Self(*id, VersionNumber::MAX_VALID_EXCL)
477 }
478
479 pub fn min_for_id(id: &ObjectId) -> Self {
480 Self(*id, VersionNumber::MIN_VALID_INCL)
481 }
482}
483
484impl From<ObjectReference> for ObjectKey {
485 fn from(object_ref: ObjectReference) -> Self {
486 ObjectKey::from(&object_ref)
487 }
488}
489
490impl From<&ObjectReference> for ObjectKey {
491 fn from(object_ref: &ObjectReference) -> Self {
492 Self(object_ref.object_id, object_ref.version)
493 }
494}
495
496#[derive(Clone)]
497pub enum ObjectOrTombstone {
498 Object(Object),
499 Tombstone(ObjectReference),
500}
501
502impl ObjectOrTombstone {
503 pub fn as_objref(&self) -> ObjectReference {
504 match self {
505 ObjectOrTombstone::Object(obj) => obj.object_ref(),
506 ObjectOrTombstone::Tombstone(obref) => *obref,
507 }
508 }
509}
510
511impl From<Object> for ObjectOrTombstone {
512 fn from(object: Object) -> Self {
513 ObjectOrTombstone::Object(object)
514 }
515}
516
517pub fn transaction_non_shared_input_object_keys(
521 tx: &SenderSignedTransaction,
522) -> IotaResult<Vec<ObjectKey>> {
523 use crate::transaction::InputObjectKind as I;
524 Ok(tx
525 .input_objects()?
526 .into_iter()
527 .filter_map(|object| match object {
528 I::MovePackage(_) | I::SharedMoveObject { .. } => None,
529 I::ImmOrOwnedMoveObject(obj) => Some(obj.into()),
530 })
531 .collect())
532}
533
534pub fn transaction_receiving_object_keys(tx: &SenderSignedTransaction) -> Vec<ObjectKey> {
535 tx.transaction()
536 .receiving_objects()
537 .into_iter()
538 .map(|oref| oref.into())
539 .collect()
540}
541
542impl Display for DeleteKind {
543 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
544 match self {
545 DeleteKind::Wrap => write!(f, "Wrap"),
546 DeleteKind::Normal => write!(f, "Normal"),
547 DeleteKind::UnwrapThenDelete => write!(f, "UnwrapThenDelete"),
548 }
549 }
550}
551
552pub trait BackingStore: BackingPackageStore + ChildObjectResolver + ObjectStore {
553 fn as_object_store(&self) -> &dyn ObjectStore;
554}
555
556impl<T> BackingStore for T
557where
558 T: BackingPackageStore,
559 T: ChildObjectResolver,
560 T: ObjectStore,
561{
562 fn as_object_store(&self) -> &dyn ObjectStore {
563 self
564 }
565}
566
567pub fn get_transaction_input_objects(
568 object_store: &dyn ObjectStore,
569 effects: &TransactionEffects,
570) -> Result<Vec<Object>, StorageError> {
571 let input_object_keys = effects
572 .modified_at_versions()
573 .into_iter()
574 .map(|modified| ObjectKey(modified.object_id, modified.version))
575 .collect::<Vec<_>>();
576
577 let input_objects = object_store
578 .multi_get_objects_by_key(&input_object_keys)
579 .into_iter()
580 .enumerate()
581 .map(|(idx, maybe_object)| {
582 maybe_object.ok_or_else(|| {
583 StorageError::missing(format!(
584 "missing input object key {:?} from tx {}",
585 input_object_keys[idx],
586 effects.transaction_digest()
587 ))
588 })
589 })
590 .collect::<Result<Vec<_>, _>>()?;
591 Ok(input_objects)
592}
593
594pub fn get_transaction_output_objects(
595 object_store: &dyn ObjectStore,
596 effects: &TransactionEffects,
597) -> Result<Vec<Object>, StorageError> {
598 let output_object_keys = effects
599 .all_changed_objects()
600 .into_iter()
601 .map(|(changed, _kind)| ObjectKey::from(changed.reference))
602 .collect::<Vec<_>>();
603
604 let output_objects = object_store
605 .multi_get_objects_by_key(&output_object_keys)
606 .into_iter()
607 .enumerate()
608 .map(|(idx, maybe_object)| {
609 maybe_object.ok_or_else(|| {
610 StorageError::missing(format!(
611 "missing output object key {:?} from tx {}",
612 output_object_keys[idx],
613 effects.transaction_digest()
614 ))
615 })
616 })
617 .collect::<Result<Vec<_>, _>>()?;
618 Ok(output_objects)
619}
620
621pub fn extend_input_objects_with_loaded_runtime_objects(
625 input_objects: &mut BTreeMap<ObjectId, Object>,
626 effects: &TransactionEffects,
627 loaded_runtime_objects: &BTreeMap<ObjectId, DynamicallyLoadedObjectMetadata>,
628 object_store: &dyn ObjectStore,
629) {
630 let modified_at: BTreeMap<_, _> = effects
631 .modified_at_versions()
632 .into_iter()
633 .map(|modified| (modified.object_id, modified.version))
634 .collect();
635 for (id, metadata) in loaded_runtime_objects {
636 if input_objects.contains_key(id) || modified_at.get(id) != Some(&metadata.version) {
637 continue;
638 }
639 if let Some(object) = object_store.get_object_by_key(id, metadata.version) {
640 input_objects.insert(*id, object);
641 }
642 }
643}