diff --git a/src/rpc/methods/chain.rs b/src/rpc/methods/chain.rs index b24d249c097..6d044996e53 100644 --- a/src/rpc/methods/chain.rs +++ b/src/rpc/methods/chain.rs @@ -140,11 +140,62 @@ impl RpcMethod<0> for ChainGetFinalizedTipset { type Params = (); type Ok = Tipset; - async fn handle(_ctx: Ctx, (): Self::Params) -> Result { - Err(ServerError::stubbed_for_openrpc()) + async fn handle( + ctx: Ctx, + (): Self::Params, + ) -> Result { + let head = ctx.chain_store().heaviest_tipset(); + let ec_finality_epoch = (head.epoch() - ctx.chain_config().policy.chain_finality).max(0); + + // Either get the f3 finalized tipset or the ec finalized tipset + match get_f3_finality_tipset(&ctx, ec_finality_epoch).await { + Ok(f3_tipset) => { + tracing::debug!("Using F3 finalized tipset at epoch {}", f3_tipset.epoch()); + Ok((*f3_tipset).clone()) + } + Err(_) => { + // fallback to ec finality + tracing::warn!("F3 finalization unavailable, falling back to EC finality"); + let ec_tipset = ctx.chain_index().tipset_by_height( + ec_finality_epoch, + head, + ResolveNullTipset::TakeOlder, + )?; + Ok((*ec_tipset).clone()) + } + } } } +// get f3 finalized tipset based on ec finality epoch +async fn get_f3_finality_tipset( + ctx: &Ctx, + ec_finality_epoch: ChainEpoch, +) -> Result> { + let f3_finalized_cert = crate::rpc::f3::F3GetLatestCertificate::handle(ctx.clone(), ()) + .await + .map_err(|e| anyhow::anyhow!("Failed to get F3 certificate: {}", e))?; + + let f3_finalized_head = f3_finalized_cert.chain_head(); + if f3_finalized_head.epoch < ec_finality_epoch { + return Err(anyhow::anyhow!( + "F3 finalized tipset epoch {} is further back than EC finalized tipset epoch {}", + f3_finalized_head.epoch, + ec_finality_epoch + )); + } + + ctx.chain_index() + .load_required_tipset(&f3_finalized_head.key) + .map_err(|e| { + anyhow::anyhow!( + "Failed to load F3 finalized tipset at epoch {}: {}", + f3_finalized_head.epoch, + e + ) + }) +} + pub enum ChainGetMessage {} impl RpcMethod<1> for ChainGetMessage { const NAME: &'static str = "Filecoin.ChainGetMessage"; diff --git a/src/rpc/methods/f3.rs b/src/rpc/methods/f3.rs index 73c0819ad20..dedae257c2f 100644 --- a/src/rpc/methods/f3.rs +++ b/src/rpc/methods/f3.rs @@ -698,7 +698,10 @@ impl RpcMethod<0> for F3GetLatestCertificate { type Params = (); type Ok = FinalityCertificate; - async fn handle(_: Ctx, _: Self::Params) -> Result { + async fn handle( + _: Ctx, + _: Self::Params, + ) -> Result { let client = get_rpc_http_client()?; let response: LotusJson = client.request(Self::NAME, ArrayParams::new()).await?; Ok(response.into_inner()) @@ -948,7 +951,7 @@ pub fn get_f3_rpc_endpoint() -> Cow<'static, str> { } } -fn get_rpc_http_client() -> anyhow::Result { +pub fn get_rpc_http_client() -> anyhow::Result { let client = jsonrpsee::http_client::HttpClientBuilder::new() .build(format!("http://{}", get_f3_rpc_endpoint()))?; Ok(client) diff --git a/src/tool/subcommands/api_cmd/api_compare_tests.rs b/src/tool/subcommands/api_cmd/api_compare_tests.rs index 3e9e99d1965..68bdaca61bf 100644 --- a/src/tool/subcommands/api_cmd/api_compare_tests.rs +++ b/src/tool/subcommands/api_cmd/api_compare_tests.rs @@ -453,6 +453,7 @@ fn chain_tests_with_tipset( .clone() .into(),))?), RpcTest::identity(ChainTipSetWeight::request((tipset.key().into(),))?), + RpcTest::basic(ChainGetFinalizedTipset::request(())?), ]; for block in tipset.block_headers() { diff --git a/src/tool/subcommands/api_cmd/test_snapshots.txt b/src/tool/subcommands/api_cmd/test_snapshots.txt index a55294d4789..77af9fa1d1a 100644 --- a/src/tool/subcommands/api_cmd/test_snapshots.txt +++ b/src/tool/subcommands/api_cmd/test_snapshots.txt @@ -5,6 +5,7 @@ filecoin_chaingetevents_1746450533519970.rpcsnap.json.zst filecoin_chaingetevents_1746450533600537.rpcsnap.json.zst filecoin_chaingetevents_1746450551991052.rpcsnap.json.zst filecoin_chaingetevents_1750327595269729.rpcsnap.json.zst +filecoin_chaingetfinalizedtipset_1759828121342574.rpcsnap.json.zst filecoin_chaingetgenesis_1736937286915866.rpcsnap.json.zst filecoin_chaingetmessage_1741270616352800.rpcsnap.json.zst filecoin_chaingetmessagesintipset_1741270616353560.rpcsnap.json.zst