Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
55 changes: 53 additions & 2 deletions src/rpc/methods/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,62 @@ impl RpcMethod<0> for ChainGetFinalizedTipset {
type Params = ();
type Ok = Tipset;

async fn handle(_ctx: Ctx<impl Blockstore>, (): Self::Params) -> Result<Self::Ok, ServerError> {
Err(ServerError::stubbed_for_openrpc())
async fn handle(
ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
(): Self::Params,
) -> Result<Self::Ok, ServerError> {
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())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we avoid cloning here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so f3_tipset wrapped in Arc so we will have to clone only.

}
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<DB: Blockstore + Sync + Send + 'static>(
ctx: &Ctx<DB>,
ec_finality_epoch: ChainEpoch,
) -> Result<Arc<Tipset>> {
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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f3_finalized_cert.chain_head() could be newer than chain head during catchup. Lotus does not seem to handle that case, should we handle it? e.g. marking finalized tipset in F3.Finalize RPC method instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could track this in a separate issue, for now the logic matches Lotus

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";
Expand Down
7 changes: 5 additions & 2 deletions src/rpc/methods/f3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,10 @@ impl RpcMethod<0> for F3GetLatestCertificate {
type Params = ();
type Ok = FinalityCertificate;

async fn handle(_: Ctx<impl Blockstore>, _: Self::Params) -> Result<Self::Ok, ServerError> {
async fn handle(
_: Ctx<impl Blockstore + Send + Sync + 'static>,
_: Self::Params,
) -> Result<Self::Ok, ServerError> {
let client = get_rpc_http_client()?;
let response: LotusJson<Self::Ok> = client.request(Self::NAME, ArrayParams::new()).await?;
Ok(response.into_inner())
Expand Down Expand Up @@ -948,7 +951,7 @@ pub fn get_f3_rpc_endpoint() -> Cow<'static, str> {
}
}

fn get_rpc_http_client() -> anyhow::Result<jsonrpsee::http_client::HttpClient> {
pub fn get_rpc_http_client() -> anyhow::Result<jsonrpsee::http_client::HttpClient> {
let client = jsonrpsee::http_client::HttpClientBuilder::new()
.build(format!("http://{}", get_f3_rpc_endpoint()))?;
Ok(client)
Expand Down
1 change: 1 addition & 0 deletions src/tool/subcommands/api_cmd/api_compare_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ fn chain_tests_with_tipset<DB: Blockstore>(
.clone()
.into(),))?),
RpcTest::identity(ChainTipSetWeight::request((tipset.key().into(),))?),
RpcTest::basic(ChainGetFinalizedTipset::request(())?),
];

for block in tipset.block_headers() {
Expand Down
1 change: 1 addition & 0 deletions src/tool/subcommands/api_cmd/test_snapshots.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading