From 2985fd4f704d0bbf95972b285ee41833209293c5 Mon Sep 17 00:00:00 2001 From: Viraj Bhartiya Date: Wed, 8 Jan 2025 17:25:12 +0530 Subject: [PATCH] feat(rpc): add StateMinerInitialPledgeForSector method (#5096) --- CHANGELOG.md | 3 ++ src/rpc/methods/state.rs | 91 +++++++++++++++++++++++++++++++++ src/rpc/mod.rs | 1 + src/tool/subcommands/api_cmd.rs | 7 +++ 4 files changed, 102 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index db0e5603224..32b4797e5ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,9 @@ Mandatory release for calibnet node operators. It fixes a sync error at epoch 22 - [#5020](https://github.com/ChainSafe/forest/issues/5020) Add support for the `Filecoin.EthGetTransactionByBlockNumberAndIndex` RPC method. +- [#4907](https://github.com/ChainSafe/forest/issues/4907) Add support for the + `Filecoin.StateMinerInitialPledgeForSector` RPC method. + ### Changed ### Removed diff --git a/src/rpc/methods/state.rs b/src/rpc/methods/state.rs index 59c7fd7a2e7..9bb42d3b929 100644 --- a/src/rpc/methods/state.rs +++ b/src/rpc/methods/state.rs @@ -2800,3 +2800,94 @@ impl TryFrom<&ChainConfig> for ForkUpgradeParams { }) } } + +pub enum StateMinerInitialPledgeForSector {} +impl RpcMethod<4> for StateMinerInitialPledgeForSector { + const NAME: &'static str = "Filecoin.StateMinerInitialPledgeForSector"; + const PARAM_NAMES: [&'static str; 4] = [ + "sector_duration", + "sector_size", + "verified_size", + "tipset_key", + ]; + const API_PATHS: ApiPaths = ApiPaths::V1; + const PERMISSION: Permission = Permission::Read; + + type Params = (ChainEpoch, SectorSize, u64, ApiTipsetKey); + type Ok = TokenAmount; + + async fn handle( + ctx: Ctx, + (sector_duration, sector_size, verified_size, ApiTipsetKey(tsk)): Self::Params, + ) -> Result { + if sector_duration <= 0 { + return Err(anyhow::anyhow!("sector duration must be greater than 0").into()); + } + if verified_size > sector_size as u64 { + return Err( + anyhow::anyhow!("verified deal size cannot be larger than sector size").into(), + ); + } + + let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?; + + let power_state: power::State = ctx.state_manager.get_actor_state(&ts)?; + let power_smoothed = power_state.total_power_smoothed(); + let pledge_collateral = power_state.total_locked(); + + let reward_state: reward::State = ctx.state_manager.get_actor_state(&ts)?; + + let genesis_info = GenesisInfo::from_chain_config(ctx.chain_config().clone()); + let circ_supply = genesis_info.get_vm_circulating_supply_detailed( + ts.epoch(), + &ctx.store_owned(), + ts.parent_state(), + )?; + + let deal_weight = BigInt::from(0); + let verified_deal_weight = BigInt::from(verified_size) * sector_duration; + let sector_weight = qa_power_for_weight( + sector_size.into(), + sector_duration, + &deal_weight, + &verified_deal_weight, + ); + + let (epochs_since_start, duration) = get_pledge_ramp_params(&ctx, ts.epoch(), &ts)?; + + let initial_pledge: TokenAmount = reward_state + .initial_pledge_for_power( + §or_weight, + pledge_collateral, + power_smoothed, + &circ_supply.fil_circulating.into(), + epochs_since_start, + duration, + )? + .into(); + + let (value, _) = (initial_pledge * INITIAL_PLEDGE_NUM).div_rem(INITIAL_PLEDGE_DEN); + Ok(value) + } +} + +fn get_pledge_ramp_params( + ctx: &Ctx, + height: ChainEpoch, + ts: &Tipset, +) -> Result<(ChainEpoch, u64), anyhow::Error> { + let state_tree = ctx.state_manager.get_state_tree(ts.parent_state())?; + + let power_state: power::State = state_tree + .get_actor_state() + .context("loading power actor state")?; + + if power_state.ramp_start_epoch() > 0 { + Ok(( + height - power_state.ramp_start_epoch(), + power_state.ramp_duration_epochs(), + )) + } else { + Ok((0, 0)) + } +} diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index 48b21bd9a3c..5536113e6c7 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -217,6 +217,7 @@ macro_rules! for_each_method { $callback!(crate::rpc::state::StateVMCirculatingSupplyInternal); $callback!(crate::rpc::state::StateWaitMsg); $callback!(crate::rpc::state::StateWaitMsgV0); + $callback!(crate::rpc::state::StateMinerInitialPledgeForSector); // sync vertical $callback!(crate::rpc::sync::SyncCheckBad); diff --git a/src/tool/subcommands/api_cmd.rs b/src/tool/subcommands/api_cmd.rs index 501dca7b9e6..4f110366945 100644 --- a/src/tool/subcommands/api_cmd.rs +++ b/src/tool/subcommands/api_cmd.rs @@ -20,6 +20,7 @@ use crate::rpc::types::{ApiTipsetKey, MessageFilter, MessageLookup}; use crate::rpc::{prelude::*, Permission}; use crate::shim::actors::market; use crate::shim::actors::MarketActorStateLoad as _; +use crate::shim::sector::SectorSize; use crate::shim::{ address::{Address, Protocol}, crypto::Signature, @@ -810,6 +811,12 @@ fn state_tests_with_tipset( let mut tests = vec![ RpcTest::identity(StateNetworkName::request(())?), RpcTest::identity(StateGetNetworkParams::request(())?), + RpcTest::identity(StateMinerInitialPledgeForSector::request(( + 1, + SectorSize::_32GiB, + 1024, + tipset.key().into(), + ))?), RpcTest::identity(StateGetActor::request(( Address::SYSTEM_ACTOR, tipset.key().into(),