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::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
112pub struct DummyStore {}
113
114const INDEXER_ERROR: &str =
115 "indexer disabled, enable with chain_indexer.enable_indexer / FOREST_CHAIN_INDEXER_ENABLED";
116
117impl EthMappingsStore for DummyStore {
118 fn read_bin(&self, _key: &EthHash) -> anyhow::Result<Option<Vec<u8>>> {
119 bail!(INDEXER_ERROR)
120 }
121
122 fn write_bin(&self, _key: &EthHash, _value: &[u8]) -> anyhow::Result<()> {
123 bail!(INDEXER_ERROR)
124 }
125
126 fn exists(&self, _key: &EthHash) -> anyhow::Result<bool> {
127 bail!(INDEXER_ERROR)
128 }
129
130 fn get_message_cids(&self) -> anyhow::Result<Vec<(Cid, u64)>> {
131 bail!(INDEXER_ERROR)
132 }
133
134 fn delete(&self, _keys: Vec<EthHash>) -> anyhow::Result<()> {
135 bail!(INDEXER_ERROR)
136 }
137}
138
139pub trait EthMappingsStoreExt {
140 fn read_obj<V: DeserializeOwned>(&self, key: &EthHash) -> anyhow::Result<Option<V>>;
141 fn write_obj<V: Serialize>(&self, key: &EthHash, value: &V) -> anyhow::Result<()>;
142}
143
144impl<T: ?Sized + EthMappingsStore> EthMappingsStoreExt for T {
145 fn read_obj<V: DeserializeOwned>(&self, key: &EthHash) -> anyhow::Result<Option<V>> {
146 match self.read_bin(key)? {
147 Some(bytes) => Ok(Some(fvm_ipld_encoding::from_slice(&bytes)?)),
148 None => Ok(None),
149 }
150 }
151
152 fn write_obj<V: Serialize>(&self, key: &EthHash, value: &V) -> anyhow::Result<()> {
153 self.write_bin(key, &fvm_ipld_encoding::to_vec(value)?)
154 }
155}
156
157pub trait DBStatistics {
159 fn get_statistics(&self) -> Option<String> {
160 None
161 }
162}
163
164impl<DB: DBStatistics> DBStatistics for std::sync::Arc<DB> {
165 fn get_statistics(&self) -> Option<String> {
166 self.as_ref().get_statistics()
167 }
168}
169
170#[auto_impl::auto_impl(&, Arc)]
172pub trait PersistentStore: Blockstore {
173 fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()>;
180}
181
182impl PersistentStore for MemoryBlockstore {
183 fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> {
184 self.put_keyed(k, block)
185 }
186}
187
188#[auto_impl::auto_impl(&, Arc)]
189pub trait HeaviestTipsetKeyProvider {
190 fn heaviest_tipset_key(&self) -> anyhow::Result<Option<TipsetKey>>;
192
193 fn set_heaviest_tipset_key(&self, tsk: &TipsetKey) -> anyhow::Result<()>;
195}
196
197#[auto_impl::auto_impl(&, Arc)]
198pub trait BlockstoreWriteOpsSubscribable {
199 fn subscribe_write_ops(&self) -> tokio::sync::broadcast::Receiver<Vec<(Cid, bytes::Bytes)>>;
200
201 fn unsubscribe_write_ops(&self);
202}
203
204pub mod db_engine {
205 use std::path::{Path, PathBuf};
206
207 use super::db_mode::choose_db;
208
209 pub type Db = crate::db::parity_db::ParityDb;
210 pub type DbConfig = crate::db::parity_db_config::ParityDbConfig;
211
212 pub fn db_root(chain_data_root: &Path) -> anyhow::Result<PathBuf> {
214 choose_db(chain_data_root)
215 }
216
217 pub fn open_db(path: PathBuf, config: &DbConfig) -> anyhow::Result<Db> {
218 Db::open(path, config)
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 pub mod db_utils;
225 mod mem_test;
226 mod parity_test;
227 pub mod subtests;
228}