Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Miner actor: Add exported getters for info and monies #811

Merged
merged 8 commits into from
Nov 8, 2022
92 changes: 92 additions & 0 deletions actors/miner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use fvm_shared::reward::ThisEpochRewardReturn;
use fvm_shared::sector::*;
use fvm_shared::smooth::FilterEstimate;
use fvm_shared::{MethodNum, METHOD_CONSTRUCTOR, METHOD_SEND};
use itertools::Itertools;
use log::{error, info, warn};
use multihash::Code::Blake2b256;
use num_derive::FromPrimitive;
Expand Down Expand Up @@ -126,6 +127,11 @@ pub enum Method {
// Method numbers derived from FRC-XXXX standards
ChangeBenificiaryExported = frc42_dispatch::method_hash!("ChangeBeneficiary"),
GetBeneficiaryExported = frc42_dispatch::method_hash!("GetBeneficiary"),
GetOwnerExported = frc42_dispatch::method_hash!("GetOwner"),
IsControllingAddressExported = frc42_dispatch::method_hash!("IsControllingAddress"),
GetSectorSizeExported = frc42_dispatch::method_hash!("GetSectorSize"),
GetAvailableBalanceExported = frc42_dispatch::method_hash!("GetAvailableBalance"),
GetVestingFundsExported = frc42_dispatch::method_hash!("GetVestingFunds"),
}

pub const ERR_BALANCE_INVARIANTS_BROKEN: ExitCode = ExitCode::new(1000);
Expand Down Expand Up @@ -205,6 +211,7 @@ impl Actor {
Ok(())
}

/// Returns the "controlling" addresses: the owner, the worker, and all control addresses
fn control_addresses(rt: &mut impl Runtime) -> Result<GetControlAddressesReturn, ActorError> {
rt.validate_immediate_caller_accept_any()?;
let state: State = rt.state()?;
Expand All @@ -216,6 +223,71 @@ impl Actor {
})
}

/// Returns the owner address
fn get_owner(rt: &mut impl Runtime) -> Result<GetOwnerReturn, ActorError> {
rt.validate_immediate_caller_accept_any()?;
let state: State = rt.state()?;
let owner = get_miner_info(rt.store(), &state)?.owner;
Ok(GetOwnerReturn { owner })
}

/// Returns whether the provided address is "controlling".
/// The "controlling" addresses are the Owner, the Worker, and all Control Addresses.
fn is_controlling_address(
rt: &mut impl Runtime,
params: IsControllingAddressParam,
) -> Result<IsControllingAddressReturn, ActorError> {
rt.validate_immediate_caller_accept_any()?;
let input = match rt.resolve_address(&params.address) {
Some(a) => Address::new_id(a),
None => return Ok(IsControllingAddressReturn { is_controlling: false }),
};
let state: State = rt.state()?;
Copy link
Member

Choose a reason for hiding this comment

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

Resolve the parameter address to an ID address, as all the ones in state are.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could also just use ActorID here? There's no meaningful invocation of this with an unresolved address?

let info = get_miner_info(rt.store(), &state)?;
let is_controlling = info
.control_addresses
.iter()
.chain(&[info.worker, info.owner])
.into_iter()
.any(|a| *a == input);

Ok(IsControllingAddressReturn { is_controlling })
}

/// Returns the miner's sector size
fn get_sector_size(rt: &mut impl Runtime) -> Result<GetSectorSizeReturn, ActorError> {
rt.validate_immediate_caller_accept_any()?;
let state: State = rt.state()?;
let sector_size = get_miner_info(rt.store(), &state)?.sector_size;
Ok(GetSectorSizeReturn { sector_size })
}

/// Returns the available balance of this miner.
/// This is calculated as actor balance - (vesting funds + pre-commit deposit + ip requirement + fee debt)
/// Can go negative if the miner is in IP debt.
fn get_available_balance(
rt: &mut impl Runtime,
) -> Result<GetAvailableBalanceReturn, ActorError> {
rt.validate_immediate_caller_accept_any()?;
let state: State = rt.state()?;
let available_balance =
state.get_available_balance(&rt.current_balance()).map_err(|e| {
actor_error!(illegal_state, "failed to calculate available balance: {}", e)
})?;
Ok(GetAvailableBalanceReturn { available_balance })
}

/// Returns the funds vesting in this miner as a list of (vesting_epoch, vesting_amount) tuples.
fn get_vesting_funds(rt: &mut impl Runtime) -> Result<GetVestingFundsReturn, ActorError> {
rt.validate_immediate_caller_accept_any()?;
let state: State = rt.state()?;
let vesting_funds = state
.load_vesting_funds(rt.store())
.map_err(|e| actor_error!(illegal_state, "failed to load vesting funds: {}", e))?;
let ret = vesting_funds.funds.into_iter().map(|v| (v.epoch, v.amount)).collect_vec();
Ok(GetVestingFundsReturn { vesting_funds: ret })
}

/// Will ALWAYS overwrite the existing control addresses with the control addresses passed in the params.
/// If an empty addresses vector is passed, the control addresses will be cleared.
/// A worker change will be scheduled if the worker passed in the params is different from the existing worker.
Expand Down Expand Up @@ -5001,6 +5073,26 @@ impl ActorCode for Actor {
Ok(RawBytes::default())
}
None => Err(actor_error!(unhandled_message, "Invalid method")),
Some(Method::GetOwnerExported) => {
let res = Self::get_owner(rt)?;
Ok(RawBytes::serialize(res)?)
}
Some(Method::IsControllingAddressExported) => {
let res = Self::is_controlling_address(rt, cbor::deserialize_params(params)?)?;
Ok(RawBytes::serialize(res)?)
}
Some(Method::GetSectorSizeExported) => {
let res = Self::get_sector_size(rt)?;
Ok(RawBytes::serialize(res)?)
}
Some(Method::GetAvailableBalanceExported) => {
let res = Self::get_available_balance(rt)?;
Ok(RawBytes::serialize(res)?)
}
Some(Method::GetVestingFundsExported) => {
let res = Self::get_vesting_funds(rt)?;
Ok(RawBytes::serialize(res)?)
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion actors/miner/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,7 @@ impl State {
&self,
actor_balance: &TokenAmount,
) -> anyhow::Result<TokenAmount> {
// (actor_balance - &self.locked_funds) - &self.pre_commit_deposit
// (actor_balance - &self.locked_funds) - &self.pre_commit_deposit - &self.initial_pledge
Ok(self.get_unlocked_balance(actor_balance)? - &self.fee_debt)
}

Expand Down
49 changes: 48 additions & 1 deletion actors/miner/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use fvm_shared::econ::TokenAmount;
use fvm_shared::randomness::Randomness;
use fvm_shared::sector::{
PoStProof, RegisteredPoStProof, RegisteredSealProof, RegisteredUpdateProof, SectorNumber,
StoragePower,
SectorSize, StoragePower,
};
use fvm_shared::smooth::FilterEstimate;

Expand Down Expand Up @@ -482,3 +482,50 @@ pub struct GetBeneficiaryReturn {
}

impl Cbor for GetBeneficiaryReturn {}

#[derive(Serialize_tuple, Deserialize_tuple)]
#[serde(transparent)]
pub struct GetOwnerReturn {
pub owner: Address,
}

impl Cbor for GetOwnerReturn {}

#[derive(Serialize_tuple, Deserialize_tuple)]
#[serde(transparent)]
pub struct IsControllingAddressParam {
pub address: Address,
}

impl Cbor for IsControllingAddressParam {}

#[derive(Serialize_tuple, Deserialize_tuple)]
#[serde(transparent)]
pub struct IsControllingAddressReturn {
pub is_controlling: bool,
}

impl Cbor for IsControllingAddressReturn {}

#[derive(Serialize_tuple, Deserialize_tuple)]
#[serde(transparent)]
pub struct GetSectorSizeReturn {
pub sector_size: SectorSize,
}

impl Cbor for GetSectorSizeReturn {}

#[derive(Serialize_tuple, Deserialize_tuple)]
#[serde(transparent)]
pub struct GetAvailableBalanceReturn {
pub available_balance: TokenAmount,
}

impl Cbor for GetAvailableBalanceReturn {}

#[derive(Serialize_tuple, Deserialize_tuple)]
pub struct GetVestingFundsReturn {
pub vesting_funds: Vec<(ChainEpoch, TokenAmount)>,
}

impl Cbor for GetVestingFundsReturn {}
15 changes: 7 additions & 8 deletions actors/miner/tests/apply_rewards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use fvm_shared::error::ExitCode;
use fvm_shared::METHOD_SEND;

mod util;

use fil_actor_miner::testing::check_state_invariants;
use util::*;

Expand Down Expand Up @@ -165,11 +166,12 @@ fn rewards_pay_back_fee_debt() {
assert!(st.locked_funds.is_zero());

let amt = rt.get_balance();
let available_before = st.get_available_balance(&amt).unwrap();
let available_before = h.get_available_balance(&mut rt).unwrap();
assert!(available_before.is_positive());
let init_fee_debt: TokenAmount = 2 * &amt; // FeeDebt twice total balance
st.fee_debt = init_fee_debt.clone();
let available_after = st.get_available_balance(&amt).unwrap();
rt.replace_state(&st);
let available_after = h.get_available_balance(&mut rt).unwrap();
assert!(available_after.is_negative());

rt.replace_state(&st);
Expand All @@ -178,7 +180,7 @@ fn rewards_pay_back_fee_debt() {
let penalty = TokenAmount::zero();
// manually update actor balance to include the added funds from outside
let new_balance = &amt + &reward;
rt.set_balance(new_balance.clone());
rt.set_balance(new_balance);

// pledge change is new reward - reward taken for fee debt
// 3*LockedRewardFactor*amt - 2*amt = remainingLocked
Expand All @@ -203,7 +205,7 @@ fn rewards_pay_back_fee_debt() {
BURNT_FUNDS_ACTOR_ADDR,
METHOD_SEND,
RawBytes::default(),
expect_burnt.clone(),
expect_burnt,
RawBytes::default(),
ExitCode::OK,
);
Expand All @@ -212,13 +214,10 @@ fn rewards_pay_back_fee_debt() {
rt.call::<Actor>(Method::ApplyRewards as u64, &RawBytes::serialize(params).unwrap()).unwrap();
rt.verify();

// Set balance to deduct fee
let final_balance = &new_balance - &expect_burnt;

let st = h.get_state(&rt);
// balance funds used to pay off fee debt
// available balance should be 2
let available_balance = st.get_available_balance(&final_balance).unwrap();
let available_balance = h.get_available_balance(&mut rt).unwrap();
assert_eq!(available_before + reward - init_fee_debt - &remaining_locked, available_balance);
assert!(!st.fee_debt.is_positive());
// remaining funds locked in vesting table
Expand Down
Loading