Skip to main content

sui_move_natives_latest/scratch/
runtime.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use better_any::{Tid, TidAble};
5use move_core_types::account_address::AccountAddress;
6use move_vm_runtime::execution::{Type, values::Value};
7use move_vm_runtime::natives::extensions::NativeExtensionMarker;
8use std::collections::BTreeMap;
9use sui_protocol_config::ProtocolConfig;
10
11/// A single scratch entry: the runtime type of the stored value alongside the value itself. The
12/// type is retained so reads and removes can verify the caller's requested type matches what was
13/// stored.
14pub struct ScratchEntry {
15    pub ty: Type,
16    pub value: Value,
17}
18
19/// Per-transaction, in-memory scratch store. Entries are keyed by the address derived from the
20/// `(key type, key value)` pair and live only for the duration of the transaction: a fresh
21/// `ScratchRuntime` is installed per transaction, and the map is dropped at the end of it.
22#[derive(Tid)]
23pub struct ScratchRuntime<'a> {
24    protocol_config: &'a ProtocolConfig,
25    entries: BTreeMap<AccountAddress, ScratchEntry>,
26}
27
28/// The outcome of an `add`.
29pub enum AddResult {
30    /// The entry was inserted.
31    Inserted,
32    /// An entry already existed for the key, so nothing was inserted.
33    Duplicate,
34    /// The store is already at `max_scratch_pad_size` entries, so nothing was inserted.
35    LimitExceeded,
36}
37
38impl<'a> NativeExtensionMarker<'a> for ScratchRuntime<'a> {}
39
40impl<'a> ScratchRuntime<'a> {
41    pub fn new(protocol_config: &'a ProtocolConfig) -> Self {
42        Self {
43            protocol_config,
44            entries: BTreeMap::new(),
45        }
46    }
47
48    /// Removes all entries. Used to reset the store at a transaction boundary in `test_scenario`,
49    /// where a single set of native extensions is reused across simulated transactions.
50    pub fn clear(&mut self) {
51        self.entries.clear();
52    }
53
54    /// Inserts a new entry, enforcing the per-transaction entry limit (if one is configured).
55    /// Returns `Duplicate` if an entry already exists for `key` (regardless of its type)
56    /// Returns `LimitExceeded` if inserting would exceed `max_scratch_pad_size`
57    pub fn add(&mut self, key: AccountAddress, ty: Type, value: Value) -> AddResult {
58        if self.entries.contains_key(&key) {
59            return AddResult::Duplicate;
60        }
61        if let Some(max) = self.protocol_config.max_scratch_pad_size_as_option()
62            && self.entries.len() as u64 >= max
63        {
64            return AddResult::LimitExceeded;
65        }
66        self.entries.insert(key, ScratchEntry { ty, value });
67        AddResult::Inserted
68    }
69
70    pub fn get(&self, key: &AccountAddress) -> Option<&ScratchEntry> {
71        self.entries.get(key)
72    }
73
74    pub fn remove(&mut self, key: &AccountAddress) -> Option<ScratchEntry> {
75        self.entries.remove(key)
76    }
77
78    /// Returns true if an entry exists for `key`, regardless of its stored type.
79    pub fn contains(&self, key: &AccountAddress) -> bool {
80        self.entries.contains_key(key)
81    }
82}