From 39a5b18d6f7c0558f19a631f02f0c7354cac5471 Mon Sep 17 00:00:00 2001 From: Viraj Bhartiya Date: Wed, 18 Dec 2024 11:22:41 +0530 Subject: [PATCH 1/8] feat(rpc): add StateMinerInitialPledgeForSector method --- src/rpc/methods/state.rs | 60 +++++++++++++++++++++++++++++++++ src/rpc/mod.rs | 1 + src/tool/subcommands/api_cmd.rs | 7 ++++ 3 files changed, 68 insertions(+) diff --git a/src/rpc/methods/state.rs b/src/rpc/methods/state.rs index 4631a5c5ba6..db1339bbcfc 100644 --- a/src/rpc/methods/state.rs +++ b/src/rpc/methods/state.rs @@ -2800,3 +2800,63 @@ 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 { + 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 initial_pledge: TokenAmount = reward_state + .initial_pledge_for_power( + §or_weight, + pledge_collateral, + power_smoothed, + &circ_supply.fil_circulating.into(), + power_state.ramp_start_epoch(), + power_state.ramp_duration_epochs(), + )? + .into(); + + let (value, _) = (initial_pledge * INITIAL_PLEDGE_NUM).div_rem(INITIAL_PLEDGE_DEN); + Ok(value) + } +} diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index cb1c9856f0e..c0d19e968c8 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 e709a86dad6..287d24816d9 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::_2KiB, + 1024, + tipset.key().into(), + ))?), RpcTest::identity(StateGetActor::request(( Address::SYSTEM_ACTOR, tipset.key().into(), From 18bf5881f7cafcc8c9500b03fcf090485bcd099e Mon Sep 17 00:00:00 2001 From: Viraj Bhartiya Date: Wed, 18 Dec 2024 11:32:19 +0530 Subject: [PATCH 2/8] update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0993c3420be..ddbf5e77798 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,9 @@ - [#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 From de69cfa7bd8fe1913b493edd696702040d276cfa Mon Sep 17 00:00:00 2001 From: Viraj Bhartiya Date: Wed, 18 Dec 2024 18:40:46 +0530 Subject: [PATCH 3/8] fix(rpc): validate sector duration and size in StateMinerInitialPledgeForSector method --- src/rpc/methods/state.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/rpc/methods/state.rs b/src/rpc/methods/state.rs index db1339bbcfc..fcc10f963a0 100644 --- a/src/rpc/methods/state.rs +++ b/src/rpc/methods/state.rs @@ -2821,6 +2821,27 @@ impl RpcMethod<4> for StateMinerInitialPledgeForSector { 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()); + } + let sec_size: u64 = match sector_size { + SectorSize::_2KiB => 2 * 1024, + SectorSize::_8MiB => 8 * 1024 * 1024, + SectorSize::_512MiB => 512 * 1024 * 1024, + SectorSize::_32GiB => 32 * 1024 * 1024 * 1024, + SectorSize::_64GiB => 64 * 1024 * 1024 * 1024, + }; + + if sec_size == 0 { + return Err(anyhow::anyhow!("sector size must be non-zero").into()); + } + + if sec_size < verified_size { + 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)?; From 6a9a4dd8f5a6966f59801aa35da7318262587df3 Mon Sep 17 00:00:00 2001 From: Viraj Bhartiya Date: Thu, 19 Dec 2024 00:51:14 +0530 Subject: [PATCH 4/8] refactor(rpc): extract sector size calculation into a separate function in StateMinerInitialPledgeForSector method --- src/rpc/methods/state.rs | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/rpc/methods/state.rs b/src/rpc/methods/state.rs index fcc10f963a0..731d6efa148 100644 --- a/src/rpc/methods/state.rs +++ b/src/rpc/methods/state.rs @@ -2801,8 +2801,17 @@ impl TryFrom<&ChainConfig> for ForkUpgradeParams { } } -pub enum StateMinerInitialPledgeForSector {} +fn sector_size_to_bytes(sector_size: SectorSize) -> u64 { + match sector_size { + SectorSize::_2KiB => 2 * 1024, + SectorSize::_8MiB => 8 * 1024 * 1024, + SectorSize::_512MiB => 512 * 1024 * 1024, + SectorSize::_32GiB => 32 * 1024 * 1024 * 1024, + SectorSize::_64GiB => 64 * 1024 * 1024 * 1024, + } +} +pub enum StateMinerInitialPledgeForSector {} impl RpcMethod<4> for StateMinerInitialPledgeForSector { const NAME: &'static str = "Filecoin.StateMinerInitialPledgeForSector"; const PARAM_NAMES: [&'static str; 4] = [ @@ -2824,19 +2833,13 @@ impl RpcMethod<4> for StateMinerInitialPledgeForSector { if sector_duration <= 0 { return Err(anyhow::anyhow!("sector duration must be greater than 0").into()); } - let sec_size: u64 = match sector_size { - SectorSize::_2KiB => 2 * 1024, - SectorSize::_8MiB => 8 * 1024 * 1024, - SectorSize::_512MiB => 512 * 1024 * 1024, - SectorSize::_32GiB => 32 * 1024 * 1024 * 1024, - SectorSize::_64GiB => 64 * 1024 * 1024 * 1024, - }; + let sec_size = sector_size_to_bytes(sector_size); if sec_size == 0 { return Err(anyhow::anyhow!("sector size must be non-zero").into()); } - if sec_size < verified_size { + if verified_size > sec_size { return Err( anyhow::anyhow!("verified deal size cannot be larger than sector size").into(), ); @@ -2847,6 +2850,8 @@ impl RpcMethod<4> for StateMinerInitialPledgeForSector { 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 ramp_start_epoch = power_state.ramp_start_epoch(); + let ramp_duration_epochs = power_state.ramp_duration_epochs(); let reward_state: reward::State = ctx.state_manager.get_actor_state(&ts)?; @@ -2872,8 +2877,8 @@ impl RpcMethod<4> for StateMinerInitialPledgeForSector { pledge_collateral, power_smoothed, &circ_supply.fil_circulating.into(), - power_state.ramp_start_epoch(), - power_state.ramp_duration_epochs(), + ramp_start_epoch, + ramp_duration_epochs, )? .into(); From e2badee35d3561f0e489cdb49480faa67f40adb7 Mon Sep 17 00:00:00 2001 From: Viraj Bhartiya Date: Thu, 19 Dec 2024 19:10:36 +0530 Subject: [PATCH 5/8] refactor(rpc): simplify sector size handling and extract pledge ramp parameters calculation in StateMinerInitialPledgeForSector method --- src/rpc/methods/state.rs | 44 ++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/rpc/methods/state.rs b/src/rpc/methods/state.rs index 731d6efa148..7f1488dce1f 100644 --- a/src/rpc/methods/state.rs +++ b/src/rpc/methods/state.rs @@ -2801,16 +2801,6 @@ impl TryFrom<&ChainConfig> for ForkUpgradeParams { } } -fn sector_size_to_bytes(sector_size: SectorSize) -> u64 { - match sector_size { - SectorSize::_2KiB => 2 * 1024, - SectorSize::_8MiB => 8 * 1024 * 1024, - SectorSize::_512MiB => 512 * 1024 * 1024, - SectorSize::_32GiB => 32 * 1024 * 1024 * 1024, - SectorSize::_64GiB => 64 * 1024 * 1024 * 1024, - } -} - pub enum StateMinerInitialPledgeForSector {} impl RpcMethod<4> for StateMinerInitialPledgeForSector { const NAME: &'static str = "Filecoin.StateMinerInitialPledgeForSector"; @@ -2834,10 +2824,7 @@ impl RpcMethod<4> for StateMinerInitialPledgeForSector { return Err(anyhow::anyhow!("sector duration must be greater than 0").into()); } - let sec_size = sector_size_to_bytes(sector_size); - if sec_size == 0 { - return Err(anyhow::anyhow!("sector size must be non-zero").into()); - } + let sec_size: u64 = sector_size as u64; if verified_size > sec_size { return Err( @@ -2847,11 +2834,11 @@ impl RpcMethod<4> for StateMinerInitialPledgeForSector { let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?; + let (epochs_since_start, duration) = get_pledge_ramp_params(&ctx, ts.epoch(), &ts).await?; + 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 ramp_start_epoch = power_state.ramp_start_epoch(); - let ramp_duration_epochs = power_state.ramp_duration_epochs(); let reward_state: reward::State = ctx.state_manager.get_actor_state(&ts)?; @@ -2877,8 +2864,8 @@ impl RpcMethod<4> for StateMinerInitialPledgeForSector { pledge_collateral, power_smoothed, &circ_supply.fil_circulating.into(), - ramp_start_epoch, - ramp_duration_epochs, + epochs_since_start, + duration, )? .into(); @@ -2886,3 +2873,24 @@ impl RpcMethod<4> for StateMinerInitialPledgeForSector { Ok(value) } } + +async fn get_pledge_ramp_params( + ctx: &Ctx, + height: ChainEpoch, + ts: &Tipset, +) -> Result<(i64, 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() + .map_err(|e| anyhow::anyhow!("loading power actor state: {e}"))?; + + if power_state.ramp_start_epoch() > 0 { + Ok(( + height - power_state.ramp_start_epoch(), + power_state.ramp_duration_epochs(), + )) + } else { + Ok((0, 0)) + } +} From e96215bfe0ab85f4648a47a7d96c27f295d9bd81 Mon Sep 17 00:00:00 2001 From: Viraj Bhartiya Date: Fri, 20 Dec 2024 17:51:45 +0530 Subject: [PATCH 6/8] refactor(rpc): simplify sector size handling and extract pledge ramp parameters calculation in StateMinerInitialPledgeForSector method --- src/rpc/methods/state.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/rpc/methods/state.rs b/src/rpc/methods/state.rs index 7f1488dce1f..8d748ed52de 100644 --- a/src/rpc/methods/state.rs +++ b/src/rpc/methods/state.rs @@ -2824,9 +2824,7 @@ impl RpcMethod<4> for StateMinerInitialPledgeForSector { return Err(anyhow::anyhow!("sector duration must be greater than 0").into()); } - let sec_size: u64 = sector_size as u64; - - if verified_size > sec_size { + if verified_size > sector_size as u64 { return Err( anyhow::anyhow!("verified deal size cannot be larger than sector size").into(), ); @@ -2834,8 +2832,6 @@ impl RpcMethod<4> for StateMinerInitialPledgeForSector { let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?; - let (epochs_since_start, duration) = get_pledge_ramp_params(&ctx, ts.epoch(), &ts).await?; - 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(); @@ -2858,6 +2854,8 @@ impl RpcMethod<4> for StateMinerInitialPledgeForSector { &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, @@ -2874,11 +2872,11 @@ impl RpcMethod<4> for StateMinerInitialPledgeForSector { } } -async fn get_pledge_ramp_params( +fn get_pledge_ramp_params( ctx: &Ctx, height: ChainEpoch, ts: &Tipset, -) -> Result<(i64, u64), anyhow::Error> { +) -> Result<(ChainEpoch, u64), anyhow::Error> { let state_tree = ctx.state_manager.get_state_tree(ts.parent_state())?; let power_state: power::State = state_tree @@ -2888,7 +2886,7 @@ async fn get_pledge_ramp_params( if power_state.ramp_start_epoch() > 0 { Ok(( height - power_state.ramp_start_epoch(), - power_state.ramp_duration_epochs(), + power_state.ramp_duration_epochs() as u64, )) } else { Ok((0, 0)) From 42b0ae57f577ca62ae516f988586c16033f9a527 Mon Sep 17 00:00:00 2001 From: Viraj Bhartiya Date: Fri, 20 Dec 2024 19:29:41 +0530 Subject: [PATCH 7/8] Refactor get_pledge_ramp_params function to fix ramp_duration_epochs type mismatch --- src/rpc/methods/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/methods/state.rs b/src/rpc/methods/state.rs index 8d748ed52de..8c0bda983e4 100644 --- a/src/rpc/methods/state.rs +++ b/src/rpc/methods/state.rs @@ -2886,7 +2886,7 @@ fn get_pledge_ramp_params( if power_state.ramp_start_epoch() > 0 { Ok(( height - power_state.ramp_start_epoch(), - power_state.ramp_duration_epochs() as u64, + power_state.ramp_duration_epochs(), )) } else { Ok((0, 0)) From b759e953934c4a981017a0afdd8e0d53421d9482 Mon Sep 17 00:00:00 2001 From: Viraj Bhartiya Date: Fri, 20 Dec 2024 20:24:12 +0530 Subject: [PATCH 8/8] fix lint error --- src/rpc/methods/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/methods/state.rs b/src/rpc/methods/state.rs index 8c0bda983e4..0cdc2358d42 100644 --- a/src/rpc/methods/state.rs +++ b/src/rpc/methods/state.rs @@ -2876,7 +2876,7 @@ fn get_pledge_ramp_params( ctx: &Ctx, height: ChainEpoch, ts: &Tipset, -) -> Result<(ChainEpoch, u64), anyhow::Error> { +) -> Result<(ChainEpoch, u64), anyhow::Error> { let state_tree = ctx.state_manager.get_state_tree(ts.parent_state())?; let power_state: power::State = state_tree