1mod blockstore_with_read_cache;
5mod blockstore_with_write_buffer;
6pub mod car;
7mod memory;
8pub mod parity_db;
9pub mod parity_db_config;
10
11pub mod gc;
12pub mod ttl;
13pub use blockstore_with_read_cache::*;
14pub use blockstore_with_write_buffer::BlockstoreWithWriteBuffer;
15pub use memory::MemoryDB;
16mod db_mode;
17mod either;
18pub mod migration;
19pub use either::Either;
20
21use crate::blocks::{Tipset, TipsetKey};
22use crate::rpc::eth::types::EthHash;
23use anyhow::{Context as _, bail};
24use cid::Cid;
25pub use fvm_ipld_blockstore::{Blockstore, MemoryBlockstore};
26use serde::Serialize;
27use serde::de::DeserializeOwned;
28
29pub const CAR_DB_DIR_NAME: &str = "car_db";
30
31pub mod setting_keys {
32 pub const HEAD_KEY: &str = "head";
34 pub const MPOOL_CONFIG_KEY: &str = "/mpool/config";
36}
37
38#[auto_impl::auto_impl(&, Arc)]
41pub trait SettingsStore {
42 fn read_bin(&self, key: &str) -> anyhow::Result<Option<Vec<u8>>>;
45
46 fn write_bin(&self, key: &str, value: &[u8]) -> anyhow::Result<()>;
49
50 fn exists(&self, key: &str) -> anyhow::Result<bool>;
52
53 #[allow(dead_code)]
55 fn setting_keys(&self) -> anyhow::Result<Vec<String>>;
56}
57
58pub trait SettingsStoreExt {
62 fn read_obj<V: DeserializeOwned>(&self, key: &str) -> anyhow::Result<Option<V>>;
63 fn write_obj<V: Serialize>(&self, key: &str, value: &V) -> anyhow::Result<()>;
64
65 #[allow(dead_code)]
66 fn require_obj<V: DeserializeOwned>(&self, key: &str) -> anyhow::Result<V>;
68}
69
70impl<T: ?Sized + SettingsStore> SettingsStoreExt for T {
71 fn read_obj<V: DeserializeOwned>(&self, key: &str) -> anyhow::Result<Option<V>> {
72 match self.read_bin(key)? {
73 Some(bytes) => Ok(Some(serde_json::from_slice(&bytes)?)),
74 None => Ok(None),
75 }
76 }
77
78 fn write_obj<V: Serialize>(&self, key: &str, value: &V) -> anyhow::Result<()> {
79 self.write_bin(key, &serde_json::to_vec(value)?)
80 }
81
82 fn require_obj<V: DeserializeOwned>(&self, key: &str) -> anyhow::Result<V> {
83 self.read_bin(key)?
84 .with_context(|| format!("Key {key} not found"))
85 .and_then(|bytes| serde_json::from_slice(&bytes).map_err(Into::into))
86 }
87}
88
89#[auto_impl::auto_impl(&, Arc)]
92pub trait EthMappingsStore {
93 fn read_bin(&self, key: &EthHash) -> anyhow::Result<Option<Vec<u8>>>;
96
97 fn write_bin(&self, key: &EthHash, value: &[u8]) -> anyhow::Result<()>;
100
101 #[allow(dead_code)]
103 fn exists(&self, key: &EthHash) -> anyhow::Result<bool>;
104
105 fn get_message_cids(&self) -> anyhow::Result<Vec<(Cid, u64)>>;
107
108 fn delete(&self, keys: Vec<EthHash>) -> anyhow::Result<()>;
110
111 fn tipset_key_by_epoch(&self, epoch: i64) -> anyhow::Result<Option<TipsetKey>>;
113
114 fn set_tipset_key_at_epoch(&self, ts: &Tipset) -> anyhow::Result<()>;
116}
117
118pub struct DummyStore {}
119
120const INDEXER_ERROR: &str =
121 "indexer disabled, enable with chain_indexer.enable_indexer / FOREST_CHAIN_INDEXER_ENABLED";
122
123impl EthMappingsStore for DummyStore {
124 fn read_bin(&self, _key: &EthHash) -> anyhow::Result<Option<Vec<u8>>> {
125 bail!(INDEXER_ERROR)
126 }
127
128 fn write_bin(&self, _key: &EthHash, _value: &[u8]) -> anyhow::Result<()> {
129 bail!(INDEXER_ERROR)
130 }
131
132 fn exists(&self, _key: &EthHash) -> anyhow::Result<bool> {
133 bail!(INDEXER_ERROR)
134 }
135
136 fn get_message_cids(&self) -> anyhow::Result<Vec<(Cid, u64)>> {
137 bail!(INDEXER_ERROR)
138 }
139
140 fn delete(&self, _keys: Vec<EthHash>) -> anyhow::Result<()> {
141 bail!(INDEXER_ERROR)
142 }
143
144 fn tipset_key_by_epoch(&self, _epoch: i64) -> anyhow::Result<Option<TipsetKey>> {
145 bail!(INDEXER_ERROR)
146 }
147
148 fn set_tipset_key_at_epoch(&self, _ts: &Tipset) -> anyhow::Result<()> {
149 bail!(INDEXER_ERROR)
150 }
151}
152
153pub trait EthMappingsStoreExt {
154 fn read_obj<V: DeserializeOwned>(&self, key: &EthHash) -> anyhow::Result<Option<V>>;
155 fn write_obj<V: Serialize>(&self, key: &EthHash, value: &V) -> anyhow::Result<()>;
156}
157
158impl<T: ?Sized + EthMappingsStore> EthMappingsStoreExt for T {
159 fn read_obj<V: DeserializeOwned>(&self, key: &EthHash) -> anyhow::Result<Option<V>> {
160 match self.read_bin(key)? {
161 Some(bytes) => Ok(Some(fvm_ipld_encoding::from_slice(&bytes)?)),
162 None => Ok(None),
163 }
164 }
165
166 fn write_obj<V: Serialize>(&self, key: &EthHash, value: &V) -> anyhow::Result<()> {
167 self.write_bin(key, &fvm_ipld_encoding::to_vec(value)?)
168 }
169}
170
171pub trait DBStatistics {
173 fn get_statistics(&self) -> Option<String> {
174 None
175 }
176}
177
178impl<DB: DBStatistics> DBStatistics for std::sync::Arc<DB> {
179 fn get_statistics(&self) -> Option<String> {
180 self.as_ref().get_statistics()
181 }
182}
183
184#[auto_impl::auto_impl(&, Arc)]
186pub trait PersistentStore: Blockstore {
187 fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()>;
194}
195
196impl PersistentStore for MemoryBlockstore {
197 fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> {
198 self.put_keyed(k, block)
199 }
200}
201
202#[auto_impl::auto_impl(&, Arc)]
203pub trait HeaviestTipsetKeyProvider {
204 fn heaviest_tipset_key(&self) -> anyhow::Result<Option<TipsetKey>>;
206
207 fn set_heaviest_tipset_key(&self, tsk: &TipsetKey) -> anyhow::Result<()>;
209}
210
211#[auto_impl::auto_impl(&, Arc)]
212pub trait BlockstoreWriteOpsSubscribable {
213 fn subscribe_write_ops(&self) -> tokio::sync::broadcast::Receiver<Vec<(Cid, bytes::Bytes)>>;
214
215 fn unsubscribe_write_ops(&self);
216}
217
218pub mod db_engine {
219 use std::path::{Path, PathBuf};
220
221 use super::db_mode::choose_db;
222
223 pub type Db = crate::db::parity_db::ParityDb;
224 pub type DbConfig = crate::db::parity_db_config::ParityDbConfig;
225
226 pub fn db_root(chain_data_root: &Path) -> anyhow::Result<PathBuf> {
228 choose_db(chain_data_root)
229 }
230
231 pub fn open_db(path: PathBuf, config: &DbConfig) -> anyhow::Result<Db> {
232 Db::open(path, config)
233 }
234}
235
236#[cfg(test)]
237mod tests {
238 pub mod db_utils;
239 mod mem_test;
240 mod parity_test;
241 pub mod subtests;
242}