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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
// Copyright 2022-2023, Offchain Labs, Inc.
// For licensing, see https://github.com/OffchainLabs/stylus-sdk-rs/blob/stylus/licenses/COPYRIGHT.md

use alloy_primitives::{FixedBytes, Signed, Uint, B256, U256};
use core::{
    marker::PhantomData,
    ops::{Deref, DerefMut},
    ptr,
};
use derivative::Derivative;

/// Accessor trait that lets a type be used in persistent storage.
/// Users can implement this trait to add novel data structures to their contract definitions.
/// The Stylus SDK by default provides only solidity types, which are represented [`the same way`].
///
/// [`the same way`]: https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html
pub trait StorageType: Sized {
    /// For primitive types, this is the type being stored.
    /// For collections, this is the [`StorageType`] being collected.
    type Wraps<'a>: 'a
    where
        Self: 'a;

    /// Mutable accessor to the type being stored.
    type WrapsMut<'a>: 'a
    where
        Self: 'a;

    /// The number of bytes in a slot needed to represent the type. Must not exceed 32.
    /// For types larger than 32 bytes that are stored inline with a struct's fields,
    /// set this to 32 and return the full size in [`StorageType::new`].
    ///
    /// For implementing collections, see how Solidity slots are assigned for [`Arrays and Maps`] and their
    /// Stylus equivalents [`StorageVec`](super::StorageVec) and [`StorageMap`](super::StorageMap).
    /// For multi-word, but still fixed-size types, see the implementations for structs
    /// and [`StorageArray`](super::StorageArray).
    ///
    /// [`Arrays and Maps`]: https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html#mappings-and-dynamic-arrays
    const SLOT_BYTES: usize = 32;

    /// The number of words this type must fill. For primitives this is always 0.
    /// For complex types requiring more than one inline word, set this to the total size.
    const REQUIRED_SLOTS: usize = 0;

    /// Where in persistent storage the type should live. Although useful for framework designers
    /// creating new storage types, most user programs shouldn't call this.
    /// Note: implementations will have to be `const` once [`generic_const_exprs`] stabilizes.
    ///
    /// # Safety
    ///
    /// Aliases storage if two calls to the same slot and offset occur within the same lifetime.
    ///
    /// [`generic_const_exprs`]: https://github.com/rust-lang/rust/issues/76560
    unsafe fn new(slot: U256, offset: u8) -> Self;

    /// Load the wrapped type, consuming the accessor.
    /// Note: most types have a `get` and/or `getter`, which don't consume `Self`.
    fn load<'s>(self) -> Self::Wraps<'s>
    where
        Self: 's;

    /// Load the wrapped mutable type, consuming the accessor.
    /// Note: most types have a `set` and/or `setter`, which don't consume `Self`.
    fn load_mut<'s>(self) -> Self::WrapsMut<'s>
    where
        Self: 's;
}

/// Trait for accessors that can be used to completely erase their underlying value.
/// Note that some collections, like [`StorageMap`](super::StorageMap), don't implement this trait.
pub trait Erase: StorageType {
    /// Erase the value from persistent storage.
    fn erase(&mut self);
}

/// Trait for simple accessors that store no more than their wrapped value.
/// The type's representation must be entirely inline, or storage leaks become possible.
/// Note: it is a logic error if erasure does anything more than writing the zero-value.
pub trait SimpleStorageType<'a>: StorageType + Erase + Into<Self::Wraps<'a>>
where
    Self: 'a,
{
    /// Write the value to persistent storage.
    fn set_by_wrapped(&mut self, value: Self::Wraps<'a>);
}

/// Trait for top-level storage types, usually implemented by proc macros.
/// Top-level types are special in that their lifetimes track the entirety
/// of all the EVM state-changes throughout a contract invocation.
///
/// To prevent storage aliasing during reentrancy, you must hold a reference
/// to such a type when making an EVM call. This may change in the future
/// for programs that prevent reentrancy.
///
/// # Safety
///
/// The type must be top-level to prevent storage aliasing.
pub unsafe trait TopLevelStorage {}

/// Binds a storage accessor to a lifetime to prevent aliasing.
/// Because this type doesn't implement `DerefMut`, mutable methods on the accessor aren't available.
/// For a mutable accessor, see [`StorageGuardMut`].
#[derive(Derivative)]
#[derivative(Debug = "transparent")]
pub struct StorageGuard<'a, T: 'a> {
    inner: T,
    #[derivative(Debug = "ignore")]
    marker: PhantomData<&'a T>,
}

impl<'a, T: 'a> StorageGuard<'a, T> {
    /// Creates a new storage guard around an arbitrary type.
    pub fn new(inner: T) -> Self {
        Self {
            inner,
            marker: PhantomData,
        }
    }

    /// Get the underlying `T` directly, bypassing the borrow checker.
    ///
    /// # Safety
    ///
    /// Enables storage aliasing.
    pub unsafe fn into_raw(self) -> T {
        self.inner
    }
}

impl<'a, T: 'a> Deref for StorageGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

/// Binds a storage accessor to a lifetime to prevent aliasing.
pub struct StorageGuardMut<'a, T: 'a> {
    inner: T,
    marker: PhantomData<&'a T>,
}

impl<'a, T: 'a> StorageGuardMut<'a, T> {
    /// Creates a new storage guard around an arbitrary type.
    pub fn new(inner: T) -> Self {
        Self {
            inner,
            marker: PhantomData,
        }
    }

    /// Get the underlying `T` directly, bypassing the borrow checker.
    ///
    /// # Safety
    ///
    /// Enables storage aliasing.
    pub unsafe fn into_raw(self) -> T {
        self.inner
    }
}

impl<'a, T: 'a> Deref for StorageGuardMut<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<'a, T: 'a> DerefMut for StorageGuardMut<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

/// Trait for managing access to persistent storage.
/// Notable implementations include the [`StorageCache`](super::StorageCache)
/// and [`EagerStorage`](super::EagerStorage) types.
pub trait GlobalStorage {
    /// Retrieves `N ≤ 32` bytes from persistent storage, performing [`SLOAD`]'s only as needed.
    /// The bytes are read from slot `key`, starting `offset` bytes from the left.
    /// Note that the bytes must exist within a single, 32-byte EVM word.
    ///
    /// # Safety
    ///
    /// UB if the read would cross a word boundary.
    /// May become safe when Rust stabilizes [`generic_const_exprs`].
    ///
    /// [`SLOAD`]: https://www.evm.codes/#54
    /// [`generic_const_exprs`]: https://github.com/rust-lang/rust/issues/76560
    unsafe fn get<const N: usize>(key: U256, offset: usize) -> FixedBytes<N> {
        debug_assert!(N + offset <= 32);
        let word = Self::get_word(key);
        let value = &word[offset..][..N];
        FixedBytes::from_slice(value)
    }

    /// Retrieves a [`Uint`] from persistent storage, performing [`SLOAD`]'s only as needed.
    /// The integer's bytes are read from slot `key`, starting `offset` bytes from the left.
    /// Note that the bytes must exist within a single, 32-byte EVM word.
    ///
    /// # Safety
    ///
    /// UB if the read would cross a word boundary.
    /// May become safe when Rust stabilizes [`generic_const_exprs`].
    ///
    /// [`SLOAD`]: https://www.evm.codes/#54
    /// [`generic_const_exprs`]: https://github.com/rust-lang/rust/issues/76560
    unsafe fn get_uint<const B: usize, const L: usize>(key: U256, offset: usize) -> Uint<B, L> {
        debug_assert!(B / 8 + offset <= 32);
        let word = Self::get_word(key);
        let value = &word[offset..][..B / 8];
        Uint::try_from_be_slice(value).unwrap()
    }

    /// Retrieves a [`Signed`] from persistent storage, performing [`SLOAD`]'s only as needed.
    /// The integer's bytes are read from slot `key`, starting `offset` bytes from the left.
    /// Note that the bytes must exist within a single, 32-byte EVM word.
    ///
    /// # Safety
    ///
    /// UB if the read would cross a word boundary.
    /// May become safe when Rust stabilizes [`generic_const_exprs`].
    ///
    /// [`SLOAD`]: https://www.evm.codes/#54
    /// [`generic_const_exprs`]: https://github.com/rust-lang/rust/issues/76560
    unsafe fn get_signed<const B: usize, const L: usize>(key: U256, offset: usize) -> Signed<B, L> {
        Signed::from_raw(Self::get_uint(key, offset))
    }

    /// Retrieves a [`u8`] from persistent storage, performing [`SLOAD`]'s only as needed.
    /// The byte is read from slot `key`, starting `offset` bytes from the left.
    ///
    /// # Safety
    ///
    /// UB if the read is out of bounds.
    /// May become safe when Rust stabilizes [`generic_const_exprs`].
    ///
    /// [`SLOAD`]: https://www.evm.codes/#54
    /// [`generic_const_exprs`]: https://github.com/rust-lang/rust/issues/76560
    unsafe fn get_byte(key: U256, offset: usize) -> u8 {
        debug_assert!(offset <= 32);
        let word = Self::get::<1>(key, offset);
        word[0]
    }

    /// Retrieves a [`Signed`] from persistent storage, performing [`SLOAD`]'s only as needed.
    /// The integer's bytes are read from slot `key`, starting `offset` bytes from the left.
    /// Note that the bytes must exist within a single, 32-byte EVM word.
    ///
    /// # Safety
    ///
    /// UB if the read would cross a word boundary.
    /// May become safe when Rust stabilizes [`generic_const_exprs`].
    ///
    /// [`SLOAD`]: https://www.evm.codes/#54
    /// [`generic_const_exprs`]: https://github.com/rust-lang/rust/issues/76560
    fn get_word(key: U256) -> B256;

    /// Writes `N ≤ 32` bytes to persistent storage, performing [`SSTORE`]'s only as needed.
    /// The bytes are written to slot `key`, starting `offset` bytes from the left.
    /// Note that the bytes must be written to a single, 32-byte EVM word.
    ///
    /// # Safety
    ///
    /// UB if the write would cross a word boundary.
    /// Aliases if called during the lifetime an overlapping accessor.
    ///
    /// [`SSTORE`]: https://www.evm.codes/#55
    unsafe fn set<const N: usize>(key: U256, offset: usize, value: FixedBytes<N>) {
        debug_assert!(N + offset <= 32);

        if N == 32 {
            return Self::set_word(key, FixedBytes::from_slice(value.as_slice()));
        }

        let mut word = Self::get_word(key);

        let dest = word[offset..].as_mut_ptr();
        ptr::copy(value.as_ptr(), dest, N);

        Self::set_word(key, word);
    }

    /// Writes a [`Uint`] to persistent storage, performing [`SSTORE`]'s only as needed.
    /// The integer's bytes are written to slot `key`, starting `offset` bytes from the left.
    /// Note that the bytes must be written to a single, 32-byte EVM word.
    ///
    /// # Safety
    ///
    /// UB if the write would cross a word boundary.
    /// Aliases if called during the lifetime an overlapping accessor.
    ///
    /// [`SSTORE`]: https://www.evm.codes/#55
    unsafe fn set_uint<const B: usize, const L: usize>(
        key: U256,
        offset: usize,
        value: Uint<B, L>,
    ) {
        debug_assert!(B / 8 + offset <= 32);

        if B == 256 {
            return Self::set_word(key, FixedBytes::from_slice(&value.to_be_bytes::<32>()));
        }

        let mut word = Self::get_word(key);

        let value = value.to_be_bytes_vec();
        let dest = word[offset..].as_mut_ptr();
        ptr::copy(value.as_ptr(), dest, B / 8);
        Self::set_word(key, word);
    }

    /// Writes a [`Signed`] to persistent storage, performing [`SSTORE`]'s only as needed.
    /// The bytes are written to slot `key`, starting `offset` bytes from the left.
    /// Note that the bytes must be written to a single, 32-byte EVM word.
    ///
    /// # Safety
    ///
    /// UB if the write would cross a word boundary.
    /// Aliases if called during the lifetime an overlapping accessor.
    ///
    /// [`SSTORE`]: https://www.evm.codes/#55
    unsafe fn set_signed<const B: usize, const L: usize>(
        key: U256,
        offset: usize,
        value: Signed<B, L>,
    ) {
        Self::set_uint(key, offset, value.into_raw())
    }

    /// Writes a [`u8`] to persistent storage, performing [`SSTORE`]'s only as needed.
    /// The byte is written to slot `key`, starting `offset` bytes from the left.
    ///
    /// # Safety
    ///
    /// UB if the write is out of bounds.
    /// Aliases if called during the lifetime an overlapping accessor.
    ///
    /// [`SSTORE`]: https://www.evm.codes/#55
    unsafe fn set_byte(key: U256, offset: usize, value: u8) {
        let fixed = FixedBytes::from_slice(&[value]);
        Self::set::<1>(key, offset, fixed)
    }

    /// Stores a 32-byte EVM word to persistent storage, performing [`SSTORE`]'s only as needed.
    ///
    /// # Safety
    ///
    /// Aliases if called during the lifetime an overlapping accessor.
    ///
    /// [`SSTORE`]: https://www.evm.codes/#55
    unsafe fn set_word(key: U256, value: B256);

    /// Clears the 32-byte word at the given key, performing [`SSTORE`]'s only as needed.
    ///
    /// # Safety
    ///
    /// Aliases if called during the lifetime an overlapping accessor.
    ///
    /// [`SSTORE`]: https://www.evm.codes/#55
    unsafe fn clear_word(key: U256) {
        Self::set_word(key, B256::ZERO)
    }
}