Skip to content

Commit 96b75ad

Browse files
authored
Balances map should be keyed by bytes (#113)
1 parent fe34b92 commit 96b75ad

File tree

2 files changed

+31
-13
lines changed

2 files changed

+31
-13
lines changed

frc46_token/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ fvm_shared = { version = "2.0.0-alpha.2" }
2121
num-traits = { version = "0.2.15" }
2222
serde = { version = "1.0.136", features = ["derive"] }
2323
serde_tuple = { version = "0.5.0" }
24-
thiserror = { version = "1.0.31" }
24+
thiserror = { version = "1.0.31" }
25+
integer-encoding = { version = "3.0.4" }

frc46_token/src/token/state.rs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ use fvm_ipld_encoding::tuple::*;
99
use fvm_ipld_encoding::Cbor;
1010
use fvm_ipld_encoding::CborStore;
1111
use fvm_ipld_encoding::DAG_CBOR;
12-
use fvm_ipld_hamt::Error as HamtError;
1312
use fvm_ipld_hamt::Hamt;
13+
use fvm_ipld_hamt::{BytesKey, Error as HamtError};
1414
use fvm_shared::address::Address;
1515
use fvm_shared::bigint::Zero;
1616
use fvm_shared::econ::TokenAmount;
1717
use fvm_shared::ActorID;
18+
use integer_encoding::VarInt;
1819
use thiserror::Error;
1920

2021
/// This value has been chosen to optimise to reduce gas-costs when accessing the balances map. Non-
@@ -153,7 +154,7 @@ impl TokenState {
153154
pub fn get_balance<BS: Blockstore>(&self, bs: &BS, owner: ActorID) -> Result<TokenAmount> {
154155
let balances = self.get_balance_map(bs)?;
155156

156-
let balance = match balances.get(&owner)? {
157+
let balance = match balances.get(&actor_id_key(owner))? {
157158
Some(amount) => amount.clone(),
158159
None => TokenAmount::zero(),
159160
};
@@ -177,7 +178,8 @@ impl TokenState {
177178
}
178179

179180
let mut balance_map = self.get_balance_map(bs)?;
180-
let balance = balance_map.get(&owner)?;
181+
let owner_key = actor_id_key(owner);
182+
let balance = balance_map.get(&owner_key)?;
181183
let balance = match balance {
182184
Some(amount) => amount.clone(),
183185
None => TokenAmount::zero(),
@@ -191,9 +193,9 @@ impl TokenState {
191193
}
192194

193195
if new_balance.is_zero() {
194-
balance_map.delete(&owner)?;
196+
balance_map.delete(&owner_key)?;
195197
} else {
196-
balance_map.set(owner, new_balance.clone())?;
198+
balance_map.set(owner_key, new_balance.clone())?;
197199
}
198200

199201
self.balances = balance_map.flush()?;
@@ -214,20 +216,21 @@ impl TokenState {
214216
}
215217

216218
let mut balance_map = self.get_balance_map(bs)?;
217-
let old_balance = match balance_map.get(&owner)? {
219+
let owner_key = actor_id_key(owner);
220+
let old_balance = match balance_map.get(&owner_key)? {
218221
Some(amount) => amount.clone(),
219222
None => TokenAmount::zero(),
220223
};
221224

222225
// if the new balance is zero, remove from balance map
223226
if new_balance.is_zero() {
224-
balance_map.delete(&owner)?;
227+
balance_map.delete(&owner_key)?;
225228
self.balances = balance_map.flush()?;
226229
return Ok(old_balance);
227230
}
228231

229232
// else, set the new balance
230-
balance_map.set(owner, new_balance.clone())?;
233+
balance_map.set(owner_key, new_balance.clone())?;
231234
self.balances = balance_map.flush()?;
232235
Ok(old_balance)
233236
}
@@ -236,7 +239,7 @@ impl TokenState {
236239
pub fn get_balance_map<'bs, BS: Blockstore>(
237240
&self,
238241
bs: &'bs BS,
239-
) -> Result<Map<'bs, BS, ActorID, TokenAmount>> {
242+
) -> Result<Map<'bs, BS, BytesKey, TokenAmount>> {
240243
Ok(Hamt::load_with_bit_width(&self.balances, bs, self.hamt_bit_width)?)
241244
}
242245

@@ -509,18 +512,24 @@ impl TokenState {
509512
let mut balance_sum = TokenAmount::zero();
510513
let mut maybe_err: Option<StateInvariantError> = None;
511514
let balances = self.get_balance_map(bs)?;
512-
let res = balances.for_each(|owner, balance| {
515+
let res = balances.for_each(|owner_key, balance| {
516+
let owner = match decode_actor_id(owner_key) {
517+
None => {
518+
bail!("invalid key in balances map")
519+
}
520+
Some(a) => a,
521+
};
513522
// all balances must be positive
514523
if balance.is_negative() {
515524
maybe_err = Some(StateInvariantError::BalanceNegative {
516-
account: *owner,
525+
account: owner,
517526
balance: balance.clone(),
518527
});
519528
bail!("invariant failed")
520529
}
521530
// zero balances should not be stored in the Hamt
522531
if balance.is_zero() {
523-
maybe_err = Some(StateInvariantError::ExplicitZeroBalance(*owner));
532+
maybe_err = Some(StateInvariantError::ExplicitZeroBalance(owner));
524533
bail!("invariant failed")
525534
}
526535
balance_sum = balance_sum.clone() + balance.clone();
@@ -589,6 +598,14 @@ impl TokenState {
589598
}
590599
}
591600

601+
pub fn actor_id_key(a: ActorID) -> BytesKey {
602+
a.encode_var_vec().into()
603+
}
604+
605+
pub fn decode_actor_id(key: &BytesKey) -> Option<ActorID> {
606+
u64::decode_var(key.0.as_slice()).map(|a| a.0)
607+
}
608+
592609
impl Cbor for TokenState {}
593610

594611
#[cfg(test)]

0 commit comments

Comments
 (0)