sov_db/schema/
types.rs

1use std::sync::Arc;
2
3use borsh::{BorshDeserialize, BorshSerialize};
4use serde::de::DeserializeOwned;
5use serde::{Deserialize, Serialize};
6use sov_rollup_interface::rpc::{BatchResponse, TxIdentifier, TxResponse};
7use sov_rollup_interface::stf::{Event, EventKey, TransactionReceipt};
8
9/// A cheaply cloneable bytes abstraction for use within the trust boundary of the node
10/// (i.e. when interfacing with the database). Serializes and deserializes more efficiently,
11/// than most bytes abstractions, but is vulnerable to out-of-memory attacks
12/// when read from an untrusted source.
13///
14/// # Warning
15/// Do not use this type when deserializing data from an untrusted source!!
16#[derive(
17    Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Default, BorshDeserialize, BorshSerialize,
18)]
19#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
20pub struct DbBytes(Arc<Vec<u8>>);
21
22impl DbBytes {
23    /// Create `DbBytes` from a `Vec<u8>`
24    pub fn new(contents: Vec<u8>) -> Self {
25        Self(Arc::new(contents))
26    }
27}
28
29impl From<Vec<u8>> for DbBytes {
30    fn from(value: Vec<u8>) -> Self {
31        Self(Arc::new(value))
32    }
33}
34
35impl AsRef<[u8]> for DbBytes {
36    fn as_ref(&self) -> &[u8] {
37        self.0.as_ref()
38    }
39}
40
41/// The "key" half of a key/value pair from accessory state.
42///
43/// See [`NativeDB`](crate::native_db::NativeDB) for more information.
44pub type AccessoryKey = Vec<u8>;
45/// The "value" half of a key/value pair from accessory state.
46///
47/// See [`NativeDB`](crate::native_db::NativeDB) for more information.
48pub type AccessoryStateValue = Option<Vec<u8>>;
49
50/// A hash stored in the database
51pub type DbHash = [u8; 32];
52/// The "value" half of a key/value pair from the JMT
53pub type JmtValue = Option<Vec<u8>>;
54pub(crate) type StateKey = Vec<u8>;
55
56/// The on-disk format of a slot. Specifies the batches contained in the slot
57/// and the hash of the da block. TODO(@preston-evans98): add any additional data
58/// required to reconstruct the da block proof.
59#[derive(Debug, PartialEq, BorshDeserialize, BorshSerialize)]
60#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
61pub struct StoredSlot {
62    /// The slot's hash, as reported by the DA layer.
63    pub hash: DbHash,
64    /// Any extra data which the rollup decides to store relating to this slot.
65    pub extra_data: DbBytes,
66    /// The range of batches which occurred in this slot.
67    pub batches: std::ops::Range<BatchNumber>,
68}
69
70/// The on-disk format for a batch. Stores the hash and identifies the range of transactions
71/// included in the batch.
72#[derive(Debug, PartialEq, BorshDeserialize, BorshSerialize)]
73#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
74pub struct StoredBatch {
75    /// The hash of the batch, as reported by the DA layer.
76    pub hash: DbHash,
77    /// The range of transactions which occurred in this batch.
78    pub txs: std::ops::Range<TxNumber>,
79    /// A customer "receipt" for this batch defined by the rollup.
80    pub custom_receipt: DbBytes,
81}
82
83impl<B: DeserializeOwned, T> TryFrom<StoredBatch> for BatchResponse<B, T> {
84    type Error = anyhow::Error;
85    fn try_from(value: StoredBatch) -> Result<Self, Self::Error> {
86        Ok(Self {
87            hash: value.hash,
88            custom_receipt: bincode::deserialize(&value.custom_receipt.0)?,
89            tx_range: value.txs.start.into()..value.txs.end.into(),
90            txs: None,
91        })
92    }
93}
94
95/// The on-disk format of a transaction. Includes the txhash, the serialized tx data,
96/// and identifies the events emitted by this transaction
97#[derive(Debug, PartialEq, BorshSerialize, BorshDeserialize, Clone)]
98pub struct StoredTransaction {
99    /// The hash of the transaction.
100    pub hash: DbHash,
101    /// The range of event-numbers emitted by this transaction.
102    pub events: std::ops::Range<EventNumber>,
103    /// The serialized transaction data, if the rollup decides to store it.
104    pub body: Option<Vec<u8>>,
105    /// A customer "receipt" for this transaction defined by the rollup.
106    pub custom_receipt: DbBytes,
107}
108
109impl<R: DeserializeOwned> TryFrom<StoredTransaction> for TxResponse<R> {
110    type Error = anyhow::Error;
111    fn try_from(value: StoredTransaction) -> Result<Self, Self::Error> {
112        Ok(Self {
113            hash: value.hash,
114            event_range: value.events.start.into()..value.events.end.into(),
115            body: value.body,
116            custom_receipt: bincode::deserialize(&value.custom_receipt.0)?,
117        })
118    }
119}
120
121/// Split a `TransactionReceipt` into a `StoredTransaction` and a list of `Event`s for storage in the database.
122pub fn split_tx_for_storage<R: Serialize>(
123    tx: TransactionReceipt<R>,
124    event_offset: u64,
125) -> (StoredTransaction, Vec<Event>) {
126    let event_range = EventNumber(event_offset)..EventNumber(event_offset + tx.events.len() as u64);
127    let tx_for_storage = StoredTransaction {
128        hash: tx.tx_hash,
129        events: event_range,
130        body: tx.body_to_save,
131        custom_receipt: DbBytes::new(
132            bincode::serialize(&tx.receipt).expect("Serialization to vec is infallible"),
133        ),
134    };
135    (tx_for_storage, tx.events)
136}
137
138/// An identifier that specifies a single event
139#[derive(Debug, PartialEq, Serialize, Deserialize)]
140pub enum EventIdentifier {
141    /// A unique identifier for an event consisting of a [`TxIdentifier`] and an offset into that transaction's event list
142    TxIdAndIndex((TxIdentifier, u64)),
143    /// A unique identifier for an event consisting of a [`TxIdentifier`] and an event key
144    TxIdAndKey((TxIdentifier, EventKey)),
145    /// The monotonically increasing number of the event, ordered by the DA layer For example, if the first tx
146    /// contains 7 events, tx 2 contains 11 events, and tx 3 contains 7 txs,
147    /// the last event in tx 3 would have number 25. The counter never resets.
148    Number(EventNumber),
149}
150
151/// An identifier for a group of related events
152#[derive(Debug, PartialEq, Serialize, Deserialize)]
153pub enum EventGroupIdentifier {
154    /// All of the events which occurred in a particular transaction
155    TxId(TxIdentifier),
156    /// All events which a particular key
157    /// (typically, these events will have been emitted by several different transactions)
158    Key(Vec<u8>),
159}
160
161macro_rules! u64_wrapper {
162    ($name:ident) => {
163        /// A typed wrapper around u64 implementing `Encode` and `Decode`
164        #[derive(
165            Clone,
166            Copy,
167            ::core::fmt::Debug,
168            Default,
169            PartialEq,
170            Eq,
171            PartialOrd,
172            Ord,
173            ::borsh::BorshDeserialize,
174            ::borsh::BorshSerialize,
175            ::serde::Serialize,
176            ::serde::Deserialize,
177        )]
178        #[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
179        pub struct $name(pub u64);
180
181        impl From<$name> for u64 {
182            fn from(value: $name) -> Self {
183                value.0
184            }
185        }
186
187        #[cfg(feature = "arbitrary")]
188        impl<'a> ::arbitrary::Arbitrary<'a> for $name {
189            fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
190                u.arbitrary().map($name)
191            }
192        }
193    };
194}
195
196u64_wrapper!(SlotNumber);
197u64_wrapper!(BatchNumber);
198u64_wrapper!(TxNumber);
199u64_wrapper!(EventNumber);
200
201#[cfg(feature = "arbitrary")]
202pub mod arbitrary {
203    //! Arbitrary definitions for the types.
204
205    use super::*;
206
207    impl<'a> ::arbitrary::Arbitrary<'a> for DbBytes {
208        fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
209            u.arbitrary().map(DbBytes::new)
210        }
211    }
212
213    impl<'a> ::arbitrary::Arbitrary<'a> for StoredTransaction {
214        fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
215            Ok(StoredTransaction {
216                hash: u.arbitrary()?,
217                events: u.arbitrary()?,
218                body: u.arbitrary()?,
219                custom_receipt: u.arbitrary()?,
220            })
221        }
222    }
223
224    impl<'a> ::arbitrary::Arbitrary<'a> for StoredBatch {
225        fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
226            Ok(StoredBatch {
227                hash: u.arbitrary()?,
228                txs: u.arbitrary()?,
229                custom_receipt: u.arbitrary()?,
230            })
231        }
232    }
233
234    impl<'a> ::arbitrary::Arbitrary<'a> for StoredSlot {
235        fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
236            Ok(StoredSlot {
237                hash: u.arbitrary()?,
238                extra_data: u.arbitrary()?,
239                batches: u.arbitrary()?,
240            })
241        }
242    }
243}