Skip to content

Commit 4661ae8

Browse files
authored
feat(api): implement the ChainGetFinalizedTipset API (#6133)
1 parent 2d24c11 commit 4661ae8

File tree

4 files changed

+60
-4
lines changed

4 files changed

+60
-4
lines changed

src/rpc/methods/chain.rs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,62 @@ impl RpcMethod<0> for ChainGetFinalizedTipset {
140140
type Params = ();
141141
type Ok = Tipset;
142142

143-
async fn handle(_ctx: Ctx<impl Blockstore>, (): Self::Params) -> Result<Self::Ok, ServerError> {
144-
Err(ServerError::stubbed_for_openrpc())
143+
async fn handle(
144+
ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
145+
(): Self::Params,
146+
) -> Result<Self::Ok, ServerError> {
147+
let head = ctx.chain_store().heaviest_tipset();
148+
let ec_finality_epoch = (head.epoch() - ctx.chain_config().policy.chain_finality).max(0);
149+
150+
// Either get the f3 finalized tipset or the ec finalized tipset
151+
match get_f3_finality_tipset(&ctx, ec_finality_epoch).await {
152+
Ok(f3_tipset) => {
153+
tracing::debug!("Using F3 finalized tipset at epoch {}", f3_tipset.epoch());
154+
Ok((*f3_tipset).clone())
155+
}
156+
Err(_) => {
157+
// fallback to ec finality
158+
tracing::warn!("F3 finalization unavailable, falling back to EC finality");
159+
let ec_tipset = ctx.chain_index().tipset_by_height(
160+
ec_finality_epoch,
161+
head,
162+
ResolveNullTipset::TakeOlder,
163+
)?;
164+
Ok((*ec_tipset).clone())
165+
}
166+
}
145167
}
146168
}
147169

170+
// get f3 finalized tipset based on ec finality epoch
171+
async fn get_f3_finality_tipset<DB: Blockstore + Sync + Send + 'static>(
172+
ctx: &Ctx<DB>,
173+
ec_finality_epoch: ChainEpoch,
174+
) -> Result<Arc<Tipset>> {
175+
let f3_finalized_cert = crate::rpc::f3::F3GetLatestCertificate::handle(ctx.clone(), ())
176+
.await
177+
.map_err(|e| anyhow::anyhow!("Failed to get F3 certificate: {}", e))?;
178+
179+
let f3_finalized_head = f3_finalized_cert.chain_head();
180+
if f3_finalized_head.epoch < ec_finality_epoch {
181+
return Err(anyhow::anyhow!(
182+
"F3 finalized tipset epoch {} is further back than EC finalized tipset epoch {}",
183+
f3_finalized_head.epoch,
184+
ec_finality_epoch
185+
));
186+
}
187+
188+
ctx.chain_index()
189+
.load_required_tipset(&f3_finalized_head.key)
190+
.map_err(|e| {
191+
anyhow::anyhow!(
192+
"Failed to load F3 finalized tipset at epoch {}: {}",
193+
f3_finalized_head.epoch,
194+
e
195+
)
196+
})
197+
}
198+
148199
pub enum ChainGetMessage {}
149200
impl RpcMethod<1> for ChainGetMessage {
150201
const NAME: &'static str = "Filecoin.ChainGetMessage";

src/rpc/methods/f3.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,10 @@ impl RpcMethod<0> for F3GetLatestCertificate {
698698
type Params = ();
699699
type Ok = FinalityCertificate;
700700

701-
async fn handle(_: Ctx<impl Blockstore>, _: Self::Params) -> Result<Self::Ok, ServerError> {
701+
async fn handle(
702+
_: Ctx<impl Blockstore + Send + Sync + 'static>,
703+
_: Self::Params,
704+
) -> Result<Self::Ok, ServerError> {
702705
let client = get_rpc_http_client()?;
703706
let response: LotusJson<Self::Ok> = client.request(Self::NAME, ArrayParams::new()).await?;
704707
Ok(response.into_inner())
@@ -948,7 +951,7 @@ pub fn get_f3_rpc_endpoint() -> Cow<'static, str> {
948951
}
949952
}
950953

951-
fn get_rpc_http_client() -> anyhow::Result<jsonrpsee::http_client::HttpClient> {
954+
pub fn get_rpc_http_client() -> anyhow::Result<jsonrpsee::http_client::HttpClient> {
952955
let client = jsonrpsee::http_client::HttpClientBuilder::new()
953956
.build(format!("http://{}", get_f3_rpc_endpoint()))?;
954957
Ok(client)

src/tool/subcommands/api_cmd/api_compare_tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ fn chain_tests_with_tipset<DB: Blockstore>(
453453
.clone()
454454
.into(),))?),
455455
RpcTest::identity(ChainTipSetWeight::request((tipset.key().into(),))?),
456+
RpcTest::basic(ChainGetFinalizedTipset::request(())?),
456457
];
457458

458459
for block in tipset.block_headers() {

src/tool/subcommands/api_cmd/test_snapshots.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ filecoin_chaingetevents_1746450533519970.rpcsnap.json.zst
55
filecoin_chaingetevents_1746450533600537.rpcsnap.json.zst
66
filecoin_chaingetevents_1746450551991052.rpcsnap.json.zst
77
filecoin_chaingetevents_1750327595269729.rpcsnap.json.zst
8+
filecoin_chaingetfinalizedtipset_1759828121342574.rpcsnap.json.zst
89
filecoin_chaingetgenesis_1736937286915866.rpcsnap.json.zst
910
filecoin_chaingetmessage_1741270616352800.rpcsnap.json.zst
1011
filecoin_chaingetmessagesintipset_1741270616353560.rpcsnap.json.zst

0 commit comments

Comments
 (0)