diff --git a/actors/market/src/state.rs b/actors/market/src/state.rs index b290bcd81..9bcc0c705 100644 --- a/actors/market/src/state.rs +++ b/actors/market/src/state.rs @@ -74,7 +74,7 @@ pub struct State { } pub type PendingDealAllocationsMap = Map2; -pub const PENDING_ALLOCATIONS_CONF: Config = +pub const PENDING_ALLOCATIONS_CONFIG: Config = Config { bit_width: HAMT_BIT_WIDTH, ..DEFAULT_HAMT_CONFIG }; impl State { @@ -104,7 +104,7 @@ impl State { let empty_pending_deal_allocation_map = Map2::<&BS, DealID, AllocationID>::empty( store, - PENDING_ALLOCATIONS_CONF, + PENDING_ALLOCATIONS_CONFIG, "pending deal allocations", ) .flush()?; @@ -301,7 +301,7 @@ impl State { let mut pending_deal_allocation_ids = PendingDealAllocationsMap::load( store, &self.pending_deal_allocation_ids, - PENDING_ALLOCATIONS_CONF, + PENDING_ALLOCATIONS_CONFIG, "pending deal allocations", )?; @@ -327,7 +327,7 @@ impl State { let pending_deal_allocation_ids = PendingDealAllocationsMap::load( store, &self.pending_deal_allocation_ids, - PENDING_ALLOCATIONS_CONF, + PENDING_ALLOCATIONS_CONFIG, "pending deal allocations", )?; @@ -354,7 +354,7 @@ impl State { let mut pending_deal_allocation_ids = PendingDealAllocationsMap::load( store, &self.pending_deal_allocation_ids, - PENDING_ALLOCATIONS_CONF, + PENDING_ALLOCATIONS_CONFIG, "pending deal allocations", )?; diff --git a/actors/market/tests/harness.rs b/actors/market/tests/harness.rs index b3cc754e4..107ae8d96 100644 --- a/actors/market/tests/harness.rs +++ b/actors/market/tests/harness.rs @@ -3,7 +3,7 @@ use cid::Cid; use fil_actor_market::{ BatchActivateDealsParams, BatchActivateDealsResult, PendingDealAllocationsMap, - PENDING_ALLOCATIONS_CONF, + PENDING_ALLOCATIONS_CONFIG, }; use frc46_token::token::types::{TransferFromParams, TransferFromReturn}; use num_traits::{FromPrimitive, Zero}; @@ -403,7 +403,7 @@ pub fn get_pending_deal_allocation(rt: &MockRuntime, deal_id: DealID) -> Allocat let pending_allocations = PendingDealAllocationsMap::load( &rt.store, &st.pending_deal_allocation_ids, - PENDING_ALLOCATIONS_CONF, + PENDING_ALLOCATIONS_CONFIG, "pending deal allocations", ) .unwrap(); diff --git a/actors/market/tests/market_actor_test.rs b/actors/market/tests/market_actor_test.rs index ed70ce177..57a87df2f 100644 --- a/actors/market/tests/market_actor_test.rs +++ b/actors/market/tests/market_actor_test.rs @@ -8,7 +8,7 @@ use fil_actor_market::{ DealArray, DealMetaArray, Label, MarketNotifyDealParams, Method, PendingDealAllocationsMap, PublishStorageDealsParams, PublishStorageDealsReturn, SectorDeals, State, WithdrawBalanceParams, EX_DEAL_EXPIRED, MARKET_NOTIFY_DEAL_METHOD, NO_ALLOCATION_ID, - PENDING_ALLOCATIONS_CONF, PROPOSALS_AMT_BITWIDTH, STATES_AMT_BITWIDTH, + PENDING_ALLOCATIONS_CONFIG, PROPOSALS_AMT_BITWIDTH, STATES_AMT_BITWIDTH, }; use fil_actors_runtime::cbor::{deserialize, serialize}; use fil_actors_runtime::network::EPOCHS_IN_DAY; @@ -759,7 +759,7 @@ fn deal_expires() { let pending_allocs = PendingDealAllocationsMap::load( &rt.store, &st.pending_deal_allocation_ids, - PENDING_ALLOCATIONS_CONF, + PENDING_ALLOCATIONS_CONFIG, "pending allocations", ) .unwrap(); diff --git a/actors/multisig/src/lib.rs b/actors/multisig/src/lib.rs index 1530c038c..ea347ff81 100644 --- a/actors/multisig/src/lib.rs +++ b/actors/multisig/src/lib.rs @@ -1,10 +1,9 @@ // Copyright 2019-2022 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0, MIT -use fvm_actor_utils::receiver::UniversalReceiverParams; use std::collections::BTreeSet; -use fil_actors_runtime::FIRST_EXPORTED_METHOD_NUMBER; +use fvm_actor_utils::receiver::UniversalReceiverParams; use fvm_ipld_blockstore::Blockstore; use fvm_ipld_encoding::ipld_block::IpldBlock; use fvm_ipld_encoding::RawBytes; @@ -12,15 +11,16 @@ use fvm_shared::address::Address; use fvm_shared::econ::TokenAmount; use fvm_shared::error::ExitCode; use fvm_shared::MethodNum; -use fvm_shared::{HAMT_BIT_WIDTH, METHOD_CONSTRUCTOR}; +use fvm_shared::METHOD_CONSTRUCTOR; use num_derive::FromPrimitive; use num_traits::Zero; use fil_actors_runtime::cbor::serialize_vec; use fil_actors_runtime::runtime::{ActorCode, Primitives, Runtime}; +use fil_actors_runtime::FIRST_EXPORTED_METHOD_NUMBER; use fil_actors_runtime::{ - actor_dispatch, actor_error, extract_send_result, make_empty_map, make_map_with_root, - resolve_to_actor_id, ActorContext, ActorError, AsActorError, Map, INIT_ACTOR_ADDR, + actor_dispatch, actor_error, extract_send_result, resolve_to_actor_id, ActorContext, + ActorError, AsActorError, INIT_ACTOR_ADDR, }; pub use self::state::*; @@ -97,9 +97,7 @@ impl Actor { return Err(actor_error!(illegal_argument; "negative unlock duration disallowed")); } - let empty_root = make_empty_map::<_, ()>(rt.store(), HAMT_BIT_WIDTH) - .flush() - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to create empty map")?; + let empty_root = PendingTxnMap::empty(rt.store(), PENDING_TXN_CONFIG, "empty").flush()?; let mut st: State = State { signers: resolved_signers, @@ -141,9 +139,12 @@ impl Actor { return Err(actor_error!(forbidden, "{} is not a signer", proposer)); } - let mut ptx = make_map_with_root(&st.pending_txs, rt.store()) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load pending transactions")?; - + let mut ptx = PendingTxnMap::load( + rt.store(), + &st.pending_txs, + PENDING_TXN_CONFIG, + "pending txns", + )?; let t_id = st.next_tx_id; st.next_tx_id.0 += 1; @@ -155,21 +156,12 @@ impl Actor { approved: Vec::new(), }; - ptx.set(t_id.key(), txn.clone()).context_code( - ExitCode::USR_ILLEGAL_STATE, - "failed to put transaction for propose", - )?; - - st.pending_txs = ptx.flush().context_code( - ExitCode::USR_ILLEGAL_STATE, - "failed to flush pending transactions", - )?; - + ptx.set(&t_id, txn.clone())?; + st.pending_txs = ptx.flush()?; Ok((t_id, txn)) })?; let (applied, ret, code) = Self::approve_transaction(rt, txn_id, txn)?; - Ok(ProposeReturn { txn_id, applied, code, ret }) } @@ -183,9 +175,12 @@ impl Actor { if !st.is_signer(&approver) { return Err(actor_error!(forbidden; "{} is not a signer", approver)); } - - let ptx = make_map_with_root(&st.pending_txs, rt.store()) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load pending transactions")?; + let ptx = PendingTxnMap::load( + rt.store(), + &st.pending_txs, + PENDING_TXN_CONFIG, + "pending txns", + )?; let txn = get_transaction(rt, &ptx, params.id, params.proposal_hash)?; @@ -215,17 +210,16 @@ impl Actor { return Err(actor_error!(forbidden; "{} is not a signer", caller_addr)); } - let mut ptx = make_map_with_root::<_, Transaction>(&st.pending_txs, rt.store()) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load pending transactions")?; + let mut ptx = PendingTxnMap::load( + rt.store(), + &st.pending_txs, + PENDING_TXN_CONFIG, + "pending txns", + )?; - let (_, tx) = ptx - .delete(¶ms.id.key()) - .with_context_code(ExitCode::USR_ILLEGAL_STATE, || { - format!("failed to pop transaction {:?} for cancel", params.id) - })? - .ok_or_else(|| { - actor_error!(not_found, "no such transaction {:?} to cancel", params.id) - })?; + let tx = ptx.delete(¶ms.id)?.ok_or_else(|| { + actor_error!(not_found, "no such transaction {:?} to cancel", params.id) + })?; // Check to make sure transaction proposer is caller address if tx.approved.get(0) != Some(&caller_addr) { @@ -241,11 +235,7 @@ impl Actor { return Err(actor_error!(illegal_state, "hash does not match proposal params")); } - st.pending_txs = ptx.flush().context_code( - ExitCode::USR_ILLEGAL_STATE, - "failed to flush pending transactions", - )?; - + st.pending_txs = ptx.flush()?; Ok(()) }) } @@ -416,21 +406,18 @@ impl Actor { } let st = rt.transaction(|st: &mut State, rt| { - let mut ptx = make_map_with_root(&st.pending_txs, rt.store()) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load pending transactions")?; + let mut ptx = PendingTxnMap::load( + rt.store(), + &st.pending_txs, + PENDING_TXN_CONFIG, + "pending txns", + )?; // update approved on the transaction txn.approved.push(rt.message().caller()); - ptx.set(tx_id.key(), txn.clone()) - .with_context_code(ExitCode::USR_ILLEGAL_STATE, || { - format!("failed to put transaction {} for approval", tx_id.0) - })?; - - st.pending_txs = ptx.flush().context_code( - ExitCode::USR_ILLEGAL_STATE, - "failed to flush pending transactions", - )?; + ptx.set(&tx_id, txn.clone())?; + st.pending_txs = ptx.flush()?; // Go implementation holds reference to state after transaction so this must be cloned // to match to handle possible exit code inconsistency @@ -493,18 +480,14 @@ fn execute_transaction_if_approved( applied = true; rt.transaction(|st: &mut State, rt| { - let mut ptx = make_map_with_root::<_, Transaction>(&st.pending_txs, rt.store()) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load pending transactions")?; - - ptx.delete(&txn_id.key()).context_code( - ExitCode::USR_ILLEGAL_STATE, - "failed to delete transaction for cleanup", - )?; - - st.pending_txs = ptx.flush().context_code( - ExitCode::USR_ILLEGAL_STATE, - "failed to flush pending transactions", + let mut ptx = PendingTxnMap::load( + rt.store(), + &st.pending_txs, + PENDING_TXN_CONFIG, + "pending txns", )?; + ptx.delete(&txn_id)?; + st.pending_txs = ptx.flush()?; Ok(()) })?; } @@ -514,7 +497,7 @@ fn execute_transaction_if_approved( fn get_transaction<'m, BS, RT>( rt: &RT, - ptx: &'m Map<'_, BS, Transaction>, + ptx: &'m PendingTxnMap, txn_id: TxnID, proposal_hash: Vec, ) -> Result<&'m Transaction, ActorError> @@ -523,10 +506,7 @@ where RT: Runtime, { let txn = ptx - .get(&txn_id.key()) - .with_context_code(ExitCode::USR_ILLEGAL_STATE, || { - format!("failed to load transaction {:?} for approval", txn_id) - })? + .get(&txn_id)? .ok_or_else(|| actor_error!(not_found, "no such transaction {:?} for approval", txn_id))?; if !proposal_hash.is_empty() { diff --git a/actors/multisig/src/state.rs b/actors/multisig/src/state.rs index 8056e4bc4..054285298 100644 --- a/actors/multisig/src/state.rs +++ b/actors/multisig/src/state.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0, MIT use cid::Cid; -use fil_actors_runtime::{actor_error, ActorError, AsActorError}; use fvm_ipld_blockstore::Blockstore; use fvm_ipld_encoding::tuple::*; use fvm_shared::address::Address; @@ -10,13 +9,16 @@ use fvm_shared::bigint::BigInt; use fvm_shared::bigint::Integer; use fvm_shared::clock::ChainEpoch; use fvm_shared::econ::TokenAmount; -use fvm_shared::error::ExitCode; use indexmap::IndexMap; use num_traits::Zero; +use fil_actors_runtime::{actor_error, ActorError, Config, Map2, DEFAULT_HAMT_CONFIG}; + use super::types::Transaction; use super::TxnID; -use crate::make_map_with_root; + +pub type PendingTxnMap = Map2; +pub const PENDING_TXN_CONFIG: Config = DEFAULT_HAMT_CONFIG; /// Multisig actor state #[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)] @@ -76,37 +78,32 @@ impl State { store: &BS, addr: &Address, ) -> Result<(), ActorError> { - let mut txns = make_map_with_root(&self.pending_txs, store) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load txn map")?; + let mut txns = + PendingTxnMap::load(store, &self.pending_txs, PENDING_TXN_CONFIG, "pending txns")?; // Identify transactions that need updating let mut txn_ids_to_purge = IndexMap::new(); txns.for_each(|tx_id, txn: &Transaction| { for approver in txn.approved.iter() { if approver == addr { - txn_ids_to_purge.insert(tx_id.0.clone(), txn.clone()); + txn_ids_to_purge.insert(tx_id, txn.clone()); } } Ok(()) - }) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to scan txns")?; + })?; // Update or remove those transactions. for (tx_id, mut txn) in txn_ids_to_purge { txn.approved.retain(|approver| approver != addr); if !txn.approved.is_empty() { - txns.set(tx_id.into(), txn) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to update entry")?; + txns.set(&tx_id, txn)?; } else { - txns.delete(&tx_id) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to delete entry")?; + txns.delete(&tx_id)?; } } - self.pending_txs = - txns.flush().context_code(ExitCode::USR_ILLEGAL_STATE, "failed to store entries")?; - + self.pending_txs = txns.flush()?; Ok(()) } diff --git a/actors/multisig/src/testing.rs b/actors/multisig/src/testing.rs index 58dc328dc..02c3d6722 100644 --- a/actors/multisig/src/testing.rs +++ b/actors/multisig/src/testing.rs @@ -1,12 +1,11 @@ use std::{collections::HashSet, iter::FromIterator}; -use anyhow::anyhow; -use fil_actors_runtime::{Map, MessageAccumulator}; use fvm_ipld_blockstore::Blockstore; use fvm_shared::address::Address; -use integer_encoding::VarInt; -use crate::{State, Transaction, TxnID, SIGNERS_MAX}; +use fil_actors_runtime::MessageAccumulator; + +use crate::{PendingTxnMap, State, TxnID, PENDING_TXN_CONFIG, SIGNERS_MAX}; pub struct StateSummary { pub pending_tx_count: u64, @@ -54,15 +53,9 @@ pub fn check_state_invariants( let mut max_tx_id = TxnID(-1); let mut pending_tx_count = 0u64; - match Map::<_, Transaction>::load(&state.pending_txs, store) { + match PendingTxnMap::load(store, &state.pending_txs, PENDING_TXN_CONFIG, "pending txns") { Ok(transactions) => { let ret = transactions.for_each(|tx_id, transaction| { - let tx_id = TxnID( - i64::decode_var(tx_id) - .ok_or_else(|| anyhow!("failed to decode key: {:?}", tx_id))? - .0, - ); - if tx_id > max_tx_id { max_tx_id = tx_id; } diff --git a/actors/multisig/src/types.rs b/actors/multisig/src/types.rs index f5b78b28f..aff1cca9f 100644 --- a/actors/multisig/src/types.rs +++ b/actors/multisig/src/types.rs @@ -5,16 +5,15 @@ use std::fmt::Display; use fvm_ipld_encoding::tuple::*; use fvm_ipld_encoding::{strict_bytes, RawBytes}; -use fvm_ipld_hamt::BytesKey; use fvm_shared::address::Address; - use fvm_shared::clock::ChainEpoch; use fvm_shared::econ::TokenAmount; use fvm_shared::error::ExitCode; use fvm_shared::MethodNum; -use integer_encoding::VarInt; use serde::{Deserialize, Serialize}; +use fil_actors_runtime::MapKey; + /// SignersMax is the maximum number of signers allowed in a multisig. If more /// are required, please use a combining tree of multisigs. pub const SIGNERS_MAX: usize = 256; @@ -24,9 +23,13 @@ pub const SIGNERS_MAX: usize = 256; #[serde(transparent)] pub struct TxnID(pub i64); -impl TxnID { - pub fn key(self) -> BytesKey { - self.0.encode_var_vec().into() +impl MapKey for TxnID { + fn from_bytes(b: &[u8]) -> Result { + i64::from_bytes(b).map(TxnID) + } + + fn to_bytes(&self) -> Result, String> { + self.0.to_bytes() } } diff --git a/actors/power/src/lib.rs b/actors/power/src/lib.rs index d714ff25b..f922ea352 100644 --- a/actors/power/src/lib.rs +++ b/actors/power/src/lib.rs @@ -5,14 +5,6 @@ use std::collections::BTreeSet; use std::convert::TryInto; use anyhow::anyhow; -use ext::init; -use fil_actors_runtime::runtime::builtins::Type; -use fil_actors_runtime::runtime::{ActorCode, Runtime}; -use fil_actors_runtime::{ - actor_dispatch, actor_error, deserialize_block, extract_send_result, - make_map_with_root_and_bitwidth, ActorDowncast, ActorError, Multimap, CRON_ACTOR_ADDR, - INIT_ACTOR_ADDR, REWARD_ACTOR_ADDR, SYSTEM_ACTOR_ADDR, -}; use fvm_ipld_encoding::ipld_block::IpldBlock; use fvm_ipld_encoding::RawBytes; use fvm_shared::address::Address; @@ -26,6 +18,14 @@ use log::{debug, error}; use num_derive::FromPrimitive; use num_traits::Zero; +use ext::init; +use fil_actors_runtime::runtime::builtins::Type; +use fil_actors_runtime::runtime::{ActorCode, Runtime}; +use fil_actors_runtime::{ + actor_dispatch, actor_error, deserialize_block, extract_send_result, ActorDowncast, ActorError, + Multimap, CRON_ACTOR_ADDR, INIT_ACTOR_ADDR, REWARD_ACTOR_ADDR, SYSTEM_ACTOR_ADDR, +}; + pub use self::policy::*; pub use self::state::*; pub use self::types::*; @@ -118,10 +118,7 @@ impl Actor { let window_post_proof_type = params.window_post_proof_type; rt.transaction(|st: &mut State, rt| { - let mut claims = - make_map_with_root_and_bitwidth(&st.claims, rt.store(), HAMT_BIT_WIDTH).map_err( - |e| e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to load claims"), - )?; + let mut claims = st.load_claims(rt.store())?; set_claim( &mut claims, &id_address, @@ -130,13 +127,7 @@ impl Actor { quality_adj_power: Default::default(), raw_byte_power: Default::default(), }, - ) - .map_err(|e| { - e.downcast_default( - ExitCode::USR_ILLEGAL_STATE, - "failed to put power in claimed table while creating miner", - ) - })?; + )?; st.miner_count += 1; st.update_stats_for_new_miner(rt.policy(), window_post_proof_type).map_err(|e| { @@ -148,9 +139,7 @@ impl Actor { ) })?; - st.claims = claims.flush().map_err(|e| { - e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to flush claims") - })?; + st.save_claims(&mut claims)?; Ok(()) })?; Ok(CreateMinerReturn { id_address, robust_address }) @@ -166,10 +155,7 @@ impl Actor { let miner_addr = rt.message().caller(); rt.transaction(|st: &mut State, rt| { - let mut claims = - make_map_with_root_and_bitwidth(&st.claims, rt.store(), HAMT_BIT_WIDTH).map_err( - |e| e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to load claims"), - )?; + let mut claims = st.load_claims(rt.store())?; st.add_to_claim( rt.policy(), @@ -177,20 +163,9 @@ impl Actor { &miner_addr, ¶ms.raw_byte_delta, ¶ms.quality_adjusted_delta, - ) - .map_err(|e| { - e.downcast_default( - ExitCode::USR_ILLEGAL_STATE, - format!( - "failed to update power raw {}, qa {}", - params.raw_byte_delta, params.quality_adjusted_delta, - ), - ) - })?; + )?; - st.claims = claims.flush().map_err(|e| { - e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to flush claims") - })?; + st.save_claims(&mut claims)?; Ok(()) }) } @@ -448,11 +423,7 @@ impl Actor { } }; - let claims = match make_map_with_root_and_bitwidth::<_, Claim>( - &st.claims, - rt.store(), - HAMT_BIT_WIDTH, - ) { + let claims = match st.load_claims(rt.store()) { Ok(claims) => claims, Err(e) => { st_err = Some(format!("failed to load claims: {}", e)); @@ -468,7 +439,7 @@ impl Actor { } }; - let contains_claim = match claims.contains_key(&addr.to_bytes()) { + let contains_claim = match claims.contains_key(&addr) { Ok(contains_claim) => contains_claim, Err(e) => return Err(anyhow!("failed to look up clain: {}", e)), }; @@ -573,11 +544,7 @@ impl Actor { e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to load cron events") })?; - let claims = - make_map_with_root_and_bitwidth::<_, Claim>(&st.claims, rt.store(), HAMT_BIT_WIDTH) - .map_err(|e| { - e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to load claims") - })?; + let claims = st.load_claims(rt.store())?; for epoch in st.first_cron_epoch..=rt_epoch { let epoch_events = load_cron_events(&events, epoch).map_err(|e| { e.downcast_default( @@ -591,13 +558,7 @@ impl Actor { } for evt in epoch_events.into_iter() { - let miner_has_claim = - claims.contains_key(&evt.miner_addr.to_bytes()).map_err(|e| { - e.downcast_default( - ExitCode::USR_ILLEGAL_STATE, - "failed to look up claim", - ) - })?; + let miner_has_claim = claims.contains_key(&evt.miner_addr)?; if !miner_has_claim { debug!("skipping cron event for unknown miner: {}", evt.miner_addr); continue; @@ -646,11 +607,7 @@ impl Actor { if !failed_miner_crons.is_empty() { rt.transaction(|st: &mut State, rt| { - let mut claims = - make_map_with_root_and_bitwidth(&st.claims, rt.store(), HAMT_BIT_WIDTH) - .map_err(|e| { - e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to load claims") - })?; + let mut claims = st.load_claims(rt.store())?; // Remove power and leave miner frozen for miner_addr in failed_miner_crons { @@ -664,10 +621,7 @@ impl Actor { } st.miner_count -= 1 } - - st.claims = claims.flush().map_err(|e| { - e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to flush claims") - })?; + st.save_claims(&mut claims)?; Ok(()) })?; } diff --git a/actors/power/src/state.rs b/actors/power/src/state.rs index e47b76daa..9f8edbb52 100644 --- a/actors/power/src/state.rs +++ b/actors/power/src/state.rs @@ -5,11 +5,6 @@ use std::ops::Neg; use anyhow::anyhow; use cid::Cid; -use fil_actors_runtime::runtime::Policy; -use fil_actors_runtime::{ - actor_error, make_empty_map, make_map_with_root, make_map_with_root_and_bitwidth, - ActorDowncast, ActorError, AsActorError, Map, Multimap, -}; use fvm_ipld_blockstore::Blockstore; use fvm_ipld_encoding::tuple::*; use fvm_ipld_encoding::RawBytes; @@ -21,12 +16,18 @@ use fvm_shared::econ::TokenAmount; use fvm_shared::error::ExitCode; use fvm_shared::sector::{RegisteredPoStProof, StoragePower}; use fvm_shared::smooth::{AlphaBetaFilter, FilterEstimate, DEFAULT_ALPHA, DEFAULT_BETA}; -use fvm_shared::{ActorID, HAMT_BIT_WIDTH}; +use fvm_shared::ActorID; use integer_encoding::VarInt; use lazy_static::lazy_static; use num_traits::Signed; -use super::{CONSENSUS_MINER_MIN_MINERS, CRON_QUEUE_AMT_BITWIDTH, CRON_QUEUE_HAMT_BITWIDTH}; +use fil_actors_runtime::runtime::Policy; +use fil_actors_runtime::{ + actor_error, ActorContext, ActorDowncast, ActorError, AsActorError, Config, Map2, Multimap, + DEFAULT_HAMT_CONFIG, +}; + +use super::CONSENSUS_MINER_MIN_MINERS; lazy_static! { /// genesis power in bytes = 750,000 GiB @@ -35,6 +36,13 @@ lazy_static! { pub static ref INITIAL_QA_POWER_ESTIMATE_VELOCITY: StoragePower = StoragePower::from(3_840) * (1 << 30); } +pub const CRON_QUEUE_HAMT_BITWIDTH: u32 = 6; +pub const CRON_QUEUE_AMT_BITWIDTH: u32 = 6; +pub const PROOF_VALIDATION_BATCH_AMT_BITWIDTH: u32 = 4; + +pub type ClaimsMap = Map2; +pub const CLAIMS_CONFIG: Config = DEFAULT_HAMT_CONFIG; + /// Storage power actor state #[derive(Default, Serialize_tuple, Deserialize_tuple, Clone, Debug)] pub struct State { @@ -74,18 +82,13 @@ pub struct State { impl State { pub fn new(store: &BS) -> anyhow::Result { - let empty_map = make_empty_map::<_, ()>(store, HAMT_BIT_WIDTH) - .flush() - .map_err(|e| anyhow!("Failed to create empty map: {}", e))?; - + let empty_claims = ClaimsMap::empty(store, CLAIMS_CONFIG, "empty").flush()?; let empty_mmap = Multimap::new(store, CRON_QUEUE_HAMT_BITWIDTH, CRON_QUEUE_AMT_BITWIDTH) .root() - .map_err(|e| { - e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "Failed to get empty multimap cid") - })?; + .context_code(ExitCode::USR_ILLEGAL_STATE, "Failed to get empty multimap cid")?; Ok(State { cron_event_queue: empty_mmap, - claims: empty_map, + claims: empty_claims, this_epoch_qa_power_smoothed: FilterEstimate::new( INITIAL_QA_POWER_ESTIMATE_POSITION.clone(), INITIAL_QA_POWER_ESTIMATE_VELOCITY.clone(), @@ -105,18 +108,11 @@ impl State { s: &BS, miner: ActorID, ) -> Result<(StoragePower, bool), ActorError> { - let claims = make_map_with_root_and_bitwidth(&self.claims, s, HAMT_BIT_WIDTH) - .with_context_code(ExitCode::USR_ILLEGAL_STATE, || { - format!("failed to load claims for miner: {}", miner) - })?; - - let claim = get_claim(&claims, &Address::new_id(miner)) - .with_context_code(ExitCode::USR_ILLEGAL_STATE, || { - format!("failed to get claim for miner: {}", miner) - })? - .with_context_code(ExitCode::USR_ILLEGAL_ARGUMENT, || { - format!("no claim for actor: {}", miner) - })?; + let claims = self.load_claims(s)?; + let a = &Address::new_id(miner); + let claim = claims.get(a)?.with_context_code(ExitCode::USR_ILLEGAL_ARGUMENT, || { + format!("no claim for actor: {}", miner) + })?; let miner_nominal_power = claim.raw_byte_power.clone(); let miner_min_power = consensus_miner_min_power(policy, claim.window_post_proof_type) @@ -141,20 +137,21 @@ impl State { &self, s: &BS, miner: &Address, - ) -> anyhow::Result> { - let claims = make_map_with_root(&self.claims, s)?; - get_claim(&claims, miner).map(|s| s.cloned()) + ) -> Result, ActorError> { + let claims = self.load_claims(s)?; + claims.get(miner).map(|s| s.cloned()) } pub(super) fn add_to_claim( &mut self, policy: &Policy, - claims: &mut Map, + claims: &mut ClaimsMap, miner: &Address, power: &StoragePower, qa_power: &StoragePower, - ) -> anyhow::Result<()> { - let old_claim = get_claim(claims, miner)? + ) -> Result<(), ActorError> { + let old_claim = claims + .get(miner)? .ok_or_else(|| actor_error!(not_found, "no claim for actor {}", miner))?; self.total_qa_bytes_committed += qa_power; @@ -167,7 +164,8 @@ impl State { }; let min_power: StoragePower = - consensus_miner_min_power(policy, old_claim.window_post_proof_type)?; + consensus_miner_min_power(policy, old_claim.window_post_proof_type) + .exit_code(ExitCode::USR_ILLEGAL_STATE)?; let prev_below: bool = old_claim.raw_byte_power < min_power; let still_below: bool = new_claim.raw_byte_power < min_power; @@ -194,30 +192,42 @@ impl State { } if new_claim.raw_byte_power.is_negative() { - return Err(anyhow!(actor_error!( + return Err(actor_error!( illegal_state, "negative claimed raw byte power: {}", new_claim.raw_byte_power - ))); + )); } if new_claim.quality_adj_power.is_negative() { - return Err(anyhow!(actor_error!( + return Err(actor_error!( illegal_state, "negative claimed quality adjusted power: {}", new_claim.quality_adj_power - ))); + )); } if self.miner_above_min_power_count < 0 { - return Err(anyhow!(actor_error!( + return Err(actor_error!( illegal_state, "negative amount of miners lather than min: {}", self.miner_above_min_power_count - ))); + )); } set_claim(claims, miner, new_claim) } + pub fn load_claims(&self, s: BS) -> Result, ActorError> { + ClaimsMap::load(s, &self.claims, CLAIMS_CONFIG, "claims") + } + + pub fn save_claims( + &mut self, + claims: &mut ClaimsMap, + ) -> Result<(), ActorError> { + self.claims = claims.flush()?; + Ok(()) + } + pub(super) fn add_pledge_total(&mut self, amount: TokenAmount) { self.total_pledge_collateral += amount; } @@ -280,13 +290,8 @@ impl State { where BS: Blockstore, { - let claims = make_map_with_root::<_, Claim>(&self.claims, store).map_err(|e| { - e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to load claims") - })?; - - if !claims.contains_key(&miner_addr.to_bytes()).map_err(|e| { - e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to look up claim") - })? { + let claims = self.load_claims(store)?; + if !claims.contains_key(miner_addr)? { return Err(actor_error!( forbidden, "unknown miner {} forbidden to interact with power actor", @@ -301,38 +306,30 @@ impl State { store: &BS, miner: &Address, ) -> anyhow::Result> { - let claims = - make_map_with_root_and_bitwidth::<_, Claim>(&self.claims, store, HAMT_BIT_WIDTH) - .map_err(|e| { - e.downcast_default(ExitCode::USR_ILLEGAL_STATE, "failed to load claims") - })?; - - let claim = get_claim(&claims, miner)?; + let claims = self.load_claims(store)?; + let claim = claims.get(miner)?; Ok(claim.cloned()) } pub(super) fn delete_claim( &mut self, policy: &Policy, - claims: &mut Map, + claims: &mut ClaimsMap, miner: &Address, ) -> anyhow::Result<()> { - let (rbp, qap) = - match get_claim(claims, miner).map_err(|e| e.downcast_wrap("failed to get claim"))? { - None => { - return Ok(()); - } - Some(claim) => (claim.raw_byte_power.clone(), claim.quality_adj_power.clone()), - }; + let (rbp, qap) = match claims.get(miner)? { + None => { + return Ok(()); + } + Some(claim) => (claim.raw_byte_power.clone(), claim.quality_adj_power.clone()), + }; // Subtract from stats to remove power self.add_to_claim(policy, claims, miner, &rbp.neg(), &qap.neg()) - .map_err(|e| e.downcast_wrap("failed to subtract miner power before deleting claim"))?; - + .context("subtract miner power before deleting claim")?; claims - .delete(&miner.to_bytes()) - .map_err(|e| e.downcast_wrap(format!("failed to delete claim for address {}", miner)))? - .ok_or_else(|| anyhow!("failed to delete claim for address: doesn't exist"))?; + .delete(miner)? + .ok_or_else(|| anyhow!("failed to delete claim for {miner}: doesn't exist"))?; Ok(()) } } @@ -351,39 +348,27 @@ pub(super) fn load_cron_events( Ok(events) } -/// Gets claim from claims map by address -fn get_claim<'m, BS: Blockstore>( - claims: &'m Map, - a: &Address, -) -> anyhow::Result> { - claims - .get(&a.to_bytes()) - .map_err(|e| e.downcast_wrap(format!("failed to get claim for address {}", a))) -} - pub fn set_claim( - claims: &mut Map, + claims: &mut ClaimsMap, a: &Address, claim: Claim, -) -> anyhow::Result<()> { +) -> Result<(), ActorError> { if claim.raw_byte_power.is_negative() { - return Err(anyhow!(actor_error!( + return Err(actor_error!( illegal_state, "negative claim raw power {}", claim.raw_byte_power - ))); + )); } if claim.quality_adj_power.is_negative() { - return Err(anyhow!(actor_error!( + return Err(actor_error!( illegal_state, "negative claim quality-adjusted power {}", claim.quality_adj_power - ))); + )); } - claims - .set(a.to_bytes().into(), claim) - .map_err(|e| e.downcast_wrap(format!("failed to set claim for address {}", a)))?; + claims.set(a, claim)?; Ok(()) } diff --git a/actors/power/src/testing.rs b/actors/power/src/testing.rs index b3c58f9ef..e6c9d8131 100644 --- a/actors/power/src/testing.rs +++ b/actors/power/src/testing.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use fil_actors_runtime::{parse_uint_key, runtime::Policy, Map, MessageAccumulator, Multimap}; use fvm_ipld_blockstore::Blockstore; use fvm_ipld_encoding::RawBytes; use fvm_shared::{ @@ -11,9 +10,11 @@ use fvm_shared::{ }; use num_traits::{Signed, Zero}; +use fil_actors_runtime::{parse_uint_key, runtime::Policy, MessageAccumulator, Multimap}; + use crate::{ - consensus_miner_min_power, Claim, CronEvent, State, CRON_QUEUE_AMT_BITWIDTH, - CRON_QUEUE_HAMT_BITWIDTH, MAX_MINER_PROVE_COMMITS_PER_EPOCH, + consensus_miner_min_power, Claim, ClaimsMap, CronEvent, State, CLAIMS_CONFIG, + CRON_QUEUE_AMT_BITWIDTH, CRON_QUEUE_HAMT_BITWIDTH, MAX_MINER_PROVE_COMMITS_PER_EPOCH, PROOF_VALIDATION_BATCH_AMT_BITWIDTH, }; @@ -156,12 +157,10 @@ fn check_claims_invariants( let mut qa_power = StoragePower::zero(); let mut claims_with_sufficient_power_count = 0; - match Map::<_, Claim>::load(&state.claims, store) { + match ClaimsMap::load(store, &state.claims, CLAIMS_CONFIG, "claims") { Ok(claims) => { - let ret = claims.for_each(|key, claim| { - let address = Address::from_bytes(key)?; + let ret = claims.for_each(|address, claim| { claims_by_address.insert(address, claim.clone()); - committed_raw_power += &claim.raw_byte_power; committed_qa_power += &claim.quality_adj_power; diff --git a/actors/power/src/types.rs b/actors/power/src/types.rs index 0e5fdc132..57316ede9 100644 --- a/actors/power/src/types.rs +++ b/actors/power/src/types.rs @@ -22,10 +22,6 @@ pub const SECTOR_TERMINATION_MANUAL: SectorTermination = 1; /// Implicit termination due to unrecovered fault pub const SECTOR_TERMINATION_FAULTY: SectorTermination = 3; -pub const CRON_QUEUE_HAMT_BITWIDTH: u32 = 6; -pub const CRON_QUEUE_AMT_BITWIDTH: u32 = 6; -pub const PROOF_VALIDATION_BATCH_AMT_BITWIDTH: u32 = 4; - #[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, Eq, PartialEq)] pub struct CreateMinerParams { pub owner: Address, diff --git a/actors/power/tests/harness/mod.rs b/actors/power/tests/harness/mod.rs index 7d747e844..71d0fe214 100644 --- a/actors/power/tests/harness/mod.rs +++ b/actors/power/tests/harness/mod.rs @@ -1,28 +1,10 @@ use std::cell::RefCell; use cid::Cid; -use fil_actor_power::detail::GAS_ON_SUBMIT_VERIFY_SEAL; -use fil_actor_power::ext::miner::ConfirmSectorProofsParams; -use fil_actor_power::ext::miner::CONFIRM_SECTOR_PROOFS_VALID_METHOD; -use fil_actor_power::ext::reward::Method::ThisEpochReward; -use fil_actor_power::ext::reward::UPDATE_NETWORK_KPI; -use fil_actor_power::testing::check_state_invariants; -use fil_actor_power::EnrollCronEventParams; -use fil_actor_power::CRON_QUEUE_AMT_BITWIDTH; -use fil_actor_power::CRON_QUEUE_HAMT_BITWIDTH; -use fil_actor_power::{epoch_key, MinerCountReturn}; -use fil_actor_power::{CronEvent, MinerConsensusCountReturn}; -use fil_actors_runtime::runtime::RuntimePolicy; -use fil_actors_runtime::test_utils::CRON_ACTOR_CODE_ID; -use fil_actors_runtime::Multimap; -use fil_actors_runtime::CRON_ACTOR_ADDR; -use fil_actors_runtime::REWARD_ACTOR_ADDR; use fvm_ipld_blockstore::Blockstore; +use fvm_ipld_encoding::ipld_block::IpldBlock; use fvm_ipld_encoding::{BytesDe, RawBytes}; -use fvm_ipld_hamt::BytesKey; -use fvm_ipld_hamt::Error; use fvm_shared::address::Address; -use fvm_shared::bigint::bigint_ser::BigIntDe; use fvm_shared::bigint::bigint_ser::BigIntSer; use fvm_shared::bigint::BigInt; use fvm_shared::clock::ChainEpoch; @@ -39,23 +21,36 @@ use num_traits::Zero; use serde::de::DeserializeOwned; use serde::Serialize; +use fil_actor_power::detail::GAS_ON_SUBMIT_VERIFY_SEAL; use fil_actor_power::ext::init::ExecParams; +use fil_actor_power::ext::miner::ConfirmSectorProofsParams; use fil_actor_power::ext::miner::MinerConstructorParams; +use fil_actor_power::ext::miner::CONFIRM_SECTOR_PROOFS_VALID_METHOD; +use fil_actor_power::ext::reward::Method::ThisEpochReward; +use fil_actor_power::ext::reward::UPDATE_NETWORK_KPI; +use fil_actor_power::testing::check_state_invariants; +use fil_actor_power::EnrollCronEventParams; +use fil_actor_power::CRON_QUEUE_AMT_BITWIDTH; +use fil_actor_power::CRON_QUEUE_HAMT_BITWIDTH; +use fil_actor_power::{epoch_key, MinerCountReturn}; use fil_actor_power::{ ext, Claim, CreateMinerParams, CreateMinerReturn, CurrentTotalPowerReturn, Method, State, UpdateClaimedPowerParams, }; -use fil_actors_runtime::builtin::HAMT_BIT_WIDTH; +use fil_actor_power::{CronEvent, MinerConsensusCountReturn}; use fil_actors_runtime::runtime::builtins::Type; use fil_actors_runtime::runtime::Runtime; +use fil_actors_runtime::runtime::RuntimePolicy; +use fil_actors_runtime::test_utils::CRON_ACTOR_CODE_ID; use fil_actors_runtime::test_utils::{ MockRuntime, ACCOUNT_ACTOR_CODE_ID, MINER_ACTOR_CODE_ID, SYSTEM_ACTOR_CODE_ID, }; +use fil_actors_runtime::REWARD_ACTOR_ADDR; use fil_actors_runtime::{ - make_map_with_root_and_bitwidth, ActorError, Map, INIT_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR, - SYSTEM_ACTOR_ADDR, + ActorError, INIT_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR, SYSTEM_ACTOR_ADDR, }; -use fvm_ipld_encoding::ipld_block::IpldBlock; +use fil_actors_runtime::{Map2, MapKey, Multimap}; +use fil_actors_runtime::{CRON_ACTOR_ADDR, DEFAULT_HAMT_CONFIG}; use crate::PowerActor; @@ -207,10 +202,8 @@ impl Harness { pub fn list_miners(&self, rt: &MockRuntime) -> Vec
{ let st: State = rt.get_state(); - let claims: Map<_, Claim> = - make_map_with_root_and_bitwidth(&st.claims, rt.store(), HAMT_BIT_WIDTH).unwrap(); - let keys = collect_keys(claims).unwrap(); - keys.iter().map(|k| Address::from_bytes(k).unwrap()).collect::>() + let claims = st.load_claims(rt.store()).unwrap(); + collect_keys(claims).unwrap() } pub fn miner_count(&self, rt: &MockRuntime) -> i64 { @@ -237,10 +230,8 @@ impl Harness { pub fn delete_claim(&mut self, rt: &MockRuntime, miner: &Address) { let mut state: State = rt.get_state(); - let mut claims = - make_map_with_root_and_bitwidth::<_, Claim>(&state.claims, rt.store(), HAMT_BIT_WIDTH) - .unwrap(); - claims.delete(&miner.to_bytes()).expect("Failed to delete claim"); + let mut claims = state.load_claims(rt.store()).unwrap(); + claims.delete(miner).expect("Failed to delete claim"); state.claims = claims.flush().unwrap(); rt.replace_state(&state); @@ -489,22 +480,22 @@ pub fn batch_verify_default_output(infos: &[SealVerifyInfo]) -> Vec { } /// Collects all keys from a map into a vector. -fn collect_keys(m: Map) -> Result, Error> +fn collect_keys(m: Map2) -> Result, ActorError> where BS: Blockstore, + K: MapKey + Clone, V: DeserializeOwned + Serialize, { let mut ret_keys = Vec::new(); m.for_each(|k, _| { - ret_keys.push(k.clone()); + ret_keys.push(k); Ok(()) })?; - Ok(ret_keys) } pub fn verify_empty_map(rt: &MockRuntime, key: Cid) { let map = - make_map_with_root_and_bitwidth::<_, BigIntDe>(&key, &rt.store, HAMT_BIT_WIDTH).unwrap(); + Map2::<_, Vec, Vec>::load(&rt.store, &key, DEFAULT_HAMT_CONFIG, "empty?").unwrap(); map.for_each(|_key, _val| panic!("expected no keys")).unwrap(); } diff --git a/actors/verifreg/src/expiration.rs b/actors/verifreg/src/expiration.rs index 53b13a05e..9df270e69 100644 --- a/actors/verifreg/src/expiration.rs +++ b/actors/verifreg/src/expiration.rs @@ -40,7 +40,7 @@ where { let mut found_ids = Vec::::new(); collection - .for_each(owner, |key, record| { + .for_each_in(owner, |key, record| { if curr_epoch >= record.expiration() { let id = parse_uint_key(key) .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to parse uint key")?; diff --git a/actors/verifreg/src/lib.rs b/actors/verifreg/src/lib.rs index e86299e02..4ac69bd44 100644 --- a/actors/verifreg/src/lib.rs +++ b/actors/verifreg/src/lib.rs @@ -6,15 +6,15 @@ use frc46_token::token::types::{BurnParams, TransferParams}; use frc46_token::token::TOKEN_PRECISION; use fvm_actor_utils::receiver::UniversalReceiverParams; use fvm_ipld_blockstore::Blockstore; +use fvm_ipld_encoding::ipld_block::IpldBlock; use fvm_ipld_encoding::RawBytes; -use fvm_ipld_hamt::BytesKey; use fvm_shared::address::Address; -use fvm_shared::bigint::bigint_ser::BigIntDe; use fvm_shared::bigint::BigInt; use fvm_shared::clock::ChainEpoch; use fvm_shared::econ::TokenAmount; use fvm_shared::error::ExitCode; -use fvm_shared::{ActorID, HAMT_BIT_WIDTH, METHOD_CONSTRUCTOR}; +use fvm_shared::sys::SendFlags; +use fvm_shared::{ActorID, METHOD_CONSTRUCTOR}; use log::info; use num_derive::FromPrimitive; use num_traits::{Signed, Zero}; @@ -23,16 +23,16 @@ use fil_actors_runtime::cbor::deserialize; use fil_actors_runtime::runtime::builtins::Type; use fil_actors_runtime::runtime::{ActorCode, Policy, Runtime}; use fil_actors_runtime::{ - actor_dispatch, actor_error, deserialize_block, extract_send_result, - make_map_with_root_and_bitwidth, resolve_to_actor_id, ActorDowncast, ActorError, BatchReturn, - Map, DATACAP_TOKEN_ACTOR_ADDR, STORAGE_MARKET_ACTOR_ADDR, SYSTEM_ACTOR_ADDR, - VERIFIED_REGISTRY_ACTOR_ADDR, + actor_dispatch, actor_error, deserialize_block, extract_send_result, resolve_to_actor_id, + ActorError, BatchReturn, DATACAP_TOKEN_ACTOR_ADDR, STORAGE_MARKET_ACTOR_ADDR, + SYSTEM_ACTOR_ADDR, VERIFIED_REGISTRY_ACTOR_ADDR, }; use fil_actors_runtime::{ActorContext, AsActorError, BatchReturnGen}; -use fvm_ipld_encoding::ipld_block::IpldBlock; -use fvm_shared::sys::SendFlags; use crate::ext::datacap::{DestroyParams, MintParams}; +use crate::state::{ + DataCapMap, RemoveDataCapProposalMap, DATACAP_MAP_CONFIG, REMOVE_DATACAP_PROPOSALS_CONFIG, +}; pub use self::state::Allocation; pub use self::state::Claim; @@ -247,25 +247,18 @@ impl Actor { } // validate signatures - let mut proposal_ids = make_map_with_root_and_bitwidth::<_, RemoveDataCapProposalID>( - &st.remove_data_cap_proposal_ids, + let mut proposal_ids = RemoveDataCapProposalMap::load( rt.store(), - HAMT_BIT_WIDTH, - ) - .map_err(|e| { - e.downcast_default( - ExitCode::USR_ILLEGAL_STATE, - "failed to load datacap removal proposal ids", - ) - })?; + &st.remove_data_cap_proposal_ids, + REMOVE_DATACAP_PROPOSALS_CONFIG, + "remove datacap proposals", + )?; let verifier_1_id = use_proposal_id(&mut proposal_ids, verifier_1, client)?; let verifier_2_id = use_proposal_id(&mut proposal_ids, verifier_2, client)?; // Assume proposal ids are valid and increment them - st.remove_data_cap_proposal_ids = proposal_ids - .flush() - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to flush proposal ids")?; + st.remove_data_cap_proposal_ids = proposal_ids.flush()?; Ok((verifier_1_id, verifier_2_id)) })?; @@ -708,15 +701,9 @@ impl Actor { // Checks whether an address has a verifier entry (which could be zero). fn is_verifier(rt: &impl Runtime, st: &State, address: Address) -> Result { - let verifiers = - make_map_with_root_and_bitwidth::<_, BigIntDe>(&st.verifiers, rt.store(), HAMT_BIT_WIDTH) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load verifiers")?; - + let verifiers = DataCapMap::load(rt.store(), &st.verifiers, DATACAP_MAP_CONFIG, "verifiers")?; // check that the `address` is currently a verified client - let found = verifiers - .contains_key(&address.to_bytes()) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to get verifier")?; - + let found = verifiers.contains_key(&address)?; Ok(found) } @@ -818,7 +805,7 @@ fn tokens_to_datacap(amount: &TokenAmount) -> BigInt { } fn use_proposal_id( - proposal_ids: &mut Map, + proposal_ids: &mut RemoveDataCapProposalMap, verifier: Address, client: Address, ) -> Result @@ -826,16 +813,8 @@ where BS: Blockstore, { let key = AddrPairKey::new(verifier, client); - - let maybe_id = proposal_ids.get(&key.to_bytes()).map_err(|e| { - actor_error!( - illegal_state, - "failed to get proposal id for verifier {} and client {}: {}", - verifier, - client, - e - ) - })?; + let maybe_id = + proposal_ids.get(&key).with_context(|| format!("verifier {verifier} client {client}"))?; let curr_id = if let Some(RemoveDataCapProposalID { id }) = maybe_id { RemoveDataCapProposalID { id: *id } @@ -844,16 +823,9 @@ where }; let next_id = RemoveDataCapProposalID { id: curr_id.id + 1 }; - proposal_ids.set(BytesKey::from(key.to_bytes()), next_id).map_err(|e| { - actor_error!( - illegal_state, - "failed to update proposal id for verifier {} and client {}: {}", - verifier, - client, - e - ) - })?; - + proposal_ids + .set(&key, next_id) + .with_context(|| format!("verifier {verifier} client {client}"))?; Ok(curr_id) } diff --git a/actors/verifreg/src/state.rs b/actors/verifreg/src/state.rs index bdd1d1ead..10c983f8f 100644 --- a/actors/verifreg/src/state.rs +++ b/actors/verifreg/src/state.rs @@ -13,12 +13,17 @@ use fvm_shared::sector::SectorNumber; use fvm_shared::{ActorID, HAMT_BIT_WIDTH}; use fil_actors_runtime::{ - actor_error, make_empty_map, make_map_with_root_and_bitwidth, ActorError, AsActorError, Map, - MapMap, + actor_error, ActorError, AsActorError, Config, Map2, MapMap, DEFAULT_HAMT_CONFIG, }; -use crate::DataCap; -use crate::{AllocationID, ClaimID}; +use crate::{AddrPairKey, AllocationID, ClaimID}; +use crate::{DataCap, RemoveDataCapProposalID}; + +pub type DataCapMap = Map2; +pub const DATACAP_MAP_CONFIG: Config = DEFAULT_HAMT_CONFIG; + +pub type RemoveDataCapProposalMap = Map2; +pub const REMOVE_DATACAP_PROPOSALS_CONFIG: Config = DEFAULT_HAMT_CONFIG; #[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone)] pub struct State { @@ -37,11 +42,8 @@ pub struct State { impl State { pub fn new(store: &BS, root_key: Address) -> Result { - let empty_map = make_empty_map::<_, ()>(store, HAMT_BIT_WIDTH) - .flush() - .map_err(|e| actor_error!(illegal_state, "failed to create empty map: {}", e))?; - - let empty_mapmap = + let empty_dcap = DataCapMap::empty(store, DATACAP_MAP_CONFIG, "empty").flush()?; + let empty_allocs_claims = MapMap::<_, (), ActorID, u64>::new(store, HAMT_BIT_WIDTH, HAMT_BIT_WIDTH) .flush() .map_err(|e| { @@ -50,11 +52,11 @@ impl State { Ok(State { root_key, - verifiers: empty_map, - remove_data_cap_proposal_ids: empty_map, - allocations: empty_mapmap, + verifiers: empty_dcap, + remove_data_cap_proposal_ids: empty_dcap, + allocations: empty_allocs_claims, next_allocation_id: 1, - claims: empty_mapmap, + claims: empty_allocs_claims, }) } @@ -65,15 +67,9 @@ impl State { verifier: &Address, cap: &DataCap, ) -> Result<(), ActorError> { - let mut verifiers = - make_map_with_root_and_bitwidth::<_, BigIntDe>(&self.verifiers, store, HAMT_BIT_WIDTH) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load verifiers")?; - verifiers - .set(verifier.to_bytes().into(), BigIntDe(cap.clone())) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to set verifier")?; - self.verifiers = verifiers - .flush() - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to flush verifiers")?; + let mut verifiers = self.load_verifiers(store)?; + verifiers.set(verifier, BigIntDe(cap.clone()))?; + self.verifiers = verifiers.flush()?; Ok(()) } @@ -82,18 +78,11 @@ impl State { store: &impl Blockstore, verifier: &Address, ) -> Result<(), ActorError> { - let mut verifiers = - make_map_with_root_and_bitwidth::<_, BigIntDe>(&self.verifiers, store, HAMT_BIT_WIDTH) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load verifiers")?; - + let mut verifiers = self.load_verifiers(store)?; verifiers - .delete(&verifier.to_bytes()) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to remove verifier")? + .delete(verifier)? .context_code(ExitCode::USR_ILLEGAL_ARGUMENT, "verifier not found")?; - - self.verifiers = verifiers - .flush() - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to flush verifiers")?; + self.verifiers = verifiers.flush()?; Ok(()) } @@ -102,21 +91,13 @@ impl State { store: &impl Blockstore, verifier: &Address, ) -> Result, ActorError> { - let verifiers = - make_map_with_root_and_bitwidth::<_, BigIntDe>(&self.verifiers, store, HAMT_BIT_WIDTH) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load verifiers")?; - let allowance = verifiers - .get(&verifier.to_bytes()) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to get verifier")?; - Ok(allowance.map(|a| a.0.clone() as DataCap)) + let verifiers = self.load_verifiers(store)?; + let allowance = verifiers.get(verifier)?; + Ok(allowance.map(|a| a.clone().0)) } - pub fn load_verifiers<'a, BS: Blockstore>( - &self, - store: &'a BS, - ) -> Result, ActorError> { - make_map_with_root_and_bitwidth::<_, BigIntDe>(&self.verifiers, store, HAMT_BIT_WIDTH) - .context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load verifiers") + pub fn load_verifiers(&self, store: BS) -> Result, ActorError> { + DataCapMap::load(store, &self.verifiers, DATACAP_MAP_CONFIG, "verifiers") } pub fn load_allocs<'a, BS: Blockstore>( diff --git a/actors/verifreg/src/testing.rs b/actors/verifreg/src/testing.rs index c55e7f673..d4430eacc 100644 --- a/actors/verifreg/src/testing.rs +++ b/actors/verifreg/src/testing.rs @@ -1,21 +1,18 @@ -use frc46_token::token::state::decode_actor_id; use std::collections::HashMap; -use fil_actors_runtime::runtime::policy_constants::{ - MAXIMUM_VERIFIED_ALLOCATION_EXPIRATION, MAXIMUM_VERIFIED_ALLOCATION_TERM, - MINIMUM_VERIFIED_ALLOCATION_SIZE, MINIMUM_VERIFIED_ALLOCATION_TERM, -}; -use fil_actors_runtime::shared::HAMT_BIT_WIDTH; -use fil_actors_runtime::{ - make_map_with_root_and_bitwidth, parse_uint_key, Map, MessageAccumulator, -}; +use frc46_token::token::state::decode_actor_id; use fvm_ipld_blockstore::Blockstore; use fvm_shared::address::{Address, Protocol}; -use fvm_shared::bigint::bigint_ser::BigIntDe; use fvm_shared::clock::ChainEpoch; use fvm_shared::ActorID; use num_traits::Signed; +use fil_actors_runtime::runtime::policy_constants::{ + MAXIMUM_VERIFIED_ALLOCATION_EXPIRATION, MAXIMUM_VERIFIED_ALLOCATION_TERM, + MINIMUM_VERIFIED_ALLOCATION_SIZE, MINIMUM_VERIFIED_ALLOCATION_TERM, +}; +use fil_actors_runtime::{Map2, MessageAccumulator, DEFAULT_HAMT_CONFIG}; + use crate::{Allocation, AllocationID, Claim, ClaimID, DataCap, State}; pub struct StateSummary { @@ -27,28 +24,25 @@ pub struct StateSummary { /// Checks internal invariants of verified registry state. pub fn check_state_invariants( state: &State, - store: &BS, + store: BS, prior_epoch: ChainEpoch, ) -> (StateSummary, MessageAccumulator) { let acc = MessageAccumulator::default(); // Load and check verifiers let mut all_verifiers = HashMap::new(); - match Map::<_, BigIntDe>::load(&state.verifiers, store) { + match state.load_verifiers(&store) { Ok(verifiers) => { - let ret = verifiers.for_each(|key, cap| { - let verifier = Address::from_bytes(key)?; - let cap = &cap.0; - + let ret = verifiers.for_each(|verifier, cap| { acc.require( verifier.protocol() == Protocol::ID, format!("verifier {verifier} should have ID protocol"), ); acc.require( - !cap.is_negative(), - format!("verifier {verifier} cap {cap} is negative"), + !cap.0.is_negative(), + format!("verifier {verifier} cap {} is negative", cap.0), ); - all_verifiers.insert(verifier, cap.clone()); + all_verifiers.insert(verifier, cap.clone().0); Ok(()) }); @@ -59,14 +53,19 @@ pub fn check_state_invariants( // Load and check allocations let mut all_allocations = HashMap::new(); - match make_map_with_root_and_bitwidth(&state.allocations, store, HAMT_BIT_WIDTH) { + match state.load_allocs(&store) { Ok(allocations) => { let ret = allocations.for_each(|client_key, inner_root| { let client_id = decode_actor_id(client_key).unwrap(); - match make_map_with_root_and_bitwidth(inner_root, store, HAMT_BIT_WIDTH) { + let inner = Map2::<&BS, AllocationID, Allocation>::load( + &store, + inner_root, + DEFAULT_HAMT_CONFIG, + "allocations inner", + ); + match inner { Ok(allocations) => { - let ret = allocations.for_each(|alloc_id_key, allocation: &Allocation| { - let allocation_id = parse_uint_key(alloc_id_key).unwrap(); + let ret = allocations.for_each(|allocation_id, allocation: &Allocation| { check_allocation_state( allocation_id, allocation, @@ -95,14 +94,19 @@ pub fn check_state_invariants( } let mut all_claims = HashMap::new(); - match make_map_with_root_and_bitwidth(&state.claims, store, HAMT_BIT_WIDTH) { + match state.load_claims(&store) { Ok(claims) => { let ret = claims.for_each(|provider_key, inner_root| { let provider_id = decode_actor_id(provider_key).unwrap(); - match make_map_with_root_and_bitwidth(inner_root, store, HAMT_BIT_WIDTH) { + let inner = Map2::<&BS, ClaimID, Claim>::load( + &store, + inner_root, + DEFAULT_HAMT_CONFIG, + "allocations inner", + ); + match inner { Ok(claims) => { - let ret = claims.for_each(|claim_id_key, claim: &Claim| { - let claim_id = parse_uint_key(claim_id_key).unwrap(); + let ret = claims.for_each(|claim_id, claim: &Claim| { check_claim_state( claim_id, claim, diff --git a/actors/verifreg/src/types.rs b/actors/verifreg/src/types.rs index 425258ceb..a58eb5310 100644 --- a/actors/verifreg/src/types.rs +++ b/actors/verifreg/src/types.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0, MIT use cid::Cid; -use fil_actors_runtime::BatchReturn; +use fil_actors_runtime::{BatchReturn, MapKey}; use fvm_ipld_encoding::tuple::*; use fvm_shared::address::Address; use fvm_shared::bigint::{bigint_ser, BigInt}; @@ -12,6 +12,7 @@ use fvm_shared::piece::PaddedPieceSize; use fvm_shared::sector::SectorNumber; use fvm_shared::sector::StoragePower; use fvm_shared::ActorID; +use std::fmt::{Debug, Formatter}; use crate::Claim; @@ -91,12 +92,24 @@ impl AddrPairKey { pub fn new(first: Address, second: Address) -> Self { AddrPairKey { first, second } } +} + +impl Debug for AddrPairKey { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + (self.first, self.second).fmt(f) + } +} + +impl MapKey for AddrPairKey { + fn from_bytes(_b: &[u8]) -> Result { + unimplemented!() + } - pub fn to_bytes(&self) -> Vec { + fn to_bytes(&self) -> Result, String> { let mut first = self.first.to_bytes(); let mut second = self.second.to_bytes(); first.append(&mut second); - first + Ok(first) } } diff --git a/actors/verifreg/tests/harness/mod.rs b/actors/verifreg/tests/harness/mod.rs index fa97f1baa..027fd2903 100644 --- a/actors/verifreg/tests/harness/mod.rs +++ b/actors/verifreg/tests/harness/mod.rs @@ -1,3 +1,22 @@ +use std::cell::RefCell; +use std::collections::HashMap; + +use frc46_token::receiver::{FRC46TokenReceived, FRC46_TOKEN_TYPE}; +use frc46_token::token::types::{BurnParams, BurnReturn, TransferParams}; +use frc46_token::token::TOKEN_PRECISION; +use fvm_actor_utils::receiver::UniversalReceiverParams; +use fvm_ipld_encoding::ipld_block::IpldBlock; +use fvm_ipld_encoding::RawBytes; +use fvm_shared::address::Address; +use fvm_shared::bigint::bigint_ser::BigIntSer; +use fvm_shared::clock::ChainEpoch; +use fvm_shared::econ::TokenAmount; +use fvm_shared::error::ExitCode; +use fvm_shared::piece::PaddedPieceSize; +use fvm_shared::sector::SectorNumber; +use fvm_shared::{ActorID, MethodNum, HAMT_BIT_WIDTH}; +use num_traits::{ToPrimitive, Zero}; + use fil_actor_verifreg::testing::check_state_invariants; use fil_actor_verifreg::{ ext, Actor as VerifregActor, AddVerifiedClientParams, AddVerifierParams, Allocation, @@ -18,23 +37,6 @@ use fil_actors_runtime::{ make_empty_map, ActorError, AsActorError, BatchReturn, DATACAP_TOKEN_ACTOR_ADDR, STORAGE_MARKET_ACTOR_ADDR, SYSTEM_ACTOR_ADDR, VERIFIED_REGISTRY_ACTOR_ADDR, }; -use frc46_token::receiver::{FRC46TokenReceived, FRC46_TOKEN_TYPE}; -use frc46_token::token::types::{BurnParams, BurnReturn, TransferParams}; -use frc46_token::token::TOKEN_PRECISION; -use fvm_actor_utils::receiver::UniversalReceiverParams; -use fvm_ipld_encoding::ipld_block::IpldBlock; -use fvm_ipld_encoding::RawBytes; -use fvm_shared::address::Address; -use fvm_shared::bigint::bigint_ser::{BigIntDe, BigIntSer}; -use fvm_shared::clock::ChainEpoch; -use fvm_shared::econ::TokenAmount; -use fvm_shared::error::ExitCode; -use fvm_shared::piece::PaddedPieceSize; -use fvm_shared::sector::SectorNumber; -use fvm_shared::{ActorID, MethodNum, HAMT_BIT_WIDTH}; -use num_traits::{ToPrimitive, Zero}; -use std::cell::RefCell; -use std::collections::HashMap; pub const ROOT_ADDR: Address = Address::new_id(101); @@ -171,14 +173,13 @@ impl Harness { pub fn get_verifier_allowance(&self, rt: &MockRuntime, verifier: &Address) -> DataCap { let verifiers = rt.get_state::().load_verifiers(&rt.store).unwrap(); - let BigIntDe(allowance) = verifiers.get(&verifier.to_bytes()).unwrap().unwrap(); - allowance.clone() + verifiers.get(verifier).unwrap().unwrap().clone().0 } pub fn assert_verifier_removed(&self, rt: &MockRuntime, verifier: &Address) { let verifier_id_addr = rt.get_id_address(verifier).unwrap(); let verifiers = rt.get_state::().load_verifiers(&rt.store).unwrap(); - assert!(!verifiers.contains_key(&verifier_id_addr.to_bytes()).unwrap()) + assert!(!verifiers.contains_key(&verifier_id_addr).unwrap()) } pub fn add_client( diff --git a/integration_tests/src/tests/verified_claim_test.rs b/integration_tests/src/tests/verified_claim_test.rs index 755437426..0389ac0b7 100644 --- a/integration_tests/src/tests/verified_claim_test.rs +++ b/integration_tests/src/tests/verified_claim_test.rs @@ -1,28 +1,31 @@ +use std::ops::Neg; + +use fvm_shared::bigint::Zero; +use fvm_shared::econ::TokenAmount; +use fvm_shared::piece::PaddedPieceSize; +use fvm_shared::sector::{RegisteredSealProof, SectorNumber, StoragePower}; + use fil_actor_datacap::State as DatacapState; -use fil_actor_market::State as MarketState; -use fil_actor_market::{deal_id_key, DealArray, DealMetaArray}; +use fil_actor_market::{DealArray, DealMetaArray}; +use fil_actor_market::{ + PendingDealAllocationsMap, State as MarketState, PENDING_ALLOCATIONS_CONFIG, +}; use fil_actor_miner::{max_prove_commit_duration, PowerPair, SectorClaim, State as MinerState}; use fil_actor_power::State as PowerState; use fil_actor_verifreg::{ - AllocationID, Claim, Method as VerifregMethod, RemoveExpiredClaimsParams, - RemoveExpiredClaimsReturn, State as VerifregState, + Claim, Method as VerifregMethod, RemoveExpiredClaimsParams, RemoveExpiredClaimsReturn, + State as VerifregState, }; use fil_actors_runtime::cbor::deserialize; use fil_actors_runtime::runtime::policy_constants::{ DEAL_UPDATES_INTERVAL, MARKET_DEFAULT_ALLOCATION_TERM_BUFFER, }; use fil_actors_runtime::runtime::Policy; -use fil_actors_runtime::shared::HAMT_BIT_WIDTH; use fil_actors_runtime::test_utils::make_piece_cid; use fil_actors_runtime::{ - make_map_with_root_and_bitwidth, DealWeight, Map, DATACAP_TOKEN_ACTOR_ADDR, EPOCHS_IN_DAY, - STORAGE_MARKET_ACTOR_ADDR, STORAGE_POWER_ACTOR_ADDR, VERIFIED_REGISTRY_ACTOR_ADDR, + DealWeight, DATACAP_TOKEN_ACTOR_ADDR, EPOCHS_IN_DAY, STORAGE_MARKET_ACTOR_ADDR, + STORAGE_POWER_ACTOR_ADDR, VERIFIED_REGISTRY_ACTOR_ADDR, }; -use fvm_shared::bigint::Zero; -use fvm_shared::econ::TokenAmount; -use fvm_shared::piece::PaddedPieceSize; -use fvm_shared::sector::{RegisteredSealProof, SectorNumber, StoragePower}; -use std::ops::Neg; use vm_api::util::{apply_ok, get_state, DynBlockstore}; use vm_api::VM; @@ -418,13 +421,14 @@ pub fn expired_allocations_test(v: &dyn VM) { let store = DynBlockstore::wrap(v.blockstore()); let proposals = DealArray::load(&market_state.proposals, &store).unwrap(); assert!(proposals.get(deal1).unwrap().is_none()); - let pending_deal_allocs: Map<_, AllocationID> = make_map_with_root_and_bitwidth( - &market_state.pending_deal_allocation_ids, + let pending_deal_allocs = PendingDealAllocationsMap::load( &store, - HAMT_BIT_WIDTH, + &market_state.pending_deal_allocation_ids, + PENDING_ALLOCATIONS_CONFIG, + "pending allocations", ) .unwrap(); - assert!(pending_deal_allocs.get(&deal_id_key(deal1)).unwrap().is_none()); + assert!(pending_deal_allocs.get(&deal1).unwrap().is_none()); // Allocation still exists until explicit cleanup let alloc_id = 1; diff --git a/integration_tests/src/tests/verifreg_remove_datacap_test.rs b/integration_tests/src/tests/verifreg_remove_datacap_test.rs index 04c488b74..dc412da50 100644 --- a/integration_tests/src/tests/verifreg_remove_datacap_test.rs +++ b/integration_tests/src/tests/verifreg_remove_datacap_test.rs @@ -1,6 +1,7 @@ use fil_actor_datacap::{ DestroyParams, Method as DataCapMethod, MintParams, State as DataCapState, }; +use fil_actor_verifreg::state::{RemoveDataCapProposalMap, REMOVE_DATACAP_PROPOSALS_CONFIG}; use fil_actor_verifreg::{ AddVerifiedClientParams, DataCap, RemoveDataCapParams, RemoveDataCapRequest, RemoveDataCapReturn, SIGNATURE_DOMAIN_SEPARATION_REMOVE_DATA_CAP, @@ -102,20 +103,21 @@ pub fn remove_datacap_simple_successful_path_test(v: &dyn VM) { assert_eq!(balance, TokenAmount::from_whole(verifier_allowance.to_i64().unwrap())); let store = DynBlockstore::wrap(v.blockstore()); - let mut proposal_ids = make_map_with_root_and_bitwidth::<_, RemoveDataCapProposalID>( - &v_st.remove_data_cap_proposal_ids, + let mut proposal_ids = RemoveDataCapProposalMap::load( &store, - HAMT_BIT_WIDTH, + &v_st.remove_data_cap_proposal_ids, + REMOVE_DATACAP_PROPOSALS_CONFIG, + "remove datacap proposals", ) .unwrap(); assert!(proposal_ids - .get(&AddrPairKey::new(verifier1_id_addr, verified_client_id_addr).to_bytes()) + .get(&AddrPairKey::new(verifier1_id_addr, verified_client_id_addr)) .unwrap() .is_none()); assert!(proposal_ids - .get(&AddrPairKey::new(verifier2_id_addr, verified_client_id_addr).to_bytes()) + .get(&AddrPairKey::new(verifier2_id_addr, verified_client_id_addr)) .unwrap() .is_none()); @@ -188,19 +190,23 @@ pub fn remove_datacap_simple_successful_path_test(v: &dyn VM) { let v_st: VerifregState = get_state(v, &VERIFIED_REGISTRY_ACTOR_ADDR).unwrap(); // confirm proposalIds has changed as expected let store = DynBlockstore::wrap(v.blockstore()); - proposal_ids = - make_map_with_root_and_bitwidth(&v_st.remove_data_cap_proposal_ids, &store, HAMT_BIT_WIDTH) - .unwrap(); + proposal_ids = RemoveDataCapProposalMap::load( + &store, + &v_st.remove_data_cap_proposal_ids, + REMOVE_DATACAP_PROPOSALS_CONFIG, + "remove datacap proposals", + ) + .unwrap(); let verifier1_proposal_id: &RemoveDataCapProposalID = proposal_ids - .get(&AddrPairKey::new(verifier1_id_addr, verified_client_id_addr).to_bytes()) + .get(&AddrPairKey::new(verifier1_id_addr, verified_client_id_addr)) .unwrap() .unwrap(); assert_eq!(1u64, verifier1_proposal_id.id); let verifier2_proposal_id: &RemoveDataCapProposalID = proposal_ids - .get(&AddrPairKey::new(verifier2_id_addr, verified_client_id_addr).to_bytes()) + .get(&AddrPairKey::new(verifier2_id_addr, verified_client_id_addr)) .unwrap() .unwrap(); @@ -273,19 +279,23 @@ pub fn remove_datacap_simple_successful_path_test(v: &dyn VM) { // confirm proposalIds has changed as expected let v_st: VerifregState = get_state(v, &VERIFIED_REGISTRY_ACTOR_ADDR).unwrap(); let store = DynBlockstore::wrap(v.blockstore()); - proposal_ids = - make_map_with_root_and_bitwidth(&v_st.remove_data_cap_proposal_ids, &store, HAMT_BIT_WIDTH) - .unwrap(); + proposal_ids = RemoveDataCapProposalMap::load( + &store, + &v_st.remove_data_cap_proposal_ids, + REMOVE_DATACAP_PROPOSALS_CONFIG, + "remove datacap proposals", + ) + .unwrap(); let verifier1_proposal_id: &RemoveDataCapProposalID = proposal_ids - .get(&AddrPairKey::new(verifier1_id_addr, verified_client_id_addr).to_bytes()) + .get(&AddrPairKey::new(verifier1_id_addr, verified_client_id_addr)) .unwrap() .unwrap(); assert_eq!(2u64, verifier1_proposal_id.id); let verifier2_proposal_id: &RemoveDataCapProposalID = proposal_ids - .get(&AddrPairKey::new(verifier2_id_addr, verified_client_id_addr).to_bytes()) + .get(&AddrPairKey::new(verifier2_id_addr, verified_client_id_addr)) .unwrap() .unwrap(); diff --git a/runtime/src/util/map.rs b/runtime/src/util/map.rs index f92d27391..c5cbc8622 100644 --- a/runtime/src/util/map.rs +++ b/runtime/src/util/map.rs @@ -6,8 +6,10 @@ use fvm_ipld_blockstore::Blockstore; use fvm_ipld_hamt as hamt; use fvm_shared::address::Address; use fvm_shared::error::ExitCode; +use integer_encoding::VarInt; use serde::de::DeserializeOwned; use serde::Serialize; +use std::fmt::Debug; use std::marker::PhantomData; /// Wraps a HAMT to provide a convenient map API. @@ -24,7 +26,7 @@ where key_type: PhantomData, } -pub trait MapKey: Sized { +pub trait MapKey: Sized + Debug { fn from_bytes(b: &[u8]) -> Result; fn to_bytes(&self) -> Result, String>; } @@ -89,7 +91,14 @@ where pub fn get(&self, key: &K) -> Result, ActorError> { let k = key.to_bytes().context_code(ExitCode::USR_ASSERTION_FAILED, "invalid key")?; self.hamt.get(&k).with_context_code(ExitCode::USR_ILLEGAL_STATE, || { - format!("failed to get from HAMT '{}'", self.name) + format!("failed to get key {key:?} from HAMT '{}'", self.name) + }) + } + + pub fn contains_key(&self, key: &K) -> Result { + let k = key.to_bytes().context_code(ExitCode::USR_ASSERTION_FAILED, "invalid key")?; + self.hamt.contains_key(&k).with_context_code(ExitCode::USR_ILLEGAL_STATE, || { + format!("failed to check key {key:?} in HAMT '{}'", self.name) }) } @@ -101,7 +110,7 @@ where { let k = key.to_bytes().context_code(ExitCode::USR_ASSERTION_FAILED, "invalid key")?; self.hamt.set(k.into(), value).with_context_code(ExitCode::USR_ILLEGAL_STATE, || { - format!("failed to set in HAMT '{}'", self.name) + format!("failed to set key {key:?} in HAMT '{}'", self.name) }) } @@ -115,17 +124,19 @@ where self.hamt .set_if_absent(k.into(), value) .with_context_code(ExitCode::USR_ILLEGAL_STATE, || { - format!("failed to set in HAMT '{}'", self.name) + format!("failed to set key {key:?} in HAMT '{}'", self.name) }) } pub fn delete(&mut self, key: &K) -> Result, ActorError> { - let k = key.to_bytes().context_code(ExitCode::USR_ASSERTION_FAILED, "invalid key")?; + let k = key + .to_bytes() + .with_context_code(ExitCode::USR_ASSERTION_FAILED, || format!("invalid key {key:?}"))?; self.hamt .delete(&k) .map(|delete_result| delete_result.map(|(_k, v)| v)) .with_context_code(ExitCode::USR_ILLEGAL_STATE, || { - format!("failed to delete from HAMT '{}'", self.name) + format!("failed to delete key {key:?} from HAMT '{}'", self.name) }) } @@ -146,7 +157,7 @@ where hamt::Error::Dynamic(e) => match e.downcast::() { Ok(ae) => Err(ae), Err(e) => Err(ActorError::illegal_state(format!( - "error traversing HAMT {}: {}", + "error in callback traversing HAMT {}: {}", self.name, e ))), }, @@ -159,19 +170,47 @@ where } } +impl MapKey for Vec { + fn from_bytes(b: &[u8]) -> Result { + Ok(b.to_vec()) + } + + fn to_bytes(&self) -> Result, String> { + Ok(self.clone()) + } +} + impl MapKey for u64 { fn from_bytes(b: &[u8]) -> Result { - let (v, rem) = unsigned_varint::decode::u64(b).map_err(|e| e.to_string())?; - if !rem.is_empty() { - return Err(format!("trailing bytes after varint: {:?}", rem)); + if let Some((result, size)) = VarInt::decode_var(b) { + if size != b.len() { + return Err(format!("trailing bytes after varint in {:?}", b)); + } + Ok(result) + } else { + Err(format!("failed to decode varint in {:?}", b)) } - Ok(v) } fn to_bytes(&self) -> Result, String> { - let mut bz = unsigned_varint::encode::u64_buffer(); - let slice = unsigned_varint::encode::u64(*self, &mut bz); - Ok(slice.into()) + Ok(self.encode_var_vec()) + } +} + +impl MapKey for i64 { + fn from_bytes(b: &[u8]) -> Result { + if let Some((result, size)) = VarInt::decode_var(b) { + if size != b.len() { + return Err(format!("trailing bytes after varint in {:?}", b)); + } + Ok(result) + } else { + Err(format!("failed to decode varint in {:?}", b)) + } + } + + fn to_bytes(&self) -> Result, String> { + Ok(self.encode_var_vec()) } } @@ -185,6 +224,16 @@ impl MapKey for Address { } } +impl MapKey for Cid { + fn from_bytes(b: &[u8]) -> Result { + Cid::try_from(b).map_err(|e| e.to_string()) + } + + fn to_bytes(&self) -> Result, String> { + Ok(self.to_bytes()) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/runtime/src/util/mapmap.rs b/runtime/src/util/mapmap.rs index 5689be059..ef0048f86 100644 --- a/runtime/src/util/mapmap.rs +++ b/runtime/src/util/mapmap.rs @@ -102,8 +102,16 @@ where in_map.get(&inside_k.key()) } + // Iterates over all outer keys. + pub fn for_each(&self, f: F) -> Result<(), Error> + where + F: FnMut(&BytesKey, &Cid) -> anyhow::Result<()>, + { + self.outer.for_each(f) + } + // Runs a function over all values for one outer key. - pub fn for_each(&mut self, outside_k: K1, f: F) -> Result<(), Error> + pub fn for_each_in(&mut self, outside_k: K1, f: F) -> Result<(), Error> where F: FnMut(&BytesKey, &V) -> anyhow::Result<()>, { diff --git a/runtime/tests/mapmap_test.rs b/runtime/tests/mapmap_test.rs index 2b87149d6..2a6716a3f 100644 --- a/runtime/tests/mapmap_test.rs +++ b/runtime/tests/mapmap_test.rs @@ -32,7 +32,7 @@ fn mapmap_test() { // for each accounts for all inner keys and values let mut count = 0; - mm.for_each("tree", |bk, v| -> anyhow::Result<()> { + mm.for_each_in("tree", |bk, v| -> anyhow::Result<()> { count += 1; assert!( (bk == &"deciduous".key() && v == &"mango".to_string()) @@ -44,7 +44,7 @@ fn mapmap_test() { assert_eq!(2, count); let mut count = 0; - mm.for_each("rock", |bk, v| -> anyhow::Result<()> { + mm.for_each_in("rock", |bk, v| -> anyhow::Result<()> { count += 1; assert_eq!(&"igneous".key(), bk); assert_eq!(&"basalt".to_string(), v); @@ -77,7 +77,7 @@ fn mapmap_test() { MapMap::from_root(&store, &root, HAMT_BIT_WIDTH, HAMT_BIT_WIDTH).unwrap(); let mut count = 0; mm_reloaded - .for_each("tree", |bk, v| -> anyhow::Result<()> { + .for_each_in("tree", |bk, v| -> anyhow::Result<()> { count += 1; assert!( (bk == &"deciduous".key() && v == &"mango".to_string())