sui_adapter_latest/data_store/
linked_data_store.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::{
    data_store::PackageStore,
    static_programmable_transactions::linkage::resolved_linkage::RootedLinkage,
};
use move_binary_format::errors::{Location, PartialVMError, PartialVMResult, VMResult};
use move_core_types::{
    account_address::AccountAddress,
    identifier::IdentStr,
    language_storage::ModuleId,
    resolver::{LinkageResolver, ModuleResolver},
    vm_status::StatusCode,
};
use move_vm_types::data_store::DataStore;
use sui_types::{
    base_types::ObjectID,
    error::{ExecutionErrorKind, SuiError},
};

/// A `LinkedDataStore` is a wrapper around a `PackageStore` (i.e., a package store where
/// we can also resolve types to defining IDs) along with a specific `linkage`. These two together
/// allow us to resolve modules and types in a way that is consistent with the `linkage` provided
/// and allow us to then pass this into the VM. Until we have a linkage set it is not possible to
/// construct a valid `DataStore` for execution in the VM as it needs to be able to resolve modules
/// under a specific linkage.
pub struct LinkedDataStore<'a> {
    pub linkage: &'a RootedLinkage,
    pub store: &'a dyn PackageStore,
}

impl<'a> LinkedDataStore<'a> {
    pub fn new(linkage: &'a RootedLinkage, store: &'a dyn PackageStore) -> Self {
        Self { linkage, store }
    }
}

impl DataStore for LinkedDataStore<'_> {
    fn link_context(&self) -> PartialVMResult<AccountAddress> {
        Ok(self.linkage.link_context)
    }

    fn relocate(&self, module_id: &ModuleId) -> PartialVMResult<ModuleId> {
        self.linkage
            .resolved_linkage
            .linkage
            .get(&ObjectID::from(*module_id.address()))
            .map(|obj_id| ModuleId::new(**obj_id, module_id.name().to_owned()))
            .ok_or_else(|| {
                PartialVMError::new(StatusCode::LINKER_ERROR).with_message(format!(
                    "Error relocating {module_id} -- could not find linkage"
                ))
            })
    }

    fn defining_module(
        &self,
        module_id: &ModuleId,
        struct_: &IdentStr,
    ) -> PartialVMResult<ModuleId> {
        self.store
            .resolve_type_to_defining_id(
                    ObjectID::from(*module_id.address()),
                    module_id.name(),
                    struct_,
                )
                .ok()
                .flatten()
                .map(|obj_id| ModuleId::new(*obj_id, module_id.name().to_owned()))
                .ok_or_else(|| {
                    PartialVMError::new(StatusCode::LINKER_ERROR).with_message(format!(
                        "Error finding defining module for {module_id}::{struct_} -- could nod find linkage"
                    ))
                })
    }

    // NB: module_id is original ID based
    fn load_module(&self, module_id: &ModuleId) -> VMResult<Vec<u8>> {
        let package_storage_id = ObjectID::from(*module_id.address());
        match self
            .store
            .get_package(&package_storage_id)
            .map(|pkg| pkg.and_then(|pkg| pkg.get_module(module_id).cloned()))
        {
            Ok(Some(bytes)) => Ok(bytes),
            Ok(None) => Err(PartialVMError::new(StatusCode::LINKER_ERROR)
                .with_message(format!("Cannot find {:?} in data cache", module_id))
                .finish(Location::Undefined)),
            Err(err) => {
                let msg = format!("Unexpected storage error: {:?}", err);
                Err(
                    PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
                        .with_message(msg)
                        .finish(Location::Undefined),
                )
            }
        }
    }

    fn publish_module(&mut self, _module_id: &ModuleId, _blob: Vec<u8>) -> VMResult<()> {
        Ok(())
    }
}

impl DataStore for &LinkedDataStore<'_> {
    fn link_context(&self) -> PartialVMResult<AccountAddress> {
        DataStore::link_context(*self)
    }

    fn relocate(&self, module_id: &ModuleId) -> PartialVMResult<ModuleId> {
        DataStore::relocate(*self, module_id)
    }

    fn defining_module(
        &self,
        module_id: &ModuleId,
        struct_: &IdentStr,
    ) -> PartialVMResult<ModuleId> {
        DataStore::defining_module(*self, module_id, struct_)
    }

    fn load_module(&self, module_id: &ModuleId) -> VMResult<Vec<u8>> {
        DataStore::load_module(*self, module_id)
    }

    fn publish_module(&mut self, _module_id: &ModuleId, _blob: Vec<u8>) -> VMResult<()> {
        Ok(())
    }
}

impl ModuleResolver for LinkedDataStore<'_> {
    type Error = SuiError;

    fn get_module(&self, id: &ModuleId) -> Result<Option<Vec<u8>>, Self::Error> {
        self.load_module(id)
            .map(Some)
            .map_err(|_| SuiError::from(ExecutionErrorKind::VMVerificationOrDeserializationError))
    }
}

impl LinkageResolver for LinkedDataStore<'_> {
    type Error = SuiError;
}