@@ -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+
148199pub enum ChainGetMessage { }
149200impl RpcMethod < 1 > for ChainGetMessage {
150201 const NAME : & ' static str = "Filecoin.ChainGetMessage" ;
0 commit comments