Skip to content

Commit

Permalink
Power actor: Add exported getters for raw power (#810)
Browse files Browse the repository at this point in the history
* Power actor: Add exported getters for raw power

* FRC-XXXX is FRC-0042

* Power actor: network_raw_power: Return this_epoch_raw_byte_power

* Power actor: miner_raw_power: Return whether above consensus min power

* Power actor: types: serialize one-element structs transparently

* Address review

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

* Miner actor: Add exported getters for info and monies

* Tweak comment

* Miner actor: Replace GetWorker and GetControls with IsControllingAddress

* Miner actor: Add exported GetAvailableBalance

* Miner actor: Add exported GetVestingFunds

* Miner actor: Remove exported monies getters

* Miner actor: types: serialize one-element structs transparently

* Address review

* Address review
  • Loading branch information
arajasek committed Dec 11, 2022
1 parent dec77b8 commit 8542732
Show file tree
Hide file tree
Showing 17 changed files with 480 additions and 50 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions actors/datacap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ lazy_static! {

/// Datacap actor methods available
/// Some methods are available under 2 method nums -- a static number for "private" builtin actor usage,
/// and via FRC-XXXX calling convention, with number determined by method name.
/// and via FRC-0042 calling convention, with number determined by method name.
#[derive(FromPrimitive)]
#[repr(u64)]
pub enum Method {
Expand All @@ -67,7 +67,7 @@ pub enum Method {
Burn = 19,
BurnFrom = 20,
Allowance = 21,
// Method numbers derived from FRC-XXXX standards
// Method numbers derived from FRC-0042 standards
NameExported = frc42_dispatch::method_hash!("Name"),
SymbolExported = frc42_dispatch::method_hash!("Symbol"),
TotalSupplyExported = frc42_dispatch::method_hash!("TotalSupply"),
Expand Down
2 changes: 1 addition & 1 deletion actors/init/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fil_actors_runtime::wasm_trampoline!(Actor);
pub enum Method {
Constructor = METHOD_CONSTRUCTOR,
Exec = 2,
// Method numbers derived from FRC-XXXX standards
// Method numbers derived from FRC-0042 standards
ExecExported = frc42_dispatch::method_hash!("Exec"),
}

Expand Down
94 changes: 93 additions & 1 deletion 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 @@ -123,9 +124,14 @@ pub enum Method {
ChangeBeneficiary = 30,
GetBeneficiary = 31,
ExtendSectorExpiration2 = 32,
// Method numbers derived from FRC-XXXX standards
// Method numbers derived from FRC-0042 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()?;
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 @@ -5000,6 +5072,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

0 comments on commit 8542732

Please sign in to comment.