Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@

### Changed

- [#6655](https://github.com/ChainSafe/forest/issues/6655): Updated garbage collector to keep message receipts and events.

### Removed

### Fixed
Expand Down
10 changes: 10 additions & 0 deletions src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ use tokio::io::{AsyncWrite, AsyncWriteExt, BufWriter};
#[derive(Debug, Clone, Default)]
pub struct ExportOptions {
pub skip_checksum: bool,
pub include_receipts: bool,
pub include_events: bool,
pub seen: CidHashSet,
}

Expand Down Expand Up @@ -140,9 +142,15 @@ async fn export_to_forest_car<D: Digest>(
) -> anyhow::Result<Option<digest::Output<D>>> {
let ExportOptions {
skip_checksum,
include_receipts,
include_events,
seen,
} = options.unwrap_or_default();

if include_events && !include_receipts {
anyhow::bail!("message receipts must be included when events are included");
}

let stateroot_lookup_limit = tipset.epoch() - lookup_depth;

// Wrap writer in optional checksum calculator
Expand All @@ -161,6 +169,8 @@ async fn export_to_forest_car<D: Digest>(
stateroot_lookup_limit,
)
.with_seen(seen)
.with_message_receipts(include_receipts)
.with_events(include_events)
.track_progress(true),
);

Expand Down
2 changes: 2 additions & 0 deletions src/cli/subcommands/snapshot_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ impl SnapshotCommands {
recent_roots: depth,
output_path: temp_path.to_path_buf(),
tipset_keys: tipset.key().clone().into(),
include_receipts: false,
include_events: false,
skip_checksum,
dry_run,
};
Expand Down
4 changes: 3 additions & 1 deletion src/db/gc/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,9 @@ where
file,
Some(ExportOptions {
Comment thread
LesnyRumcajs marked this conversation as resolved.
skip_checksum: true,
..Default::default()
include_receipts: true,
include_events: true,
seen: Default::default(),
}),
)
.await?;
Expand Down
62 changes: 62 additions & 0 deletions src/ipld/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::blocks::Tipset;
use crate::cid_collections::CidHashSet;
use crate::ipld::Ipld;
use crate::shim::clock::ChainEpoch;
use crate::shim::executor::Receipt;
use crate::utils::db::car_stream::CarBlock;
use crate::utils::encoding::extract_cids;
use crate::utils::multihash::prelude::*;
Expand Down Expand Up @@ -137,7 +138,9 @@ impl Iterator for DfsIter {

enum IterateType {
Message(Cid),
MessageReceipts(Cid),
StateRoot(Cid),
EventsRoot(Cid),
}

enum Task {
Expand All @@ -155,6 +158,8 @@ pin_project! {
seen: CidHashSet,
stateroot_limit_exclusive: ChainEpoch,
fail_on_dead_links: bool,
message_receipts: bool,
events: bool,
track_progress: bool,
}
}
Expand All @@ -175,6 +180,19 @@ impl<DB, T> ChainStream<DB, T> {
self
}

/// Enable traversal of message receipt roots during chain export.
pub fn with_message_receipts(mut self, message_receipts: bool) -> Self {
self.message_receipts = message_receipts;
self
}

/// Enable traversal of events roots during chain export.
/// Requires message receipts to be enabled as well.
pub fn with_events(mut self, events: bool) -> Self {
self.events = events;
self
}
Comment thread
hanabi1224 marked this conversation as resolved.

#[allow(dead_code)]
pub fn into_seen(self) -> CidHashSet {
self.seen
Expand Down Expand Up @@ -204,6 +222,8 @@ pub fn stream_chain<DB: Blockstore, T: Borrow<Tipset>, ITER: Iterator<Item = T>
seen: CidHashSet::default(),
stateroot_limit_exclusive,
fail_on_dead_links: true,
message_receipts: false,
events: false,
track_progress: false,
}
}
Expand Down Expand Up @@ -276,6 +296,20 @@ impl<DB: Blockstore, T: Borrow<Tipset>, ITER: Iterator<Item = T> + Unpin> Stream
IterateType::StateRoot(c) => {
format!("state root {c}")
}
IterateType::MessageReceipts(c) => {
// Forgive message receipts
tracing::trace!(
"[Iterate] missing key: {cid} from message receipts {c} in block {block_cid} at epoch {epoch}"
);
continue;
}
IterateType::EventsRoot(c) => {
// Forgive events
tracing::trace!(
"[Iterate] missing key: {cid} from events root {c} in block {block_cid} at epoch {epoch}"
);
continue;
}
};
return Poll::Ready(Some(Err(anyhow::anyhow!(
"[Iterate] missing key: {cid} from {type_display} in block {block_cid} at epoch {epoch}"
Expand Down Expand Up @@ -318,6 +352,34 @@ impl<DB: Blockstore, T: Borrow<Tipset>, ITER: Iterator<Item = T> + Unpin> Stream
.filter_map(ipld_to_cid)
.collect(),
));
if *this.message_receipts {
this.dfs.push_back(Iterate(
block.epoch,
*block.cid(),
IterateType::MessageReceipts(block.message_receipts),
DfsIter::from(block.message_receipts)
.filter_map(ipld_to_cid)
.collect(),
));
}
// ignore failure as receipts are not required by a lite snapshot
if *this.events
&& let Ok(receipts) =
Receipt::get_receipts(this.db, block.message_receipts)
{
Comment thread
hanabi1224 marked this conversation as resolved.
for receipt in receipts {
if let Some(events_root) = receipt.events_root() {
this.dfs.push_back(Iterate(
block.epoch,
*block.cid(),
IterateType::EventsRoot(events_root),
DfsIter::from(events_root)
.filter_map(ipld_to_cid)
.collect(),
));
}
}
}
}

// Visit the block if it's within required depth. And a special case for `0`
Expand Down
18 changes: 14 additions & 4 deletions src/rpc/methods/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ pub enum ForestChainExport {}
impl RpcMethod<1> for ForestChainExport {
const NAME: &'static str = "Forest.ChainExport";
const PARAM_NAMES: [&'static str; 1] = ["params"];
const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all_with_v2();
const PERMISSION: Permission = Permission::Read;

type Params = (ForestChainExportParams,);
Expand All @@ -425,6 +425,8 @@ impl RpcMethod<1> for ForestChainExport {
recent_roots,
output_path,
tipset_keys: ApiTipsetKey(tsk),
include_receipts,
include_events,
skip_checksum,
dry_run,
} = params;
Expand All @@ -448,6 +450,8 @@ impl RpcMethod<1> for ForestChainExport {

let options = Some(ExportOptions {
skip_checksum,
include_receipts,
include_events,
seen: Default::default(),
});
let writer = if dry_run {
Expand Down Expand Up @@ -534,7 +538,7 @@ pub enum ForestChainExportStatus {}
impl RpcMethod<0> for ForestChainExportStatus {
const NAME: &'static str = "Forest.ChainExportStatus";
const PARAM_NAMES: [&'static str; 0] = [];
const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all_with_v2();
const PERMISSION: Permission = Permission::Read;

type Params = ();
Expand Down Expand Up @@ -575,7 +579,7 @@ pub enum ForestChainExportCancel {}
impl RpcMethod<0> for ForestChainExportCancel {
const NAME: &'static str = "Forest.ChainExportCancel";
const PARAM_NAMES: [&'static str; 0] = [];
const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all_with_v2();
const PERMISSION: Permission = Permission::Read;

type Params = ();
Expand All @@ -599,7 +603,7 @@ pub enum ForestChainExportDiff {}
impl RpcMethod<1> for ForestChainExportDiff {
const NAME: &'static str = "Forest.ChainExportDiff";
const PARAM_NAMES: [&'static str; 1] = ["params"];
const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all_with_v2();
const PERMISSION: Permission = Permission::Read;

type Params = (ForestChainExportDiffParams,);
Expand Down Expand Up @@ -682,6 +686,8 @@ impl RpcMethod<1> for ChainExport {
recent_roots,
output_path,
tipset_keys,
include_receipts: false,
include_events: false,
skip_checksum,
dry_run,
},),
Expand Down Expand Up @@ -1468,6 +1474,10 @@ pub struct ForestChainExportParams {
#[schemars(with = "LotusJson<ApiTipsetKey>")]
#[serde(with = "crate::lotus_json")]
pub tipset_keys: ApiTipsetKey,
#[serde(default)]
pub include_receipts: bool,
#[serde(default)]
pub include_events: bool,
pub skip_checksum: bool,
pub dry_run: bool,
}
Expand Down
6 changes: 6 additions & 0 deletions src/rpc/snapshots/forest__rpc__tests__rpc__v0.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/rpc/snapshots/forest__rpc__tests__rpc__v1.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading