diff --git a/src/chain/store/chain_store.rs b/src/chain/store/chain_store.rs index 040dae41c8e..996c8dde76b 100644 --- a/src/chain/store/chain_store.rs +++ b/src/chain/store/chain_store.rs @@ -313,27 +313,23 @@ where } } - pub fn load_child_tipset(&self, ts: &Tipset) -> Result { + /// Returns [`None`] when `ts` has no known child on the current heaviest chain + /// (e.g. `ts` is the chain head). Blockstore errors are returned as [`Err`]. + pub fn load_child_tipset(&self, ts: &Tipset) -> Result, Error> { let head = self.heaviest_tipset(); if head.parents() == ts.key() { - Ok(head) + Ok(Some(head)) } else if head.epoch() > ts.epoch() { - let maybe_child = self.chain_index().tipset_by_height( + match self.chain_index().tipset_by_height( ts.epoch() + 1, head, ResolveNullTipset::TakeNewer, - )?; - if maybe_child.parents() == ts.key() { - Ok(maybe_child) - } else { - Err(Error::NotFound( - format!("child of tipset@{}", ts.epoch()).into(), - )) + )? { + Some(maybe_child) if maybe_child.parents() == ts.key() => Ok(Some(maybe_child)), + _ => Ok(None), } } else { - Err(Error::NotFound( - format!("child of tipset@{}", ts.epoch()).into(), - )) + Ok(None) } } @@ -432,7 +428,7 @@ where } let next_ts = chain_index - .tipset_by_height( + .load_required_tipset_by_height( lbr + 1, heaviest_tipset.clone(), ResolveNullTipset::TakeNewer, diff --git a/src/chain/store/index.rs b/src/chain/store/index.rs index 3fe8f675fa1..91f01776410 100644 --- a/src/chain/store/index.rs +++ b/src/chain/store/index.rs @@ -119,8 +119,10 @@ impl ChainIndex { } /// Find tipset at epoch `to` in the chain of ancestors starting at `from`. - /// If the tipset is _not_ in the chain of ancestors (i.e., if the `to` - /// epoch is higher than `from.epoch()`), an error will be returned. + /// + /// Returns `Ok(Some(tipset))` when epoch `to` resolves. Returns `Ok(None)` if the ancestor + /// walk completes without resolving `to` (for example missing parent tipsets). Returns `Err` + /// if `to` is greater than `from.epoch()` or genesis lookup fails when `to` is zero. /// /// # Why pass in the `from` argument? /// @@ -162,7 +164,7 @@ impl ChainIndex { to: ChainEpoch, mut from: Tipset, resolve: ResolveNullTipset, - ) -> Result { + ) -> Result, Error> { use crate::shim::policy::policy_constants::CHAIN_FINALITY; // use `20` as checkpoint interval to match Lotus: @@ -190,7 +192,7 @@ impl ChainIndex { } if to == 0 { - return Ok(Tipset::from(from.genesis(&self.db)?)); + return Ok(Some(Tipset::from(from.genesis(&self.db)?))); } if to > from.epoch() { return Err(Error::Other(format!( @@ -215,19 +217,28 @@ impl ChainIndex { } if to == child.epoch() { - return Ok(child); + return Ok(Some(child)); } if to > parent.epoch() { // We're at a point where child.epoch() > x > parent.epoch(). match resolve { - ResolveNullTipset::TakeOlder => return Ok(parent), - ResolveNullTipset::TakeNewer => return Ok(child), + ResolveNullTipset::TakeOlder => return Ok(Some(parent)), + ResolveNullTipset::TakeNewer => return Ok(Some(child)), } } } - Err(Error::Other(format!( - "Tipset with epoch={to} does not exist" - ))) + Ok(None) + } + + /// Same as [`Self::tipset_by_height`], but errors if that would return `None`. + pub fn load_required_tipset_by_height( + &self, + to: ChainEpoch, + from: Tipset, + resolve: ResolveNullTipset, + ) -> Result { + self.tipset_by_height(to, from, resolve)? + .ok_or_else(|| Error::NotFound(format!("tipset at epoch {to}").into())) } /// Finds the latest beacon entry given a tipset up to 20 tipsets behind @@ -304,14 +315,16 @@ mod tests { assert_eq!( index .tipset_by_height(2, epoch4.clone(), ResolveNullTipset::TakeOlder) - .unwrap(), + .unwrap() + .expect("epoch 2 resolved"), epoch1 ); assert_eq!( index .tipset_by_height(2, epoch4, ResolveNullTipset::TakeNewer) - .unwrap(), + .unwrap() + .expect("epoch 2 resolved"), epoch3 ); } @@ -340,15 +353,36 @@ mod tests { assert_eq!( index .tipset_by_height(2, epoch3a, ResolveNullTipset::TakeOlder) - .unwrap(), + .unwrap() + .expect("epoch 2 on branch a"), epoch2a ); assert_eq!( index .tipset_by_height(2, epoch3b, ResolveNullTipset::TakeOlder) - .unwrap(), + .unwrap() + .expect("epoch 2 on branch b"), epoch2b ); } + + #[test] + fn tipset_by_height_broken_ancestor_chain_returns_none() { + let db = Arc::new(MemoryDB::default()); + let genesis = genesis_tipset(); + // Epoch 3 header points at a parent key we never persist — `Tipset::chain` stops + // after this tipset, so `tipset_by_height` finds no `(child, parent)` window. + let epoch3 = tipset_child(&tipset_child(&genesis, 2), 3); + persist_tipset(&genesis, &db); + persist_tipset(&epoch3, &db); + + let index = ChainIndex::new(db); + assert!( + index + .tipset_by_height(2, epoch3, ResolveNullTipset::TakeOlder) + .unwrap() + .is_none() + ); + } } diff --git a/src/dev/subcommands/export_state_tree_cmd.rs b/src/dev/subcommands/export_state_tree_cmd.rs index 366edc07576..67360d17545 100644 --- a/src/dev/subcommands/export_state_tree_cmd.rs +++ b/src/dev/subcommands/export_state_tree_cmd.rs @@ -83,7 +83,7 @@ impl ExportStateTreeCommand { genesis_header, )?); - let start_ts = chain_store.chain_index().tipset_by_height( + let start_ts = chain_store.chain_index().load_required_tipset_by_height( from, chain_store.heaviest_tipset(), ResolveNullTipset::TakeNewer, diff --git a/src/dev/subcommands/state_cmd.rs b/src/dev/subcommands/state_cmd.rs index 0c463d7d220..c6f739a3aa8 100644 --- a/src/dev/subcommands/state_cmd.rs +++ b/src/dev/subcommands/state_cmd.rs @@ -14,6 +14,7 @@ use crate::{ tool::subcommands::api_cmd::generate_test_snapshot, utils::ShallowClone as _, }; +use anyhow::Context as _; use human_repr::HumanCount as _; use nonzero_ext::nonzero; use std::{num::NonZeroUsize, path::PathBuf, sync::Arc, time::Instant}; @@ -86,12 +87,17 @@ impl ComputeCommand { let (ts, ts_next) = { // We don't want to track all entries that are visited by `tipset_by_height` db.pause_tracking(); - let ts = chain_index.tipset_by_height( + let ts = chain_index.load_required_tipset_by_height( epoch, chain_store.heaviest_tipset(), ResolveNullTipset::TakeOlder, )?; - let ts_next = chain_store.load_child_tipset(&ts)?; + let ts_next = chain_store.load_child_tipset(&ts)?.with_context(|| { + format!( + "no child tipset for epoch {} (may be chain head)", + ts.epoch() + ) + })?; db.resume_tracking(); SettingsStoreExt::write_obj( &db.tracker, @@ -217,7 +223,7 @@ impl ValidateCommand { let ts = { // We don't want to track all entries that are visited by `tipset_by_height` db.pause_tracking(); - let ts = chain_index.tipset_by_height( + let ts = chain_index.load_required_tipset_by_height( epoch, chain_store.heaviest_tipset(), ResolveNullTipset::TakeOlder, diff --git a/src/interpreter/fvm3.rs b/src/interpreter/fvm3.rs index e9aa1a0635e..ad0bb52dbea 100644 --- a/src/interpreter/fvm3.rs +++ b/src/interpreter/fvm3.rs @@ -133,7 +133,7 @@ impl Chain for ForestExterns { fn get_tipset_cid(&self, epoch: ChainEpoch) -> anyhow::Result { let ts = self .chain_index - .tipset_by_height( + .load_required_tipset_by_height( epoch, self.heaviest_tipset.clone(), ResolveNullTipset::TakeOlder, diff --git a/src/interpreter/fvm4.rs b/src/interpreter/fvm4.rs index 668d1ca58ff..db51f8d6289 100644 --- a/src/interpreter/fvm4.rs +++ b/src/interpreter/fvm4.rs @@ -132,7 +132,7 @@ impl Chain for ForestExterns { fn get_tipset_cid(&self, epoch: ChainEpoch) -> anyhow::Result { let ts = self .chain_index - .tipset_by_height( + .load_required_tipset_by_height( epoch, self.heaviest_tipset.clone(), ResolveNullTipset::TakeOlder, diff --git a/src/message_pool/msgpool/provider.rs b/src/message_pool/msgpool/provider.rs index 2f76e96a8d1..48b8aaa20e0 100644 --- a/src/message_pool/msgpool/provider.rs +++ b/src/message_pool/msgpool/provider.rs @@ -121,7 +121,7 @@ impl Provider for ChainStore { _ => { let lookback_ts = if ts.epoch() > self.chain_config().policy.chain_finality { self.chain_index() - .tipset_by_height( + .load_required_tipset_by_height( ts.epoch() - self.chain_config().policy.chain_finality, ts.clone(), ResolveNullTipset::TakeOlder, diff --git a/src/rpc/methods/chain.rs b/src/rpc/methods/chain.rs index c5d52a3d1c9..8ec3ecea305 100644 --- a/src/rpc/methods/chain.rs +++ b/src/rpc/methods/chain.rs @@ -394,9 +394,11 @@ impl RpcMethod<1> for ForestChainExport { start_export(); let head = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?; - let start_ts = - ctx.chain_index() - .tipset_by_height(epoch, head, ResolveNullTipset::TakeOlder)?; + let start_ts = ctx.chain_index().load_required_tipset_by_height( + epoch, + head, + ResolveNullTipset::TakeOlder, + )?; let options = ExportOptions { skip_checksum, @@ -592,9 +594,11 @@ impl RpcMethod<1> for ForestChainExportDiff { } let head = ctx.chain_store().heaviest_tipset(); - let start_ts = - ctx.chain_index() - .tipset_by_height(from, head, ResolveNullTipset::TakeOlder)?; + let start_ts = ctx.chain_index().load_required_tipset_by_height( + from, + head, + ResolveNullTipset::TakeOlder, + )?; crate::tool::subcommands::archive_cmd::do_export( &ctx.store_owned(), @@ -891,9 +895,11 @@ impl RpcMethod<2> for ChainGetTipSetByHeight { let ts = ctx .chain_store() .load_required_tipset_or_heaviest(&tipset_key)?; - let tss = ctx - .chain_index() - .tipset_by_height(height, ts, ResolveNullTipset::TakeOlder)?; + let tss = ctx.chain_index().load_required_tipset_by_height( + height, + ts, + ResolveNullTipset::TakeOlder, + )?; Ok(tss) } } @@ -921,9 +927,11 @@ impl RpcMethod<2> for ChainGetTipSetAfterHeight { let ts = ctx .chain_store() .load_required_tipset_or_heaviest(&tipset_key)?; - let tss = ctx - .chain_index() - .tipset_by_height(height, ts, ResolveNullTipset::TakeNewer)?; + let tss = ctx.chain_index().load_required_tipset_by_height( + height, + ts, + ResolveNullTipset::TakeNewer, + )?; Ok(tss) } } @@ -1064,7 +1072,7 @@ impl ChainGetTipSetV2 { if finalized.epoch() >= safe_height { Ok(finalized) } else { - Ok(ctx.chain_index().tipset_by_height( + Ok(ctx.chain_index().load_required_tipset_by_height( safe_height, head, ResolveNullTipset::TakeOlder, @@ -1075,7 +1083,7 @@ impl ChainGetTipSetV2 { pub async fn get_latest_finalized_tipset( ctx: &Ctx, ) -> anyhow::Result { - ChainGetTipSetFinalityStatus::get_finality_status(ctx) + ChainGetTipSetFinalityStatus::get_finality_status(ctx)? .finalized_tip_set .context("failed to resolve finalized tipset") } @@ -1093,7 +1101,7 @@ impl ChainGetTipSetV2 { // Get tipset by height. if let Some(height) = &selector.height { let anchor = Self::get_tipset_by_anchor(ctx, height.anchor.as_ref()).await?; - let ts = ctx.chain_index().tipset_by_height( + let ts = ctx.chain_index().load_required_tipset_by_height( height.at, anchor, height.resolve_null_tipset_policy(), @@ -1131,10 +1139,10 @@ impl RpcMethod<1> for ChainGetTipSetV2 { pub enum ChainGetTipSetFinalityStatus {} impl ChainGetTipSetFinalityStatus { - pub fn get_finality_status(ctx: &Ctx) -> ChainFinalityStatus { + pub fn get_finality_status(ctx: &Ctx) -> anyhow::Result { let head = ctx.chain_store().heaviest_tipset(); let (ec_finality_threshold_depth, ec_finalized_tip_set) = - Self::get_ec_finality_threshold_depth_and_tipset_with_cache(ctx, head.shallow_clone()); + Self::get_ec_finality_threshold_depth_and_tipset_with_cache(ctx, head.shallow_clone())?; let f3_finalized_tip_set = ctx.chain_store().f3_finalized_tipset(); let finalized_tip_set = match (&ec_finalized_tip_set, &f3_finalized_tip_set) { (Some(ec), Some(f3)) => { @@ -1148,38 +1156,38 @@ impl ChainGetTipSetFinalityStatus { (None, Some(f3)) => Some(f3.shallow_clone()), (None, None) => None, }; - ChainFinalityStatus { + Ok(ChainFinalityStatus { ec_finality_threshold_depth, ec_finalized_tip_set, f3_finalized_tip_set, finalized_tip_set, head, - } + }) } pub fn get_ec_finality_threshold_depth_and_tipset_with_cache( ctx: &Ctx, head: Tipset, - ) -> (i64, Option) { + ) -> anyhow::Result<(i64, Option)> { static CACHE: parking_lot::Mutex)>> = parking_lot::Mutex::new(None); let mut cache = CACHE.lock(); if let Some((cached_head, cached_threshold, cached_tipset)) = &*cache && cached_head == &head { - (*cached_threshold, cached_tipset.shallow_clone()) + Ok((*cached_threshold, cached_tipset.shallow_clone())) } else { let (threshold, tipset) = - Self::get_ec_finality_threshold_depth_and_tipset(ctx, head.shallow_clone()); + Self::get_ec_finality_threshold_depth_and_tipset(ctx, head.shallow_clone())?; *cache = Some((head, threshold, tipset.shallow_clone())); - (threshold, tipset) + Ok((threshold, tipset)) } } fn get_ec_finality_threshold_depth_and_tipset( ctx: &Ctx, head: Tipset, - ) -> (i64, Option) { + ) -> anyhow::Result<(i64, Option)> { use crate::chain::ec_finality::calculator::{ DEFAULT_BLOCKS_PER_EPOCH, DEFAULT_BYZANTINE_FRACTION, DEFAULT_GUARANTEE, find_threshold_depth, @@ -1231,7 +1239,7 @@ impl ChainGetTipSetFinalityStatus { } }; let finalized = if depth >= 0 - && let Ok(ts) = ctx.chain_index().tipset_by_height( + && let Ok(Some(ts)) = ctx.chain_index().tipset_by_height( (head.epoch() - depth).max(0), head.shallow_clone(), ResolveNullTipset::TakeOlder, @@ -1240,11 +1248,13 @@ impl ChainGetTipSetFinalityStatus { } else { let ec_finality_epoch = (head.epoch() - ctx.chain_config().policy.chain_finality).max(0); - ctx.chain_index() - .tipset_by_height(ec_finality_epoch, head, ResolveNullTipset::TakeOlder) - .ok() + ctx.chain_index().tipset_by_height( + ec_finality_epoch, + head, + ResolveNullTipset::TakeOlder, + )? }; - (depth, finalized) + Ok((depth, finalized)) } } @@ -1264,7 +1274,7 @@ impl RpcMethod<0> for ChainGetTipSetFinalityStatus { (): Self::Params, _: &http::Extensions, ) -> Result { - Ok(Self::get_finality_status(&ctx)) + Ok(Self::get_finality_status(&ctx)?) } } diff --git a/src/rpc/methods/eth.rs b/src/rpc/methods/eth.rs index b895184646d..2c5c6a71271 100644 --- a/src/rpc/methods/eth.rs +++ b/src/rpc/methods/eth.rs @@ -956,7 +956,7 @@ fn resolve_block_number_tipset( } Ok(chain .chain_index() - .tipset_by_height(height, head, resolve)?) + .load_required_tipset_by_height(height, head, resolve)?) } fn resolve_block_hash_tipset( @@ -969,10 +969,11 @@ fn resolve_block_hash_tipset( // verify that the tipset is in the canonical chain if require_canonical { // walk up the current chain (our head) until we reach ts.epoch() - let walk_ts = - chain - .chain_index() - .tipset_by_height(ts.epoch(), chain.heaviest_tipset(), resolve)?; + let walk_ts = chain.chain_index().load_required_tipset_by_height( + ts.epoch(), + chain.heaviest_tipset(), + resolve, + )?; // verify that it equals the expected tipset if walk_ts != ts { bail!("tipset is not canonical"); diff --git a/src/rpc/methods/eth/filter/mod.rs b/src/rpc/methods/eth/filter/mod.rs index 86a1737fea8..1940d8e212e 100644 --- a/src/rpc/methods/eth/filter/mod.rs +++ b/src/rpc/methods/eth/filter/mod.rs @@ -430,7 +430,7 @@ impl EthEventHandler { } else { *range.end() }; - let max_tipset = ctx.chain_index().tipset_by_height( + let max_tipset = ctx.chain_index().load_required_tipset_by_height( max_height, ctx.chain_store().heaviest_tipset(), ResolveNullTipset::TakeOlder, diff --git a/src/rpc/methods/eth/tipset_resolver.rs b/src/rpc/methods/eth/tipset_resolver.rs index acdbd595934..4a555e69332 100644 --- a/src/rpc/methods/eth/tipset_resolver.rs +++ b/src/rpc/methods/eth/tipset_resolver.rs @@ -3,6 +3,7 @@ use super::*; use crate::rpc::chain::{ChainGetTipSetFinalityStatus, SAFE_HEIGHT_DISTANCE}; +use anyhow::Context as _; pub struct TipsetResolver<'a, DB> where @@ -160,7 +161,7 @@ where pub fn get_ec_safe_tipset(&self) -> anyhow::Result { let head = self.ctx.chain_store().heaviest_tipset(); let safe_height = (head.epoch() - SAFE_HEIGHT_DISTANCE).max(0); - Ok(self.ctx.chain_index().tipset_by_height( + Ok(self.ctx.chain_index().load_required_tipset_by_height( safe_height, head, ResolveNullTipset::TakeOlder, @@ -174,7 +175,7 @@ where ChainGetTipSetFinalityStatus::get_ec_finality_threshold_depth_and_tipset_with_cache( self.ctx, head.clone(), - ); + )?; ec_finalized_tipset.context("failed to resolve EC finalized tipset") } } diff --git a/src/rpc/methods/f3.rs b/src/rpc/methods/f3.rs index 258884e2e37..ce29c7d6b66 100644 --- a/src/rpc/methods/f3.rs +++ b/src/rpc/methods/f3.rs @@ -95,7 +95,7 @@ impl RpcMethod<1> for GetTipsetByEpoch { (epoch,): Self::Params, _: &http::Extensions, ) -> Result { - let ts = ctx.chain_index().tipset_by_height( + let ts = ctx.chain_index().load_required_tipset_by_height( epoch, ctx.chain_store().heaviest_tipset(), ResolveNullTipset::TakeOlder, diff --git a/src/rpc/methods/state.rs b/src/rpc/methods/state.rs index 55feef3a786..52c8db8f38f 100644 --- a/src/rpc/methods/state.rs +++ b/src/rpc/methods/state.rs @@ -1567,7 +1567,7 @@ impl RpcMethod<3> for ForestStateCompute { let force_recompute = force_recompute.unwrap_or_default(); let n_epochs = n_epochs.map(|n| n.get()).unwrap_or(1) as ChainEpoch; let to_epoch = from_epoch + n_epochs - 1; - let to_ts = ctx.chain_index().tipset_by_height( + let to_ts = ctx.chain_index().load_required_tipset_by_height( to_epoch, ctx.chain_store().heaviest_tipset(), ResolveNullTipset::TakeOlder, @@ -1577,7 +1577,7 @@ impl RpcMethod<3> for ForestStateCompute { // `to_ts.epoch()` could be less than or equal to `from_epoch` to_ts.shallow_clone() } else { - ctx.chain_index().tipset_by_height( + ctx.chain_index().load_required_tipset_by_height( from_epoch, to_ts.shallow_clone(), ResolveNullTipset::TakeOlder, diff --git a/src/state_manager/chain_rand.rs b/src/state_manager/chain_rand.rs index 4f9b3f88848..e43ad94619e 100644 --- a/src/state_manager/chain_rand.rs +++ b/src/state_manager/chain_rand.rs @@ -60,9 +60,9 @@ where } else { ResolveNullTipset::TakeNewer }; - let rand_ts = self - .chain_index - .tipset_by_height(search_height, ts, resolve)?; + let rand_ts = + self.chain_index + .load_required_tipset_by_height(search_height, ts, resolve)?; Ok(digest( rand_ts @@ -150,7 +150,7 @@ where }; self.chain_index - .tipset_by_height(search_height, ts, resolve) + .load_required_tipset_by_height(search_height, ts, resolve) .map_err(|e| e.into()) } } diff --git a/src/state_manager/mod.rs b/src/state_manager/mod.rs index 57d8181cd8b..413f9b0a9eb 100644 --- a/src/state_manager/mod.rs +++ b/src/state_manager/mod.rs @@ -256,7 +256,7 @@ where let bundle_metadata = state.get_actor_bundle_metadata()?; if expected_bundle_metadata != bundle_metadata { let current_epoch = head.epoch(); - let target_head = self.chain_index().tipset_by_height( + let target_head = self.chain_index().load_required_tipset_by_height( (expected_height_info.epoch - 1).max(0), head, ResolveNullTipset::TakeOlder, @@ -454,13 +454,14 @@ where pub async fn load_tipset_state(self: &Arc, ts: &Tipset) -> anyhow::Result { if let Some(state) = self.cache.get_map(ts.key(), |et| et.into()) { Ok(state) - } else if let Ok(receipt_ts) = self.chain_store().load_child_tipset(ts) { - Ok(TipsetState { - state_root: *receipt_ts.parent_state(), - receipt_root: *receipt_ts.parent_message_receipts(), - }) } else { - Ok(self.load_executed_tipset(ts).await?.into()) + match self.chain_store().load_child_tipset(ts)? { + Some(receipt_ts) => Ok(TipsetState { + state_root: *receipt_ts.parent_state(), + receipt_root: *receipt_ts.parent_message_receipts(), + }), + None => Ok(self.load_executed_tipset(ts).await?.into()), + } } } @@ -481,7 +482,7 @@ where } self.cache .get_or_else(ts.key(), || async move { - let receipt_ts = self.chain_store().load_child_tipset(ts).ok(); + let receipt_ts = self.chain_store().load_child_tipset(ts)?; self.load_executed_tipset_inner(ts, receipt_ts.as_ref()) .await }) @@ -1686,15 +1687,15 @@ where pub fn validate_range(&self, epochs: RangeInclusive) -> anyhow::Result<()> { let heaviest = self.heaviest_tipset(); let heaviest_epoch = heaviest.epoch(); - let end = self - .chain_index() - .tipset_by_height(*epochs.end(), heaviest, ResolveNullTipset::TakeOlder) - .with_context(|| { - format!( - "couldn't get a tipset at height {} behind heaviest tipset at height {heaviest_epoch}", + let end = self.chain_index().load_required_tipset_by_height( *epochs.end(), - ) - })?; + heaviest, + ResolveNullTipset::TakeOlder, + ).with_context(|| { + format!( + "couldn't get a tipset at height {} behind heaviest tipset at height {heaviest_epoch}", + *epochs.end(), + )})?; // lookup tipset parents as we go along, iterating DOWN from `end` let tipsets = end diff --git a/src/tool/subcommands/archive_cmd.rs b/src/tool/subcommands/archive_cmd.rs index dca8f981e72..15d58d76e0e 100644 --- a/src/tool/subcommands/archive_cmd.rs +++ b/src/tool/subcommands/archive_cmd.rs @@ -581,12 +581,12 @@ pub async fn do_export( let index = ChainIndex::new(store.clone()); let ts = index - .tipset_by_height(epoch, ts, ResolveNullTipset::TakeOlder) + .load_required_tipset_by_height(epoch, ts, ResolveNullTipset::TakeOlder) .context("unable to get a tipset at given height")?; let seen = if let Some(diff) = diff { let diff_ts: Tipset = index - .tipset_by_height(diff, ts.shallow_clone(), ResolveNullTipset::TakeOlder) + .load_required_tipset_by_height(diff, ts.shallow_clone(), ResolveNullTipset::TakeOlder) .context("diff epoch must be smaller than target epoch")?; let diff_ts: &Tipset = &diff_ts; let diff_limit = diff_depth.map(|depth| diff_ts.epoch() - depth).unwrap_or(0); @@ -839,13 +839,13 @@ async fn show_tipset_diff( CurrentNetwork::set_global(Network::Testnet); } let beacon = Arc::new(chain_config.get_beacon_schedule(timestamp)); - let tipset = chain_index.tipset_by_height( + let tipset = chain_index.load_required_tipset_by_height( epoch, heaviest_tipset.clone(), ResolveNullTipset::TakeOlder, )?; - let child_tipset = chain_index.tipset_by_height( + let child_tipset = chain_index.load_required_tipset_by_height( epoch + 1, heaviest_tipset.clone(), ResolveNullTipset::TakeNewer, diff --git a/src/tool/subcommands/benchmark_cmd.rs b/src/tool/subcommands/benchmark_cmd.rs index 57bf6ed2624..6b3922807db 100644 --- a/src/tool/subcommands/benchmark_cmd.rs +++ b/src/tool/subcommands/benchmark_cmd.rs @@ -224,7 +224,7 @@ async fn benchmark_exporting( let store = Arc::new(open_store(input)?); let heaviest = store.heaviest_tipset()?; let idx = ChainIndex::new(store.clone()); - let ts = idx.tipset_by_height( + let ts = idx.load_required_tipset_by_height( epoch.unwrap_or(heaviest.epoch()), heaviest, ResolveNullTipset::TakeOlder, diff --git a/src/tool/subcommands/index_cmd.rs b/src/tool/subcommands/index_cmd.rs index 910e79b61ab..d1775f8cbfa 100644 --- a/src/tool/subcommands/index_cmd.rs +++ b/src/tool/subcommands/index_cmd.rs @@ -101,7 +101,7 @@ impl IndexCommands { // ensure from epoch is not greater than head epoch. This can happen if the // assumed head is actually a null tipset. let from = std::cmp::min(*from, head_ts.epoch()); - chain_store.chain_index().tipset_by_height( + chain_store.chain_index().load_required_tipset_by_height( from, head_ts, ResolveNullTipset::TakeOlder, diff --git a/src/tool/subcommands/snapshot_cmd.rs b/src/tool/subcommands/snapshot_cmd.rs index 8a0815f7917..628cc17ea19 100644 --- a/src/tool/subcommands/snapshot_cmd.rs +++ b/src/tool/subcommands/snapshot_cmd.rs @@ -482,7 +482,7 @@ fn print_computed_state(snapshot: PathBuf, epoch: ChainEpoch, json: bool) -> any } let beacon = Arc::new(chain_config.get_beacon_schedule(timestamp)); let tipset = chain_index - .tipset_by_height(epoch, ts, ResolveNullTipset::TakeOlder) + .load_required_tipset_by_height(epoch, ts, ResolveNullTipset::TakeOlder) .with_context(|| format!("couldn't get a tipset at height {epoch}"))?; let mut message_calls = vec![];