mod blockstore_with_read_cache;
mod blockstore_with_write_buffer;
pub mod car;
mod memory;
pub mod parity_db;
pub mod parity_db_config;
pub mod gc;
pub mod ttl;
pub use blockstore_with_read_cache::*;
pub use blockstore_with_write_buffer::BlockstoreWithWriteBuffer;
pub use memory::MemoryDB;
mod db_mode;
mod either;
pub mod migration;
pub use either::Either;
use crate::blocks::TipsetKey;
use crate::rpc::eth::types::EthHash;
use anyhow::{Context as _, bail};
use cid::Cid;
pub use fvm_ipld_blockstore::{Blockstore, MemoryBlockstore};
use serde::Serialize;
use serde::de::DeserializeOwned;
pub const CAR_DB_DIR_NAME: &str = "car_db";
pub mod setting_keys {
pub const HEAD_KEY: &str = "head";
pub const MPOOL_CONFIG_KEY: &str = "/mpool/config";
}
#[auto_impl::auto_impl(&, Arc)]
pub trait SettingsStore {
fn read_bin(&self, key: &str) -> anyhow::Result<Option<Vec<u8>>>;
fn write_bin(&self, key: &str, value: &[u8]) -> anyhow::Result<()>;
fn exists(&self, key: &str) -> anyhow::Result<bool>;
#[allow(dead_code)]
fn setting_keys(&self) -> anyhow::Result<Vec<String>>;
}
pub trait SettingsStoreExt {
fn read_obj<V: DeserializeOwned>(&self, key: &str) -> anyhow::Result<Option<V>>;
fn write_obj<V: Serialize>(&self, key: &str, value: &V) -> anyhow::Result<()>;
#[allow(dead_code)]
fn require_obj<V: DeserializeOwned>(&self, key: &str) -> anyhow::Result<V>;
}
impl<T: ?Sized + SettingsStore> SettingsStoreExt for T {
fn read_obj<V: DeserializeOwned>(&self, key: &str) -> anyhow::Result<Option<V>> {
match self.read_bin(key)? {
Some(bytes) => Ok(Some(serde_json::from_slice(&bytes)?)),
None => Ok(None),
}
}
fn write_obj<V: Serialize>(&self, key: &str, value: &V) -> anyhow::Result<()> {
self.write_bin(key, &serde_json::to_vec(value)?)
}
fn require_obj<V: DeserializeOwned>(&self, key: &str) -> anyhow::Result<V> {
self.read_bin(key)?
.with_context(|| format!("Key {key} not found"))
.and_then(|bytes| serde_json::from_slice(&bytes).map_err(Into::into))
}
}
#[auto_impl::auto_impl(&, Arc)]
pub trait EthMappingsStore {
fn read_bin(&self, key: &EthHash) -> anyhow::Result<Option<Vec<u8>>>;
fn write_bin(&self, key: &EthHash, value: &[u8]) -> anyhow::Result<()>;
#[allow(dead_code)]
fn exists(&self, key: &EthHash) -> anyhow::Result<bool>;
fn get_message_cids(&self) -> anyhow::Result<Vec<(Cid, u64)>>;
fn delete(&self, keys: Vec<EthHash>) -> anyhow::Result<()>;
}
pub struct DummyStore {}
const INDEXER_ERROR: &str =
"indexer disabled, enable with chain_indexer.enable_indexer / FOREST_CHAIN_INDEXER_ENABLED";
impl EthMappingsStore for DummyStore {
fn read_bin(&self, _key: &EthHash) -> anyhow::Result<Option<Vec<u8>>> {
bail!(INDEXER_ERROR)
}
fn write_bin(&self, _key: &EthHash, _value: &[u8]) -> anyhow::Result<()> {
bail!(INDEXER_ERROR)
}
fn exists(&self, _key: &EthHash) -> anyhow::Result<bool> {
bail!(INDEXER_ERROR)
}
fn get_message_cids(&self) -> anyhow::Result<Vec<(Cid, u64)>> {
bail!(INDEXER_ERROR)
}
fn delete(&self, _keys: Vec<EthHash>) -> anyhow::Result<()> {
bail!(INDEXER_ERROR)
}
}
pub trait EthMappingsStoreExt {
fn read_obj<V: DeserializeOwned>(&self, key: &EthHash) -> anyhow::Result<Option<V>>;
fn write_obj<V: Serialize>(&self, key: &EthHash, value: &V) -> anyhow::Result<()>;
}
impl<T: ?Sized + EthMappingsStore> EthMappingsStoreExt for T {
fn read_obj<V: DeserializeOwned>(&self, key: &EthHash) -> anyhow::Result<Option<V>> {
match self.read_bin(key)? {
Some(bytes) => Ok(Some(fvm_ipld_encoding::from_slice(&bytes)?)),
None => Ok(None),
}
}
fn write_obj<V: Serialize>(&self, key: &EthHash, value: &V) -> anyhow::Result<()> {
self.write_bin(key, &fvm_ipld_encoding::to_vec(value)?)
}
}
pub trait DBStatistics {
fn get_statistics(&self) -> Option<String> {
None
}
}
impl<DB: DBStatistics> DBStatistics for std::sync::Arc<DB> {
fn get_statistics(&self) -> Option<String> {
self.as_ref().get_statistics()
}
}
#[auto_impl::auto_impl(&, Arc)]
pub trait PersistentStore: Blockstore {
fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()>;
}
impl PersistentStore for MemoryBlockstore {
fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> {
self.put_keyed(k, block)
}
}
#[auto_impl::auto_impl(&, Arc)]
pub trait HeaviestTipsetKeyProvider {
fn heaviest_tipset_key(&self) -> anyhow::Result<Option<TipsetKey>>;
fn set_heaviest_tipset_key(&self, tsk: &TipsetKey) -> anyhow::Result<()>;
}
#[auto_impl::auto_impl(&, Arc)]
pub trait BlockstoreWriteOpsSubscribable {
fn subscribe_write_ops(&self) -> tokio::sync::broadcast::Receiver<Vec<(Cid, bytes::Bytes)>>;
fn unsubscribe_write_ops(&self);
}
pub mod db_engine {
use std::path::{Path, PathBuf};
use super::db_mode::choose_db;
pub type Db = crate::db::parity_db::ParityDb;
pub type DbConfig = crate::db::parity_db_config::ParityDbConfig;
pub fn db_root(chain_data_root: &Path) -> anyhow::Result<PathBuf> {
choose_db(chain_data_root)
}
pub fn open_db(path: PathBuf, config: &DbConfig) -> anyhow::Result<Db> {
Db::open(path, config)
}
}
#[cfg(test)]
mod tests {
pub mod db_utils;
mod mem_test;
mod parity_test;
pub mod subtests;
}