1mod blockstore_with_read_cache;
5mod blockstore_with_write_buffer;
6pub mod car;
7mod db_impl;
8mod db_mode;
9mod either;
10pub mod gc;
11mod memory;
12pub mod migration;
13pub mod parity_db;
14pub mod parity_db_config;
15pub mod ttl;
16
17pub use blockstore_with_read_cache::*;
18pub use blockstore_with_write_buffer::BlockstoreWithWriteBuffer;
19pub use db_impl::DbImpl;
20pub use either::Either;
21pub use fvm_ipld_blockstore::{Blockstore, MemoryBlockstore};
22pub use memory::{IndexMapBlockstore, MemoryDB};
23
24use crate::blocks::{Tipset, TipsetKey};
25use crate::prelude::*;
26use crate::rpc::eth::types::EthHash;
27use crate::shim::clock::ChainEpoch;
28use ambassador::delegatable_trait;
29use serde::Serialize;
30use serde::de::DeserializeOwned;
31
32pub const CAR_DB_DIR_NAME: &str = "car_db";
33
34pub mod setting_keys {
35 pub const HEAD_KEY: &str = "head";
37 pub const MPOOL_CONFIG_KEY: &str = "/mpool/config";
39}
40
41#[auto_impl::auto_impl(&, Arc)]
44#[delegatable_trait]
45pub trait SettingsStore {
46 fn read_bin(&self, key: &str) -> anyhow::Result<Option<Vec<u8>>>;
49
50 fn write_bin(&self, key: &str, value: &[u8]) -> anyhow::Result<()>;
53
54 fn exists(&self, key: &str) -> anyhow::Result<bool>;
56
57 #[allow(dead_code)]
59 fn setting_keys(&self) -> anyhow::Result<Vec<String>>;
60}
61
62pub trait SettingsStoreExt {
66 fn read_obj<V: DeserializeOwned>(&self, key: &str) -> anyhow::Result<Option<V>>;
67 fn write_obj<V: Serialize>(&self, key: &str, value: &V) -> anyhow::Result<()>;
68
69 #[allow(dead_code)]
70 fn require_obj<V: DeserializeOwned>(&self, key: &str) -> anyhow::Result<V>;
72}
73
74impl<T: ?Sized + SettingsStore> SettingsStoreExt for T {
75 fn read_obj<V: DeserializeOwned>(&self, key: &str) -> anyhow::Result<Option<V>> {
76 match self.read_bin(key)? {
77 Some(bytes) => Ok(Some(serde_json::from_slice(&bytes)?)),
78 None => Ok(None),
79 }
80 }
81
82 fn write_obj<V: Serialize>(&self, key: &str, value: &V) -> anyhow::Result<()> {
83 self.write_bin(key, &serde_json::to_vec(value)?)
84 }
85
86 fn require_obj<V: DeserializeOwned>(&self, key: &str) -> anyhow::Result<V> {
87 self.read_bin(key)?
88 .with_context(|| format!("Key {key} not found"))
89 .and_then(|bytes| serde_json::from_slice(&bytes).map_err(Into::into))
90 }
91}
92
93#[auto_impl::auto_impl(&, Arc)]
96#[delegatable_trait]
97pub trait EthMappingsStore {
98 fn read_bin(&self, key: &EthHash) -> anyhow::Result<Option<Vec<u8>>>;
101
102 fn write_bin(&self, key: &EthHash, value: &[u8]) -> anyhow::Result<()>;
105
106 #[allow(dead_code)]
108 fn exists(&self, key: &EthHash) -> anyhow::Result<bool>;
109
110 fn get_message_cids(&self) -> anyhow::Result<Vec<(Cid, u64)>>;
112
113 fn delete(&self, keys: Vec<EthHash>) -> anyhow::Result<()>;
115
116 fn tipset_key_by_epoch(&self, epoch: ChainEpoch) -> anyhow::Result<Option<TipsetKey>>;
118
119 fn delete_tipset_key_at_epoch(&self, epoch: ChainEpoch) -> anyhow::Result<()>;
121
122 fn set_tipset_key_at_epoch_raw(&self, epoch: ChainEpoch, tsk: &TipsetKey)
124 -> anyhow::Result<()>;
125
126 fn set_tipset_key_at_epoch(&self, ts: &Tipset) -> anyhow::Result<()> {
128 EthMappingsStore::set_tipset_key_at_epoch_raw(self, ts.epoch(), ts.key())
129 }
130}
131
132pub trait EthMappingsStoreExt {
133 fn read_obj<V: DeserializeOwned>(&self, key: &EthHash) -> anyhow::Result<Option<V>>;
134 fn write_obj<V: Serialize>(&self, key: &EthHash, value: &V) -> anyhow::Result<()>;
135}
136
137impl<T: ?Sized + EthMappingsStore> EthMappingsStoreExt for T {
138 fn read_obj<V: DeserializeOwned>(&self, key: &EthHash) -> anyhow::Result<Option<V>> {
139 match self.read_bin(key)? {
140 Some(bytes) => Ok(Some(fvm_ipld_encoding::from_slice(&bytes)?)),
141 None => Ok(None),
142 }
143 }
144
145 fn write_obj<V: Serialize>(&self, key: &EthHash, value: &V) -> anyhow::Result<()> {
146 self.write_bin(key, &fvm_ipld_encoding::to_vec(value)?)
147 }
148}
149
150pub(crate) const BLOCK_BLOOM_LEN: usize = 256;
152
153#[auto_impl::auto_impl(&, Arc)]
155#[delegatable_trait]
156pub trait EthBlockBloomStore {
157 fn read_bloom(&self, key: &Cid) -> anyhow::Result<Option<[u8; BLOCK_BLOOM_LEN]>>;
160
161 fn write_bloom(
163 &self,
164 key: &Cid,
165 height: ChainEpoch,
166 bloom: &[u8; BLOCK_BLOOM_LEN],
167 ) -> anyhow::Result<()>;
168
169 fn delete_blooms_before_height(&self, height: ChainEpoch) -> anyhow::Result<()>;
171}
172
173pub(crate) fn encode_block_bloom(height: ChainEpoch, bloom: &[u8; BLOCK_BLOOM_LEN]) -> Vec<u8> {
175 let mut entry = Vec::with_capacity(size_of::<i64>() + BLOCK_BLOOM_LEN);
176 entry.extend_from_slice(&height.to_le_bytes());
177 entry.extend_from_slice(bloom);
178 entry
179}
180
181pub(crate) fn decode_block_bloom(entry: &[u8]) -> Option<(ChainEpoch, &[u8; BLOCK_BLOOM_LEN])> {
183 if entry.len() != size_of::<i64>() + BLOCK_BLOOM_LEN {
184 return None;
185 }
186 let (height, bloom) = entry.split_at(size_of::<i64>());
187 Some((
188 i64::from_le_bytes(height.try_into().ok()?),
189 bloom.try_into().ok()?,
190 ))
191}
192
193pub trait DBStatistics {
195 fn get_statistics(&self) -> Option<String> {
196 None
197 }
198}
199
200impl<DB: DBStatistics> DBStatistics for std::sync::Arc<DB> {
201 fn get_statistics(&self) -> Option<String> {
202 self.as_ref().get_statistics()
203 }
204}
205
206#[auto_impl::auto_impl(&, Arc)]
208pub trait PersistentStore: Blockstore {
209 fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()>;
216}
217
218impl PersistentStore for MemoryBlockstore {
219 fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> {
220 self.put_keyed(k, block)
221 }
222}
223
224#[auto_impl::auto_impl(&, Arc)]
225#[delegatable_trait]
226pub trait HeaviestTipsetKeyProvider {
227 fn heaviest_tipset_key(&self) -> anyhow::Result<Option<TipsetKey>>;
229
230 fn set_heaviest_tipset_key(&self, tsk: &TipsetKey) -> anyhow::Result<()>;
232}
233
234#[auto_impl::auto_impl(&, Arc)]
235pub trait BlockstoreWriteOpsSubscribable {
236 fn subscribe_write_ops(
237 &self,
238 ) -> anyhow::Result<tokio::sync::broadcast::Receiver<Vec<(Cid, bytes::Bytes)>>>;
239
240 fn unsubscribe_write_ops(&self);
241}
242
243pub mod db_engine {
244 use std::path::{Path, PathBuf};
245
246 use super::db_mode::choose_db;
247
248 pub type Db = crate::db::parity_db::ParityDb;
249 pub type DbConfig = crate::db::parity_db_config::ParityDbConfig;
250
251 pub fn db_root(chain_data_root: &Path) -> anyhow::Result<PathBuf> {
253 choose_db(chain_data_root)
254 }
255
256 pub fn open_db(path: PathBuf, config: &DbConfig) -> anyhow::Result<Db> {
257 Db::open(path, config)
258 }
259}
260
261#[cfg(test)]
262mod tests {
263 pub mod db_utils;
264 mod mem_test;
265 mod parity_test;
266 pub mod subtests;
267}