diff --git a/src/rpc/mod.rs b/src/rpc/mod.rs index cfa21954975..902bde565e1 100644 --- a/src/rpc/mod.rs +++ b/src/rpc/mod.rs @@ -254,6 +254,10 @@ where module.register_async_method(STATE_MINER_SECTOR_COUNT, state_miner_sector_count::)?; module.register_async_method(STATE_MINER_FAULTS, state_miner_faults::)?; module.register_async_method(STATE_MINER_RECOVERIES, state_miner_recoveries::)?; + module.register_async_method( + STATE_MINER_AVAILABLE_BALANCE, + state_miner_available_balance::, + )?; module.register_async_method(STATE_MINER_POWER, state_miner_power::)?; module.register_async_method(STATE_MINER_DEADLINES, state_miner_deadlines::)?; module.register_async_method(STATE_LIST_MESSAGES, state_list_messages::)?; diff --git a/src/rpc/state_api.rs b/src/rpc/state_api.rs index c02a8cd6b93..9fc4f049aae 100644 --- a/src/rpc/state_api.rs +++ b/src/rpc/state_api.rs @@ -416,6 +416,54 @@ pub async fn state_miner_recoveries( .map(|r| r.into()) } +pub async fn state_miner_available_balance( + params: Params<'_>, + data: Data>, +) -> Result, JsonRpcError> { + let LotusJson((miner_address, ApiTipsetKey(tsk))): LotusJson<(Address, ApiTipsetKey)> = + params.parse()?; + + let store = data.chain_store.blockstore(); + let ts = data + .state_manager + .chain_store() + .load_required_tipset_or_heaviest(&tsk)?; + let actor = data + .state_manager + .get_actor(&miner_address, *ts.parent_state())? + .ok_or_else(|| anyhow::anyhow!("Miner actor not found"))?; + let state = miner::State::load(store, actor.code, actor.state)?; + let actor_balance: TokenAmount = actor.balance.clone().into(); + let (vested, available): (TokenAmount, TokenAmount) = match &state { + miner::State::V13(s) => ( + s.check_vested_funds(store, ts.epoch())?.into(), + s.get_available_balance(&actor_balance.into())?.into(), + ), + miner::State::V12(s) => ( + s.check_vested_funds(store, ts.epoch())?.into(), + s.get_available_balance(&actor_balance.into())?.into(), + ), + miner::State::V11(s) => ( + s.check_vested_funds(store, ts.epoch())?.into(), + s.get_available_balance(&actor_balance.into())?.into(), + ), + miner::State::V10(s) => ( + s.check_vested_funds(store, ts.epoch())?.into(), + s.get_available_balance(&actor_balance.into())?.into(), + ), + miner::State::V9(s) => ( + s.check_vested_funds(store, ts.epoch())?.into(), + s.get_available_balance(&actor_balance.into())?.into(), + ), + miner::State::V8(s) => ( + s.check_vested_funds(store, ts.epoch())?.into(), + s.get_available_balance(&actor_balance.into())?.into(), + ), + }; + + Ok(LotusJson(vested + available)) +} + /// returns the message receipt for the given message pub async fn state_get_receipt( params: Params<'_>, diff --git a/src/rpc_api/mod.rs b/src/rpc_api/mod.rs index 9b44a996d9e..b8111843646 100644 --- a/src/rpc_api/mod.rs +++ b/src/rpc_api/mod.rs @@ -96,6 +96,7 @@ pub static ACCESS_MAP: Lazy> = Lazy::new(|| { access.insert(state_api::STATE_MINER_POWER, Access::Read); access.insert(state_api::STATE_MINER_DEADLINES, Access::Read); access.insert(state_api::STATE_MINER_PROVING_DEADLINE, Access::Read); + access.insert(state_api::STATE_MINER_AVAILABLE_BALANCE, Access::Read); access.insert(state_api::STATE_GET_RECEIPT, Access::Read); access.insert(state_api::STATE_WAIT_MSG, Access::Read); access.insert(state_api::STATE_SEARCH_MSG, Access::Read); @@ -378,6 +379,7 @@ pub mod state_api { pub const STATE_MINER_POWER: &str = "Filecoin.StateMinerPower"; pub const STATE_MINER_DEADLINES: &str = "Filecoin.StateMinerDeadlines"; pub const STATE_MINER_PROVING_DEADLINE: &str = "Filecoin.StateMinerProvingDeadline"; + pub const STATE_MINER_AVAILABLE_BALANCE: &str = "Filecoin.StateMinerAvailableBalance"; pub const STATE_GET_RECEIPT: &str = "Filecoin.StateGetReceipt"; pub const STATE_WAIT_MSG: &str = "Filecoin.StateWaitMsg"; pub const STATE_FETCH_ROOT: &str = "Filecoin.StateFetchRoot"; diff --git a/src/rpc_client/state_ops.rs b/src/rpc_client/state_ops.rs index 9464f083613..663c670ab8d 100644 --- a/src/rpc_client/state_ops.rs +++ b/src/rpc_client/state_ops.rs @@ -99,6 +99,13 @@ impl ApiInfo { RpcRequest::new(STATE_MINER_PROVING_DEADLINE, (miner, tsk)) } + pub fn state_miner_available_balance_req( + miner: Address, + tsk: ApiTipsetKey, + ) -> RpcRequest { + RpcRequest::new(STATE_MINER_AVAILABLE_BALANCE, (miner, tsk)) + } + pub fn state_get_randomness_from_tickets_req( tsk: ApiTipsetKey, personalization: DomainSeparationTag, diff --git a/src/tool/subcommands/api_cmd.rs b/src/tool/subcommands/api_cmd.rs index 267336b3df1..9238381b24f 100644 --- a/src/tool/subcommands/api_cmd.rs +++ b/src/tool/subcommands/api_cmd.rs @@ -708,6 +708,12 @@ fn snapshot_tests(store: &ManyCar, n_tipsets: usize) -> anyhow::Result