Skip to content

Commit 584f88f

Browse files
authored
Use Map2 instead of Map and raw HAMTs in market actor (#1358)
1 parent 8882852 commit 584f88f

File tree

10 files changed

+184
-258
lines changed

10 files changed

+184
-258
lines changed

actors/init/src/state.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use fvm_ipld_encoding::tuple::*;
77
use fvm_shared::address::{Address, Protocol};
88
use fvm_shared::ActorID;
99

10-
use fil_actors_runtime::{actor_error, ActorError, Map2, DEFAULT_CONF, FIRST_NON_SINGLETON_ADDR};
10+
use fil_actors_runtime::{
11+
actor_error, ActorError, Map2, DEFAULT_HAMT_CONFIG, FIRST_NON_SINGLETON_ADDR,
12+
};
1113

1214
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
1315
pub struct State {
@@ -21,7 +23,7 @@ pub type AddressMap<BS> = Map2<BS, Address, ActorID>;
2123

2224
impl State {
2325
pub fn new<BS: Blockstore>(store: &BS, network_name: String) -> Result<Self, ActorError> {
24-
let empty = AddressMap::flush_empty(store, DEFAULT_CONF)?;
26+
let empty = AddressMap::flush_empty(store, DEFAULT_HAMT_CONFIG)?;
2527
Ok(Self { address_map: empty, next_id: FIRST_NON_SINGLETON_ADDR, network_name })
2628
}
2729

@@ -37,7 +39,7 @@ impl State {
3739
robust_addr: &Address,
3840
delegated_addr: Option<&Address>,
3941
) -> Result<(ActorID, bool), ActorError> {
40-
let mut map = AddressMap::load(store, &self.address_map, DEFAULT_CONF, "addresses")?;
42+
let mut map = AddressMap::load(store, &self.address_map, DEFAULT_HAMT_CONFIG, "addresses")?;
4143
let (id, existing) = if let Some(delegated_addr) = delegated_addr {
4244
// If there's a delegated address, either recall the already-mapped actor ID or
4345
// create and map a new one.
@@ -87,7 +89,7 @@ impl State {
8789
if addr.protocol() == Protocol::ID {
8890
return Ok(Some(*addr));
8991
}
90-
let map = AddressMap::load(store, &self.address_map, DEFAULT_CONF, "addresses")?;
92+
let map = AddressMap::load(store, &self.address_map, DEFAULT_HAMT_CONFIG, "addresses")?;
9193
let found = map.get(addr)?;
9294
Ok(found.copied().map(Address::new_id))
9395
}

actors/init/src/testing.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use fvm_shared::{
66
ActorID,
77
};
88

9-
use fil_actors_runtime::{MessageAccumulator, DEFAULT_CONF, FIRST_NON_SINGLETON_ADDR};
9+
use fil_actors_runtime::{MessageAccumulator, DEFAULT_HAMT_CONFIG, FIRST_NON_SINGLETON_ADDR};
1010

1111
use crate::state::AddressMap;
1212
use crate::State;
@@ -34,7 +34,7 @@ pub fn check_state_invariants<BS: Blockstore>(
3434
let mut stable_address_by_id = HashMap::<ActorID, Address>::new();
3535
let mut delegated_address_by_id = HashMap::<ActorID, Address>::new();
3636

37-
match AddressMap::load(store, &state.address_map, DEFAULT_CONF, "addresses") {
37+
match AddressMap::load(store, &state.address_map, DEFAULT_HAMT_CONFIG, "addresses") {
3838
Ok(address_map) => {
3939
let ret = address_map.for_each(|key, actor_id| {
4040
acc.require(key.protocol() != Protocol::ID, format!("key {key} is an ID address"));

actors/market/src/balance_table.rs

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,57 +3,64 @@
33

44
use cid::Cid;
55
use fvm_ipld_blockstore::Blockstore;
6-
use fvm_ipld_hamt::Error as HamtError;
76
use fvm_shared::address::Address;
87
use fvm_shared::econ::TokenAmount;
98
use num_traits::Zero;
109

11-
use fil_actors_runtime::{make_empty_map, make_map_with_root_and_bitwidth, Map};
12-
13-
pub const BALANCE_TABLE_BITWIDTH: u32 = 6;
10+
use fil_actors_runtime::{
11+
actor_error, ActorContext, ActorError, Config, Map2, DEFAULT_HAMT_CONFIG,
12+
};
1413

1514
/// Balance table which handles getting and updating token balances specifically
16-
pub struct BalanceTable<'a, BS>(pub Map<'a, BS, TokenAmount>);
15+
pub struct BalanceTable<BS: Blockstore>(pub Map2<BS, Address, TokenAmount>);
16+
17+
const CONF: Config = Config { bit_width: 6, ..DEFAULT_HAMT_CONFIG };
1718

18-
impl<'a, BS> BalanceTable<'a, BS>
19+
impl<BS> BalanceTable<BS>
1920
where
2021
BS: Blockstore,
2122
{
2223
/// Initializes a new empty balance table
23-
pub fn new(bs: &'a BS) -> Self {
24-
Self(make_empty_map(bs, BALANCE_TABLE_BITWIDTH))
24+
pub fn new(bs: BS, name: &'static str) -> Self {
25+
Self(Map2::empty(bs, CONF, name))
2526
}
2627

2728
/// Initializes a balance table from a root Cid
28-
pub fn from_root(bs: &'a BS, cid: &Cid) -> Result<Self, HamtError> {
29-
Ok(Self(make_map_with_root_and_bitwidth(cid, bs, BALANCE_TABLE_BITWIDTH)?))
29+
pub fn from_root(bs: BS, cid: &Cid, name: &'static str) -> Result<Self, ActorError> {
30+
Ok(Self(Map2::load(bs, cid, CONF, name)?))
3031
}
3132

3233
/// Retrieve root from balance table
33-
pub fn root(&mut self) -> Result<Cid, HamtError> {
34+
pub fn root(&mut self) -> Result<Cid, ActorError> {
3435
self.0.flush()
3536
}
3637

3738
/// Gets token amount for given address in balance table
38-
pub fn get(&self, key: &Address) -> Result<TokenAmount, HamtError> {
39-
if let Some(v) = self.0.get(&key.to_bytes())? {
39+
pub fn get(&self, key: &Address) -> Result<TokenAmount, ActorError> {
40+
if let Some(v) = self.0.get(key)? {
4041
Ok(v.clone())
4142
} else {
4243
Ok(TokenAmount::zero())
4344
}
4445
}
4546

4647
/// Adds token amount to previously initialized account.
47-
pub fn add(&mut self, key: &Address, value: &TokenAmount) -> Result<(), HamtError> {
48+
pub fn add(&mut self, key: &Address, value: &TokenAmount) -> Result<(), ActorError> {
4849
let prev = self.get(key)?;
4950
let sum = &prev + value;
5051
if sum.is_negative() {
51-
Err(format!("New balance in table cannot be negative: {}", sum).into())
52+
Err(actor_error!(
53+
illegal_argument,
54+
"negative balance for {} adding {} to {}",
55+
key,
56+
value,
57+
prev
58+
))
5259
} else if sum.is_zero() && !prev.is_zero() {
53-
self.0.delete(&key.to_bytes())?;
60+
self.0.delete(key).context("adding balance")?;
5461
Ok(())
5562
} else {
56-
self.0.set(key.to_bytes().into(), sum)?;
63+
self.0.set(key, sum).context("adding balance")?;
5764
Ok(())
5865
}
5966
}
@@ -66,34 +73,39 @@ where
6673
key: &Address,
6774
req: &TokenAmount,
6875
floor: &TokenAmount,
69-
) -> Result<TokenAmount, HamtError> {
76+
) -> Result<TokenAmount, ActorError> {
7077
let prev = self.get(key)?;
7178
let available = std::cmp::max(TokenAmount::zero(), prev - floor);
7279
let sub: TokenAmount = std::cmp::min(&available, req).clone();
7380

7481
if sub.is_positive() {
75-
self.add(key, &-sub.clone())?;
82+
self.add(key, &-sub.clone()).context("subtracting balance")?;
7683
}
7784

7885
Ok(sub)
7986
}
8087

8188
/// Subtracts value from a balance, and errors if full amount was not substracted.
82-
pub fn must_subtract(&mut self, key: &Address, req: &TokenAmount) -> Result<(), HamtError> {
89+
pub fn must_subtract(&mut self, key: &Address, req: &TokenAmount) -> Result<(), ActorError> {
8390
let prev = self.get(key)?;
8491

8592
if req > &prev {
86-
Err("couldn't subtract the requested amount".into())
93+
Err(actor_error!(
94+
illegal_argument,
95+
"negative balance for {} subtracting {} from {}",
96+
key,
97+
req,
98+
prev
99+
))
87100
} else {
88101
self.add(key, &-req)
89102
}
90103
}
91104

92105
/// Returns total balance held by this balance table
93106
#[allow(dead_code)]
94-
pub fn total(&self) -> Result<TokenAmount, HamtError> {
107+
pub fn total(&self) -> Result<TokenAmount, ActorError> {
95108
let mut total = TokenAmount::zero();
96-
97109
self.0.for_each(|_, v: &TokenAmount| {
98110
total += v;
99111
Ok(())
@@ -116,7 +128,7 @@ mod tests {
116128
let addr1 = Address::new_id(100);
117129
let addr2 = Address::new_id(101);
118130
let store = MemoryBlockstore::default();
119-
let mut bt = BalanceTable::new(&store);
131+
let mut bt = BalanceTable::new(&store, "test");
120132

121133
assert!(bt.total().unwrap().is_zero());
122134

@@ -143,7 +155,7 @@ mod tests {
143155
fn balance_subtracts() {
144156
let addr = Address::new_id(100);
145157
let store = MemoryBlockstore::default();
146-
let mut bt = BalanceTable::new(&store);
158+
let mut bt = BalanceTable::new(&store, "test");
147159

148160
bt.add(&addr, &TokenAmount::from_atto(80u8)).unwrap();
149161
assert_eq!(bt.get(&addr).unwrap(), TokenAmount::from_atto(80u8));

actors/market/src/lib.rs

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -176,16 +176,10 @@ impl Actor {
176176

177177
let store = rt.store();
178178
let st: State = rt.state()?;
179-
let balances = BalanceTable::from_root(store, &st.escrow_table)
180-
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load escrow table")?;
181-
let locks = BalanceTable::from_root(store, &st.locked_table)
182-
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to load locked table")?;
183-
let balance = balances
184-
.get(&account)
185-
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to get escrow balance")?;
186-
let locked = locks
187-
.get(&account)
188-
.context_code(ExitCode::USR_ILLEGAL_STATE, "failed to get locked balance")?;
179+
let balances = BalanceTable::from_root(store, &st.escrow_table, "escrow table")?;
180+
let locks = BalanceTable::from_root(store, &st.locked_table, "locled table")?;
181+
let balance = balances.get(&account)?;
182+
let locked = locks.get(&account)?;
189183

190184
Ok(GetBalanceReturn { balance, locked })
191185
}
@@ -427,7 +421,7 @@ impl Actor {
427421
let mut pending_deals: Vec<Cid> = vec![];
428422
let mut deal_proposals: Vec<(DealID, DealProposal)> = vec![];
429423
let mut deals_by_epoch: Vec<(ChainEpoch, DealID)> = vec![];
430-
let mut pending_deal_allocation_ids: Vec<(BytesKey, AllocationID)> = vec![];
424+
let mut pending_deal_allocation_ids: Vec<(DealID, AllocationID)> = vec![];
431425

432426
// All storage dealProposals will be added in an atomic transaction; this operation will be unrolled if any of them fails.
433427
// This should only fail on programmer error because all expected invalid conditions should be filtered in the first set of checks.
@@ -444,7 +438,7 @@ impl Actor {
444438
// Store verified allocation (if any) in the pending allocation IDs map.
445439
// It will be removed when the deal is activated or expires.
446440
if let Some(alloc_id) = deal_allocation_ids.get(&valid_deal.cid) {
447-
pending_deal_allocation_ids.push((deal_id_key(deal_id), *alloc_id));
441+
pending_deal_allocation_ids.push((deal_id, *alloc_id));
448442
}
449443

450444
// Randomize the first epoch for when the deal will be processed so an attacker isn't able to
@@ -619,13 +613,12 @@ impl Actor {
619613

620614
// Extract and remove any verified allocation ID for the pending deal.
621615
let allocation = st
622-
.remove_pending_deal_allocation_id(rt.store(), &deal_id_key(deal_id))
616+
.remove_pending_deal_allocation_id(rt.store(), deal_id)
623617
.context(format!(
624618
"failed to remove pending deal allocation id {}",
625619
deal_id
626620
))?
627-
.unwrap_or((BytesKey(vec![]), NO_ALLOCATION_ID))
628-
.1;
621+
.unwrap_or(NO_ALLOCATION_ID);
629622

630623
if allocation != NO_ALLOCATION_ID {
631624
verified_infos.push(VerifiedDealInfo {
@@ -795,7 +788,7 @@ impl Actor {
795788
})?;
796789

797790
// Delete pending deal allocation id (if present).
798-
st.remove_pending_deal_allocation_id(rt.store(), &deal_id_key(deal_id))?;
791+
st.remove_pending_deal_allocation_id(rt.store(), deal_id)?;
799792

800793
continue;
801794
}

0 commit comments

Comments
 (0)