Skip to content

Commit

Permalink
Exported API method for market actor escrow/locked balance (#812)
Browse files Browse the repository at this point in the history
  • Loading branch information
anorth authored and arajasek committed Nov 17, 2022
1 parent 893da34 commit ae5e85d
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 125 deletions.
35 changes: 34 additions & 1 deletion actors/market/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use log::info;
use num_derive::FromPrimitive;
use num_traits::{FromPrimitive, Zero};

use crate::balance_table::BalanceTable;
use fil_actors_runtime::cbor::{deserialize, serialize, serialize_vec};
use fil_actors_runtime::runtime::builtins::Type;
use fil_actors_runtime::runtime::{ActorCode, Policy, Runtime};
Expand Down Expand Up @@ -72,9 +73,10 @@ pub enum Method {
OnMinerSectorsTerminate = 7,
ComputeDataCommitment = 8,
CronTick = 9,
// Method numbers derived from FRC-XXXX standards
// Method numbers derived from FRC-0042 standards
AddBalanceExported = frc42_dispatch::method_hash!("AddBalance"),
WithdrawBalanceExported = frc42_dispatch::method_hash!("WithdrawBalance"),
GetBalanceExported = frc42_dispatch::method_hash!("GetBalance"),
}

/// Market Actor
Expand Down Expand Up @@ -185,6 +187,33 @@ impl Actor {
Ok(WithdrawBalanceReturn { amount_withdrawn: amount_extracted })
}

/// Returns the escrow balance and locked amount for an address.
fn get_balance(
rt: &mut impl Runtime,
account: Address,
) -> Result<GetBalanceReturn, ActorError> {
rt.validate_immediate_caller_accept_any()?;
let nominal = rt.resolve_address(&account).ok_or_else(|| {
actor_error!(illegal_argument, "failed to resolve address {}", account)
})?;
let account = Address::new_id(nominal);

let store = rt.store();
let st: State = rt.state()?;
let balances = BalanceTable::from_root(store, &st.escrow_table)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load escrow table")?;
let locks = BalanceTable::from_root(store, &st.locked_table)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load locked table")?;
let balance = balances
.get(&account)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to get escrow balance")?;
let locked = locks
.get(&account)
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to get locked balance")?;

Ok(GetBalanceReturn { balance, locked })
}

/// Publish a new set of storage deals (not yet included in a sector).
fn publish_storage_deals(
rt: &mut impl Runtime,
Expand Down Expand Up @@ -1431,6 +1460,10 @@ impl ActorCode for Actor {
Self::cron_tick(rt)?;
Ok(RawBytes::default())
}
Some(Method::GetBalanceExported) => {
let res = Self::get_balance(rt, cbor::deserialize_params(params)?)?;
Ok(RawBytes::serialize(res)?)
}
None => Err(actor_error!(unhandled_message, "Invalid method")),
}
}
Expand Down
55 changes: 22 additions & 33 deletions actors/market/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,41 +22,40 @@ use super::deal::{ClientDealProposal, DealProposal, DealState};
pub const PROPOSALS_AMT_BITWIDTH: u32 = 5;
pub const STATES_AMT_BITWIDTH: u32 = 6;

#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct WithdrawBalanceParams {
pub provider_or_client: Address,
pub amount: TokenAmount,
}

impl Cbor for WithdrawBalanceParams {}

#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
#[serde(transparent)]
pub struct WithdrawBalanceReturn {
pub amount_withdrawn: TokenAmount,
}

#[derive(Serialize_tuple, Deserialize_tuple)]
pub struct OnMinerSectorsTerminateParams {
pub epoch: ChainEpoch,
pub deal_ids: Vec<DealID>,
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct GetBalanceReturn {
pub balance: TokenAmount,
pub locked: TokenAmount,
}

#[derive(Serialize_tuple)]

pub struct OnMinerSectorsTerminateParamsRef<'a> {
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct OnMinerSectorsTerminateParams {
pub epoch: ChainEpoch,
pub deal_ids: &'a [DealID],
pub deal_ids: Vec<DealID>,
}

#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct PublishStorageDealsParams {
pub deals: Vec<ClientDealProposal>,
}

impl Cbor for PublishStorageDealsParams {}

#[derive(Serialize_tuple, Deserialize_tuple, Debug)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq)] // Add Eq when BitField does
pub struct PublishStorageDealsReturn {
pub ids: Vec<DealID>,
pub valid_deals: BitField,
Expand All @@ -65,73 +64,63 @@ pub struct PublishStorageDealsReturn {
// Changed since V2:
// - Array of Sectors rather than just one
// - Removed SectorStart
#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct VerifyDealsForActivationParams {
pub sectors: Vec<SectorDeals>,
}

#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct SectorDeals {
pub sector_type: RegisteredSealProof,
pub sector_expiry: ChainEpoch,
pub deal_ids: Vec<DealID>,
}

#[derive(Serialize_tuple)]
pub struct VerifyDealsForActivationParamsRef<'a> {
pub sectors: &'a [SectorDeals],
}

#[derive(Serialize_tuple, Deserialize_tuple, Default)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct VerifyDealsForActivationReturn {
pub sectors: Vec<SectorDealData>,
}

#[derive(Serialize_tuple, Deserialize_tuple, Default, Clone)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq, Default)]
pub struct SectorDealData {
/// Option::None signifies commitment to empty sector, meaning no deals.
pub commd: Option<Cid>,
}

#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct ActivateDealsParams {
pub deal_ids: Vec<DealID>,
pub sector_expiry: ChainEpoch,
}

#[derive(Serialize_tuple, Deserialize_tuple, Clone)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct VerifiedDealInfo {
pub client: ActorID,
pub allocation_id: AllocationID,
pub data: Cid,
pub size: PaddedPieceSize,
}

#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct ActivateDealsResult {
#[serde(with = "bigint_ser")]
pub nonverified_deal_space: BigInt,
pub verified_infos: Vec<VerifiedDealInfo>,
}
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Default)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct DealSpaces {
#[serde(with = "bigint_ser")]
pub deal_space: BigInt,
#[serde(with = "bigint_ser")]
pub verified_deal_space: BigInt,
}

#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct ComputeDataCommitmentParams {
pub inputs: Vec<SectorDataSpec>,
}

#[derive(Serialize_tuple)]
pub struct ComputeDataCommitmentParamsRef<'a> {
pub inputs: &'a [SectorDataSpec],
}

#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct ComputeDataCommitmentReturn {
pub commds: Vec<Cid>,
}
Expand All @@ -142,7 +131,7 @@ pub type DealArray<'bs, BS> = Array<'bs, DealProposal, BS>;
/// A specialization of a array to deals.
pub type DealMetaArray<'bs, BS> = Array<'bs, DealState, BS>;

#[derive(Serialize_tuple, Deserialize_tuple)]
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)]
pub struct SectorDataSpec {
pub deal_ids: Vec<DealID>,
pub sector_type: RegisteredSealProof,
Expand Down
16 changes: 9 additions & 7 deletions actors/market/tests/cron_tick_deal_expiry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ fn expired_deal_should_unlock_the_remaining_client_and_provider_locked_balance_a
);
let deal_proposal = get_deal_proposal(&mut rt, deal_id);

let c_escrow = get_escrow_balance(&rt, &CLIENT_ADDR).unwrap();
let p_escrow = get_escrow_balance(&rt, &PROVIDER_ADDR).unwrap();
let c_escrow = get_balance(&mut rt, &CLIENT_ADDR).balance;
let p_escrow = get_balance(&mut rt, &PROVIDER_ADDR).balance;

// move the current epoch so that deal is expired
rt.set_epoch(END_EPOCH + 1000);
Expand All @@ -173,11 +173,13 @@ fn expired_deal_should_unlock_the_remaining_client_and_provider_locked_balance_a
// assert balances
let payment = deal_proposal.total_storage_fee();

assert_eq!(c_escrow - &payment, get_escrow_balance(&rt, &CLIENT_ADDR).unwrap());
assert!(get_locked_balance(&mut rt, CLIENT_ADDR).is_zero());
let client_acct = get_balance(&mut rt, &CLIENT_ADDR);
assert_eq!(c_escrow - &payment, client_acct.balance);
assert!(client_acct.locked.is_zero());

assert_eq!(p_escrow + &payment, get_escrow_balance(&rt, &PROVIDER_ADDR).unwrap());
assert!(get_locked_balance(&mut rt, PROVIDER_ADDR).is_zero());
let provider_acct = get_balance(&mut rt, &PROVIDER_ADDR);
assert_eq!(p_escrow + &payment, provider_acct.balance);
assert!(provider_acct.locked.is_zero());

// deal should be deleted
assert_deal_deleted(&mut rt, deal_id, deal_proposal);
Expand All @@ -201,7 +203,7 @@ fn all_payments_are_made_for_a_deal_client_withdraws_collateral_and_client_accou
// move the current epoch so that deal is expired
rt.set_epoch(END_EPOCH + 100);
cron_tick(&mut rt);
assert_eq!(deal_proposal.client_collateral, get_escrow_balance(&rt, &CLIENT_ADDR).unwrap());
assert_eq!(deal_proposal.client_collateral, get_balance(&mut rt, &CLIENT_ADDR).balance);

// client withdraws collateral -> account should be removed as it now has zero balance
withdraw_client_balance(
Expand Down
7 changes: 4 additions & 3 deletions actors/market/tests/cron_tick_timedout_deals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ fn timed_out_deal_is_slashed_and_deleted() {
);
let deal_proposal = get_deal_proposal(&mut rt, deal_id);

let c_escrow = get_escrow_balance(&rt, &CLIENT_ADDR).unwrap();
let c_escrow = get_balance(&mut rt, &CLIENT_ADDR).balance;

// do a cron tick for it -> should time out and get slashed
rt.set_epoch(process_epoch(START_EPOCH, deal_id));
Expand All @@ -50,8 +50,9 @@ fn timed_out_deal_is_slashed_and_deleted() {
);
cron_tick(&mut rt);

assert_eq!(c_escrow, get_escrow_balance(&rt, &CLIENT_ADDR).unwrap());
assert!(get_locked_balance(&mut rt, CLIENT_ADDR).is_zero());
let client_acct = get_balance(&mut rt, &CLIENT_ADDR);
assert_eq!(c_escrow, client_acct.balance);
assert!(client_acct.locked.is_zero());
assert_account_zero(&mut rt, PROVIDER_ADDR);
assert_deal_deleted(&mut rt, deal_id, deal_proposal);
check_state(&rt);
Expand Down
Loading

0 comments on commit ae5e85d

Please sign in to comment.