From 4755f4b41c968dc04d5aed578677f8fae5a86de0 Mon Sep 17 00:00:00 2001 From: Sergey Ukustov Date: Tue, 29 Oct 2024 17:08:05 +0300 Subject: [PATCH 1/9] params --- fendermint/actors/blobs/shared/src/lib.rs | 3 + fendermint/actors/blobs/shared/src/params.rs | 19 +++++ fendermint/actors/blobs/src/actor.rs | 84 ++++++++++++++++++-- fendermint/actors/blobs/src/state.rs | 29 ++++++- 4 files changed, 128 insertions(+), 7 deletions(-) diff --git a/fendermint/actors/blobs/shared/src/lib.rs b/fendermint/actors/blobs/shared/src/lib.rs index 1a26225ab..1f4a26063 100644 --- a/fendermint/actors/blobs/shared/src/lib.rs +++ b/fendermint/actors/blobs/shared/src/lib.rs @@ -36,6 +36,9 @@ pub enum Method { GetPendingBlobs = frc42_dispatch::method_hash!("GetPendingBlobs"), FinalizeBlob = frc42_dispatch::method_hash!("FinalizeBlob"), DeleteBlob = frc42_dispatch::method_hash!("DeleteBlob"), + GetStorageStaked = frc42_dispatch::method_hash!("GetStorageStaked"), + StakeStorage = frc42_dispatch::method_hash!("StakeStorage"), + UnstakeStorage = frc42_dispatch::method_hash!("UnstakeStorage"), } pub fn buy_credit(rt: &impl Runtime, recipient: Address) -> Result { diff --git a/fendermint/actors/blobs/shared/src/params.rs b/fendermint/actors/blobs/shared/src/params.rs index d48c02788..32e288af5 100644 --- a/fendermint/actors/blobs/shared/src/params.rs +++ b/fendermint/actors/blobs/shared/src/params.rs @@ -11,6 +11,25 @@ use serde::{Deserialize, Serialize}; use crate::state::{BlobStatus, Hash, PublicKey}; +/// Params to get storage staked per validator. +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(transparent)] +pub struct GetStorageStakedParams(pub Address); + +/// Params to increase storage staked per validator. +#[derive(Clone, Debug, Serialize_tuple, Deserialize_tuple)] +pub struct StakeStorageParams { + pub address: Address, + pub storage: u64, +} + +/// Params to decrease storage staked per validator. +#[derive(Clone, Debug, Serialize_tuple, Deserialize_tuple)] +pub struct UnstakeStorageParams { + pub address: Address, + pub storage: u64, +} + /// Params for buying credits. #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(transparent)] diff --git a/fendermint/actors/blobs/src/actor.rs b/fendermint/actors/blobs/src/actor.rs index 45f22c075..05d310189 100644 --- a/fendermint/actors/blobs/src/actor.rs +++ b/fendermint/actors/blobs/src/actor.rs @@ -4,11 +4,7 @@ use std::collections::HashSet; -use fendermint_actor_blobs_shared::params::{ - AddBlobParams, ApproveCreditParams, BuyCreditParams, DeleteBlobParams, FinalizeBlobParams, - GetAccountParams, GetBlobParams, GetBlobStatusParams, GetPendingBlobsParams, GetStatsReturn, - RevokeCreditParams, -}; +use fendermint_actor_blobs_shared::params::{AddBlobParams, ApproveCreditParams, BuyCreditParams, DeleteBlobParams, FinalizeBlobParams, GetAccountParams, GetBlobParams, GetBlobStatusParams, GetPendingBlobsParams, GetStatsReturn, GetStorageStakedParams, RevokeCreditParams, StakeStorageParams, UnstakeStorageParams}; use fendermint_actor_blobs_shared::state::{ Account, Blob, BlobStatus, CreditApproval, Hash, PublicKey, Subscription, }; @@ -47,6 +43,18 @@ impl BlobsActor { Ok(stats) } + fn get_storage_staked(rt: &impl Runtime, params: GetStorageStakedParams) -> Result { + Ok(0) + } + + fn stake_storage(rt: &impl Runtime, params: StakeStorageParams) -> Result { + Ok(0) + } + + fn unstake_storage(rt: &impl Runtime, params: UnstakeStorageParams) -> Result { + Ok(0) + } + fn buy_credit(rt: &impl Runtime, params: BuyCreditParams) -> Result { rt.validate_immediate_caller_accept_any()?; let (recipient, actor_type) = resolve_external(rt, params.0)?; @@ -317,6 +325,9 @@ impl ActorCode for BlobsActor { actor_dispatch! { Constructor => constructor, GetStats => get_stats, + StakeStorage => stake_storage, + UnstakeStorage => unstake_storage, + GetStorageStaked => get_storage_staked, BuyCredit => buy_credit, ApproveCredit => approve_credit, RevokeCredit => revoke_credit, @@ -798,4 +809,67 @@ mod tests { assert_eq!(subscription.delegate, None); rt.verify(); } + + #[test] + fn test_stake_storage() { + let rt = construct_and_verify(1024 * 1024, 1); + + let id_addr = Address::new_id(110); + let eth_addr = EthAddress(hex_literal::hex!( + "CAFEB0BA00000000000000000000000000000000" + )); + let f4_eth_addr = Address::new_delegated(10, ð_addr.0).unwrap(); + + rt.set_delegated_address(id_addr.id().unwrap(), f4_eth_addr); + rt.set_caller(*ETHACCOUNT_ACTOR_CODE_ID, id_addr); + rt.set_origin(id_addr); + + let mut expected_credits = BigInt::from(1000000000000000000u64); + rt.set_received(TokenAmount::from_whole(1)); + rt.expect_validate_caller_any(); + let fund_params = BuyCreditParams(f4_eth_addr); + let result = rt + .call::( + Method::BuyCredit as u64, + IpldBlock::serialize_cbor(&fund_params).unwrap(), + ) + .unwrap() + .unwrap() + .deserialize::() + .unwrap(); + assert_eq!(result.credit_free, expected_credits); + rt.verify(); + + expected_credits += BigInt::from(1000000000u64); + rt.set_received(TokenAmount::from_nano(1)); + rt.expect_validate_caller_any(); + let fund_params = BuyCreditParams(f4_eth_addr); + let result = rt + .call::( + Method::BuyCredit as u64, + IpldBlock::serialize_cbor(&fund_params).unwrap(), + ) + .unwrap() + .unwrap() + .deserialize::() + .unwrap(); + assert_eq!(result.credit_free, expected_credits); + rt.verify(); + + expected_credits += BigInt::from(1u64); + rt.set_received(TokenAmount::from_atto(1)); + rt.expect_validate_caller_any(); + let fund_params = BuyCreditParams(f4_eth_addr); + let result = rt + .call::( + Method::BuyCredit as u64, + IpldBlock::serialize_cbor(&fund_params).unwrap(), + ) + .unwrap() + .unwrap() + .deserialize::() + .unwrap(); + assert_eq!(result.credit_free, expected_credits); + rt.verify(); + } } diff --git a/fendermint/actors/blobs/src/state.rs b/fendermint/actors/blobs/src/state.rs index 05c86bc48..838052351 100644 --- a/fendermint/actors/blobs/src/state.rs +++ b/fendermint/actors/blobs/src/state.rs @@ -15,7 +15,7 @@ use fvm_shared::address::Address; use fvm_shared::bigint::{BigInt, BigUint}; use fvm_shared::clock::ChainEpoch; use fvm_shared::econ::TokenAmount; -use log::{debug, warn}; +use log::{debug, error, warn}; use num_traits::{Signed, ToPrimitive, Zero}; /// The minimum epoch duration a blob can be stored. @@ -28,7 +28,9 @@ const AUTO_TTL: ChainEpoch = 3600; // one hour #[derive(Debug, Serialize_tuple, Deserialize_tuple)] pub struct State { /// The total storage capacity of the subnet. - pub capacity_total: BigInt, + pub capacity_total: BigInt, // TODO SU That should be maintained as a cache of total(capacity_committed) + /// Committed storage capacity of the subnet. + pub capacity_commited: BTreeMap, /// The total used storage capacity of the subnet. pub capacity_used: BigInt, /// The total number of credits sold in the subnet. @@ -69,6 +71,7 @@ impl State { Self { capacity_total: BigInt::from(capacity), capacity_used: BigInt::zero(), + capacity_commited: BTreeMap::new(), credit_sold: BigInt::zero(), credit_committed: BigInt::zero(), credit_debited: BigInt::zero(), @@ -95,6 +98,28 @@ impl State { } } + pub fn get_storage_staked(&mut self, validator: Address) -> anyhow::Result<(Address, u64), ActorError> { + let storage_commitment = self.capacity_commited.entry(validator).or_default(); + Ok((validator, storage_commitment.clone())) + } + + pub fn stake_storage(&mut self, validator: Address, amount: u64) -> anyhow::Result<(Address, u64), ActorError> { + let storage_commitment = self.capacity_commited.entry(validator).and_modify(|v| *v += amount).or_insert(amount); + Ok((validator, storage_commitment.clone())) + } + + pub fn unstake_storage(&mut self, validator: Address, amount: u64) -> anyhow::Result<(Address, u64), ActorError> { + let storage_commitment = self.capacity_commited.entry(validator).and_modify(|v| { + let current = *v; + if (current > amount) { + *v -= amount; + } else { + *v = 0; + } + }).or_default(); + Ok((validator, storage_commitment.clone())) + } + pub fn buy_credit( &mut self, recipient: Address, From b9f09bcb74c8779ed839b24baacf7b61dbe6fc9b Mon Sep 17 00:00:00 2001 From: Sergey Ukustov Date: Tue, 29 Oct 2024 18:18:14 +0300 Subject: [PATCH 2/9] storage-staking on blobs --- fendermint/actors/blobs/shared/src/params.rs | 6 + fendermint/actors/blobs/src/actor.rs | 252 +++++++++++-------- fendermint/actors/blobs/src/state.rs | 43 ++-- 3 files changed, 189 insertions(+), 112 deletions(-) diff --git a/fendermint/actors/blobs/shared/src/params.rs b/fendermint/actors/blobs/shared/src/params.rs index 32e288af5..5094a53c8 100644 --- a/fendermint/actors/blobs/shared/src/params.rs +++ b/fendermint/actors/blobs/shared/src/params.rs @@ -16,6 +16,12 @@ use crate::state::{BlobStatus, Hash, PublicKey}; #[serde(transparent)] pub struct GetStorageStakedParams(pub Address); +#[derive(Clone, Debug, Serialize_tuple, Deserialize_tuple)] +pub struct StorageStakedReturn { + pub address: Address, + pub storage: u64, +} + /// Params to increase storage staked per validator. #[derive(Clone, Debug, Serialize_tuple, Deserialize_tuple)] pub struct StakeStorageParams { diff --git a/fendermint/actors/blobs/src/actor.rs b/fendermint/actors/blobs/src/actor.rs index 05d310189..798ffa9f9 100644 --- a/fendermint/actors/blobs/src/actor.rs +++ b/fendermint/actors/blobs/src/actor.rs @@ -4,7 +4,7 @@ use std::collections::HashSet; -use fendermint_actor_blobs_shared::params::{AddBlobParams, ApproveCreditParams, BuyCreditParams, DeleteBlobParams, FinalizeBlobParams, GetAccountParams, GetBlobParams, GetBlobStatusParams, GetPendingBlobsParams, GetStatsReturn, GetStorageStakedParams, RevokeCreditParams, StakeStorageParams, UnstakeStorageParams}; +use fendermint_actor_blobs_shared::params::{AddBlobParams, ApproveCreditParams, BuyCreditParams, DeleteBlobParams, FinalizeBlobParams, GetAccountParams, GetBlobParams, GetBlobStatusParams, GetPendingBlobsParams, GetStatsReturn, GetStorageStakedParams, RevokeCreditParams, StakeStorageParams, StorageStakedReturn, UnstakeStorageParams}; use fendermint_actor_blobs_shared::state::{ Account, Blob, BlobStatus, CreditApproval, Hash, PublicKey, Subscription, }; @@ -43,16 +43,29 @@ impl BlobsActor { Ok(stats) } - fn get_storage_staked(rt: &impl Runtime, params: GetStorageStakedParams) -> Result { - Ok(0) + fn get_storage_staked(rt: &impl Runtime, params: GetStorageStakedParams) -> Result { + rt.validate_immediate_caller_accept_any()?; + let address = resolve_external_non_machine(rt, params.0)?; + let storage_committed = rt.state::()?.get_storage_staked(address); + Ok(storage_committed) } - fn stake_storage(rt: &impl Runtime, params: StakeStorageParams) -> Result { - Ok(0) + fn stake_storage(rt: &impl Runtime, params: StakeStorageParams) -> Result { + rt.validate_immediate_caller_accept_any()?; + let address = resolve_external_non_machine(rt, params.address)?; + assert_message_source(rt, address)?; + rt.transaction(|st: &mut State, _rt| { + st.stake_storage(address, params.storage) + }) } - fn unstake_storage(rt: &impl Runtime, params: UnstakeStorageParams) -> Result { - Ok(0) + fn unstake_storage(rt: &impl Runtime, params: UnstakeStorageParams) -> Result { + rt.validate_immediate_caller_accept_any()?; + let address = resolve_external_non_machine(rt, params.address)?; + assert_message_source(rt, address)?; + rt.transaction(|st: &mut State, _rt| { + st.unstake_storage(address, params.storage) + }) } fn buy_credit(rt: &impl Runtime, params: BuyCreditParams) -> Result { @@ -75,29 +88,9 @@ impl BlobsActor { params: ApproveCreditParams, ) -> Result { rt.validate_immediate_caller_accept_any()?; - let (from, actor_type) = resolve_external(rt, params.from)?; - let (origin, caller) = if rt.message().origin() == rt.message().caller() { - let (origin, _) = resolve_external(rt, rt.message().origin())?; - (origin, origin) - } else { - let (origin, _) = resolve_external(rt, rt.message().origin())?; - let (caller, _) = resolve_external(rt, rt.message().caller())?; - (origin, caller) - }; - // Credit owner must be the transaction origin or caller - if from != caller && from != origin { - return Err(ActorError::illegal_argument(format!( - "from {} does not match origin or caller", - from - ))); - } // Credit owner cannot be a machine - if matches!(actor_type, ActorType::Machine) { - return Err(ActorError::illegal_argument(format!( - "from {} cannot be a machine", - from - ))); - } + let from = resolve_external_non_machine(rt, params.from)?; + assert_message_source(rt, from)?; let (receiver, actor_type) = resolve_external(rt, params.receiver)?; // Receiver cannot be a machine if matches!(actor_type, ActorType::Machine) { @@ -126,37 +119,10 @@ impl BlobsActor { fn revoke_credit(rt: &impl Runtime, params: RevokeCreditParams) -> Result<(), ActorError> { rt.validate_immediate_caller_accept_any()?; - let (from, actor_type) = resolve_external(rt, params.from)?; - let (origin, caller) = if rt.message().origin() == rt.message().caller() { - let (origin, _) = resolve_external(rt, rt.message().origin())?; - (origin, origin) - } else { - let (origin, _) = resolve_external(rt, rt.message().origin())?; - let (caller, _) = resolve_external(rt, rt.message().caller())?; - (origin, caller) - }; - // Credit owner must be the transaction origin or caller - if from != caller && from != origin { - return Err(ActorError::illegal_argument(format!( - "from {} does not match origin or caller", - from - ))); - } // Credit owner cannot be a machine - if matches!(actor_type, ActorType::Machine) { - return Err(ActorError::illegal_argument(format!( - "from {} cannot be a machine", - from - ))); - } - let (receiver, actor_type) = resolve_external(rt, params.receiver)?; - // Receiver cannot be a machine - if matches!(actor_type, ActorType::Machine) { - return Err(ActorError::illegal_argument(format!( - "receiver {} cannot be a machine", - receiver - ))); - } + let from = resolve_external_non_machine(rt, params.from)?; + assert_message_source(rt, from)?; + let receiver = resolve_external_non_machine(rt, params.receiver)?; let required_caller = if let Some(required_caller) = params.required_caller { let (required_caller, _) = resolve_external(rt, required_caller)?; Some(required_caller) @@ -350,6 +316,39 @@ enum ActorType { Machine, } +/// Return Err if `source` is neither `rt.message().origin()` nor `rt.message.caller()`. +fn assert_message_source(rt: &impl Runtime, source: Address) -> Result<(), ActorError> { + let (origin, caller) = if rt.message().origin() == rt.message().caller() { + let (origin, _) = resolve_external(rt, rt.message().origin())?; + (origin, origin) + } else { + let (origin, _) = resolve_external(rt, rt.message().origin())?; + let (caller, _) = resolve_external(rt, rt.message().caller())?; + (origin, caller) + }; + if source != caller && source != origin { + return Err(ActorError::illegal_argument(format!( + "address {} does not match origin or caller", + source + ))); + } + Ok(()) +} + +/// Resolve robust address and ensure it is not a Machine actor type. +/// See `resolve_external`. +fn resolve_external_non_machine(rt: &impl Runtime, address: Address) -> Result { + let (address, actor_type) = resolve_external(rt, address)?; + if matches!(actor_type, ActorType::Machine) { + Err(ActorError::illegal_argument(format!( + "address {} cannot be a machine", + address + ))) + } else { + Ok(address) + } +} + // Resolves robust address of an actor. fn resolve_external( rt: &impl Runtime, @@ -471,6 +470,24 @@ mod tests { PublicKey(data) } + // TODO SU add tokens to the stake + + fn get_storage_staked(rt: &MockRuntime, address: Address) -> StorageStakedReturn { + let get_storage_staked_params = GetStorageStakedParams(address); + rt.expect_validate_caller_any(); + let result = rt + .call::( + Method::GetStorageStaked as u64, + IpldBlock::serialize_cbor(&get_storage_staked_params).unwrap(), + ) + .unwrap() + .unwrap() + .deserialize::() + .unwrap(); + rt.verify(); + result + } + pub fn construct_and_verify(capacity: u64, debit_rate: u64) -> MockRuntime { let rt = MockRuntime { receiver: Address::new_id(10), @@ -820,56 +837,95 @@ mod tests { )); let f4_eth_addr = Address::new_delegated(10, ð_addr.0).unwrap(); + let f4_eth_addr_wrong = Address::new_delegated(10, &hex_literal::hex!( + "DEADB0BA00000000000000000000000000000000" + )).unwrap(); + rt.set_delegated_address(id_addr.id().unwrap(), f4_eth_addr); rt.set_caller(*ETHACCOUNT_ACTOR_CODE_ID, id_addr); rt.set_origin(id_addr); - let mut expected_credits = BigInt::from(1000000000000000000u64); - rt.set_received(TokenAmount::from_whole(1)); + let staked_0 = get_storage_staked(&rt, f4_eth_addr); + assert_eq!(staked_0.storage, 0); + + // Stake 42 rt.expect_validate_caller_any(); - let fund_params = BuyCreditParams(f4_eth_addr); - let result = rt - .call::( - Method::BuyCredit as u64, - IpldBlock::serialize_cbor(&fund_params).unwrap(), - ) - .unwrap() - .unwrap() - .deserialize::() - .unwrap(); - assert_eq!(result.credit_free, expected_credits); + let stake_params = StakeStorageParams { + // Use id_addr, see below why + address: id_addr, + storage: 42, + }; + let result = rt.call::( + Method::StakeStorage as u64, + IpldBlock::serialize_cbor(&stake_params).unwrap(), + ); rt.verify(); + let result_params = result.unwrap().unwrap().deserialize::().unwrap(); + // Used id_addr, but robust address returned is f4_eth_addr + assert_eq!(result_params.address, f4_eth_addr); + assert_eq!(result_params.storage, 42); + assert_eq!(get_storage_staked(&rt, id_addr).storage, 42); - expected_credits += BigInt::from(1000000000u64); - rt.set_received(TokenAmount::from_nano(1)); + // Stake 58 more, to get to 100 total rt.expect_validate_caller_any(); - let fund_params = BuyCreditParams(f4_eth_addr); - let result = rt - .call::( - Method::BuyCredit as u64, - IpldBlock::serialize_cbor(&fund_params).unwrap(), - ) - .unwrap() - .unwrap() - .deserialize::() - .unwrap(); - assert_eq!(result.credit_free, expected_credits); + let stake_params = StakeStorageParams { + address: f4_eth_addr, + storage: 58, + }; + let result = rt.call::( + Method::StakeStorage as u64, + IpldBlock::serialize_cbor(&stake_params).unwrap(), + ); rt.verify(); + let result_params = result.unwrap().unwrap().deserialize::().unwrap(); + assert_eq!(result_params.address, f4_eth_addr); + assert_eq!(result_params.storage, 100); + assert_eq!(get_storage_staked(&rt, id_addr).storage, 100); - expected_credits += BigInt::from(1u64); - rt.set_received(TokenAmount::from_atto(1)); + // Unstake 20 rt.expect_validate_caller_any(); - let fund_params = BuyCreditParams(f4_eth_addr); - let result = rt - .call::( - Method::BuyCredit as u64, - IpldBlock::serialize_cbor(&fund_params).unwrap(), - ) - .unwrap() - .unwrap() - .deserialize::() - .unwrap(); - assert_eq!(result.credit_free, expected_credits); + let unstake_params = UnstakeStorageParams { + address: f4_eth_addr, + storage: 20, + }; + let result = rt.call::( + Method::UnstakeStorage as u64, + IpldBlock::serialize_cbor(&unstake_params).unwrap(), + ); + rt.verify(); + let result_params = result.unwrap().unwrap().deserialize::().unwrap(); + assert_eq!(result_params.address, f4_eth_addr); + assert_eq!(result_params.storage, 80); + assert_eq!(get_storage_staked(&rt, id_addr).storage, 80); + + // Unstake 200 + rt.expect_validate_caller_any(); + let unstake_params = UnstakeStorageParams { + address: id_addr, + storage: 200, + }; + let result = rt.call::( + Method::UnstakeStorage as u64, + IpldBlock::serialize_cbor(&unstake_params).unwrap(), + ); rt.verify(); + let result_params = result.unwrap().unwrap().deserialize::().unwrap(); + assert_eq!(result_params.address, f4_eth_addr); + assert_eq!(result_params.storage, 0); + assert_eq!(get_storage_staked(&rt, id_addr).storage, 0); + + // Try staking as a "wrong" address -> should err + rt.expect_validate_caller_any(); + let stake_params = StakeStorageParams { + // Use id_addr, see below why + address: f4_eth_addr_wrong, + storage: 42, + }; + let result = rt.call::( + Method::StakeStorage as u64, + IpldBlock::serialize_cbor(&stake_params).unwrap(), + ); + rt.verify(); + assert!(result.is_err()); } } diff --git a/fendermint/actors/blobs/src/state.rs b/fendermint/actors/blobs/src/state.rs index 838052351..0f2b88735 100644 --- a/fendermint/actors/blobs/src/state.rs +++ b/fendermint/actors/blobs/src/state.rs @@ -3,9 +3,10 @@ // SPDX-License-Identifier: Apache-2.0, MIT use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::btree_map::Entry; use std::ops::Bound::{Included, Unbounded}; -use fendermint_actor_blobs_shared::params::GetStatsReturn; +use fendermint_actor_blobs_shared::params::{GetStatsReturn, StorageStakedReturn}; use fendermint_actor_blobs_shared::state::{ Account, Blob, BlobStatus, CreditApproval, Hash, PublicKey, Subscription, }; @@ -15,7 +16,7 @@ use fvm_shared::address::Address; use fvm_shared::bigint::{BigInt, BigUint}; use fvm_shared::clock::ChainEpoch; use fvm_shared::econ::TokenAmount; -use log::{debug, error, warn}; +use log::{debug, warn}; use num_traits::{Signed, ToPrimitive, Zero}; /// The minimum epoch duration a blob can be stored. @@ -98,26 +99,40 @@ impl State { } } - pub fn get_storage_staked(&mut self, validator: Address) -> anyhow::Result<(Address, u64), ActorError> { + pub fn get_storage_staked(&mut self, validator: Address) -> StorageStakedReturn { let storage_commitment = self.capacity_commited.entry(validator).or_default(); - Ok((validator, storage_commitment.clone())) + StorageStakedReturn { + address: validator, + storage: *storage_commitment, + } } - pub fn stake_storage(&mut self, validator: Address, amount: u64) -> anyhow::Result<(Address, u64), ActorError> { + pub fn stake_storage(&mut self, validator: Address, amount: u64) -> Result { let storage_commitment = self.capacity_commited.entry(validator).and_modify(|v| *v += amount).or_insert(amount); - Ok((validator, storage_commitment.clone())) + Ok(StorageStakedReturn { + address: validator, + storage: *storage_commitment, + }) } - pub fn unstake_storage(&mut self, validator: Address, amount: u64) -> anyhow::Result<(Address, u64), ActorError> { - let storage_commitment = self.capacity_commited.entry(validator).and_modify(|v| { - let current = *v; - if (current > amount) { - *v -= amount; + pub fn unstake_storage(&mut self, validator: Address, amount: u64) -> anyhow::Result { + if let Entry::Occupied(mut entry) = self.capacity_commited.entry(validator) { + let current = entry.get_mut(); + // If current commitment is gt amount, deduct, otherwise remove the entry + if *current > amount { + *current -= amount; + return Ok(StorageStakedReturn { + address: validator, + storage: *current, + }) } else { - *v = 0; + entry.remove(); } - }).or_default(); - Ok((validator, storage_commitment.clone())) + } + Ok(StorageStakedReturn { + address: validator, + storage: 0, + }) } pub fn buy_credit( From eb788d3e1d0560f0543c68f30ebed629e38ba1f4 Mon Sep 17 00:00:00 2001 From: Sergey Ukustov Date: Tue, 29 Oct 2024 18:22:47 +0300 Subject: [PATCH 3/9] non machines --- fendermint/actors/blobs/src/actor.rs | 37 +++------------------------- 1 file changed, 4 insertions(+), 33 deletions(-) diff --git a/fendermint/actors/blobs/src/actor.rs b/fendermint/actors/blobs/src/actor.rs index 798ffa9f9..e02825a5d 100644 --- a/fendermint/actors/blobs/src/actor.rs +++ b/fendermint/actors/blobs/src/actor.rs @@ -70,14 +70,8 @@ impl BlobsActor { fn buy_credit(rt: &impl Runtime, params: BuyCreditParams) -> Result { rt.validate_immediate_caller_accept_any()?; - let (recipient, actor_type) = resolve_external(rt, params.0)?; // Recipient cannot be a machine - if matches!(actor_type, ActorType::Machine) { - return Err(ActorError::illegal_argument(format!( - "recipient {} cannot be a machine", - recipient - ))); - } + let recipient = resolve_external_non_machine(rt, params.0)?; rt.transaction(|st: &mut State, rt| { st.buy_credit(recipient, rt.message().value_received(), rt.curr_epoch()) }) @@ -91,14 +85,7 @@ impl BlobsActor { // Credit owner cannot be a machine let from = resolve_external_non_machine(rt, params.from)?; assert_message_source(rt, from)?; - let (receiver, actor_type) = resolve_external(rt, params.receiver)?; - // Receiver cannot be a machine - if matches!(actor_type, ActorType::Machine) { - return Err(ActorError::illegal_argument(format!( - "receiver {} cannot be a machine", - receiver - ))); - } + let receiver = resolve_external_non_machine(rt, params.receiver)?; let required_caller = if let Some(required_caller) = params.required_caller { let (required_caller, _) = resolve_external(rt, required_caller)?; Some(required_caller) @@ -156,15 +143,7 @@ impl BlobsActor { let (caller, _) = resolve_external(rt, rt.message().caller())?; // The blob subscriber will be the sponsor if specified and approved let subscriber = if let Some(sponsor) = params.sponsor { - let (sponsor, actor_type) = resolve_external(rt, sponsor)?; - // Sponsor cannot be a machine - if matches!(actor_type, ActorType::Machine) { - return Err(ActorError::illegal_argument(format!( - "sponsor {} cannot be a machine", - sponsor - ))); - } - sponsor + resolve_external_non_machine(rt, sponsor)? } else { origin }; @@ -229,15 +208,7 @@ impl BlobsActor { let (caller, _) = resolve_external(rt, rt.message().caller())?; // The blob subscriber will be the sponsor if specified and approved let subscriber = if let Some(sponsor) = params.sponsor { - let (sponsor, actor_type) = resolve_external(rt, sponsor)?; - // Sponsor cannot be a machine - if matches!(actor_type, ActorType::Machine) { - return Err(ActorError::illegal_argument(format!( - "sponsor {} cannot be a machine", - sponsor - ))); - } - sponsor + resolve_external_non_machine(rt, sponsor)? } else { origin }; From 6e9738569de917deeec561bc25f669d0f248f517 Mon Sep 17 00:00:00 2001 From: Sergey Ukustov Date: Tue, 29 Oct 2024 18:25:10 +0300 Subject: [PATCH 4/9] tests --- fendermint/actors/blobs/src/actor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fendermint/actors/blobs/src/actor.rs b/fendermint/actors/blobs/src/actor.rs index e02825a5d..b83c7ccc6 100644 --- a/fendermint/actors/blobs/src/actor.rs +++ b/fendermint/actors/blobs/src/actor.rs @@ -627,7 +627,7 @@ mod tests { IpldBlock::serialize_cbor(&approve_params).unwrap(), ); let expected_return = Err(ActorError::illegal_argument(format!( - "from {} does not match origin or caller", + "address {} does not match origin or caller", receiver_f4_eth_addr ))); assert_eq!(result, expected_return); @@ -728,7 +728,7 @@ mod tests { IpldBlock::serialize_cbor(&revoke_params).unwrap(), ); let expected_return = Err(ActorError::illegal_argument(format!( - "from {} does not match origin or caller", + "address {} does not match origin or caller", receiver_f4_eth_addr ))); assert_eq!(result, expected_return); From e44b5c041d9b1a40aca60ae1bfd3b62afcb7c608 Mon Sep 17 00:00:00 2001 From: Sergey Ukustov Date: Wed, 30 Oct 2024 12:43:10 +0300 Subject: [PATCH 5/9] commitment, not stake --- fendermint/actors/blobs/shared/src/lib.rs | 6 +- fendermint/actors/blobs/shared/src/params.rs | 14 +-- fendermint/actors/blobs/src/actor.rs | 94 ++++++++++---------- fendermint/actors/blobs/src/state.rs | 16 ++-- 4 files changed, 65 insertions(+), 65 deletions(-) diff --git a/fendermint/actors/blobs/shared/src/lib.rs b/fendermint/actors/blobs/shared/src/lib.rs index 1f4a26063..d25371fb6 100644 --- a/fendermint/actors/blobs/shared/src/lib.rs +++ b/fendermint/actors/blobs/shared/src/lib.rs @@ -36,9 +36,9 @@ pub enum Method { GetPendingBlobs = frc42_dispatch::method_hash!("GetPendingBlobs"), FinalizeBlob = frc42_dispatch::method_hash!("FinalizeBlob"), DeleteBlob = frc42_dispatch::method_hash!("DeleteBlob"), - GetStorageStaked = frc42_dispatch::method_hash!("GetStorageStaked"), - StakeStorage = frc42_dispatch::method_hash!("StakeStorage"), - UnstakeStorage = frc42_dispatch::method_hash!("UnstakeStorage"), + GetStorageCommitted = frc42_dispatch::method_hash!("GetStorageCommitted"), + CommitStorage = frc42_dispatch::method_hash!("CommitStorage"), + UncommitStorage = frc42_dispatch::method_hash!("UncommitStorage"), } pub fn buy_credit(rt: &impl Runtime, recipient: Address) -> Result { diff --git a/fendermint/actors/blobs/shared/src/params.rs b/fendermint/actors/blobs/shared/src/params.rs index 5094a53c8..96dc4d198 100644 --- a/fendermint/actors/blobs/shared/src/params.rs +++ b/fendermint/actors/blobs/shared/src/params.rs @@ -11,27 +11,27 @@ use serde::{Deserialize, Serialize}; use crate::state::{BlobStatus, Hash, PublicKey}; -/// Params to get storage staked per validator. +/// Params to get storage committed per validator. #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(transparent)] -pub struct GetStorageStakedParams(pub Address); +pub struct GetStorageCommittedParams(pub Address); #[derive(Clone, Debug, Serialize_tuple, Deserialize_tuple)] -pub struct StorageStakedReturn { +pub struct StorageCommittedReturn { pub address: Address, pub storage: u64, } -/// Params to increase storage staked per validator. +/// Params to increase storage committed per validator. #[derive(Clone, Debug, Serialize_tuple, Deserialize_tuple)] -pub struct StakeStorageParams { +pub struct CommitStorageParams { pub address: Address, pub storage: u64, } -/// Params to decrease storage staked per validator. +/// Params to decrease storage committed per validator. #[derive(Clone, Debug, Serialize_tuple, Deserialize_tuple)] -pub struct UnstakeStorageParams { +pub struct UncommitStorageParams { pub address: Address, pub storage: u64, } diff --git a/fendermint/actors/blobs/src/actor.rs b/fendermint/actors/blobs/src/actor.rs index b83c7ccc6..54793e763 100644 --- a/fendermint/actors/blobs/src/actor.rs +++ b/fendermint/actors/blobs/src/actor.rs @@ -4,7 +4,7 @@ use std::collections::HashSet; -use fendermint_actor_blobs_shared::params::{AddBlobParams, ApproveCreditParams, BuyCreditParams, DeleteBlobParams, FinalizeBlobParams, GetAccountParams, GetBlobParams, GetBlobStatusParams, GetPendingBlobsParams, GetStatsReturn, GetStorageStakedParams, RevokeCreditParams, StakeStorageParams, StorageStakedReturn, UnstakeStorageParams}; +use fendermint_actor_blobs_shared::params::{AddBlobParams, ApproveCreditParams, BuyCreditParams, DeleteBlobParams, FinalizeBlobParams, GetAccountParams, GetBlobParams, GetBlobStatusParams, GetPendingBlobsParams, GetStatsReturn, GetStorageCommittedParams, RevokeCreditParams, CommitStorageParams, StorageCommittedReturn, UncommitStorageParams}; use fendermint_actor_blobs_shared::state::{ Account, Blob, BlobStatus, CreditApproval, Hash, PublicKey, Subscription, }; @@ -43,28 +43,28 @@ impl BlobsActor { Ok(stats) } - fn get_storage_staked(rt: &impl Runtime, params: GetStorageStakedParams) -> Result { + fn get_storage_committed(rt: &impl Runtime, params: GetStorageCommittedParams) -> Result { rt.validate_immediate_caller_accept_any()?; let address = resolve_external_non_machine(rt, params.0)?; - let storage_committed = rt.state::()?.get_storage_staked(address); + let storage_committed = rt.state::()?.get_storage_committed(address); Ok(storage_committed) } - fn stake_storage(rt: &impl Runtime, params: StakeStorageParams) -> Result { + fn commit_storage(rt: &impl Runtime, params: CommitStorageParams) -> Result { rt.validate_immediate_caller_accept_any()?; let address = resolve_external_non_machine(rt, params.address)?; assert_message_source(rt, address)?; rt.transaction(|st: &mut State, _rt| { - st.stake_storage(address, params.storage) + st.commit_storage(address, params.storage) }) } - fn unstake_storage(rt: &impl Runtime, params: UnstakeStorageParams) -> Result { + fn uncommit_storage(rt: &impl Runtime, params: UncommitStorageParams) -> Result { rt.validate_immediate_caller_accept_any()?; let address = resolve_external_non_machine(rt, params.address)?; assert_message_source(rt, address)?; rt.transaction(|st: &mut State, _rt| { - st.unstake_storage(address, params.storage) + st.uncommit_storage(address, params.storage) }) } @@ -262,9 +262,9 @@ impl ActorCode for BlobsActor { actor_dispatch! { Constructor => constructor, GetStats => get_stats, - StakeStorage => stake_storage, - UnstakeStorage => unstake_storage, - GetStorageStaked => get_storage_staked, + CommitStorage => commit_storage, + UncommitStorage => uncommit_storage, + GetStorageCommitted => get_storage_committed, BuyCredit => buy_credit, ApproveCredit => approve_credit, RevokeCredit => revoke_credit, @@ -441,19 +441,19 @@ mod tests { PublicKey(data) } - // TODO SU add tokens to the stake + // TODO SU add tokens to the storage commitment - fn get_storage_staked(rt: &MockRuntime, address: Address) -> StorageStakedReturn { - let get_storage_staked_params = GetStorageStakedParams(address); + fn get_storage_committed(rt: &MockRuntime, address: Address) -> StorageCommittedReturn { + let get_storage_committed_params = GetStorageCommittedParams(address); rt.expect_validate_caller_any(); let result = rt .call::( - Method::GetStorageStaked as u64, - IpldBlock::serialize_cbor(&get_storage_staked_params).unwrap(), + Method::GetStorageCommitted as u64, + IpldBlock::serialize_cbor(&get_storage_committed_params).unwrap(), ) .unwrap() .unwrap() - .deserialize::() + .deserialize::() .unwrap(); rt.verify(); result @@ -799,7 +799,7 @@ mod tests { } #[test] - fn test_stake_storage() { + fn test_commit_storage() { let rt = construct_and_verify(1024 * 1024, 1); let id_addr = Address::new_id(110); @@ -816,85 +816,85 @@ mod tests { rt.set_caller(*ETHACCOUNT_ACTOR_CODE_ID, id_addr); rt.set_origin(id_addr); - let staked_0 = get_storage_staked(&rt, f4_eth_addr); - assert_eq!(staked_0.storage, 0); + let committed_0 = get_storage_committed(&rt, f4_eth_addr); + assert_eq!(committed_0.storage, 0); - // Stake 42 + // Commit 42 rt.expect_validate_caller_any(); - let stake_params = StakeStorageParams { + let commitment_params = CommitStorageParams { // Use id_addr, see below why address: id_addr, storage: 42, }; let result = rt.call::( - Method::StakeStorage as u64, - IpldBlock::serialize_cbor(&stake_params).unwrap(), + Method::CommitStorage as u64, + IpldBlock::serialize_cbor(&commitment_params).unwrap(), ); rt.verify(); - let result_params = result.unwrap().unwrap().deserialize::().unwrap(); + let result_params = result.unwrap().unwrap().deserialize::().unwrap(); // Used id_addr, but robust address returned is f4_eth_addr assert_eq!(result_params.address, f4_eth_addr); assert_eq!(result_params.storage, 42); - assert_eq!(get_storage_staked(&rt, id_addr).storage, 42); + assert_eq!(get_storage_committed(&rt, id_addr).storage, 42); - // Stake 58 more, to get to 100 total + // Commit 58 more, to get to 100 total rt.expect_validate_caller_any(); - let stake_params = StakeStorageParams { + let commitment_params = CommitStorageParams { address: f4_eth_addr, storage: 58, }; let result = rt.call::( - Method::StakeStorage as u64, - IpldBlock::serialize_cbor(&stake_params).unwrap(), + Method::CommitStorage as u64, + IpldBlock::serialize_cbor(&commitment_params).unwrap(), ); rt.verify(); - let result_params = result.unwrap().unwrap().deserialize::().unwrap(); + let result_params = result.unwrap().unwrap().deserialize::().unwrap(); assert_eq!(result_params.address, f4_eth_addr); assert_eq!(result_params.storage, 100); - assert_eq!(get_storage_staked(&rt, id_addr).storage, 100); + assert_eq!(get_storage_committed(&rt, id_addr).storage, 100); - // Unstake 20 + // Uncommit 20 rt.expect_validate_caller_any(); - let unstake_params = UnstakeStorageParams { + let uncommit_params = UncommitStorageParams { address: f4_eth_addr, storage: 20, }; let result = rt.call::( - Method::UnstakeStorage as u64, - IpldBlock::serialize_cbor(&unstake_params).unwrap(), + Method::UncommitStorage as u64, + IpldBlock::serialize_cbor(&uncommit_params).unwrap(), ); rt.verify(); - let result_params = result.unwrap().unwrap().deserialize::().unwrap(); + let result_params = result.unwrap().unwrap().deserialize::().unwrap(); assert_eq!(result_params.address, f4_eth_addr); assert_eq!(result_params.storage, 80); - assert_eq!(get_storage_staked(&rt, id_addr).storage, 80); + assert_eq!(get_storage_committed(&rt, id_addr).storage, 80); - // Unstake 200 + // Uncommit 200 rt.expect_validate_caller_any(); - let unstake_params = UnstakeStorageParams { + let uncommit_params = UncommitStorageParams { address: id_addr, storage: 200, }; let result = rt.call::( - Method::UnstakeStorage as u64, - IpldBlock::serialize_cbor(&unstake_params).unwrap(), + Method::UncommitStorage as u64, + IpldBlock::serialize_cbor(&uncommit_params).unwrap(), ); rt.verify(); - let result_params = result.unwrap().unwrap().deserialize::().unwrap(); + let result_params = result.unwrap().unwrap().deserialize::().unwrap(); assert_eq!(result_params.address, f4_eth_addr); assert_eq!(result_params.storage, 0); - assert_eq!(get_storage_staked(&rt, id_addr).storage, 0); + assert_eq!(get_storage_committed(&rt, id_addr).storage, 0); - // Try staking as a "wrong" address -> should err + // Try committing as a "wrong" address -> should err rt.expect_validate_caller_any(); - let stake_params = StakeStorageParams { + let commitment_params = CommitStorageParams { // Use id_addr, see below why address: f4_eth_addr_wrong, storage: 42, }; let result = rt.call::( - Method::StakeStorage as u64, - IpldBlock::serialize_cbor(&stake_params).unwrap(), + Method::CommitStorage as u64, + IpldBlock::serialize_cbor(&commitment_params).unwrap(), ); rt.verify(); assert!(result.is_err()); diff --git a/fendermint/actors/blobs/src/state.rs b/fendermint/actors/blobs/src/state.rs index 0f2b88735..0126d0d84 100644 --- a/fendermint/actors/blobs/src/state.rs +++ b/fendermint/actors/blobs/src/state.rs @@ -6,7 +6,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::collections::btree_map::Entry; use std::ops::Bound::{Included, Unbounded}; -use fendermint_actor_blobs_shared::params::{GetStatsReturn, StorageStakedReturn}; +use fendermint_actor_blobs_shared::params::{GetStatsReturn, StorageCommittedReturn}; use fendermint_actor_blobs_shared::state::{ Account, Blob, BlobStatus, CreditApproval, Hash, PublicKey, Subscription, }; @@ -99,29 +99,29 @@ impl State { } } - pub fn get_storage_staked(&mut self, validator: Address) -> StorageStakedReturn { + pub fn get_storage_committed(&mut self, validator: Address) -> StorageCommittedReturn { let storage_commitment = self.capacity_commited.entry(validator).or_default(); - StorageStakedReturn { + StorageCommittedReturn { address: validator, storage: *storage_commitment, } } - pub fn stake_storage(&mut self, validator: Address, amount: u64) -> Result { + pub fn commit_storage(&mut self, validator: Address, amount: u64) -> Result { let storage_commitment = self.capacity_commited.entry(validator).and_modify(|v| *v += amount).or_insert(amount); - Ok(StorageStakedReturn { + Ok(StorageCommittedReturn { address: validator, storage: *storage_commitment, }) } - pub fn unstake_storage(&mut self, validator: Address, amount: u64) -> anyhow::Result { + pub fn uncommit_storage(&mut self, validator: Address, amount: u64) -> anyhow::Result { if let Entry::Occupied(mut entry) = self.capacity_commited.entry(validator) { let current = entry.get_mut(); // If current commitment is gt amount, deduct, otherwise remove the entry if *current > amount { *current -= amount; - return Ok(StorageStakedReturn { + return Ok(StorageCommittedReturn { address: validator, storage: *current, }) @@ -129,7 +129,7 @@ impl State { entry.remove(); } } - Ok(StorageStakedReturn { + Ok(StorageCommittedReturn { address: validator, storage: 0, }) From ec489d54c028f64942541646bb0483831c675a1b Mon Sep 17 00:00:00 2001 From: Sergey Ukustov Date: Wed, 30 Oct 2024 12:44:21 +0300 Subject: [PATCH 6/9] commitment, not stake --- fendermint/actors/blobs/shared/src/lib.rs | 2 +- fendermint/actors/blobs/shared/src/params.rs | 2 +- fendermint/actors/blobs/src/actor.rs | 26 ++++++++++---------- fendermint/actors/blobs/src/state.rs | 16 ++++++------ 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/fendermint/actors/blobs/shared/src/lib.rs b/fendermint/actors/blobs/shared/src/lib.rs index d25371fb6..539ce0adf 100644 --- a/fendermint/actors/blobs/shared/src/lib.rs +++ b/fendermint/actors/blobs/shared/src/lib.rs @@ -36,7 +36,7 @@ pub enum Method { GetPendingBlobs = frc42_dispatch::method_hash!("GetPendingBlobs"), FinalizeBlob = frc42_dispatch::method_hash!("FinalizeBlob"), DeleteBlob = frc42_dispatch::method_hash!("DeleteBlob"), - GetStorageCommitted = frc42_dispatch::method_hash!("GetStorageCommitted"), + GetStorageCommitment = frc42_dispatch::method_hash!("GetStorageCommitment"), CommitStorage = frc42_dispatch::method_hash!("CommitStorage"), UncommitStorage = frc42_dispatch::method_hash!("UncommitStorage"), } diff --git a/fendermint/actors/blobs/shared/src/params.rs b/fendermint/actors/blobs/shared/src/params.rs index 96dc4d198..c9c94a0fb 100644 --- a/fendermint/actors/blobs/shared/src/params.rs +++ b/fendermint/actors/blobs/shared/src/params.rs @@ -17,7 +17,7 @@ use crate::state::{BlobStatus, Hash, PublicKey}; pub struct GetStorageCommittedParams(pub Address); #[derive(Clone, Debug, Serialize_tuple, Deserialize_tuple)] -pub struct StorageCommittedReturn { +pub struct StorageCommitment { pub address: Address, pub storage: u64, } diff --git a/fendermint/actors/blobs/src/actor.rs b/fendermint/actors/blobs/src/actor.rs index 54793e763..4e4c769e5 100644 --- a/fendermint/actors/blobs/src/actor.rs +++ b/fendermint/actors/blobs/src/actor.rs @@ -4,7 +4,7 @@ use std::collections::HashSet; -use fendermint_actor_blobs_shared::params::{AddBlobParams, ApproveCreditParams, BuyCreditParams, DeleteBlobParams, FinalizeBlobParams, GetAccountParams, GetBlobParams, GetBlobStatusParams, GetPendingBlobsParams, GetStatsReturn, GetStorageCommittedParams, RevokeCreditParams, CommitStorageParams, StorageCommittedReturn, UncommitStorageParams}; +use fendermint_actor_blobs_shared::params::{AddBlobParams, ApproveCreditParams, BuyCreditParams, DeleteBlobParams, FinalizeBlobParams, GetAccountParams, GetBlobParams, GetBlobStatusParams, GetPendingBlobsParams, GetStatsReturn, GetStorageCommittedParams, RevokeCreditParams, CommitStorageParams, StorageCommitment, UncommitStorageParams}; use fendermint_actor_blobs_shared::state::{ Account, Blob, BlobStatus, CreditApproval, Hash, PublicKey, Subscription, }; @@ -43,14 +43,14 @@ impl BlobsActor { Ok(stats) } - fn get_storage_committed(rt: &impl Runtime, params: GetStorageCommittedParams) -> Result { + fn get_storage_commitment(rt: &impl Runtime, params: GetStorageCommittedParams) -> Result { rt.validate_immediate_caller_accept_any()?; let address = resolve_external_non_machine(rt, params.0)?; - let storage_committed = rt.state::()?.get_storage_committed(address); + let storage_committed = rt.state::()?.get_storage_commitment(address); Ok(storage_committed) } - fn commit_storage(rt: &impl Runtime, params: CommitStorageParams) -> Result { + fn commit_storage(rt: &impl Runtime, params: CommitStorageParams) -> Result { rt.validate_immediate_caller_accept_any()?; let address = resolve_external_non_machine(rt, params.address)?; assert_message_source(rt, address)?; @@ -59,7 +59,7 @@ impl BlobsActor { }) } - fn uncommit_storage(rt: &impl Runtime, params: UncommitStorageParams) -> Result { + fn uncommit_storage(rt: &impl Runtime, params: UncommitStorageParams) -> Result { rt.validate_immediate_caller_accept_any()?; let address = resolve_external_non_machine(rt, params.address)?; assert_message_source(rt, address)?; @@ -264,7 +264,7 @@ impl ActorCode for BlobsActor { GetStats => get_stats, CommitStorage => commit_storage, UncommitStorage => uncommit_storage, - GetStorageCommitted => get_storage_committed, + GetStorageCommitment => get_storage_commitment, BuyCredit => buy_credit, ApproveCredit => approve_credit, RevokeCredit => revoke_credit, @@ -443,17 +443,17 @@ mod tests { // TODO SU add tokens to the storage commitment - fn get_storage_committed(rt: &MockRuntime, address: Address) -> StorageCommittedReturn { + fn get_storage_committed(rt: &MockRuntime, address: Address) -> StorageCommitment { let get_storage_committed_params = GetStorageCommittedParams(address); rt.expect_validate_caller_any(); let result = rt .call::( - Method::GetStorageCommitted as u64, + Method::GetStorageCommitment as u64, IpldBlock::serialize_cbor(&get_storage_committed_params).unwrap(), ) .unwrap() .unwrap() - .deserialize::() + .deserialize::() .unwrap(); rt.verify(); result @@ -831,7 +831,7 @@ mod tests { IpldBlock::serialize_cbor(&commitment_params).unwrap(), ); rt.verify(); - let result_params = result.unwrap().unwrap().deserialize::().unwrap(); + let result_params = result.unwrap().unwrap().deserialize::().unwrap(); // Used id_addr, but robust address returned is f4_eth_addr assert_eq!(result_params.address, f4_eth_addr); assert_eq!(result_params.storage, 42); @@ -848,7 +848,7 @@ mod tests { IpldBlock::serialize_cbor(&commitment_params).unwrap(), ); rt.verify(); - let result_params = result.unwrap().unwrap().deserialize::().unwrap(); + let result_params = result.unwrap().unwrap().deserialize::().unwrap(); assert_eq!(result_params.address, f4_eth_addr); assert_eq!(result_params.storage, 100); assert_eq!(get_storage_committed(&rt, id_addr).storage, 100); @@ -864,7 +864,7 @@ mod tests { IpldBlock::serialize_cbor(&uncommit_params).unwrap(), ); rt.verify(); - let result_params = result.unwrap().unwrap().deserialize::().unwrap(); + let result_params = result.unwrap().unwrap().deserialize::().unwrap(); assert_eq!(result_params.address, f4_eth_addr); assert_eq!(result_params.storage, 80); assert_eq!(get_storage_committed(&rt, id_addr).storage, 80); @@ -880,7 +880,7 @@ mod tests { IpldBlock::serialize_cbor(&uncommit_params).unwrap(), ); rt.verify(); - let result_params = result.unwrap().unwrap().deserialize::().unwrap(); + let result_params = result.unwrap().unwrap().deserialize::().unwrap(); assert_eq!(result_params.address, f4_eth_addr); assert_eq!(result_params.storage, 0); assert_eq!(get_storage_committed(&rt, id_addr).storage, 0); diff --git a/fendermint/actors/blobs/src/state.rs b/fendermint/actors/blobs/src/state.rs index 0126d0d84..46d1045ba 100644 --- a/fendermint/actors/blobs/src/state.rs +++ b/fendermint/actors/blobs/src/state.rs @@ -6,7 +6,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::collections::btree_map::Entry; use std::ops::Bound::{Included, Unbounded}; -use fendermint_actor_blobs_shared::params::{GetStatsReturn, StorageCommittedReturn}; +use fendermint_actor_blobs_shared::params::{GetStatsReturn, StorageCommitment}; use fendermint_actor_blobs_shared::state::{ Account, Blob, BlobStatus, CreditApproval, Hash, PublicKey, Subscription, }; @@ -99,29 +99,29 @@ impl State { } } - pub fn get_storage_committed(&mut self, validator: Address) -> StorageCommittedReturn { + pub fn get_storage_commitment(&mut self, validator: Address) -> StorageCommitment { let storage_commitment = self.capacity_commited.entry(validator).or_default(); - StorageCommittedReturn { + StorageCommitment { address: validator, storage: *storage_commitment, } } - pub fn commit_storage(&mut self, validator: Address, amount: u64) -> Result { + pub fn commit_storage(&mut self, validator: Address, amount: u64) -> Result { let storage_commitment = self.capacity_commited.entry(validator).and_modify(|v| *v += amount).or_insert(amount); - Ok(StorageCommittedReturn { + Ok(StorageCommitment { address: validator, storage: *storage_commitment, }) } - pub fn uncommit_storage(&mut self, validator: Address, amount: u64) -> anyhow::Result { + pub fn uncommit_storage(&mut self, validator: Address, amount: u64) -> anyhow::Result { if let Entry::Occupied(mut entry) = self.capacity_commited.entry(validator) { let current = entry.get_mut(); // If current commitment is gt amount, deduct, otherwise remove the entry if *current > amount { *current -= amount; - return Ok(StorageCommittedReturn { + return Ok(StorageCommitment { address: validator, storage: *current, }) @@ -129,7 +129,7 @@ impl State { entry.remove(); } } - Ok(StorageCommittedReturn { + Ok(StorageCommitment { address: validator, storage: 0, }) From 8213b8cc61e7cdd77a208ad7e6b7ded62380e101 Mon Sep 17 00:00:00 2001 From: Sergey Ukustov Date: Wed, 30 Oct 2024 13:44:00 +0300 Subject: [PATCH 7/9] rename stuff --- fendermint/actors/blobs/shared/src/lib.rs | 4 +-- fendermint/actors/blobs/shared/src/params.rs | 2 +- fendermint/actors/blobs/src/actor.rs | 30 ++++++++++---------- fendermint/actors/blobs/src/state.rs | 4 +-- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/fendermint/actors/blobs/shared/src/lib.rs b/fendermint/actors/blobs/shared/src/lib.rs index 539ce0adf..4123e20f9 100644 --- a/fendermint/actors/blobs/shared/src/lib.rs +++ b/fendermint/actors/blobs/shared/src/lib.rs @@ -37,8 +37,8 @@ pub enum Method { FinalizeBlob = frc42_dispatch::method_hash!("FinalizeBlob"), DeleteBlob = frc42_dispatch::method_hash!("DeleteBlob"), GetStorageCommitment = frc42_dispatch::method_hash!("GetStorageCommitment"), - CommitStorage = frc42_dispatch::method_hash!("CommitStorage"), - UncommitStorage = frc42_dispatch::method_hash!("UncommitStorage"), + AddStorageCommitment = frc42_dispatch::method_hash!("CommitStorage"), + RemoveStorageCommitment = frc42_dispatch::method_hash!("UncommitStorage"), } pub fn buy_credit(rt: &impl Runtime, recipient: Address) -> Result { diff --git a/fendermint/actors/blobs/shared/src/params.rs b/fendermint/actors/blobs/shared/src/params.rs index c9c94a0fb..d64f94c88 100644 --- a/fendermint/actors/blobs/shared/src/params.rs +++ b/fendermint/actors/blobs/shared/src/params.rs @@ -24,7 +24,7 @@ pub struct StorageCommitment { /// Params to increase storage committed per validator. #[derive(Clone, Debug, Serialize_tuple, Deserialize_tuple)] -pub struct CommitStorageParams { +pub struct AddStorageCommitmentParams { pub address: Address, pub storage: u64, } diff --git a/fendermint/actors/blobs/src/actor.rs b/fendermint/actors/blobs/src/actor.rs index 4e4c769e5..5f191722d 100644 --- a/fendermint/actors/blobs/src/actor.rs +++ b/fendermint/actors/blobs/src/actor.rs @@ -4,7 +4,7 @@ use std::collections::HashSet; -use fendermint_actor_blobs_shared::params::{AddBlobParams, ApproveCreditParams, BuyCreditParams, DeleteBlobParams, FinalizeBlobParams, GetAccountParams, GetBlobParams, GetBlobStatusParams, GetPendingBlobsParams, GetStatsReturn, GetStorageCommittedParams, RevokeCreditParams, CommitStorageParams, StorageCommitment, UncommitStorageParams}; +use fendermint_actor_blobs_shared::params::{AddBlobParams, ApproveCreditParams, BuyCreditParams, DeleteBlobParams, FinalizeBlobParams, GetAccountParams, GetBlobParams, GetBlobStatusParams, GetPendingBlobsParams, GetStatsReturn, GetStorageCommittedParams, RevokeCreditParams, AddStorageCommitmentParams, StorageCommitment, UncommitStorageParams}; use fendermint_actor_blobs_shared::state::{ Account, Blob, BlobStatus, CreditApproval, Hash, PublicKey, Subscription, }; @@ -50,21 +50,21 @@ impl BlobsActor { Ok(storage_committed) } - fn commit_storage(rt: &impl Runtime, params: CommitStorageParams) -> Result { + fn add_storage_commitment(rt: &impl Runtime, params: AddStorageCommitmentParams) -> Result { rt.validate_immediate_caller_accept_any()?; let address = resolve_external_non_machine(rt, params.address)?; assert_message_source(rt, address)?; rt.transaction(|st: &mut State, _rt| { - st.commit_storage(address, params.storage) + st.add_storage_commitment(address, params.storage) }) } - fn uncommit_storage(rt: &impl Runtime, params: UncommitStorageParams) -> Result { + fn remove_storage_commitment(rt: &impl Runtime, params: UncommitStorageParams) -> Result { rt.validate_immediate_caller_accept_any()?; let address = resolve_external_non_machine(rt, params.address)?; assert_message_source(rt, address)?; rt.transaction(|st: &mut State, _rt| { - st.uncommit_storage(address, params.storage) + st.remove_storage_commitment(address, params.storage) }) } @@ -262,9 +262,9 @@ impl ActorCode for BlobsActor { actor_dispatch! { Constructor => constructor, GetStats => get_stats, - CommitStorage => commit_storage, - UncommitStorage => uncommit_storage, GetStorageCommitment => get_storage_commitment, + AddStorageCommitment => add_storage_commitment, + RemoveStorageCommitment => remove_storage_commitment, BuyCredit => buy_credit, ApproveCredit => approve_credit, RevokeCredit => revoke_credit, @@ -821,13 +821,13 @@ mod tests { // Commit 42 rt.expect_validate_caller_any(); - let commitment_params = CommitStorageParams { + let commitment_params = AddStorageCommitmentParams { // Use id_addr, see below why address: id_addr, storage: 42, }; let result = rt.call::( - Method::CommitStorage as u64, + Method::AddStorageCommitment as u64, IpldBlock::serialize_cbor(&commitment_params).unwrap(), ); rt.verify(); @@ -839,12 +839,12 @@ mod tests { // Commit 58 more, to get to 100 total rt.expect_validate_caller_any(); - let commitment_params = CommitStorageParams { + let commitment_params = AddStorageCommitmentParams { address: f4_eth_addr, storage: 58, }; let result = rt.call::( - Method::CommitStorage as u64, + Method::AddStorageCommitment as u64, IpldBlock::serialize_cbor(&commitment_params).unwrap(), ); rt.verify(); @@ -860,7 +860,7 @@ mod tests { storage: 20, }; let result = rt.call::( - Method::UncommitStorage as u64, + Method::RemoveStorageCommitment as u64, IpldBlock::serialize_cbor(&uncommit_params).unwrap(), ); rt.verify(); @@ -876,7 +876,7 @@ mod tests { storage: 200, }; let result = rt.call::( - Method::UncommitStorage as u64, + Method::RemoveStorageCommitment as u64, IpldBlock::serialize_cbor(&uncommit_params).unwrap(), ); rt.verify(); @@ -887,13 +887,13 @@ mod tests { // Try committing as a "wrong" address -> should err rt.expect_validate_caller_any(); - let commitment_params = CommitStorageParams { + let commitment_params = AddStorageCommitmentParams { // Use id_addr, see below why address: f4_eth_addr_wrong, storage: 42, }; let result = rt.call::( - Method::CommitStorage as u64, + Method::AddStorageCommitment as u64, IpldBlock::serialize_cbor(&commitment_params).unwrap(), ); rt.verify(); diff --git a/fendermint/actors/blobs/src/state.rs b/fendermint/actors/blobs/src/state.rs index 46d1045ba..684127f1c 100644 --- a/fendermint/actors/blobs/src/state.rs +++ b/fendermint/actors/blobs/src/state.rs @@ -107,7 +107,7 @@ impl State { } } - pub fn commit_storage(&mut self, validator: Address, amount: u64) -> Result { + pub fn add_storage_commitment(&mut self, validator: Address, amount: u64) -> Result { let storage_commitment = self.capacity_commited.entry(validator).and_modify(|v| *v += amount).or_insert(amount); Ok(StorageCommitment { address: validator, @@ -115,7 +115,7 @@ impl State { }) } - pub fn uncommit_storage(&mut self, validator: Address, amount: u64) -> anyhow::Result { + pub fn remove_storage_commitment(&mut self, validator: Address, amount: u64) -> anyhow::Result { if let Entry::Occupied(mut entry) = self.capacity_commited.entry(validator) { let current = entry.get_mut(); // If current commitment is gt amount, deduct, otherwise remove the entry From f815f62561e58a0897b2eb01deb7d328285d61f7 Mon Sep 17 00:00:00 2001 From: Sergey Ukustov Date: Wed, 30 Oct 2024 14:47:54 +0300 Subject: [PATCH 8/9] uncommit on zero --- fendermint/actors/blobs/shared/src/params.rs | 2 +- fendermint/actors/blobs/src/actor.rs | 23 +++++++++++++++----- fendermint/actors/blobs/src/state.rs | 16 +++++++++----- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/fendermint/actors/blobs/shared/src/params.rs b/fendermint/actors/blobs/shared/src/params.rs index d64f94c88..d7a8ab2d8 100644 --- a/fendermint/actors/blobs/shared/src/params.rs +++ b/fendermint/actors/blobs/shared/src/params.rs @@ -31,7 +31,7 @@ pub struct AddStorageCommitmentParams { /// Params to decrease storage committed per validator. #[derive(Clone, Debug, Serialize_tuple, Deserialize_tuple)] -pub struct UncommitStorageParams { +pub struct RemoveStorageCommitmentParams { pub address: Address, pub storage: u64, } diff --git a/fendermint/actors/blobs/src/actor.rs b/fendermint/actors/blobs/src/actor.rs index 5f191722d..7bf755794 100644 --- a/fendermint/actors/blobs/src/actor.rs +++ b/fendermint/actors/blobs/src/actor.rs @@ -4,7 +4,7 @@ use std::collections::HashSet; -use fendermint_actor_blobs_shared::params::{AddBlobParams, ApproveCreditParams, BuyCreditParams, DeleteBlobParams, FinalizeBlobParams, GetAccountParams, GetBlobParams, GetBlobStatusParams, GetPendingBlobsParams, GetStatsReturn, GetStorageCommittedParams, RevokeCreditParams, AddStorageCommitmentParams, StorageCommitment, UncommitStorageParams}; +use fendermint_actor_blobs_shared::params::{AddBlobParams, ApproveCreditParams, BuyCreditParams, DeleteBlobParams, FinalizeBlobParams, GetAccountParams, GetBlobParams, GetBlobStatusParams, GetPendingBlobsParams, GetStatsReturn, GetStorageCommittedParams, RevokeCreditParams, AddStorageCommitmentParams, StorageCommitment, RemoveStorageCommitmentParams}; use fendermint_actor_blobs_shared::state::{ Account, Blob, BlobStatus, CreditApproval, Hash, PublicKey, Subscription, }; @@ -59,7 +59,7 @@ impl BlobsActor { }) } - fn remove_storage_commitment(rt: &impl Runtime, params: UncommitStorageParams) -> Result { + fn remove_storage_commitment(rt: &impl Runtime, params: RemoveStorageCommitmentParams) -> Result { rt.validate_immediate_caller_accept_any()?; let address = resolve_external_non_machine(rt, params.address)?; assert_message_source(rt, address)?; @@ -855,7 +855,7 @@ mod tests { // Uncommit 20 rt.expect_validate_caller_any(); - let uncommit_params = UncommitStorageParams { + let uncommit_params = RemoveStorageCommitmentParams { address: f4_eth_addr, storage: 20, }; @@ -869,9 +869,9 @@ mod tests { assert_eq!(result_params.storage, 80); assert_eq!(get_storage_committed(&rt, id_addr).storage, 80); - // Uncommit 200 + // Uncommit 200 -> error rt.expect_validate_caller_any(); - let uncommit_params = UncommitStorageParams { + let uncommit_params = RemoveStorageCommitmentParams { address: id_addr, storage: 200, }; @@ -880,6 +880,19 @@ mod tests { IpldBlock::serialize_cbor(&uncommit_params).unwrap(), ); rt.verify(); + assert!(result.is_err()); + + // Uncommit 80 + rt.expect_validate_caller_any(); + let uncommit_params = RemoveStorageCommitmentParams { + address: id_addr, + storage: 80, + }; + let result = rt.call::( + Method::RemoveStorageCommitment as u64, + IpldBlock::serialize_cbor(&uncommit_params).unwrap(), + ); + rt.verify(); let result_params = result.unwrap().unwrap().deserialize::().unwrap(); assert_eq!(result_params.address, f4_eth_addr); assert_eq!(result_params.storage, 0); diff --git a/fendermint/actors/blobs/src/state.rs b/fendermint/actors/blobs/src/state.rs index 684127f1c..d9bcd608c 100644 --- a/fendermint/actors/blobs/src/state.rs +++ b/fendermint/actors/blobs/src/state.rs @@ -121,18 +121,22 @@ impl State { // If current commitment is gt amount, deduct, otherwise remove the entry if *current > amount { *current -= amount; - return Ok(StorageCommitment { + Ok(StorageCommitment { address: validator, storage: *current, }) - } else { + } else if *current == amount { entry.remove(); + Ok(StorageCommitment { + address: validator, + storage: 0, + }) + } else { + Err(ActorError::illegal_state(format!("can not remove more than currently committed on address {}", validator))) } + } else { + Err(ActorError::illegal_state(format!("no storage committed on address {}", validator))) } - Ok(StorageCommitment { - address: validator, - storage: 0, - }) } pub fn buy_credit( From 4fa33cc3630d0bf4998f9ca09cc837cea9b55c2a Mon Sep 17 00:00:00 2001 From: Sergey Ukustov Date: Wed, 30 Oct 2024 19:16:28 +0300 Subject: [PATCH 9/9] trigger build --- fendermint/actors/blobs/src/actor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fendermint/actors/blobs/src/actor.rs b/fendermint/actors/blobs/src/actor.rs index 7bf755794..11492a6ce 100644 --- a/fendermint/actors/blobs/src/actor.rs +++ b/fendermint/actors/blobs/src/actor.rs @@ -882,7 +882,7 @@ mod tests { rt.verify(); assert!(result.is_err()); - // Uncommit 80 + // Uncommit 80 -> okay rt.expect_validate_caller_any(); let uncommit_params = RemoveStorageCommitmentParams { address: id_addr,