From e75471b7de12148cd944246c3b09753d8feb2b50 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Thu, 31 Oct 2024 16:36:32 +0100 Subject: [PATCH 01/21] remove redundant match block --- src/db/parity_db.rs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/db/parity_db.rs b/src/db/parity_db.rs index 07d6d3ae1a91..90e53bdfd494 100644 --- a/src/db/parity_db.rs +++ b/src/db/parity_db.rs @@ -216,24 +216,14 @@ impl EthMappingsStore for ParityDb { impl Blockstore for ParityDb { fn get(&self, k: &Cid) -> anyhow::Result>> { let column = Self::choose_column(k); - match column { - DbColumn::GraphDagCborBlake2b256 | DbColumn::GraphFull => { - self.read_from_column(k.to_bytes(), column) - } - DbColumn::Settings | DbColumn::EthMappings => panic!("invalid column for IPLD data"), - } + self.read_from_column(k.to_bytes(), column) } fn put_keyed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { let column = Self::choose_column(k); - match column { - // We can put the data directly into the database without any encoding. - DbColumn::GraphDagCborBlake2b256 | DbColumn::GraphFull => { - self.write_to_column(k.to_bytes(), block, column) - } - DbColumn::Settings | DbColumn::EthMappings => panic!("invalid column for IPLD data"), - } + // We can put the data directly into the database without any encoding. + self.write_to_column(k.to_bytes(), block, column) } fn put_many_keyed(&self, blocks: I) -> anyhow::Result<()> From b291b786e31087915fffdb19adcda357be24e834 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Thu, 31 Oct 2024 19:16:16 +0100 Subject: [PATCH 02/21] wip --- src/daemon/bundle.rs | 16 ++++++++++----- src/db/car/any.rs | 14 ++++++++++++++ src/db/car/forest.rs | 11 +++++++++++ src/db/car/many.rs | 8 +++++++- src/db/car/plain.rs | 10 ++++++++++ src/db/memory.rs | 8 +++++++- src/db/mod.rs | 18 +++++++++++++++++ src/db/parity_db.rs | 29 ++++++++++++++++++++++------ src/tool/subcommands/snapshot_cmd.rs | 5 +++-- src/utils/db/car_util.rs | 1 + 10 files changed, 105 insertions(+), 15 deletions(-) diff --git a/src/daemon/bundle.rs b/src/daemon/bundle.rs index f04ff3a799ce..093df5d0827f 100644 --- a/src/daemon/bundle.rs +++ b/src/daemon/bundle.rs @@ -1,6 +1,7 @@ // Copyright 2019-2024 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT +use crate::db::BlessedStore; use crate::{ networks::{ActorBundleInfo, NetworkChain, ACTOR_BUNDLES}, utils::{ @@ -18,12 +19,13 @@ use futures::{stream::FuturesUnordered, TryStreamExt}; use fvm_ipld_blockstore::Blockstore; use std::mem::discriminant; use std::{io::Cursor, path::Path}; +use tokio::io::BufReader; use tracing::{info, warn}; /// Tries to load the missing actor bundles to the blockstore. If the bundle is /// not present, it will be downloaded. pub async fn load_actor_bundles( - db: &impl Blockstore, + db: &impl BlessedStore, network: &NetworkChain, ) -> anyhow::Result<()> { if let Some(bundle_path) = match std::env::var("FOREST_ACTOR_BUNDLE_PATH") { @@ -40,7 +42,7 @@ pub async fn load_actor_bundles( } pub async fn load_actor_bundles_from_path( - db: &impl Blockstore, + db: &impl BlessedStore, network: &NetworkChain, bundle_path: impl AsRef, ) -> anyhow::Result<()> { @@ -70,7 +72,7 @@ pub async fn load_actor_bundles_from_path( // Load into DB while let Some(CarBlock { cid, data }) = car_stream.try_next().await? { - db.put_keyed(&cid, &data)?; + db.put_keyed_blessed(&cid, &data)?; } Ok(()) @@ -78,7 +80,7 @@ pub async fn load_actor_bundles_from_path( /// Loads the missing actor bundle, returns the CIDs of the loaded bundles. pub async fn load_actor_bundles_from_server( - db: &impl Blockstore, + db: &impl BlessedStore, network: &NetworkChain, bundles: &[ActorBundleInfo], ) -> anyhow::Result> { @@ -106,7 +108,11 @@ pub async fn load_actor_bundles_from_server( http_get(alt_url).await? }; let bytes = response.bytes().await?; - let header = load_car(db, Cursor::new(bytes)).await?; + let mut stream = CarStream::new(BufReader::new(Cursor::new(bytes))).await?; + while let Some(block) = stream.try_next().await? { + db.put_keyed_blessed(&block.cid, &block.data)?; + } + let header = stream.header; ensure!(header.roots.len() == 1); ensure!(header.roots.first() == root); Ok(*header.roots.first()) diff --git a/src/db/car/any.rs b/src/db/car/any.rs index d4a9eb422991..a7f73b5a7cc1 100644 --- a/src/db/car/any.rs +++ b/src/db/car/any.rs @@ -10,6 +10,7 @@ use super::{CacheKey, RandomAccessFileReader, ZstdFrameCache}; use crate::blocks::Tipset; +use crate::db::BlessedStore; use crate::utils::io::EitherMmapOrRandomAccessFile; use cid::Cid; use fvm_ipld_blockstore::Blockstore; @@ -124,6 +125,19 @@ where } } +impl BlessedStore for AnyCar +where + ReaderT: ReadAt, +{ + fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + match self { + AnyCar::Forest(forest) => forest.put_keyed_blessed(k, block), + AnyCar::Plain(plain) => plain.put_keyed_blessed(k, block), + AnyCar::Memory(mem) => mem.put_keyed_blessed(k, block), + } + } +} + impl From> for AnyCar { fn from(car: super::ForestCar) -> Self { Self::Forest(car) diff --git a/src/db/car/forest.rs b/src/db/car/forest.rs index bb5f2829f287..ff9954fcedb7 100644 --- a/src/db/car/forest.rs +++ b/src/db/car/forest.rs @@ -50,6 +50,7 @@ use super::{CacheKey, ZstdFrameCache}; use crate::blocks::{Tipset, TipsetKey}; use crate::db::car::plain::write_skip_frame_header_async; use crate::db::car::RandomAccessFileReader; +use crate::db::BlessedStore; use crate::utils::db::car_stream::{CarBlock, CarHeader}; use crate::utils::encoding::from_slice_with_fallback; use crate::utils::io::EitherMmapOrRandomAccessFile; @@ -73,6 +74,7 @@ use std::{ use tokio::io::{AsyncWrite, AsyncWriteExt}; use tokio_util::codec::{Decoder, Encoder as _}; use unsigned_varint::codec::UviBytes; + #[cfg(feature = "benchmark-private")] pub mod index; #[cfg(not(feature = "benchmark-private"))] @@ -237,6 +239,15 @@ where } } +impl BlessedStore for ForestCar +where + ReaderT: ReadAt, +{ + fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + self.put_keyed(k, block) + } +} + fn decode_zstd_single_frame(reader: ReaderT) -> io::Result { let mut zstd_frame = vec![]; zstd::Decoder::new(reader)? diff --git a/src/db/car/many.rs b/src/db/car/many.rs index 4f279440564e..4656ce322d8b 100644 --- a/src/db/car/many.rs +++ b/src/db/car/many.rs @@ -9,7 +9,7 @@ //! A single z-frame cache is shared between all read-only stores. use super::{AnyCar, ZstdFrameCache}; -use crate::db::{EthMappingsStore, MemoryDB, SettingsStore}; +use crate::db::{BlessedStore, EthMappingsStore, MemoryDB, SettingsStore}; use crate::libp2p_bitswap::BitswapStoreReadWrite; use crate::rpc::eth::types::EthHash; use crate::shim::clock::ChainEpoch; @@ -169,6 +169,12 @@ impl Blockstore for ManyCar { } } +impl BlessedStore for ManyCar { + fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + self.writer.put_keyed_blessed(k, block) + } +} + impl BitswapStoreRead for ManyCar { fn contains(&self, cid: &Cid) -> anyhow::Result { Blockstore::has(self, cid) diff --git a/src/db/car/plain.rs b/src/db/car/plain.rs index 8c7b6c54e11a..6a5403263900 100644 --- a/src/db/car/plain.rs +++ b/src/db/car/plain.rs @@ -71,6 +71,7 @@ use cid::Cid; use fvm_ipld_blockstore::Blockstore; use integer_encoding::VarIntReader; +use crate::db::BlessedStore; use nunny::Vec as NonEmpty; use parking_lot::RwLock; use positioned_io::ReadAt; @@ -233,6 +234,15 @@ where } } +impl BlessedStore for PlainCar +where + ReaderT: ReadAt, +{ + fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + self.put_keyed(k, block) + } +} + pub async fn write_skip_frame_header_async( mut writer: impl AsyncWrite + Unpin, data_len: u32, diff --git a/src/db/memory.rs b/src/db/memory.rs index 95b371a1af06..d1aba056ca05 100644 --- a/src/db/memory.rs +++ b/src/db/memory.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0, MIT use crate::cid_collections::CidHashSet; -use crate::db::GarbageCollectable; +use crate::db::{BlessedStore, GarbageCollectable}; use crate::libp2p_bitswap::{BitswapStoreRead, BitswapStoreReadWrite}; use crate::rpc::eth::types::EthHash; use ahash::HashMap; @@ -120,6 +120,12 @@ impl Blockstore for MemoryDB { } } +impl BlessedStore for MemoryDB { + fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + self.put_keyed(k, block) + } +} + impl BitswapStoreRead for MemoryDB { fn contains(&self, cid: &Cid) -> anyhow::Result { Ok(self.blockchain_db.read().contains_key(&cid.to_bytes())) diff --git a/src/db/mod.rs b/src/db/mod.rs index dd0a648c761b..e7b8dac4ad64 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -17,6 +17,7 @@ pub mod migration; use crate::rpc::eth::types::EthHash; use anyhow::Context as _; use cid::Cid; +use fvm_ipld_blockstore::{Blockstore, MemoryBlockstore}; use serde::de::DeserializeOwned; use serde::Serialize; use std::sync::Arc; @@ -211,6 +212,23 @@ pub trait GarbageCollectable { fn remove_keys(&self, keys: T) -> anyhow::Result; } +/// A trait that allows for storing data that is not garbage collected. +pub trait BlessedStore: Blockstore { + /// Puts a keyed block with pre-computed CID into the database. + /// + /// # Arguments + /// + /// * `k` - The key to be stored. + /// * `block` - The block to be stored. + fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()>; +} + +impl BlessedStore for MemoryBlockstore { + fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + self.put_keyed(k, block) + } +} + pub mod db_engine { use std::path::{Path, PathBuf}; diff --git a/src/db/parity_db.rs b/src/db/parity_db.rs index 90e53bdfd494..fe26158045e8 100644 --- a/src/db/parity_db.rs +++ b/src/db/parity_db.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; -use super::SettingsStore; +use super::{BlessedStore, SettingsStore}; use super::EthMappingsStore; @@ -32,6 +32,10 @@ use tracing::warn; #[derive(Copy, Clone, Debug, Display, PartialEq, FromRepr, EnumIter)] #[repr(u8)] enum DbColumn { + /// Column for storing IPLD data that has to be ignored by the garbage collector. + /// Anything stored in this column can be considered permanent, unless manually + /// deleted. + BlessedGraph, /// Column for storing IPLD data with `Blake2b256` hash and `DAG_CBOR` codec. /// Most entries in the `blockstore` will be stored in this column. GraphDagCborBlake2b256, @@ -51,11 +55,13 @@ impl DbColumn { DbColumn::iter() .map(|col| { match col { - DbColumn::GraphDagCborBlake2b256 => parity_db::ColumnOptions { - preimage: true, - compression, - ..Default::default() - }, + DbColumn::GraphDagCborBlake2b256 | DbColumn::BlessedGraph => { + parity_db::ColumnOptions { + preimage: true, + compression, + ..Default::default() + } + } DbColumn::GraphFull => parity_db::ColumnOptions { preimage: true, // This is needed for key retrieval. @@ -245,6 +251,12 @@ impl Blockstore for ParityDb { } } +impl BlessedStore for ParityDb { + fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + self.write_to_column(k.to_bytes(), block, DbColumn::BlessedGraph) + } +} + impl BitswapStoreRead for ParityDb { fn contains(&self, cid: &Cid) -> anyhow::Result { // We need to check both columns because we don't know which one @@ -323,6 +335,11 @@ impl ParityDb { pub fn set_operation(column: u8, key: Vec, value: Vec) -> Op { (column, Operation::Set(key, value)) } + + // Get data from persistent graph column. + fn get_blessed(&self, k: &Cid) -> anyhow::Result>> { + self.read_from_column(k.to_bytes(), DbColumn::BlessedGraph) + } } impl GarbageCollectable for ParityDb { diff --git a/src/tool/subcommands/snapshot_cmd.rs b/src/tool/subcommands/snapshot_cmd.rs index b9a096bebef8..61583e71b169 100644 --- a/src/tool/subcommands/snapshot_cmd.rs +++ b/src/tool/subcommands/snapshot_cmd.rs @@ -8,6 +8,7 @@ use crate::cli_shared::snapshot; use crate::daemon::bundle::load_actor_bundles; use crate::db::car::forest::DEFAULT_FOREST_CAR_FRAME_SIZE; use crate::db::car::{AnyCar, ManyCar}; +use crate::db::BlessedStore; use crate::interpreter::{MessageCallbackCtx, VMEvent, VMTrace}; use crate::ipld::stream_chain; use crate::networks::{butterflynet, calibnet, mainnet, ChainConfig, NetworkChain}; @@ -294,7 +295,7 @@ async fn validate_with_blockstore( check_stateroots: u32, ) -> anyhow::Result<()> where - BlockstoreT: Blockstore + Send + Sync + 'static, + BlockstoreT: BlessedStore + Send + Sync + 'static, { if check_links != 0 { validate_ipld_links(root.clone(), &store, check_links).await?; @@ -396,7 +397,7 @@ async fn validate_stateroots( epochs: u32, ) -> anyhow::Result<()> where - DB: Blockstore + Send + Sync + 'static, + DB: BlessedStore + Send + Sync + 'static, { let chain_config = Arc::new(ChainConfig::from_chain(&network)); let genesis = ts.genesis(db)?; diff --git a/src/utils/db/car_util.rs b/src/utils/db/car_util.rs index 0a7706861184..8670b4248139 100644 --- a/src/utils/db/car_util.rs +++ b/src/utils/db/car_util.rs @@ -6,6 +6,7 @@ use fvm_ipld_blockstore::Blockstore; use tokio::io::{AsyncBufRead, AsyncSeek, BufReader}; use crate::cid_collections::CidHashSet; +use crate::db::BlessedStore; use crate::utils::db::car_stream::{CarBlock, CarHeader, CarStream}; /// Stream key-value pairs from a CAR archive into a block store. From 51d3e4d280b1ccbef03a7978ddef6453fa295f8d Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Thu, 31 Oct 2024 19:32:55 +0100 Subject: [PATCH 03/21] fix compilation --- src/daemon/bundle.rs | 1 + src/db/mod.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/daemon/bundle.rs b/src/daemon/bundle.rs index 093df5d0827f..25dc4f7b9d45 100644 --- a/src/daemon/bundle.rs +++ b/src/daemon/bundle.rs @@ -108,6 +108,7 @@ pub async fn load_actor_bundles_from_server( http_get(alt_url).await? }; let bytes = response.bytes().await?; + let mut stream = CarStream::new(BufReader::new(Cursor::new(bytes))).await?; while let Some(block) = stream.try_next().await? { db.put_keyed_blessed(&block.cid, &block.data)?; diff --git a/src/db/mod.rs b/src/db/mod.rs index e7b8dac4ad64..7029afbc20ce 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -229,6 +229,18 @@ impl BlessedStore for MemoryBlockstore { } } +impl BlessedStore for Arc { + fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + BlessedStore::put_keyed_blessed(self.as_ref(), k, block) + } +} + +impl BlessedStore for &Arc { + fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + BlessedStore::put_keyed_blessed(self.as_ref(), k, block) + } +} + pub mod db_engine { use std::path::{Path, PathBuf}; From 9835839e82e69626fd71f99cef10a88aff2e6d72 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Thu, 31 Oct 2024 19:35:35 +0100 Subject: [PATCH 04/21] fix warns --- src/daemon/bundle.rs | 6 +----- src/utils/db/car_util.rs | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/daemon/bundle.rs b/src/daemon/bundle.rs index 25dc4f7b9d45..544326df04cc 100644 --- a/src/daemon/bundle.rs +++ b/src/daemon/bundle.rs @@ -5,10 +5,7 @@ use crate::db::BlessedStore; use crate::{ networks::{ActorBundleInfo, NetworkChain, ACTOR_BUNDLES}, utils::{ - db::{ - car_stream::{CarBlock, CarStream}, - car_util::load_car, - }, + db::car_stream::{CarBlock, CarStream}, net::http_get, }, }; @@ -16,7 +13,6 @@ use ahash::HashSet; use anyhow::ensure; use cid::Cid; use futures::{stream::FuturesUnordered, TryStreamExt}; -use fvm_ipld_blockstore::Blockstore; use std::mem::discriminant; use std::{io::Cursor, path::Path}; use tokio::io::BufReader; diff --git a/src/utils/db/car_util.rs b/src/utils/db/car_util.rs index 8670b4248139..0a7706861184 100644 --- a/src/utils/db/car_util.rs +++ b/src/utils/db/car_util.rs @@ -6,7 +6,6 @@ use fvm_ipld_blockstore::Blockstore; use tokio::io::{AsyncBufRead, AsyncSeek, BufReader}; use crate::cid_collections::CidHashSet; -use crate::db::BlessedStore; use crate::utils::db::car_stream::{CarBlock, CarHeader, CarStream}; /// Stream key-value pairs from a CAR archive into a block store. From d58f9f10a686fe7b48f54084cfabdb92137c69d6 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Mon, 4 Nov 2024 20:14:52 +0100 Subject: [PATCH 05/21] add parity_db tests --- src/db/parity_db.rs | 55 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/src/db/parity_db.rs b/src/db/parity_db.rs index fe26158045e8..95bb0a95a876 100644 --- a/src/db/parity_db.rs +++ b/src/db/parity_db.rs @@ -222,7 +222,11 @@ impl EthMappingsStore for ParityDb { impl Blockstore for ParityDb { fn get(&self, k: &Cid) -> anyhow::Result>> { let column = Self::choose_column(k); - self.read_from_column(k.to_bytes(), column) + let res = self.read_from_column(k.to_bytes(), column)?; + if res.is_some() { + return Ok(res); + } + self.get_blessed(k) } fn put_keyed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { @@ -400,8 +404,10 @@ impl GarbageCollectable for ParityDb { mod test { use cid::multihash::Code::Sha2_256; use cid::multihash::MultihashDigest; + use fil_actors_shared::v15::MapKey; use fvm_ipld_encoding::IPLD_RAW; use nom::AsBytes; + use std::ops::Deref; use crate::db::tests::db_utils::parity::TempParityDB; @@ -444,6 +450,7 @@ mod test { DbColumn::GraphFull => DbColumn::GraphDagCborBlake2b256, DbColumn::Settings => panic!("invalid column for IPLD data"), DbColumn::EthMappings => panic!("invalid column for IPLD data"), + DbColumn::BlessedGraph => panic!("invalid column for GC enabled IPLD data"), }; let actual = db.read_from_column(cid.to_bytes(), other_column).unwrap(); assert!(actual.is_none()); @@ -530,4 +537,50 @@ mod test { assert_eq!(expected, actual); } } + + #[test] + fn blessed_tests() { + let db = TempParityDB::new(); + let data = [ + b"h'nglui mglw'nafh".to_vec(), + b"Cthulhu".to_vec(), + b"R'lyeh wgah'nagl fhtagn!!".to_vec(), + ]; + + let blessed_data = data + .clone() + .into_iter() + .map(|mut entry| { + entry.push(255); + entry + }) + .collect::>>(); + + let cids = [ + Cid::new_v1(DAG_CBOR, Blake2b256.digest(&data[0])), + Cid::new_v1(DAG_CBOR, Sha2_256.digest(&data[1])), + Cid::new_v1(IPLD_RAW, Blake2b256.digest(&data[1])), + ]; + + for idx in 0..3 { + let cid = &cids[idx]; + let blessed_entry = &blessed_data[idx]; + let data_entry = &data[idx]; + db.put_keyed_blessed(cid, blessed_entry).unwrap(); + // Check that we get blessed data if the data is otherwise absent from the GC enabled + // storage. + assert_eq!( + Blockstore::get(db.deref(), &cid).unwrap(), + Some(blessed_entry.clone()) + ); + assert!(db + .read_from_column(cid.to_bytes(), DbColumn::BlessedGraph)? + .is_some()); + db.put_keyed(cid, data_entry).unwrap(); + assert_eq!( + Blockstore::get(db.deref(), &cid).unwrap(), + Some(data_entry.clone()) + ); + } + } } From 83e37575eba7dae5d67333ca416854786be0e345 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Mon, 4 Nov 2024 20:23:52 +0100 Subject: [PATCH 06/21] fix --- src/db/parity_db.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/parity_db.rs b/src/db/parity_db.rs index 95bb0a95a876..22f4443a918c 100644 --- a/src/db/parity_db.rs +++ b/src/db/parity_db.rs @@ -404,7 +404,6 @@ impl GarbageCollectable for ParityDb { mod test { use cid::multihash::Code::Sha2_256; use cid::multihash::MultihashDigest; - use fil_actors_shared::v15::MapKey; use fvm_ipld_encoding::IPLD_RAW; use nom::AsBytes; use std::ops::Deref; @@ -574,7 +573,8 @@ mod test { Some(blessed_entry.clone()) ); assert!(db - .read_from_column(cid.to_bytes(), DbColumn::BlessedGraph)? + .read_from_column(cid.to_bytes(), DbColumn::BlessedGraph) + .unwrap() .is_some()); db.put_keyed(cid, data_entry).unwrap(); assert_eq!( From 1969edc6a2c99ad7106f7ddd2310a83584ebe546 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Mon, 4 Nov 2024 20:24:34 +0100 Subject: [PATCH 07/21] re-enable GC --- src/daemon/mod.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/daemon/mod.rs b/src/daemon/mod.rs index e752b1c47d08..f0e6e31f77e5 100644 --- a/src/daemon/mod.rs +++ b/src/daemon/mod.rs @@ -246,11 +246,7 @@ pub(super) async fn start( genesis_header.clone(), )?); - // Network Upgrade manifests are stored in the blockstore but may not be - // garbage collected. Until this is fixed, the GC has to be disabled. - // Tracking issue: https://github.com/ChainSafe/forest/issues/4926 - // if !opts.no_gc { - if false { + if !opts.no_gc { let mut db_garbage_collector = { let chain_store = chain_store.clone(); let depth = cmp::max( From 3525185ab8a4d792f98010d653dde4e2303dc6e0 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Mon, 4 Nov 2024 20:31:05 +0100 Subject: [PATCH 08/21] changelog --- CHANGELOG.md | 14 +++++++++----- README.md | 6 +++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9fbd8d26823..1a64be5a51c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,9 @@ ### Fixed +- [#4959](https://github.com/ChainSafe/forest/pull/4959) Re-enable garbage + collection after implementing a "blessed" storage for manifests. + ## Forest 0.21.1 "Songthaew Plus" This is an optional release for calibration network node operators. It enables @@ -1796,8 +1799,8 @@ All initial change sets: - `ccf1ac11` Return Ok when validating drand beacon entries similar to how Lotus does as per the audit recommendation. ([#1206](https://github.com/ChainSafe/forest/pull/1206)) (Hunter Trujillo) -- `f5fe14d2` [Audit fixes] FOR-03 - Inconsistent Deserialization of Randomness ([#1205](https://github.com/ChainSafe/forest/pull/1205)) - (Hunter Trujillo) +- `f5fe14d2` [Audit fixes] FOR-03 - Inconsistent Deserialization of Randomness + ([#1205](https://github.com/ChainSafe/forest/pull/1205)) (Hunter Trujillo) - `32a9ae5f` Rest of V5 Updates ([#1217](https://github.com/ChainSafe/forest/pull/1217)) (Eric Tu) - `e6e1c8ad` API_IMPLEMENTATION.md build script formatting improvements @@ -1852,10 +1855,11 @@ All initial change sets: ([#1160](https://github.com/ChainSafe/forest/pull/1160)) (creativcoder) - `34799734` Wallet CLI Implementation ([#1128](https://github.com/ChainSafe/forest/pull/1128)) (Connor Mullett) -- `f698ba88` [Audit fixes] FOR-02: Inconsistent Deserialization of Address ID ([#1149](https://github.com/ChainSafe/forest/pull/1149)) - (Hunter Trujillo) +- `f698ba88` [Audit fixes] FOR-02: Inconsistent Deserialization of Address ID + ([#1149](https://github.com/ChainSafe/forest/pull/1149)) (Hunter Trujillo) - `e50d2ae8` [Audit fixes] FOR-16: Unnecessary Extensive Permissions for Private - Keys ([#1151](https://github.com/ChainSafe/forest/pull/1151)) (Hunter Trujillo) + Keys ([#1151](https://github.com/ChainSafe/forest/pull/1151)) (Hunter + Trujillo) - `665ca476` Subtract 1 ([#1152](https://github.com/ChainSafe/forest/pull/1152)) (Eric Tu) - `4047ff5e` 3 -> 4 ([#1153](https://github.com/ChainSafe/forest/pull/1153)) diff --git a/README.md b/README.md index 1ad5a25e916e..339507ade4c6 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,9 @@ docker exec -it forest /bin/bash ``` For more in-depth usage and sample use cases, please refer to the Forest Docker -documentation in the [Forest Book]. Keep in mind that the `latest` tag is the latest -stable release. If you want to use the current development build, use the `edge` -tag. +documentation in the [Forest Book]. Keep in mind that the `latest` tag is the +latest stable release. If you want to use the current development build, use the +`edge` tag. ## Dependencies From a406b8f114b83d79eae6dd907c4f971cee5b70f9 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Mon, 4 Nov 2024 20:40:47 +0100 Subject: [PATCH 09/21] lint fix --- src/db/parity_db.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/parity_db.rs b/src/db/parity_db.rs index 22f4443a918c..ac1e178cd783 100644 --- a/src/db/parity_db.rs +++ b/src/db/parity_db.rs @@ -569,7 +569,7 @@ mod test { // Check that we get blessed data if the data is otherwise absent from the GC enabled // storage. assert_eq!( - Blockstore::get(db.deref(), &cid).unwrap(), + Blockstore::get(db.deref(), cid).unwrap(), Some(blessed_entry.clone()) ); assert!(db @@ -578,7 +578,7 @@ mod test { .is_some()); db.put_keyed(cid, data_entry).unwrap(); assert_eq!( - Blockstore::get(db.deref(), &cid).unwrap(), + Blockstore::get(db.deref(), cid).unwrap(), Some(data_entry.clone()) ); } From b48527e714112226bc59489454d6cb9053442ef7 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Mon, 4 Nov 2024 20:54:39 +0100 Subject: [PATCH 10/21] fmt again --- CHANGELOG.md | 11 +++++------ README.md | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a64be5a51c6..f3907f9148e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1799,8 +1799,8 @@ All initial change sets: - `ccf1ac11` Return Ok when validating drand beacon entries similar to how Lotus does as per the audit recommendation. ([#1206](https://github.com/ChainSafe/forest/pull/1206)) (Hunter Trujillo) -- `f5fe14d2` [Audit fixes] FOR-03 - Inconsistent Deserialization of Randomness - ([#1205](https://github.com/ChainSafe/forest/pull/1205)) (Hunter Trujillo) +- `f5fe14d2` [Audit fixes] FOR-03 - Inconsistent Deserialization of Randomness ([#1205](https://github.com/ChainSafe/forest/pull/1205)) + (Hunter Trujillo) - `32a9ae5f` Rest of V5 Updates ([#1217](https://github.com/ChainSafe/forest/pull/1217)) (Eric Tu) - `e6e1c8ad` API_IMPLEMENTATION.md build script formatting improvements @@ -1855,11 +1855,10 @@ All initial change sets: ([#1160](https://github.com/ChainSafe/forest/pull/1160)) (creativcoder) - `34799734` Wallet CLI Implementation ([#1128](https://github.com/ChainSafe/forest/pull/1128)) (Connor Mullett) -- `f698ba88` [Audit fixes] FOR-02: Inconsistent Deserialization of Address ID - ([#1149](https://github.com/ChainSafe/forest/pull/1149)) (Hunter Trujillo) +- `f698ba88` [Audit fixes] FOR-02: Inconsistent Deserialization of Address ID ([#1149](https://github.com/ChainSafe/forest/pull/1149)) + (Hunter Trujillo) - `e50d2ae8` [Audit fixes] FOR-16: Unnecessary Extensive Permissions for Private - Keys ([#1151](https://github.com/ChainSafe/forest/pull/1151)) (Hunter - Trujillo) + Keys ([#1151](https://github.com/ChainSafe/forest/pull/1151)) (Hunter Trujillo) - `665ca476` Subtract 1 ([#1152](https://github.com/ChainSafe/forest/pull/1152)) (Eric Tu) - `4047ff5e` 3 -> 4 ([#1153](https://github.com/ChainSafe/forest/pull/1153)) diff --git a/README.md b/README.md index 339507ade4c6..1ad5a25e916e 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,9 @@ docker exec -it forest /bin/bash ``` For more in-depth usage and sample use cases, please refer to the Forest Docker -documentation in the [Forest Book]. Keep in mind that the `latest` tag is the -latest stable release. If you want to use the current development build, use the -`edge` tag. +documentation in the [Forest Book]. Keep in mind that the `latest` tag is the latest +stable release. If you want to use the current development build, use the `edge` +tag. ## Dependencies From 88c86ec944ab5f8eb6fb92b1e58345e7974c1597 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Tue, 5 Nov 2024 12:21:54 +0100 Subject: [PATCH 11/21] add BlessedGraph to the end --- src/db/parity_db.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/db/parity_db.rs b/src/db/parity_db.rs index ac1e178cd783..ecf481f737c9 100644 --- a/src/db/parity_db.rs +++ b/src/db/parity_db.rs @@ -32,10 +32,6 @@ use tracing::warn; #[derive(Copy, Clone, Debug, Display, PartialEq, FromRepr, EnumIter)] #[repr(u8)] enum DbColumn { - /// Column for storing IPLD data that has to be ignored by the garbage collector. - /// Anything stored in this column can be considered permanent, unless manually - /// deleted. - BlessedGraph, /// Column for storing IPLD data with `Blake2b256` hash and `DAG_CBOR` codec. /// Most entries in the `blockstore` will be stored in this column. GraphDagCborBlake2b256, @@ -48,6 +44,10 @@ enum DbColumn { Settings, /// Column for storing Ethereum mappings. EthMappings, + /// Column for storing IPLD data that has to be ignored by the garbage collector. + /// Anything stored in this column can be considered permanent, unless manually + /// deleted. + BlessedGraph, } impl DbColumn { From 612e41b3795266f158e1c3b0b20d23b6b3585027 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Tue, 5 Nov 2024 14:04:41 +0100 Subject: [PATCH 12/21] add a db migration --- Cargo.lock | 2 +- Cargo.toml | 54 +++--- src/db/migration/migration_map.rs | 2 + src/db/migration/mod.rs | 1 + src/db/migration/v0_21_2.rs | 288 ++++++++++++++++++++++++++++++ 5 files changed, 319 insertions(+), 28 deletions(-) create mode 100644 src/db/migration/v0_21_2.rs diff --git a/Cargo.lock b/Cargo.lock index 1f8975d65405..0397f423de7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3124,7 +3124,7 @@ checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" [[package]] name = "forest-filecoin" -version = "0.21.1" +version = "0.21.2" dependencies = [ "ahash", "anes 0.2.0", diff --git a/Cargo.toml b/Cargo.toml index 81c64c695844..0e8b257d8c74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "forest-filecoin" -version = "0.21.1" +version = "0.21.2" authors = ["ChainSafe Systems "] repository = "https://github.com/ChainSafe/forest" edition = "2021" @@ -23,8 +23,8 @@ base64 = "0.22" bigdecimal = "=0.4.2" # TODO(forest): https://github.com/ChainSafe/forest/issues/4035 blake2b_simd = "1.0" bls-signatures = { version = "0.15", default-features = false, features = [ - "multicore", - "blst-portable", + "multicore", + "blst-portable", ] } # prevent SIGINT on CI runners by using portable assembly blstrs = { version = "0.7", features = ["portable"] } byteorder = "1" @@ -93,27 +93,27 @@ libipld = { version = "0.16", default-features = false, features = ["dag-cbor", libipld-core = { version = "0.16", features = ['arb', 'serde-codec'] } libipld-macro = "0.16" libp2p = { version = "0.54", default-features = false, features = [ - 'autonat', - 'gossipsub', - 'kad', - 'identify', - 'ping', - 'mdns', - 'noise', - 'yamux', - 'tcp', - 'quic', - 'dns', - 'request-response', - 'metrics', - 'tokio', - 'macros', - 'serde', - 'upnp', - 'rsa', - 'ecdsa', - 'ed25519', - 'secp256k1', + 'autonat', + 'gossipsub', + 'kad', + 'identify', + 'ping', + 'mdns', + 'noise', + 'yamux', + 'tcp', + 'quic', + 'dns', + 'request-response', + 'metrics', + 'tokio', + 'macros', + 'serde', + 'upnp', + 'rsa', + 'ecdsa', + 'ed25519', + 'secp256k1', ] } libsecp256k1 = "0.7" lru = "0.12" @@ -147,9 +147,9 @@ raw_sync_2 = "0.1" rayon = "1" regex = "1" reqwest = { version = "0.12", default-features = false, features = [ - "stream", - "rustls-tls", - "json", + "stream", + "rustls-tls", + "json", ] } # use rustls instead of native (openSSL) tls to drop the number of build dependencies rlimit = "0.10" rlp = "0.6" diff --git a/src/db/migration/migration_map.rs b/src/db/migration/migration_map.rs index 9e2f1de63874..e862a89ea373 100644 --- a/src/db/migration/migration_map.rs +++ b/src/db/migration/migration_map.rs @@ -9,6 +9,7 @@ use std::{ use crate::db::migration::v0_16_0::Migration0_15_2_0_16_0; use crate::db::migration::v0_19_0::Migration0_18_0_0_19_0; +use crate::db::migration::v0_21_2::Migration0_19_0_0_21_2; use crate::Config; use anyhow::bail; use anyhow::Context as _; @@ -80,6 +81,7 @@ create_migrations!( "0.12.1" -> "0.13.0" @ Migration0_12_1_0_13_0, "0.15.2" -> "0.16.0" @ Migration0_15_2_0_16_0, "0.18.0" -> "0.19.0" @ Migration0_18_0_0_19_0, + "0.19.0" -> "0.21.2" @ Migration0_19_0_0_21_2, ); pub struct Migration { diff --git a/src/db/migration/mod.rs b/src/db/migration/mod.rs index f0e9f390f06d..f71a597b893d 100644 --- a/src/db/migration/mod.rs +++ b/src/db/migration/mod.rs @@ -6,6 +6,7 @@ mod migration_map; mod v0_12_1; mod v0_16_0; mod v0_19_0; +mod v0_21_2; mod void_migration; pub use db_migration::DbMigration; diff --git a/src/db/migration/v0_21_2.rs b/src/db/migration/v0_21_2.rs new file mode 100644 index 000000000000..4200aa3d5d73 --- /dev/null +++ b/src/db/migration/v0_21_2.rs @@ -0,0 +1,288 @@ +// Copyright 2019-2024 ChainSafe Systems +// SPDX-License-Identifier: Apache-2.0, MIT + +//! Migration logic for 0.19.0 to 0.21.2 version. +//! A `BlessedGraph` column has been introduced to allow for storage of persistent data that isn't +//! garbage collected. The initial use-case is network upgrade manifest storage. + +use crate::db::db_engine::Db; +use crate::db::migration::migration_map::temporary_db_name; +use crate::db::migration::v0_21_2::paritydb_0_19_0::{DbColumn, ParityDb}; +use crate::db::CAR_DB_DIR_NAME; +use crate::Config; +use anyhow::Context; +use cid::multihash::Code::Blake2b256; +use cid::multihash::MultihashDigest; +use cid::Cid; +use fs_extra::dir::CopyOptions; +use fvm_ipld_encoding::DAG_CBOR; +use semver::Version; +use std::path::{Path, PathBuf}; +use strum::IntoEnumIterator; +use tracing::info; + +use super::migration_map::MigrationOperation; + +pub(super) struct Migration0_19_0_0_21_2 { + from: Version, + to: Version, +} + +/// Migrates the database from version 0.19.0 to 0.21.2 +impl MigrationOperation for Migration0_19_0_0_21_2 { + fn new(from: Version, to: Version) -> Self + where + Self: Sized, + { + Self { from, to } + } + + fn pre_checks(&self, _chain_data_path: &Path) -> anyhow::Result<()> { + Ok(()) + } + + fn migrate(&self, chain_data_path: &Path, _: &Config) -> anyhow::Result { + let source_db = chain_data_path.join(self.from.to_string()); + + let temp_db_path = chain_data_path.join(temporary_db_name(&self.from, &self.to)); + if temp_db_path.exists() { + info!( + "Removing old temporary database {temp_db_path}", + temp_db_path = temp_db_path.display() + ); + std::fs::remove_dir_all(&temp_db_path)?; + } + + let old_car_db_path = source_db.join(CAR_DB_DIR_NAME); + let new_car_db_path = temp_db_path.join(CAR_DB_DIR_NAME); + + // Make sure `car_db` dir exists as it might not be the case when migrating + // from older versions. + if old_car_db_path.is_dir() { + info!( + "Copying snapshot from {source_db} to {temp_db_path}", + source_db = old_car_db_path.display(), + temp_db_path = new_car_db_path.display() + ); + + fs_extra::copy_items( + &[old_car_db_path.as_path()], + new_car_db_path, + &CopyOptions::default().copy_inside(true), + )?; + } + + let db = ParityDb::open(source_db)?; + + // open the new database to migrate data from the old one. + let new_db = paritydb_0_21_2::ParityDb::open(&temp_db_path)?; + + for col in DbColumn::iter() { + info!("Migrating column {}", col); + let mut res = anyhow::Ok(()); + if col == DbColumn::GraphDagCborBlake2b256 { + db.db.iter_column_while(col as u8, |val| { + let hash = Blake2b256.digest(&val.value); + let cid = Cid::new_v1(DAG_CBOR, hash); + res = new_db + .db + .commit_changes([Db::set_operation(col as u8, cid.to_bytes(), val.value)]) + .context("failed to commit"); + + if res.is_err() { + return false; + } + + true + })?; + res?; + } else { + let mut iter = db.db.iter(col as u8)?; + while let Some((key, value)) = iter.next()? { + new_db + .db + .commit_changes([Db::set_operation(col as u8, key, value)]) + .context("failed to commit")?; + } + } + } + + drop(new_db); + + Ok(temp_db_path) + } + + fn post_checks(&self, chain_data_path: &Path) -> anyhow::Result<()> { + let temp_db_name = temporary_db_name(&self.from, &self.to); + if !chain_data_path.join(&temp_db_name).exists() { + anyhow::bail!( + "migration database {} does not exist", + chain_data_path.join(temp_db_name).display() + ); + } + Ok(()) + } +} + +/// Database settings from Forest `v0.19.0` +mod paritydb_0_19_0 { + use parity_db::{CompressionType, Db, Options}; + use std::path::PathBuf; + use strum::{Display, EnumIter, IntoEnumIterator}; + + #[derive(Copy, Clone, Debug, PartialEq, EnumIter, Display)] + #[repr(u8)] + pub(super) enum DbColumn { + GraphDagCborBlake2b256, + GraphFull, + Settings, + EthMappings, + } + + impl DbColumn { + fn create_column_options(compression: CompressionType) -> Vec { + DbColumn::iter() + .map(|col| { + match col { + DbColumn::GraphDagCborBlake2b256 => parity_db::ColumnOptions { + preimage: true, + compression, + ..Default::default() + }, + DbColumn::GraphFull => parity_db::ColumnOptions { + preimage: true, + // This is needed for key retrieval. + btree_index: true, + compression, + ..Default::default() + }, + DbColumn::Settings => parity_db::ColumnOptions { + // explicitly disable preimage for settings column + // othewise we are not able to overwrite entries + preimage: false, + // This is needed for key retrieval. + btree_index: true, + compression, + ..Default::default() + }, + DbColumn::EthMappings => parity_db::ColumnOptions { + preimage: false, + btree_index: false, + compression, + ..Default::default() + }, + } + }) + .collect() + } + } + + pub(super) struct ParityDb { + pub db: parity_db::Db, + } + + impl ParityDb { + pub(super) fn to_options(path: PathBuf) -> Options { + Options { + path, + sync_wal: true, + sync_data: true, + stats: false, + salt: None, + columns: DbColumn::create_column_options(CompressionType::Lz4), + compression_threshold: [(0, 128)].into_iter().collect(), + } + } + + pub(super) fn open(path: impl Into) -> anyhow::Result { + let opts = Self::to_options(path.into()); + Ok(Self { + db: Db::open_or_create(&opts)?, + }) + } + } +} + +/// Database settings from Forest `v0.21.2` +mod paritydb_0_21_2 { + use parity_db::{CompressionType, Db, Options}; + use std::path::PathBuf; + use strum::{Display, EnumIter, IntoEnumIterator}; + + #[derive(Copy, Clone, Debug, PartialEq, EnumIter, Display)] + #[repr(u8)] + pub(super) enum DbColumn { + GraphDagCborBlake2b256, + GraphFull, + Settings, + EthMappings, + BlessedGraph, + } + + impl DbColumn { + fn create_column_options(compression: CompressionType) -> Vec { + DbColumn::iter() + .map(|col| { + match col { + DbColumn::GraphDagCborBlake2b256 | DbColumn::BlessedGraph => { + parity_db::ColumnOptions { + preimage: true, + compression, + ..Default::default() + } + } + DbColumn::GraphFull => parity_db::ColumnOptions { + preimage: true, + // This is needed for key retrieval. + btree_index: true, + compression, + ..Default::default() + }, + DbColumn::Settings => { + parity_db::ColumnOptions { + // explicitly disable preimage for settings column + // othewise we are not able to overwrite entries + preimage: false, + // This is needed for key retrieval. + btree_index: true, + compression, + ..Default::default() + } + } + DbColumn::EthMappings => parity_db::ColumnOptions { + preimage: false, + btree_index: false, + compression, + ..Default::default() + }, + } + }) + .collect() + } + } + + pub(super) struct ParityDb { + pub db: parity_db::Db, + } + + impl ParityDb { + pub(super) fn to_options(path: PathBuf) -> Options { + Options { + path, + sync_wal: true, + sync_data: true, + stats: false, + salt: None, + columns: DbColumn::create_column_options(CompressionType::Lz4), + compression_threshold: [(0, 128)].into_iter().collect(), + } + } + + pub(super) fn open(path: impl Into) -> anyhow::Result { + let opts = Self::to_options(path.into()); + Ok(Self { + db: Db::open_or_create(&opts)?, + }) + } + } +} From 480cfd6ff7b8c724487143353e165aba95f30053 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Tue, 5 Nov 2024 14:31:48 +0100 Subject: [PATCH 13/21] fmt --- Cargo.toml | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0e8b257d8c74..517341d670bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,8 +23,8 @@ base64 = "0.22" bigdecimal = "=0.4.2" # TODO(forest): https://github.com/ChainSafe/forest/issues/4035 blake2b_simd = "1.0" bls-signatures = { version = "0.15", default-features = false, features = [ - "multicore", - "blst-portable", + "multicore", + "blst-portable", ] } # prevent SIGINT on CI runners by using portable assembly blstrs = { version = "0.7", features = ["portable"] } byteorder = "1" @@ -93,27 +93,27 @@ libipld = { version = "0.16", default-features = false, features = ["dag-cbor", libipld-core = { version = "0.16", features = ['arb', 'serde-codec'] } libipld-macro = "0.16" libp2p = { version = "0.54", default-features = false, features = [ - 'autonat', - 'gossipsub', - 'kad', - 'identify', - 'ping', - 'mdns', - 'noise', - 'yamux', - 'tcp', - 'quic', - 'dns', - 'request-response', - 'metrics', - 'tokio', - 'macros', - 'serde', - 'upnp', - 'rsa', - 'ecdsa', - 'ed25519', - 'secp256k1', + 'autonat', + 'gossipsub', + 'kad', + 'identify', + 'ping', + 'mdns', + 'noise', + 'yamux', + 'tcp', + 'quic', + 'dns', + 'request-response', + 'metrics', + 'tokio', + 'macros', + 'serde', + 'upnp', + 'rsa', + 'ecdsa', + 'ed25519', + 'secp256k1', ] } libsecp256k1 = "0.7" lru = "0.12" @@ -147,9 +147,9 @@ raw_sync_2 = "0.1" rayon = "1" regex = "1" reqwest = { version = "0.12", default-features = false, features = [ - "stream", - "rustls-tls", - "json", + "stream", + "rustls-tls", + "json", ] } # use rustls instead of native (openSSL) tls to drop the number of build dependencies rlimit = "0.10" rlp = "0.6" From f8d964d22b1c1bff9025996fdabf4054aaad8f78 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Tue, 5 Nov 2024 15:45:41 +0100 Subject: [PATCH 14/21] fix 0.19.0 migration --- src/db/migration/v0_19_0.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/db/migration/v0_19_0.rs b/src/db/migration/v0_19_0.rs index 7f747312c340..ea33a36df231 100644 --- a/src/db/migration/v0_19_0.rs +++ b/src/db/migration/v0_19_0.rs @@ -9,14 +9,14 @@ use crate::chain::ChainStore; use crate::cli_shared::chain_path; use crate::daemon::db_util::{load_all_forest_cars, populate_eth_mappings}; use crate::db::car::ManyCar; -use crate::db::db_engine::{open_db, Db}; +use crate::db::db_engine::Db; use crate::db::migration::migration_map::temporary_db_name; use crate::db::migration::v0_19_0::paritydb_0_18_0::{DbColumn, ParityDb}; use crate::db::CAR_DB_DIR_NAME; use crate::genesis::read_genesis_header; use crate::networks::ChainConfig; use crate::state_manager::StateManager; -use crate::Config; +use crate::{db, Config}; use anyhow::Context; use cid::multihash::Code::Blake2b256; use cid::multihash::MultihashDigest; @@ -147,9 +147,15 @@ impl MigrationOperation for Migration0_18_0_0_19_0 { } async fn create_state_manager_and_populate(config: Config, db_name: String) -> anyhow::Result<()> { + use db::parity_db::ParityDb as ParityDbCurrent; + let chain_data_path = chain_path(&config); let db_root_dir = chain_data_path.join(db_name); - let db_writer = Arc::new(open_db(db_root_dir.clone(), config.db_config().clone())?); + let db = ParityDbCurrent::wrap( + paritydb_0_19_0::ParityDb::open(db_root_dir.clone())?.db, + false, + ); + let db_writer = Arc::new(db); let db = Arc::new(ManyCar::new(db_writer.clone())); let forest_car_db_dir = db_root_dir.join(CAR_DB_DIR_NAME); load_all_forest_cars(&db, &forest_car_db_dir)?; From fa0dd54c90e08b157822048e2103b06f1e230b3c Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Tue, 5 Nov 2024 18:54:53 +0100 Subject: [PATCH 15/21] introduce a flag to fix older migrations --- src/db/migration/v0_16_0.rs | 2 +- src/db/migration/v0_19_0.rs | 1 + src/db/parity_db.rs | 9 ++++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/db/migration/v0_16_0.rs b/src/db/migration/v0_16_0.rs index 71204629dea4..9cd2aca0f9ee 100644 --- a/src/db/migration/v0_16_0.rs +++ b/src/db/migration/v0_16_0.rs @@ -210,7 +210,7 @@ mod paritydb_0_15_1 { // if it changes and then this migration should either be maintained or removed. pub(super) fn open(path: impl Into) -> anyhow::Result { let opts = Self::to_options(path.into()); - let db = db::parity_db::ParityDb::wrap(Db::open_or_create(&opts)?, false); + let db = db::parity_db::ParityDb::wrap(Db::open_or_create(&opts)?, false, false); Ok(db) } } diff --git a/src/db/migration/v0_19_0.rs b/src/db/migration/v0_19_0.rs index ea33a36df231..032dec2d5a39 100644 --- a/src/db/migration/v0_19_0.rs +++ b/src/db/migration/v0_19_0.rs @@ -154,6 +154,7 @@ async fn create_state_manager_and_populate(config: Config, db_name: String) -> a let db = ParityDbCurrent::wrap( paritydb_0_19_0::ParityDb::open(db_root_dir.clone())?.db, false, + true, ); let db_writer = Arc::new(db); let db = Arc::new(ManyCar::new(db_writer.clone())); diff --git a/src/db/parity_db.rs b/src/db/parity_db.rs index ecf481f737c9..886538cc9fa0 100644 --- a/src/db/parity_db.rs +++ b/src/db/parity_db.rs @@ -93,6 +93,8 @@ impl DbColumn { pub struct ParityDb { pub db: parity_db::Db, statistics_enabled: bool, + // This is needed to maintain backwards-compatibility for pre-blessed-column migrations. + disable_blessed_fallback: bool, } impl ParityDb { @@ -113,13 +115,15 @@ impl ParityDb { Ok(Self { db: Db::open_or_create(&opts)?, statistics_enabled: opts.stats, + disable_blessed_fallback: false, }) } - pub fn wrap(db: parity_db::Db, stats: bool) -> Self { + pub fn wrap(db: parity_db::Db, stats: bool, disable_blessed: bool) -> Self { Self { db, statistics_enabled: stats, + disable_blessed_fallback: disable_blessed, } } @@ -342,6 +346,9 @@ impl ParityDb { // Get data from persistent graph column. fn get_blessed(&self, k: &Cid) -> anyhow::Result>> { + if self.disable_blessed_fallback { + return Ok(None); + } self.read_from_column(k.to_bytes(), DbColumn::BlessedGraph) } } From 9f7cc5ee709c9b291d8ec5199d49964957704ec9 Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Tue, 5 Nov 2024 19:44:46 +0100 Subject: [PATCH 16/21] ethMappings migration --- src/db/migration/v0_21_2.rs | 86 +++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 22 deletions(-) diff --git a/src/db/migration/v0_21_2.rs b/src/db/migration/v0_21_2.rs index 4200aa3d5d73..7d7ade3a933c 100644 --- a/src/db/migration/v0_21_2.rs +++ b/src/db/migration/v0_21_2.rs @@ -5,10 +5,12 @@ //! A `BlessedGraph` column has been introduced to allow for storage of persistent data that isn't //! garbage collected. The initial use-case is network upgrade manifest storage. +use crate::blocks::TipsetKey; use crate::db::db_engine::Db; use crate::db::migration::migration_map::temporary_db_name; use crate::db::migration::v0_21_2::paritydb_0_19_0::{DbColumn, ParityDb}; use crate::db::CAR_DB_DIR_NAME; +use crate::rpc::eth::types::EthHash; use crate::Config; use anyhow::Context; use cid::multihash::Code::Blake2b256; @@ -80,29 +82,69 @@ impl MigrationOperation for Migration0_19_0_0_21_2 { for col in DbColumn::iter() { info!("Migrating column {}", col); let mut res = anyhow::Ok(()); - if col == DbColumn::GraphDagCborBlake2b256 { - db.db.iter_column_while(col as u8, |val| { - let hash = Blake2b256.digest(&val.value); - let cid = Cid::new_v1(DAG_CBOR, hash); - res = new_db - .db - .commit_changes([Db::set_operation(col as u8, cid.to_bytes(), val.value)]) - .context("failed to commit"); - - if res.is_err() { - return false; - } + match col { + DbColumn::GraphDagCborBlake2b256 => { + db.db.iter_column_while(col as u8, |val| { + let hash = Blake2b256.digest(&val.value); + let cid = Cid::new_v1(DAG_CBOR, hash); + res = new_db + .db + .commit_changes([Db::set_operation( + col as u8, + cid.to_bytes(), + val.value, + )]) + .context("failed to commit"); + + if res.is_err() { + return false; + } - true - })?; - res?; - } else { - let mut iter = db.db.iter(col as u8)?; - while let Some((key, value)) = iter.next()? { - new_db - .db - .commit_changes([Db::set_operation(col as u8, key, value)]) - .context("failed to commit")?; + true + })?; + res?; + } + DbColumn::EthMappings => { + db.db.iter_column_while(col as u8, |val| { + let tsk: Result = + fvm_ipld_encoding::from_slice(&val.value); + if tsk.is_err() { + res = Err(tsk.context("serde error").unwrap_err()); + return false; + } + let cid = tsk.unwrap().cid(); + + if cid.is_err() { + res = Err(cid.context("serde error").unwrap_err()); + return false; + } + + let hash: EthHash = cid.unwrap().into(); + res = new_db + .db + .commit_changes([Db::set_operation( + col as u8, + hash.0.as_bytes().to_vec(), + val.value, + )]) + .context("failed to commit"); + + if res.is_err() { + return false; + } + + true + })?; + res?; + } + _ => { + let mut iter = db.db.iter(col as u8)?; + while let Some((key, value)) = iter.next()? { + new_db + .db + .commit_changes([Db::set_operation(col as u8, key, value)]) + .context("failed to commit")?; + } } } } From da0ade0bcc2dba270a8a639480149c9e9929f32f Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Mon, 11 Nov 2024 10:49:39 +0100 Subject: [PATCH 17/21] temporarily ignore an audit error --- .cargo/audit.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.cargo/audit.toml b/.cargo/audit.toml index 88f4ea1b9c88..d8f6ac29f7f1 100644 --- a/.cargo/audit.toml +++ b/.cargo/audit.toml @@ -12,6 +12,10 @@ ignore = [ "RUSTSEC-2020-0168", # mach is unmaintained "RUSTSEC-2022-0061", # parity-wasm is deprecated "RUSTSEC-2024-0370", # proc-macro-error is unmaintained + # Instant is unmaintained, but there is a replacement in + # the pipeline - see + # https://github.com/console-rs/indicatif/pull/666 + "RUSTSEC-2024-0384", ] [output] From ab874a2cb673c75fabf0404ed98010766e8341bb Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Mon, 11 Nov 2024 10:53:12 +0100 Subject: [PATCH 18/21] fix versions --- CHANGELOG.md | 6 +++--- Cargo.toml | 2 +- src/db/migration/migration_map.rs | 4 ++-- src/db/migration/mod.rs | 2 +- src/db/migration/{v0_21_2.rs => v0_22_1.rs} | 16 ++++++++-------- 5 files changed, 15 insertions(+), 15 deletions(-) rename src/db/migration/{v0_21_2.rs => v0_22_1.rs} (96%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22a73ce5a208..e06557eed6ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,9 @@ ### Fixed +- [#4959](https://github.com/ChainSafe/forest/pull/4959) Re-enable garbage + collection after implementing a "blessed" storage for manifests. + ## Forest 0.22.0 "Pad Thai" Mandatory release for mainnet node operators. It sets the upgrade epoch for the @@ -71,9 +74,6 @@ for more details. - [#4801](https://github.com/ChainSafe/forest/issues/4801) Add support for `Tuk Tuk` NV24 upgrade for mainnet -- [#4959](https://github.com/ChainSafe/forest/pull/4959) Re-enable garbage - collection after implementing a "blessed" storage for manifests. - ## Forest 0.21.1 "Songthaew Plus" This is an optional release for calibration network node operators. It enables diff --git a/Cargo.toml b/Cargo.toml index bcbef3c1d59c..0b9dbdf53202 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "forest-filecoin" -version = "0.22.0" +version = "0.22.1" authors = ["ChainSafe Systems "] repository = "https://github.com/ChainSafe/forest" edition = "2021" diff --git a/src/db/migration/migration_map.rs b/src/db/migration/migration_map.rs index e862a89ea373..97a1efc69925 100644 --- a/src/db/migration/migration_map.rs +++ b/src/db/migration/migration_map.rs @@ -9,7 +9,7 @@ use std::{ use crate::db::migration::v0_16_0::Migration0_15_2_0_16_0; use crate::db::migration::v0_19_0::Migration0_18_0_0_19_0; -use crate::db::migration::v0_21_2::Migration0_19_0_0_21_2; +use crate::db::migration::v0_22_1::Migration0_19_0_0_22_1; use crate::Config; use anyhow::bail; use anyhow::Context as _; @@ -81,7 +81,7 @@ create_migrations!( "0.12.1" -> "0.13.0" @ Migration0_12_1_0_13_0, "0.15.2" -> "0.16.0" @ Migration0_15_2_0_16_0, "0.18.0" -> "0.19.0" @ Migration0_18_0_0_19_0, - "0.19.0" -> "0.21.2" @ Migration0_19_0_0_21_2, + "0.19.0" -> "0.22.1" @ Migration0_19_0_0_22_1, ); pub struct Migration { diff --git a/src/db/migration/mod.rs b/src/db/migration/mod.rs index f71a597b893d..a9c85af22314 100644 --- a/src/db/migration/mod.rs +++ b/src/db/migration/mod.rs @@ -6,7 +6,7 @@ mod migration_map; mod v0_12_1; mod v0_16_0; mod v0_19_0; -mod v0_21_2; +mod v0_22_1; mod void_migration; pub use db_migration::DbMigration; diff --git a/src/db/migration/v0_21_2.rs b/src/db/migration/v0_22_1.rs similarity index 96% rename from src/db/migration/v0_21_2.rs rename to src/db/migration/v0_22_1.rs index 7d7ade3a933c..a140b020851d 100644 --- a/src/db/migration/v0_21_2.rs +++ b/src/db/migration/v0_22_1.rs @@ -1,14 +1,14 @@ // Copyright 2019-2024 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -//! Migration logic for 0.19.0 to 0.21.2 version. +//! Migration logic for 0.19.0 to 0.22.1 version. //! A `BlessedGraph` column has been introduced to allow for storage of persistent data that isn't //! garbage collected. The initial use-case is network upgrade manifest storage. use crate::blocks::TipsetKey; use crate::db::db_engine::Db; use crate::db::migration::migration_map::temporary_db_name; -use crate::db::migration::v0_21_2::paritydb_0_19_0::{DbColumn, ParityDb}; +use crate::db::migration::v0_22_1::paritydb_0_19_0::{DbColumn, ParityDb}; use crate::db::CAR_DB_DIR_NAME; use crate::rpc::eth::types::EthHash; use crate::Config; @@ -25,13 +25,13 @@ use tracing::info; use super::migration_map::MigrationOperation; -pub(super) struct Migration0_19_0_0_21_2 { +pub(super) struct Migration0_19_0_0_22_1 { from: Version, to: Version, } -/// Migrates the database from version 0.19.0 to 0.21.2 -impl MigrationOperation for Migration0_19_0_0_21_2 { +/// Migrates the database from version 0.19.0 to 0.22.1 +impl MigrationOperation for Migration0_19_0_0_22_1 { fn new(from: Version, to: Version) -> Self where Self: Sized, @@ -77,7 +77,7 @@ impl MigrationOperation for Migration0_19_0_0_21_2 { let db = ParityDb::open(source_db)?; // open the new database to migrate data from the old one. - let new_db = paritydb_0_21_2::ParityDb::open(&temp_db_path)?; + let new_db = paritydb_0_22_1::ParityDb::open(&temp_db_path)?; for col in DbColumn::iter() { info!("Migrating column {}", col); @@ -245,8 +245,8 @@ mod paritydb_0_19_0 { } } -/// Database settings from Forest `v0.21.2` -mod paritydb_0_21_2 { +/// Database settings from Forest `v0.22.1` +mod paritydb_0_22_1 { use parity_db::{CompressionType, Db, Options}; use std::path::PathBuf; use strum::{Display, EnumIter, IntoEnumIterator}; From c692f251cf66b5af2294869adf76d13f87195e4a Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Tue, 12 Nov 2024 14:58:34 +0100 Subject: [PATCH 19/21] fix migration --- CHANGELOG.md | 36 ++++++++++++---------- Cargo.lock | 2 +- src/daemon/bundle.rs | 12 ++++---- src/db/car/any.rs | 12 ++++---- src/db/car/forest.rs | 6 ++-- src/db/car/many.rs | 8 ++--- src/db/car/plain.rs | 6 ++-- src/db/memory.rs | 6 ++-- src/db/migration/migration_map.rs | 4 +-- src/db/migration/v0_22_1.rs | 22 ++++++------- src/db/mod.rs | 20 ++++++------ src/db/parity_db.rs | 46 ++++++++++++++-------------- src/tool/subcommands/snapshot_cmd.rs | 6 ++-- 13 files changed, 94 insertions(+), 92 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e06557eed6ae..1ff0ea29b218 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ ### Fixed - [#4959](https://github.com/ChainSafe/forest/pull/4959) Re-enable garbage - collection after implementing a "blessed" storage for manifests. + collection after implementing a "persistent" storage for manifests. ## Forest 0.22.0 "Pad Thai" @@ -926,19 +926,19 @@ usability improvements. port from 1234 to 2345. - [#3336](https://github.com/ChainSafe/forest/pull/3336) Moved following `forest-cli` subcommands to `forest-tool` - - `archive info` - - `fetch-params` - - `snapshot fetch` - - `snapshot validate` + - `archive info` + - `fetch-params` + - `snapshot fetch` + - `snapshot validate` - [#3355](https://github.com/ChainSafe/forest/pull/3355) Moved commands - - `forest-cli db stats` to `forest-tool db stats` - - `forest-cli db clean` to `forest-tool db destroy` + - `forest-cli db stats` to `forest-tool db stats` + - `forest-cli db clean` to `forest-tool db destroy` - [#3362](https://github.com/ChainSafe/forest/pull/3362) Moved the following `forest-cli wallet` subcommands to `forest-wallet` - [#3432](https://github.com/ChainSafe/forest/pull/3432) Moved following `forest-cli` subcommands to `forest-tool` - - `archive export` - - `archive checkpoints` + - `archive export` + - `archive checkpoints` - [#3431](https://github.com/ChainSafe/forest/pull/3431) Moved the following `forest-cli snapshot compress` subcommand to `forest-tool` - [#3435](https://github.com/ChainSafe/forest/pull/3435) Moved subcommand @@ -1123,8 +1123,8 @@ Notable updates: ### Breaking - [#2873](https://github.com/ChainSafe/forest/issues/2873) - - remove `--compressed` from the CLI. Snapshots are now always compressed. - - Remove snapshot ops - snapshots fetched to the current directory by default. + - remove `--compressed` from the CLI. Snapshots are now always compressed. + - Remove snapshot ops - snapshots fetched to the current directory by default. ### Added @@ -1287,10 +1287,10 @@ Notable updates: [#2576](https://github.com/ChainSafe/forest/issues/2576) - Revised how balances are displayed, defaulting to: [#2323](https://github.com/ChainSafe/forest/issues/2323) - - adding metric prefix when it's required, consequently CLI flag - `--fixed-unit` added to force to show in original `FIL` unit - - 4 significant digits, consequently CLI flag `--exact-balance` added to force - full accuracy. + - adding metric prefix when it's required, consequently CLI flag + `--fixed-unit` added to force to show in original `FIL` unit + - 4 significant digits, consequently CLI flag `--exact-balance` added to force + full accuracy. - `stats` and `compression` keys in `parity_db` section were renamed to `enable_statistics` and `compression_type` respectively. [#2433](https://github.com/ChainSafe/forest/issues/2433) @@ -1817,7 +1817,8 @@ All initial change sets: - `ccf1ac11` Return Ok when validating drand beacon entries similar to how Lotus does as per the audit recommendation. ([#1206](https://github.com/ChainSafe/forest/pull/1206)) (Hunter Trujillo) -- `f5fe14d2` [Audit fixes] FOR-03 - Inconsistent Deserialization of Randomness ([#1205](https://github.com/ChainSafe/forest/pull/1205)) +- `f5fe14d2` [Audit fixes] FOR-03 - Inconsistent Deserialization of + Randomness ([#1205](https://github.com/ChainSafe/forest/pull/1205)) (Hunter Trujillo) - `32a9ae5f` Rest of V5 Updates ([#1217](https://github.com/ChainSafe/forest/pull/1217)) (Eric Tu) @@ -1873,7 +1874,8 @@ All initial change sets: ([#1160](https://github.com/ChainSafe/forest/pull/1160)) (creativcoder) - `34799734` Wallet CLI Implementation ([#1128](https://github.com/ChainSafe/forest/pull/1128)) (Connor Mullett) -- `f698ba88` [Audit fixes] FOR-02: Inconsistent Deserialization of Address ID ([#1149](https://github.com/ChainSafe/forest/pull/1149)) +- `f698ba88` [Audit fixes] FOR-02: Inconsistent Deserialization of Address + ID ([#1149](https://github.com/ChainSafe/forest/pull/1149)) (Hunter Trujillo) - `e50d2ae8` [Audit fixes] FOR-16: Unnecessary Extensive Permissions for Private Keys ([#1151](https://github.com/ChainSafe/forest/pull/1151)) (Hunter Trujillo) diff --git a/Cargo.lock b/Cargo.lock index c3726a661b90..4cd0f1b8546a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3124,7 +3124,7 @@ checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" [[package]] name = "forest-filecoin" -version = "0.22.0" +version = "0.22.1" dependencies = [ "ahash", "anes 0.2.0", diff --git a/src/daemon/bundle.rs b/src/daemon/bundle.rs index 544326df04cc..58dc9f0fad9b 100644 --- a/src/daemon/bundle.rs +++ b/src/daemon/bundle.rs @@ -1,7 +1,7 @@ // Copyright 2019-2024 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -use crate::db::BlessedStore; +use crate::db::PersistentStore; use crate::{ networks::{ActorBundleInfo, NetworkChain, ACTOR_BUNDLES}, utils::{ @@ -21,7 +21,7 @@ use tracing::{info, warn}; /// Tries to load the missing actor bundles to the blockstore. If the bundle is /// not present, it will be downloaded. pub async fn load_actor_bundles( - db: &impl BlessedStore, + db: &impl PersistentStore, network: &NetworkChain, ) -> anyhow::Result<()> { if let Some(bundle_path) = match std::env::var("FOREST_ACTOR_BUNDLE_PATH") { @@ -38,7 +38,7 @@ pub async fn load_actor_bundles( } pub async fn load_actor_bundles_from_path( - db: &impl BlessedStore, + db: &impl PersistentStore, network: &NetworkChain, bundle_path: impl AsRef, ) -> anyhow::Result<()> { @@ -68,7 +68,7 @@ pub async fn load_actor_bundles_from_path( // Load into DB while let Some(CarBlock { cid, data }) = car_stream.try_next().await? { - db.put_keyed_blessed(&cid, &data)?; + db.put_keyed_persistent(&cid, &data)?; } Ok(()) @@ -76,7 +76,7 @@ pub async fn load_actor_bundles_from_path( /// Loads the missing actor bundle, returns the CIDs of the loaded bundles. pub async fn load_actor_bundles_from_server( - db: &impl BlessedStore, + db: &impl PersistentStore, network: &NetworkChain, bundles: &[ActorBundleInfo], ) -> anyhow::Result> { @@ -107,7 +107,7 @@ pub async fn load_actor_bundles_from_server( let mut stream = CarStream::new(BufReader::new(Cursor::new(bytes))).await?; while let Some(block) = stream.try_next().await? { - db.put_keyed_blessed(&block.cid, &block.data)?; + db.put_keyed_persistent(&block.cid, &block.data)?; } let header = stream.header; ensure!(header.roots.len() == 1); diff --git a/src/db/car/any.rs b/src/db/car/any.rs index a7f73b5a7cc1..75a20d3aacd6 100644 --- a/src/db/car/any.rs +++ b/src/db/car/any.rs @@ -10,7 +10,7 @@ use super::{CacheKey, RandomAccessFileReader, ZstdFrameCache}; use crate::blocks::Tipset; -use crate::db::BlessedStore; +use crate::db::PersistentStore; use crate::utils::io::EitherMmapOrRandomAccessFile; use cid::Cid; use fvm_ipld_blockstore::Blockstore; @@ -125,15 +125,15 @@ where } } -impl BlessedStore for AnyCar +impl PersistentStore for AnyCar where ReaderT: ReadAt, { - fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { match self { - AnyCar::Forest(forest) => forest.put_keyed_blessed(k, block), - AnyCar::Plain(plain) => plain.put_keyed_blessed(k, block), - AnyCar::Memory(mem) => mem.put_keyed_blessed(k, block), + AnyCar::Forest(forest) => forest.put_keyed_persistent(k, block), + AnyCar::Plain(plain) => plain.put_keyed_persistent(k, block), + AnyCar::Memory(mem) => mem.put_keyed_persistent(k, block), } } } diff --git a/src/db/car/forest.rs b/src/db/car/forest.rs index ff9954fcedb7..30468b98a2c1 100644 --- a/src/db/car/forest.rs +++ b/src/db/car/forest.rs @@ -50,7 +50,7 @@ use super::{CacheKey, ZstdFrameCache}; use crate::blocks::{Tipset, TipsetKey}; use crate::db::car::plain::write_skip_frame_header_async; use crate::db::car::RandomAccessFileReader; -use crate::db::BlessedStore; +use crate::db::PersistentStore; use crate::utils::db::car_stream::{CarBlock, CarHeader}; use crate::utils::encoding::from_slice_with_fallback; use crate::utils::io::EitherMmapOrRandomAccessFile; @@ -239,11 +239,11 @@ where } } -impl BlessedStore for ForestCar +impl PersistentStore for ForestCar where ReaderT: ReadAt, { - fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { self.put_keyed(k, block) } } diff --git a/src/db/car/many.rs b/src/db/car/many.rs index 4656ce322d8b..9820fed4c580 100644 --- a/src/db/car/many.rs +++ b/src/db/car/many.rs @@ -9,7 +9,7 @@ //! A single z-frame cache is shared between all read-only stores. use super::{AnyCar, ZstdFrameCache}; -use crate::db::{BlessedStore, EthMappingsStore, MemoryDB, SettingsStore}; +use crate::db::{EthMappingsStore, MemoryDB, PersistentStore, SettingsStore}; use crate::libp2p_bitswap::BitswapStoreReadWrite; use crate::rpc::eth::types::EthHash; use crate::shim::clock::ChainEpoch; @@ -169,9 +169,9 @@ impl Blockstore for ManyCar { } } -impl BlessedStore for ManyCar { - fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { - self.writer.put_keyed_blessed(k, block) +impl PersistentStore for ManyCar { + fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + self.writer.put_keyed_persistent(k, block) } } diff --git a/src/db/car/plain.rs b/src/db/car/plain.rs index 6a5403263900..df8a162281dc 100644 --- a/src/db/car/plain.rs +++ b/src/db/car/plain.rs @@ -71,7 +71,7 @@ use cid::Cid; use fvm_ipld_blockstore::Blockstore; use integer_encoding::VarIntReader; -use crate::db::BlessedStore; +use crate::db::PersistentStore; use nunny::Vec as NonEmpty; use parking_lot::RwLock; use positioned_io::ReadAt; @@ -234,11 +234,11 @@ where } } -impl BlessedStore for PlainCar +impl PersistentStore for PlainCar where ReaderT: ReadAt, { - fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { self.put_keyed(k, block) } } diff --git a/src/db/memory.rs b/src/db/memory.rs index d1aba056ca05..8f5318b72de3 100644 --- a/src/db/memory.rs +++ b/src/db/memory.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0, MIT use crate::cid_collections::CidHashSet; -use crate::db::{BlessedStore, GarbageCollectable}; +use crate::db::{GarbageCollectable, PersistentStore}; use crate::libp2p_bitswap::{BitswapStoreRead, BitswapStoreReadWrite}; use crate::rpc::eth::types::EthHash; use ahash::HashMap; @@ -120,8 +120,8 @@ impl Blockstore for MemoryDB { } } -impl BlessedStore for MemoryDB { - fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { +impl PersistentStore for MemoryDB { + fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { self.put_keyed(k, block) } } diff --git a/src/db/migration/migration_map.rs b/src/db/migration/migration_map.rs index 97a1efc69925..9493850ef569 100644 --- a/src/db/migration/migration_map.rs +++ b/src/db/migration/migration_map.rs @@ -9,7 +9,7 @@ use std::{ use crate::db::migration::v0_16_0::Migration0_15_2_0_16_0; use crate::db::migration::v0_19_0::Migration0_18_0_0_19_0; -use crate::db::migration::v0_22_1::Migration0_19_0_0_22_1; +use crate::db::migration::v0_22_1::Migration0_22_0_0_22_1; use crate::Config; use anyhow::bail; use anyhow::Context as _; @@ -81,7 +81,7 @@ create_migrations!( "0.12.1" -> "0.13.0" @ Migration0_12_1_0_13_0, "0.15.2" -> "0.16.0" @ Migration0_15_2_0_16_0, "0.18.0" -> "0.19.0" @ Migration0_18_0_0_19_0, - "0.19.0" -> "0.22.1" @ Migration0_19_0_0_22_1, + "0.22.0" -> "0.22.1" @ Migration0_22_0_0_22_1, ); pub struct Migration { diff --git a/src/db/migration/v0_22_1.rs b/src/db/migration/v0_22_1.rs index a140b020851d..2591d0f72e05 100644 --- a/src/db/migration/v0_22_1.rs +++ b/src/db/migration/v0_22_1.rs @@ -1,14 +1,14 @@ // Copyright 2019-2024 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -//! Migration logic for 0.19.0 to 0.22.1 version. -//! A `BlessedGraph` column has been introduced to allow for storage of persistent data that isn't -//! garbage collected. The initial use-case is network upgrade manifest storage. +//! Migration logic for 0.22.0 to 0.22.1 version. +//! A `PersistentGraph` column has been introduced to allow for storage of persistent data that +//! isn't garbage collected. The initial use-case is network upgrade manifest storage. use crate::blocks::TipsetKey; use crate::db::db_engine::Db; use crate::db::migration::migration_map::temporary_db_name; -use crate::db::migration::v0_22_1::paritydb_0_19_0::{DbColumn, ParityDb}; +use crate::db::migration::v0_22_1::paritydb_0_22_0::{DbColumn, ParityDb}; use crate::db::CAR_DB_DIR_NAME; use crate::rpc::eth::types::EthHash; use crate::Config; @@ -25,13 +25,13 @@ use tracing::info; use super::migration_map::MigrationOperation; -pub(super) struct Migration0_19_0_0_22_1 { +pub(super) struct Migration0_22_0_0_22_1 { from: Version, to: Version, } -/// Migrates the database from version 0.19.0 to 0.22.1 -impl MigrationOperation for Migration0_19_0_0_22_1 { +/// Migrates the database from version 0.22.0 to 0.22.1 +impl MigrationOperation for Migration0_22_0_0_22_1 { fn new(from: Version, to: Version) -> Self where Self: Sized, @@ -166,8 +166,8 @@ impl MigrationOperation for Migration0_19_0_0_22_1 { } } -/// Database settings from Forest `v0.19.0` -mod paritydb_0_19_0 { +/// Database settings from Forest `v0.22.0` +mod paritydb_0_22_0 { use parity_db::{CompressionType, Db, Options}; use std::path::PathBuf; use strum::{Display, EnumIter, IntoEnumIterator}; @@ -258,7 +258,7 @@ mod paritydb_0_22_1 { GraphFull, Settings, EthMappings, - BlessedGraph, + PersistentGraph, } impl DbColumn { @@ -266,7 +266,7 @@ mod paritydb_0_22_1 { DbColumn::iter() .map(|col| { match col { - DbColumn::GraphDagCborBlake2b256 | DbColumn::BlessedGraph => { + DbColumn::GraphDagCborBlake2b256 | DbColumn::PersistentGraph => { parity_db::ColumnOptions { preimage: true, compression, diff --git a/src/db/mod.rs b/src/db/mod.rs index 7029afbc20ce..452d0ef803a5 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -213,31 +213,31 @@ pub trait GarbageCollectable { } /// A trait that allows for storing data that is not garbage collected. -pub trait BlessedStore: Blockstore { +pub trait PersistentStore: Blockstore { /// Puts a keyed block with pre-computed CID into the database. /// /// # Arguments /// /// * `k` - The key to be stored. /// * `block` - The block to be stored. - fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()>; + fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()>; } -impl BlessedStore for MemoryBlockstore { - fn put_keyed_blessed(&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) } } -impl BlessedStore for Arc { - fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { - BlessedStore::put_keyed_blessed(self.as_ref(), k, block) +impl PersistentStore for Arc { + fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + PersistentStore::put_keyed_persistent(self.as_ref(), k, block) } } -impl BlessedStore for &Arc { - fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { - BlessedStore::put_keyed_blessed(self.as_ref(), k, block) +impl PersistentStore for &Arc { + fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + PersistentStore::put_keyed_persistent(self.as_ref(), k, block) } } diff --git a/src/db/parity_db.rs b/src/db/parity_db.rs index 886538cc9fa0..1482c0e99697 100644 --- a/src/db/parity_db.rs +++ b/src/db/parity_db.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; -use super::{BlessedStore, SettingsStore}; +use super::{PersistentStore, SettingsStore}; use super::EthMappingsStore; @@ -47,7 +47,7 @@ enum DbColumn { /// Column for storing IPLD data that has to be ignored by the garbage collector. /// Anything stored in this column can be considered permanent, unless manually /// deleted. - BlessedGraph, + PersistentGraph, } impl DbColumn { @@ -55,7 +55,7 @@ impl DbColumn { DbColumn::iter() .map(|col| { match col { - DbColumn::GraphDagCborBlake2b256 | DbColumn::BlessedGraph => { + DbColumn::GraphDagCborBlake2b256 | DbColumn::PersistentGraph => { parity_db::ColumnOptions { preimage: true, compression, @@ -93,8 +93,8 @@ impl DbColumn { pub struct ParityDb { pub db: parity_db::Db, statistics_enabled: bool, - // This is needed to maintain backwards-compatibility for pre-blessed-column migrations. - disable_blessed_fallback: bool, + // This is needed to maintain backwards-compatibility for pre-persistent-column migrations. + disable_persistent_fallback: bool, } impl ParityDb { @@ -115,15 +115,15 @@ impl ParityDb { Ok(Self { db: Db::open_or_create(&opts)?, statistics_enabled: opts.stats, - disable_blessed_fallback: false, + disable_persistent_fallback: false, }) } - pub fn wrap(db: parity_db::Db, stats: bool, disable_blessed: bool) -> Self { + pub fn wrap(db: parity_db::Db, stats: bool, disable_persistent: bool) -> Self { Self { db, statistics_enabled: stats, - disable_blessed_fallback: disable_blessed, + disable_persistent_fallback: disable_persistent, } } @@ -230,7 +230,7 @@ impl Blockstore for ParityDb { if res.is_some() { return Ok(res); } - self.get_blessed(k) + self.get_persistent(k) } fn put_keyed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { @@ -259,9 +259,9 @@ impl Blockstore for ParityDb { } } -impl BlessedStore for ParityDb { - fn put_keyed_blessed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { - self.write_to_column(k.to_bytes(), block, DbColumn::BlessedGraph) +impl PersistentStore for ParityDb { + fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { + self.write_to_column(k.to_bytes(), block, DbColumn::PersistentGraph) } } @@ -345,11 +345,11 @@ impl ParityDb { } // Get data from persistent graph column. - fn get_blessed(&self, k: &Cid) -> anyhow::Result>> { - if self.disable_blessed_fallback { + fn get_persistent(&self, k: &Cid) -> anyhow::Result>> { + if self.disable_persistent_fallback { return Ok(None); } - self.read_from_column(k.to_bytes(), DbColumn::BlessedGraph) + self.read_from_column(k.to_bytes(), DbColumn::PersistentGraph) } } @@ -456,7 +456,7 @@ mod test { DbColumn::GraphFull => DbColumn::GraphDagCborBlake2b256, DbColumn::Settings => panic!("invalid column for IPLD data"), DbColumn::EthMappings => panic!("invalid column for IPLD data"), - DbColumn::BlessedGraph => panic!("invalid column for GC enabled IPLD data"), + DbColumn::PersistentGraph => panic!("invalid column for GC enabled IPLD data"), }; let actual = db.read_from_column(cid.to_bytes(), other_column).unwrap(); assert!(actual.is_none()); @@ -545,7 +545,7 @@ mod test { } #[test] - fn blessed_tests() { + fn persistent_tests() { let db = TempParityDB::new(); let data = [ b"h'nglui mglw'nafh".to_vec(), @@ -553,7 +553,7 @@ mod test { b"R'lyeh wgah'nagl fhtagn!!".to_vec(), ]; - let blessed_data = data + let persistent_data = data .clone() .into_iter() .map(|mut entry| { @@ -570,17 +570,17 @@ mod test { for idx in 0..3 { let cid = &cids[idx]; - let blessed_entry = &blessed_data[idx]; + let persistent_entry = &persistent_data[idx]; let data_entry = &data[idx]; - db.put_keyed_blessed(cid, blessed_entry).unwrap(); - // Check that we get blessed data if the data is otherwise absent from the GC enabled + db.put_keyed_persistent(cid, persistent_entry).unwrap(); + // Check that we get persistent data if the data is otherwise absent from the GC enabled // storage. assert_eq!( Blockstore::get(db.deref(), cid).unwrap(), - Some(blessed_entry.clone()) + Some(persistent_entry.clone()) ); assert!(db - .read_from_column(cid.to_bytes(), DbColumn::BlessedGraph) + .read_from_column(cid.to_bytes(), DbColumn::PersistentGraph) .unwrap() .is_some()); db.put_keyed(cid, data_entry).unwrap(); diff --git a/src/tool/subcommands/snapshot_cmd.rs b/src/tool/subcommands/snapshot_cmd.rs index 61583e71b169..9190168f990b 100644 --- a/src/tool/subcommands/snapshot_cmd.rs +++ b/src/tool/subcommands/snapshot_cmd.rs @@ -8,7 +8,7 @@ use crate::cli_shared::snapshot; use crate::daemon::bundle::load_actor_bundles; use crate::db::car::forest::DEFAULT_FOREST_CAR_FRAME_SIZE; use crate::db::car::{AnyCar, ManyCar}; -use crate::db::BlessedStore; +use crate::db::PersistentStore; use crate::interpreter::{MessageCallbackCtx, VMEvent, VMTrace}; use crate::ipld::stream_chain; use crate::networks::{butterflynet, calibnet, mainnet, ChainConfig, NetworkChain}; @@ -295,7 +295,7 @@ async fn validate_with_blockstore( check_stateroots: u32, ) -> anyhow::Result<()> where - BlockstoreT: BlessedStore + Send + Sync + 'static, + BlockstoreT: PersistentStore + Send + Sync + 'static, { if check_links != 0 { validate_ipld_links(root.clone(), &store, check_links).await?; @@ -397,7 +397,7 @@ async fn validate_stateroots( epochs: u32, ) -> anyhow::Result<()> where - DB: BlessedStore + Send + Sync + 'static, + DB: PersistentStore + Send + Sync + 'static, { let chain_config = Arc::new(ChainConfig::from_chain(&network)); let genesis = ts.genesis(db)?; From 4284d1866cbe1193176f67da1e83b990e82020fc Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Tue, 12 Nov 2024 15:02:04 +0100 Subject: [PATCH 20/21] fmt --- CHANGELOG.md | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ff0ea29b218..cec5dbc79be3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -926,19 +926,19 @@ usability improvements. port from 1234 to 2345. - [#3336](https://github.com/ChainSafe/forest/pull/3336) Moved following `forest-cli` subcommands to `forest-tool` - - `archive info` - - `fetch-params` - - `snapshot fetch` - - `snapshot validate` + - `archive info` + - `fetch-params` + - `snapshot fetch` + - `snapshot validate` - [#3355](https://github.com/ChainSafe/forest/pull/3355) Moved commands - - `forest-cli db stats` to `forest-tool db stats` - - `forest-cli db clean` to `forest-tool db destroy` + - `forest-cli db stats` to `forest-tool db stats` + - `forest-cli db clean` to `forest-tool db destroy` - [#3362](https://github.com/ChainSafe/forest/pull/3362) Moved the following `forest-cli wallet` subcommands to `forest-wallet` - [#3432](https://github.com/ChainSafe/forest/pull/3432) Moved following `forest-cli` subcommands to `forest-tool` - - `archive export` - - `archive checkpoints` + - `archive export` + - `archive checkpoints` - [#3431](https://github.com/ChainSafe/forest/pull/3431) Moved the following `forest-cli snapshot compress` subcommand to `forest-tool` - [#3435](https://github.com/ChainSafe/forest/pull/3435) Moved subcommand @@ -1123,8 +1123,8 @@ Notable updates: ### Breaking - [#2873](https://github.com/ChainSafe/forest/issues/2873) - - remove `--compressed` from the CLI. Snapshots are now always compressed. - - Remove snapshot ops - snapshots fetched to the current directory by default. + - remove `--compressed` from the CLI. Snapshots are now always compressed. + - Remove snapshot ops - snapshots fetched to the current directory by default. ### Added @@ -1287,10 +1287,10 @@ Notable updates: [#2576](https://github.com/ChainSafe/forest/issues/2576) - Revised how balances are displayed, defaulting to: [#2323](https://github.com/ChainSafe/forest/issues/2323) - - adding metric prefix when it's required, consequently CLI flag - `--fixed-unit` added to force to show in original `FIL` unit - - 4 significant digits, consequently CLI flag `--exact-balance` added to force - full accuracy. + - adding metric prefix when it's required, consequently CLI flag + `--fixed-unit` added to force to show in original `FIL` unit + - 4 significant digits, consequently CLI flag `--exact-balance` added to force + full accuracy. - `stats` and `compression` keys in `parity_db` section were renamed to `enable_statistics` and `compression_type` respectively. [#2433](https://github.com/ChainSafe/forest/issues/2433) @@ -1817,8 +1817,7 @@ All initial change sets: - `ccf1ac11` Return Ok when validating drand beacon entries similar to how Lotus does as per the audit recommendation. ([#1206](https://github.com/ChainSafe/forest/pull/1206)) (Hunter Trujillo) -- `f5fe14d2` [Audit fixes] FOR-03 - Inconsistent Deserialization of - Randomness ([#1205](https://github.com/ChainSafe/forest/pull/1205)) +- `f5fe14d2` [Audit fixes] FOR-03 - Inconsistent Deserialization of Randomness ([#1205](https://github.com/ChainSafe/forest/pull/1205)) (Hunter Trujillo) - `32a9ae5f` Rest of V5 Updates ([#1217](https://github.com/ChainSafe/forest/pull/1217)) (Eric Tu) @@ -1874,8 +1873,7 @@ All initial change sets: ([#1160](https://github.com/ChainSafe/forest/pull/1160)) (creativcoder) - `34799734` Wallet CLI Implementation ([#1128](https://github.com/ChainSafe/forest/pull/1128)) (Connor Mullett) -- `f698ba88` [Audit fixes] FOR-02: Inconsistent Deserialization of Address - ID ([#1149](https://github.com/ChainSafe/forest/pull/1149)) +- `f698ba88` [Audit fixes] FOR-02: Inconsistent Deserialization of Address ID ([#1149](https://github.com/ChainSafe/forest/pull/1149)) (Hunter Trujillo) - `e50d2ae8` [Audit fixes] FOR-16: Unnecessary Extensive Permissions for Private Keys ([#1151](https://github.com/ChainSafe/forest/pull/1151)) (Hunter Trujillo) From 6b42fafa7ef7119c545f502d81e7a52e4ec5b4bf Mon Sep 17 00:00:00 2001 From: Roman Useinov Date: Tue, 26 Nov 2024 13:59:09 +0100 Subject: [PATCH 21/21] add a gc test --- src/db/gc/mod.rs | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/db/memory.rs | 17 +++++++++++++++-- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/db/gc/mod.rs b/src/db/gc/mod.rs index 150e08cfd73a..9baabe03407d 100644 --- a/src/db/gc/mod.rs +++ b/src/db/gc/mod.rs @@ -238,7 +238,7 @@ mod test { use crate::blocks::{CachingBlockHeader, Tipset}; use crate::chain::{ChainEpochDelta, ChainStore}; - use crate::db::{GarbageCollectable, MarkAndSweep, MemoryDB}; + use crate::db::{GarbageCollectable, MarkAndSweep, MemoryDB, PersistentStore}; use crate::message_pool::test_provider::{mock_block, mock_block_with_parents}; use crate::networks::ChainConfig; @@ -247,7 +247,11 @@ mod test { use core::time::Duration; use crate::shim::clock::ChainEpoch; + use cid::multihash::Code::Identity; + use cid::multihash::MultihashDigest; + use cid::Cid; use fvm_ipld_blockstore::Blockstore; + use fvm_ipld_encoding::DAG_CBOR; use std::sync::Arc; const ZERO_DURATION: Duration = Duration::from_secs(0); @@ -473,4 +477,43 @@ mod test { current_epoch + 1 + depth * 2 ); } + + #[tokio::test] + async fn persistent_data_resilient_to_gc() { + let depth = 5 as ChainEpochDelta; + let current_epoch = 0 as ChainEpochDelta; + + let tester = GCTester::new(); + let mut gc = MarkAndSweep::new( + tester.db.clone(), + tester.get_heaviest_tipset_fn(), + depth, + ZERO_DURATION, + ); + + let depth = depth as ChainEpochDelta; + let current_epoch = current_epoch as ChainEpochDelta; + + let persistent_data = [1, 55]; + let persistent_cid = Cid::new_v1(DAG_CBOR, Identity.digest(&persistent_data)); + + // Make sure we run enough epochs to initiate GC. + tester.run_epochs(current_epoch); + tester.run_epochs(depth); + tester + .db + .put_keyed_persistent(&persistent_cid, &persistent_data) + .unwrap(); + // Mark. + gc.gc_workflow(ZERO_DURATION).await.unwrap(); + tester.run_epochs(depth); + // Sweep. + gc.gc_workflow(ZERO_DURATION).await.unwrap(); + + // Make sure persistent data stays. + assert_eq!( + tester.db.get(&persistent_cid).unwrap(), + Some(persistent_data.to_vec()) + ); + } } diff --git a/src/db/memory.rs b/src/db/memory.rs index 8f5318b72de3..62194952ea45 100644 --- a/src/db/memory.rs +++ b/src/db/memory.rs @@ -16,6 +16,7 @@ use super::{EthMappingsStore, SettingsStore}; #[derive(Debug, Default)] pub struct MemoryDB { blockchain_db: RwLock, Vec>>, + blockchain_persistent_db: RwLock, Vec>>, settings_db: RwLock>>, eth_mappings_db: RwLock>>, } @@ -109,7 +110,16 @@ impl EthMappingsStore for MemoryDB { impl Blockstore for MemoryDB { fn get(&self, k: &Cid) -> anyhow::Result>> { - Ok(self.blockchain_db.read().get(&k.to_bytes()).cloned()) + Ok(self + .blockchain_db + .read() + .get(&k.to_bytes()) + .cloned() + .or(self + .blockchain_persistent_db + .read() + .get(&k.to_bytes()) + .cloned())) } fn put_keyed(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { @@ -122,7 +132,10 @@ impl Blockstore for MemoryDB { impl PersistentStore for MemoryDB { fn put_keyed_persistent(&self, k: &Cid, block: &[u8]) -> anyhow::Result<()> { - self.put_keyed(k, block) + self.blockchain_persistent_db + .write() + .insert(k.to_bytes(), block.to_vec()); + Ok(()) } }