Skip to main content

dusk_node/
database.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) DUSK NETWORK. All rights reserved.
6
7use std::collections::HashSet;
8use std::path::Path;
9
10pub mod rocksdb;
11
12use anyhow::Result;
13use node_data::ledger::{
14    Block, Fault, Header, Label, LedgerTransaction, SpendingId,
15    SpentTransaction,
16};
17use node_data::message::{ConsensusHeader, payload};
18use serde::{Deserialize, Serialize};
19
20pub struct LightBlock {
21    pub header: Header,
22    pub transactions_ids: Vec<[u8; 32]>,
23    pub faults_ids: Vec<[u8; 32]>,
24}
25
26pub trait DB: Send + Sync + 'static {
27    type P<'a>: Persist;
28
29    /// Creates or open a database located at this path.
30    ///
31    /// Panics if opening db or creating one fails.
32    fn create_or_open<T>(path: T, opts: DatabaseOptions) -> Self
33    where
34        T: AsRef<Path>;
35
36    /// Provides a managed execution of a read-only isolated transaction.
37    fn view<F, T>(&self, f: F) -> T
38    where
39        F: for<'a> FnOnce(&Self::P<'a>) -> T;
40
41    /// Provides a managed execution of a read-write atomic transaction.
42    ///
43    /// An atomic transaction is an indivisible and irreducible series of
44    /// database operations such that either all occur, or nothing occurs.
45    ///
46    /// Transaction commit will happen only if no error is returned by `fn`
47    /// and no panic is raised on `fn` execution.
48    fn update<F, T>(&self, f: F) -> Result<T>
49    where
50        F: for<'a> FnOnce(&mut Self::P<'a>) -> Result<T>;
51
52    fn update_dry_run<F, T>(&self, dry_run: bool, f: F) -> Result<T>
53    where
54        F: for<'a> FnOnce(&mut Self::P<'a>) -> Result<T>;
55
56    fn close(&mut self);
57}
58
59/// Implements both read-write and read-only transactions to DB.
60pub trait Ledger {
61    /// Read-write transactions
62    /// Returns disk footprint of the committed transaction
63    fn store_block(
64        &mut self,
65        header: &Header,
66        txs: &[SpentTransaction],
67        faults: &[Fault],
68        label: Label,
69    ) -> Result<usize>;
70
71    fn delete_block(&mut self, b: &Block) -> Result<()>;
72    fn block_header(&self, hash: &[u8]) -> Result<Option<Header>>;
73
74    fn light_block(&self, hash: &[u8]) -> Result<Option<LightBlock>>;
75
76    fn block(&self, hash: &[u8]) -> Result<Option<Block>>;
77    fn block_hash_by_height(&self, height: u64) -> Result<Option<[u8; 32]>>;
78    fn block_by_height(&self, height: u64) -> Result<Option<Block>>;
79
80    fn store_blob_data(&self, hash: &[u8; 32], data: Vec<u8>) -> Result<()>;
81    fn blob_data_by_hash(&self, hash: &[u8; 32]) -> Result<Option<Vec<u8>>>;
82    fn store_blobs_height(
83        &self,
84        block_height: u64,
85        blob_hashes: &[[u8; 32]],
86    ) -> Result<()>;
87    fn blobs_by_height(
88        &self,
89        block_height: u64,
90    ) -> Result<Option<Vec<[u8; 32]>>>;
91    fn delete_blobs_by_height(&self, block_height: u64) -> Result<()>;
92
93    fn block_exists(&self, hash: &[u8]) -> Result<bool>;
94
95    fn ledger_tx(&self, tx_id: &[u8]) -> Result<Option<SpentTransaction>>;
96    fn ledger_txs(
97        &self,
98        tx_ids: Vec<&[u8; 32]>,
99    ) -> Result<Vec<SpentTransaction>>;
100
101    fn ledger_tx_exists(&self, tx_id: &[u8]) -> Result<bool>;
102
103    fn block_label_by_height(
104        &self,
105        height: u64,
106    ) -> Result<Option<([u8; 32], Label)>>;
107
108    fn store_block_label(
109        &mut self,
110        height: u64,
111        hash: &[u8; 32],
112        label: Label,
113    ) -> Result<()>;
114
115    fn faults_by_block(&self, start_height: u64) -> Result<Vec<Fault>>;
116    fn faults(&self, faults_ids: &[[u8; 32]]) -> Result<Vec<Fault>>;
117
118    fn latest_block_opt(&self) -> Result<Option<LightBlock>>;
119    fn latest_block(&self) -> Result<LightBlock>;
120}
121
122pub trait ConsensusStorage {
123    /// Candidate Storage
124    fn store_candidate(&mut self, cm: Block) -> Result<()>;
125    fn candidate(&self, hash: &[u8]) -> Result<Option<Block>>;
126
127    /// Fetches a candidate block by lookup key (prev_block_hash, iteration).
128    fn candidate_by_iteration(
129        &self,
130        ch: &ConsensusHeader,
131    ) -> Result<Option<Block>>;
132
133    fn clear_candidates(&mut self) -> Result<()>;
134
135    fn delete_candidate<F>(&mut self, closure: F) -> Result<()>
136    where
137        F: FnOnce(u64) -> bool + std::marker::Copy;
138
139    fn count_candidates(&self) -> usize;
140
141    /// ValidationResult Storage
142    fn store_validation_result(
143        &mut self,
144        ch: &ConsensusHeader,
145        vr: &payload::ValidationResult,
146    ) -> Result<()>;
147
148    fn validation_result(
149        &self,
150        ch: &ConsensusHeader,
151    ) -> Result<Option<payload::ValidationResult>>;
152
153    fn clear_validation_results(&mut self) -> Result<()>;
154
155    fn delete_validation_results<F>(&mut self, closure: F) -> Result<()>
156    where
157        F: FnOnce([u8; 32]) -> bool + std::marker::Copy;
158
159    fn count_validation_results(&self) -> usize;
160}
161
162pub trait Mempool {
163    /// Adds a transaction to the mempool with a timestamp.
164    fn store_mempool_tx(
165        &mut self,
166        tx: &LedgerTransaction,
167        timestamp: u64,
168    ) -> Result<()>;
169
170    /// Gets a transaction from the mempool.
171    fn mempool_tx(&self, tx_id: [u8; 32]) -> Result<Option<LedgerTransaction>>;
172
173    /// Checks if a transaction exists in the mempool.
174    fn mempool_tx_exists(&self, tx_id: [u8; 32]) -> Result<bool>;
175
176    /// Deletes a transaction from the mempool.
177    ///
178    /// If `cascade` is true, all dependant transactions are deleted
179    ///
180    /// Return a vector with all the deleted tx_id
181    fn delete_mempool_tx(
182        &mut self,
183        tx_id: [u8; 32],
184        cascade: bool,
185    ) -> Result<Vec<[u8; 32]>>;
186
187    /// Get transactions hash from the mempool, searching by spendable ids
188    fn mempool_txs_by_spendable_ids(
189        &self,
190        n: &[SpendingId],
191    ) -> HashSet<[u8; 32]>;
192
193    /// Get an iterator over the mempool transactions sorted by gas price
194    fn mempool_txs_sorted_by_fee(
195        &self,
196    ) -> Box<dyn Iterator<Item = LedgerTransaction> + '_>;
197
198    /// Get an iterator over the mempool transactions hash by gas price
199    fn mempool_txs_ids_sorted_by_fee(
200        &self,
201    ) -> Box<dyn Iterator<Item = (u64, [u8; 32])> + '_>;
202
203    /// Get an iterator over the mempool transactions hash by gas price (asc)
204    fn mempool_txs_ids_sorted_by_low_fee(
205        &self,
206    ) -> Box<dyn Iterator<Item = (u64, [u8; 32])> + '_>;
207
208    /// Get all transactions hashes.
209    fn mempool_txs_ids(&self) -> Result<Vec<[u8; 32]>>;
210
211    /// Get all expired transactions.
212    fn mempool_expired_txs(&self, timestamp: u64) -> Result<Vec<[u8; 32]>>;
213
214    /// Number of persisted transactions
215    fn mempool_txs_count(&self) -> usize;
216}
217
218pub trait Metadata {
219    /// Assigns an value to a key in the Metadata CF
220    fn op_write<T: AsRef<[u8]>>(&mut self, key: &[u8], value: T) -> Result<()>;
221
222    /// Reads an value of a key from the Metadata CF
223    fn op_read(&self, key: &[u8]) -> Result<Option<Vec<u8>>>;
224}
225
226pub trait Persist:
227    Ledger + ConsensusStorage + Mempool + Metadata + core::fmt::Debug
228{
229    // Candidate block functions
230
231    fn clear_database(&mut self) -> Result<()>;
232    fn commit(self) -> Result<()>;
233    fn rollback(self) -> Result<()>;
234}
235
236pub fn into_array<const N: usize>(value: &[u8]) -> [u8; N] {
237    let mut res = [0u8; N];
238    res.copy_from_slice(&value[0..N]);
239    res
240}
241
242#[derive(Serialize, Deserialize, Clone, Debug)]
243pub struct DatabaseOptions {
244    /// Max write buffer size per Blocks-related CF. By default, there are two
245    /// write buffers (MemTables) per CF.
246    pub blocks_cf_max_write_buffer_size: usize,
247
248    /// Disables Block Cache for non-Mempool CFs
249    ///
250    /// Block Cache is useful in optimizing DB reads. For
251    /// non-block-explorer nodes, DB reads for block retrieval should
252    /// not be buffered in memory.
253    pub blocks_cf_disable_block_cache: bool,
254
255    /// Max write buffer size per Mempool CF.
256    pub mempool_cf_max_write_buffer_size: usize,
257
258    /// Enables a set of flags for collecting DB stats as log data.
259    pub enable_debug: bool,
260
261    /// Create the database if missing
262    pub create_if_missing: bool,
263}
264
265impl Default for DatabaseOptions {
266    fn default() -> Self {
267        Self {
268            blocks_cf_max_write_buffer_size: 1024 * 1024, // 1 MiB
269            mempool_cf_max_write_buffer_size: 10 * 1024 * 1024, // 10 MiB
270            blocks_cf_disable_block_cache: true,
271            enable_debug: false,
272            create_if_missing: true,
273        }
274    }
275}