simulacrum/store/
in_mem_store.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use move_binary_format::CompiledModule;
5use move_bytecode_utils::module_cache::GetModule;
6use move_core_types::{language_storage::ModuleId, resolver::ModuleResolver};
7use std::collections::{BTreeMap, HashMap};
8use sui_config::genesis;
9use sui_types::error::SuiErrorKind;
10use sui_types::storage::{PackageObject, get_module, load_package_object_from_object_store};
11use sui_types::{
12    base_types::{AuthorityName, ObjectID, SequenceNumber, SuiAddress},
13    committee::{Committee, EpochId},
14    crypto::{AccountKeyPair, AuthorityKeyPair},
15    digests::{ObjectDigest, TransactionDigest},
16    effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents},
17    error::SuiError,
18    messages_checkpoint::{
19        CheckpointContents, CheckpointContentsDigest, CheckpointDigest, CheckpointSequenceNumber,
20        VerifiedCheckpoint,
21    },
22    object::{Object, Owner},
23    storage::{BackingPackageStore, ChildObjectResolver, ObjectStore, ParentSync},
24    transaction::VerifiedTransaction,
25};
26
27use super::SimulatorStore;
28
29#[derive(Debug, Default)]
30pub struct InMemoryStore {
31    // Checkpoint data
32    checkpoints: BTreeMap<CheckpointSequenceNumber, VerifiedCheckpoint>,
33    checkpoint_digest_to_sequence_number: HashMap<CheckpointDigest, CheckpointSequenceNumber>,
34    checkpoint_contents: HashMap<CheckpointContentsDigest, CheckpointContents>,
35
36    // Transaction data
37    transactions: HashMap<TransactionDigest, VerifiedTransaction>,
38    effects: HashMap<TransactionDigest, TransactionEffects>,
39    events: HashMap<TransactionDigest, TransactionEvents>,
40
41    // Committee data
42    epoch_to_committee: Vec<Committee>,
43
44    // Object data
45    live_objects: HashMap<ObjectID, SequenceNumber>,
46    objects: HashMap<ObjectID, BTreeMap<SequenceNumber, Object>>,
47}
48
49impl InMemoryStore {
50    pub fn new(genesis: &genesis::Genesis) -> Self {
51        let mut store = Self::default();
52        store.init_with_genesis(genesis);
53        store
54    }
55
56    pub fn get_checkpoint_by_sequence_number(
57        &self,
58        sequence_number: CheckpointSequenceNumber,
59    ) -> Option<&VerifiedCheckpoint> {
60        self.checkpoints.get(&sequence_number)
61    }
62
63    pub fn get_checkpoint_by_digest(
64        &self,
65        digest: &CheckpointDigest,
66    ) -> Option<&VerifiedCheckpoint> {
67        self.checkpoint_digest_to_sequence_number
68            .get(digest)
69            .and_then(|sequence_number| self.get_checkpoint_by_sequence_number(*sequence_number))
70    }
71
72    pub fn get_highest_checkpint(&self) -> Option<&VerifiedCheckpoint> {
73        self.checkpoints
74            .last_key_value()
75            .map(|(_, checkpoint)| checkpoint)
76    }
77
78    pub fn get_checkpoint_contents(
79        &self,
80        digest: &CheckpointContentsDigest,
81    ) -> Option<&CheckpointContents> {
82        self.checkpoint_contents.get(digest)
83    }
84
85    pub fn get_committee_by_epoch(&self, epoch: EpochId) -> Option<&Committee> {
86        self.epoch_to_committee.get(epoch as usize)
87    }
88    pub fn get_transaction(&self, digest: &TransactionDigest) -> Option<&VerifiedTransaction> {
89        self.transactions.get(digest)
90    }
91
92    pub fn get_transaction_effects(
93        &self,
94        digest: &TransactionDigest,
95    ) -> Option<&TransactionEffects> {
96        self.effects.get(digest)
97    }
98
99    pub fn get_transaction_events(&self, digest: &TransactionDigest) -> Option<&TransactionEvents> {
100        self.events.get(digest)
101    }
102
103    pub fn get_object(&self, id: &ObjectID) -> Option<&Object> {
104        let version = self.live_objects.get(id)?;
105        self.get_object_at_version(id, *version)
106    }
107
108    pub fn get_object_at_version(&self, id: &ObjectID, version: SequenceNumber) -> Option<&Object> {
109        self.objects
110            .get(id)
111            .and_then(|versions| versions.get(&version))
112    }
113
114    pub fn get_system_state(&self) -> sui_types::sui_system_state::SuiSystemState {
115        sui_types::sui_system_state::get_sui_system_state(self).expect("system state must exist")
116    }
117
118    pub fn get_clock(&self) -> sui_types::clock::Clock {
119        self.get_object(&sui_types::SUI_CLOCK_OBJECT_ID)
120            .expect("clock should exist")
121            .to_rust()
122            .expect("clock object should deserialize")
123    }
124
125    pub fn owned_objects(&self, owner: SuiAddress) -> impl Iterator<Item = &Object> {
126        self.live_objects
127            .iter()
128            .flat_map(|(id, version)| self.get_object_at_version(id, *version))
129            .filter(
130                move |object| matches!(object.owner, Owner::AddressOwner(addr) if addr == owner),
131            )
132    }
133}
134
135impl InMemoryStore {
136    pub fn insert_checkpoint(&mut self, checkpoint: VerifiedCheckpoint) {
137        if let Some(end_of_epoch_data) = &checkpoint.data().end_of_epoch_data {
138            let next_committee = end_of_epoch_data
139                .next_epoch_committee
140                .iter()
141                .cloned()
142                .collect();
143            let committee =
144                Committee::new(checkpoint.epoch().checked_add(1).unwrap(), next_committee);
145            self.insert_committee(committee);
146        }
147
148        self.checkpoint_digest_to_sequence_number
149            .insert(*checkpoint.digest(), *checkpoint.sequence_number());
150        self.checkpoints
151            .insert(*checkpoint.sequence_number(), checkpoint);
152    }
153
154    pub fn insert_checkpoint_contents(&mut self, contents: CheckpointContents) {
155        self.checkpoint_contents
156            .insert(*contents.digest(), contents);
157    }
158
159    pub fn insert_committee(&mut self, committee: Committee) {
160        let epoch = committee.epoch as usize;
161
162        if self.epoch_to_committee.get(epoch).is_some() {
163            return;
164        }
165
166        if self.epoch_to_committee.len() == epoch {
167            self.epoch_to_committee.push(committee);
168        } else {
169            panic!("committee was inserted into EpochCommitteeMap out of order");
170        }
171    }
172
173    pub fn insert_executed_transaction(
174        &mut self,
175        transaction: VerifiedTransaction,
176        effects: TransactionEffects,
177        events: TransactionEvents,
178        written_objects: BTreeMap<ObjectID, Object>,
179    ) {
180        let deleted_objects = effects.deleted();
181        let tx_digest = *effects.transaction_digest();
182        self.insert_transaction(transaction);
183        self.insert_transaction_effects(effects);
184        self.insert_events(&tx_digest, events);
185        self.update_objects(written_objects, deleted_objects);
186    }
187
188    pub fn insert_transaction(&mut self, transaction: VerifiedTransaction) {
189        self.transactions.insert(*transaction.digest(), transaction);
190    }
191
192    pub fn insert_transaction_effects(&mut self, effects: TransactionEffects) {
193        self.effects.insert(*effects.transaction_digest(), effects);
194    }
195
196    pub fn insert_events(&mut self, tx_digest: &TransactionDigest, events: TransactionEvents) {
197        self.events.insert(*tx_digest, events);
198    }
199
200    pub fn update_objects(
201        &mut self,
202        written_objects: BTreeMap<ObjectID, Object>,
203        deleted_objects: Vec<(ObjectID, SequenceNumber, ObjectDigest)>,
204    ) {
205        for (object_id, _, _) in deleted_objects {
206            self.live_objects.remove(&object_id);
207        }
208
209        for (object_id, object) in written_objects {
210            let version = object.version();
211            self.live_objects.insert(object_id, version);
212            self.objects
213                .entry(object_id)
214                .or_default()
215                .insert(version, object);
216        }
217    }
218}
219
220impl BackingPackageStore for InMemoryStore {
221    fn get_package_object(
222        &self,
223        package_id: &ObjectID,
224    ) -> sui_types::error::SuiResult<Option<PackageObject>> {
225        load_package_object_from_object_store(self, package_id)
226    }
227}
228
229impl ChildObjectResolver for InMemoryStore {
230    fn read_child_object(
231        &self,
232        parent: &ObjectID,
233        child: &ObjectID,
234        child_version_upper_bound: SequenceNumber,
235    ) -> sui_types::error::SuiResult<Option<Object>> {
236        let child_object = match crate::store::SimulatorStore::get_object(self, child) {
237            None => return Ok(None),
238            Some(obj) => obj,
239        };
240
241        let parent = *parent;
242        if child_object.owner != Owner::ObjectOwner(parent.into()) {
243            return Err(SuiErrorKind::InvalidChildObjectAccess {
244                object: *child,
245                given_parent: parent,
246                actual_owner: child_object.owner.clone(),
247            }
248            .into());
249        }
250
251        if child_object.version() > child_version_upper_bound {
252            return Err(SuiErrorKind::UnsupportedFeatureError {
253                error: "TODO InMemoryStorage::read_child_object does not yet support bounded reads"
254                    .to_owned(),
255            }
256            .into());
257        }
258
259        Ok(Some(child_object))
260    }
261
262    fn get_object_received_at_version(
263        &self,
264        owner: &ObjectID,
265        receiving_object_id: &ObjectID,
266        receive_object_at_version: SequenceNumber,
267        _epoch_id: EpochId,
268    ) -> sui_types::error::SuiResult<Option<Object>> {
269        let recv_object = match crate::store::SimulatorStore::get_object(self, receiving_object_id)
270        {
271            None => return Ok(None),
272            Some(obj) => obj,
273        };
274        if recv_object.owner != Owner::AddressOwner((*owner).into()) {
275            return Ok(None);
276        }
277
278        if recv_object.version() != receive_object_at_version {
279            return Ok(None);
280        }
281        Ok(Some(recv_object))
282    }
283}
284
285impl GetModule for InMemoryStore {
286    type Error = SuiError;
287    type Item = CompiledModule;
288
289    fn get_module_by_id(&self, id: &ModuleId) -> Result<Option<Self::Item>, Self::Error> {
290        Ok(self
291            .get_module(id)?
292            .map(|bytes| CompiledModule::deserialize_with_defaults(&bytes).unwrap()))
293    }
294}
295
296impl ModuleResolver for InMemoryStore {
297    type Error = SuiError;
298
299    fn get_module(&self, module_id: &ModuleId) -> Result<Option<Vec<u8>>, Self::Error> {
300        get_module(self, module_id)
301    }
302}
303
304impl ObjectStore for InMemoryStore {
305    fn get_object(&self, object_id: &ObjectID) -> Option<Object> {
306        self.get_object(object_id).cloned()
307    }
308
309    fn get_object_by_key(
310        &self,
311        object_id: &ObjectID,
312        version: sui_types::base_types::VersionNumber,
313    ) -> Option<Object> {
314        self.get_object_at_version(object_id, version).cloned()
315    }
316}
317
318impl ParentSync for InMemoryStore {
319    fn get_latest_parent_entry_ref_deprecated(
320        &self,
321        _object_id: ObjectID,
322    ) -> Option<sui_types::base_types::ObjectRef> {
323        panic!("Never called in newer protocol versions")
324    }
325}
326
327#[derive(Debug)]
328pub struct KeyStore {
329    validator_keys: BTreeMap<AuthorityName, AuthorityKeyPair>,
330    #[allow(unused)]
331    account_keys: BTreeMap<SuiAddress, AccountKeyPair>,
332}
333
334impl KeyStore {
335    pub fn from_network_config(
336        network_config: &sui_swarm_config::network_config::NetworkConfig,
337    ) -> Self {
338        use fastcrypto::traits::KeyPair;
339
340        let validator_keys = network_config
341            .validator_configs()
342            .iter()
343            .map(|config| {
344                (
345                    config.protocol_public_key(),
346                    config.protocol_key_pair().copy(),
347                )
348            })
349            .collect();
350
351        let account_keys = network_config
352            .account_keys
353            .iter()
354            .map(|key| (key.public().into(), key.copy()))
355            .collect();
356        Self {
357            validator_keys,
358            account_keys,
359        }
360    }
361
362    pub fn validator(&self, name: &AuthorityName) -> Option<&AuthorityKeyPair> {
363        self.validator_keys.get(name)
364    }
365
366    pub fn accounts(&self) -> impl Iterator<Item = (&SuiAddress, &AccountKeyPair)> {
367        self.account_keys.iter()
368    }
369}
370
371impl SimulatorStore for InMemoryStore {
372    fn get_checkpoint_by_sequence_number(
373        &self,
374        sequence_number: CheckpointSequenceNumber,
375    ) -> Option<VerifiedCheckpoint> {
376        self.get_checkpoint_by_sequence_number(sequence_number)
377            .cloned()
378    }
379
380    fn get_checkpoint_by_digest(&self, digest: &CheckpointDigest) -> Option<VerifiedCheckpoint> {
381        self.get_checkpoint_by_digest(digest).cloned()
382    }
383
384    fn get_highest_checkpint(&self) -> Option<VerifiedCheckpoint> {
385        self.get_highest_checkpint().cloned()
386    }
387
388    fn get_checkpoint_contents(
389        &self,
390        digest: &CheckpointContentsDigest,
391    ) -> Option<CheckpointContents> {
392        self.get_checkpoint_contents(digest).cloned()
393    }
394
395    fn get_committee_by_epoch(&self, epoch: EpochId) -> Option<Committee> {
396        self.get_committee_by_epoch(epoch).cloned()
397    }
398
399    fn get_transaction(&self, digest: &TransactionDigest) -> Option<VerifiedTransaction> {
400        self.get_transaction(digest).cloned()
401    }
402
403    fn get_transaction_effects(&self, digest: &TransactionDigest) -> Option<TransactionEffects> {
404        self.get_transaction_effects(digest).cloned()
405    }
406
407    fn get_transaction_events(&self, digest: &TransactionDigest) -> Option<TransactionEvents> {
408        self.get_transaction_events(digest).cloned()
409    }
410
411    fn get_object(&self, id: &ObjectID) -> Option<Object> {
412        self.get_object(id).cloned()
413    }
414
415    fn get_object_at_version(&self, id: &ObjectID, version: SequenceNumber) -> Option<Object> {
416        self.get_object_at_version(id, version).cloned()
417    }
418
419    fn get_system_state(&self) -> sui_types::sui_system_state::SuiSystemState {
420        self.get_system_state()
421    }
422
423    fn get_clock(&self) -> sui_types::clock::Clock {
424        self.get_clock()
425    }
426
427    fn owned_objects(&self, owner: SuiAddress) -> Box<dyn Iterator<Item = Object> + '_> {
428        Box::new(self.owned_objects(owner).cloned())
429    }
430
431    fn insert_checkpoint(&mut self, checkpoint: VerifiedCheckpoint) {
432        self.insert_checkpoint(checkpoint)
433    }
434
435    fn insert_checkpoint_contents(&mut self, contents: CheckpointContents) {
436        self.insert_checkpoint_contents(contents)
437    }
438
439    fn insert_committee(&mut self, committee: Committee) {
440        self.insert_committee(committee)
441    }
442
443    fn insert_executed_transaction(
444        &mut self,
445        transaction: VerifiedTransaction,
446        effects: TransactionEffects,
447        events: TransactionEvents,
448        written_objects: BTreeMap<ObjectID, Object>,
449    ) {
450        self.insert_executed_transaction(transaction, effects, events, written_objects)
451    }
452
453    fn insert_transaction(&mut self, transaction: VerifiedTransaction) {
454        self.insert_transaction(transaction)
455    }
456
457    fn insert_transaction_effects(&mut self, effects: TransactionEffects) {
458        self.insert_transaction_effects(effects)
459    }
460
461    fn insert_events(&mut self, tx_digest: &TransactionDigest, events: TransactionEvents) {
462        self.insert_events(tx_digest, events)
463    }
464
465    fn update_objects(
466        &mut self,
467        written_objects: BTreeMap<ObjectID, Object>,
468        deleted_objects: Vec<(ObjectID, SequenceNumber, ObjectDigest)>,
469    ) {
470        self.update_objects(written_objects, deleted_objects)
471    }
472
473    fn backing_store(&self) -> &dyn sui_types::storage::BackingStore {
474        self
475    }
476}