Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit ddf83eb

Browse files
committed
Double map for an efficient destroy.
1 parent 911795a commit ddf83eb

File tree

1 file changed

+58
-38
lines changed

1 file changed

+58
-38
lines changed

frame/assets/src/lib.rs

Lines changed: 58 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@
135135

136136
use sp_std::{fmt::Debug};
137137
use sp_runtime::{RuntimeDebug, traits::{
138-
Member, AtLeast32Bit, AtLeast32BitUnsigned, Zero, StaticLookup, One, Saturating, CheckedSub
138+
Member, AtLeast32Bit, AtLeast32BitUnsigned, Zero, StaticLookup, Saturating, CheckedSub
139139
}};
140140
use codec::{Encode, Decode};
141141
use frame_support::{Parameter, decl_module, decl_event, decl_storage, decl_error, ensure,
@@ -203,7 +203,9 @@ pub struct AccountData<
203203
decl_storage! {
204204
trait Store for Module<T: Trait> as Assets {
205205
/// The number of units of assets held by any given account.
206-
Account: map hasher(blake2_128_concat) (T::AssetId, T::AccountId)
206+
Account: double_map
207+
hasher(blake2_128_concat) T::AssetId,
208+
hasher(blake2_128_concat) T::AccountId
207209
=> AccountData<T::Balance>;
208210

209211
/// The next asset identifier up for grabs.
@@ -226,7 +228,7 @@ decl_event! {
226228
<T as Trait>::Balance,
227229
<T as Trait>::AssetId,
228230
{
229-
/// Some assets were issued. \[asset_id, owner, total_supply\]
231+
/// Some asset class was created. \[asset_id, creator, owner\]
230232
Created(AssetId, AccountId, AccountId),
231233
/// Some assets were issued. \[asset_id, owner, total_supply\]
232234
Issued(AssetId, AccountId, Balance),
@@ -244,6 +246,8 @@ decl_event! {
244246
Frozen(AssetId, AccountId),
245247
/// Some account `who` was thawed. \[asset_id, who\]
246248
Thawed(AssetId, AccountId),
249+
/// An asset class was destroyed.
250+
Destroyed(AssetId),
247251
}
248252
}
249253

@@ -261,6 +265,8 @@ decl_error! {
261265
Unknown,
262266
/// The origin account is frozen.
263267
Frozen,
268+
/// The asset ID is already taken.
269+
InUse,
264270
}
265271
}
266272

@@ -270,6 +276,8 @@ decl_module! {
270276

271277
fn deposit_event() = default;
272278

279+
// TODO: destroy_asset
280+
273281
/// Issue a new class of fungible assets. There are, and will only ever be, `total`
274282
/// such assets and they'll all belong to the `origin` initially. It will have an
275283
/// identifier `AssetId` instance: this will be specified in the `Issued` event.
@@ -281,13 +289,11 @@ decl_module! {
281289
/// - 1 event.
282290
/// # </weight>
283291
#[weight = 0]
284-
fn create(origin, owner: <T::Lookup as StaticLookup>::Source) {
292+
fn create(origin, #[compact] id: T::AssetId, owner: <T::Lookup as StaticLookup>::Source) {
285293
let origin = ensure_signed(origin)?;
286294
let owner = T::Lookup::lookup(owner)?;
287295

288-
let id = Self::next_asset_id();
289-
NextAssetId::<T>::mutate(|id| *id += One::one());
290-
296+
ensure!(!Details::<T>::contains_key(id), Error::<T>::InUse);
291297
Details::<T>::insert(id, AssetDetails {
292298
owner: owner.clone(),
293299
issuer: owner.clone(),
@@ -301,6 +307,20 @@ decl_module! {
301307
Self::deposit_event(RawEvent::Created(id, origin, owner));
302308
}
303309

310+
#[weight = 0]
311+
fn destroy(origin, #[compact] id: T::AssetId) -> DispatchResult {
312+
let origin = ensure_signed(origin)?;
313+
314+
Details::<T>::try_mutate_exists(id, |maybe_details| {
315+
let details = maybe_details.take().ok_or(Error::<T>::Unknown)?;
316+
ensure!(details.owner == origin, Error::<T>::NoPermission);
317+
*maybe_details = None;
318+
Account::<T>::remove_prefix(&id);
319+
Self::deposit_event(RawEvent::Destroyed(id));
320+
Ok(())
321+
})
322+
}
323+
304324
#[weight = 0]
305325
fn mint(origin,
306326
#[compact] id: T::AssetId,
@@ -314,7 +334,7 @@ decl_module! {
314334
let d = maybe_details.as_mut().ok_or(Error::<T>::Unknown)?;
315335
ensure!(&origin == &d.issuer, Error::<T>::NoPermission);
316336
d.supply = d.supply.saturating_add(amount);
317-
Account::<T>::mutate((id, &beneficiary), |t|
337+
Account::<T>::mutate(id, &beneficiary, |t|
318338
t.balance = t.balance.saturating_add(amount)
319339
);
320340

@@ -337,24 +357,24 @@ decl_module! {
337357
target: <T::Lookup as StaticLookup>::Source,
338358
#[compact] amount: T::Balance
339359
) {
340-
let origin = (id, ensure_signed(origin)?);
360+
let origin = ensure_signed(origin)?;
341361
ensure!(!amount.is_zero(), Error::<T>::AmountZero);
342362

343-
let mut origin_account = Account::<T>::get(&origin);
363+
let mut origin_account = Account::<T>::get(id, &origin);
344364
ensure!(!origin_account.is_frozen, Error::<T>::Frozen);
345365
origin_account.balance = origin_account.balance.checked_sub(&amount)
346366
.ok_or(Error::<T>::BalanceLow)?;
347367

348-
let dest = (id, T::Lookup::lookup(target)?);
368+
let dest = T::Lookup::lookup(target)?;
349369

350370
if origin_account.balance.is_zero() {
351-
Account::<T>::remove(&origin);
371+
Account::<T>::remove(id, &origin);
352372
} else {
353-
Account::<T>::insert(&origin, origin_account);
373+
Account::<T>::insert(id, &origin, origin_account);
354374
}
355-
Account::<T>::mutate(&dest, |a| a.balance = a.balance.saturating_add(amount));
375+
Account::<T>::mutate(id, &dest, |a| a.balance = a.balance.saturating_add(amount));
356376

357-
Self::deposit_event(RawEvent::Transferred(id, origin.1, dest.1, amount));
377+
Self::deposit_event(RawEvent::Transferred(id, origin, dest, amount));
358378
}
359379

360380
/// Destroy up to `amount` assets of `id` owned by `who`.
@@ -375,7 +395,7 @@ decl_module! {
375395
let d = maybe_details.as_mut().ok_or(Error::<T>::Unknown)?;
376396
ensure!(&origin == &d.admin, Error::<T>::NoPermission);
377397

378-
let burned = Account::<T>::try_mutate_exists((id, &who), |maybe_account| {
398+
let burned = Account::<T>::try_mutate_exists(id, &who, |maybe_account| {
379399
if let Some(mut account) = maybe_account.take() {
380400
let burned = amount.min(account.balance);
381401
account.balance -= burned;
@@ -448,10 +468,10 @@ decl_module! {
448468
let d = Details::<T>::get(id).ok_or(Error::<T>::Unknown)?;
449469
ensure!(&origin == &d.admin, Error::<T>::NoPermission);
450470

451-
let who = (id, T::Lookup::lookup(who)?);
452-
Account::<T>::mutate(&who, |a| a.is_frozen = true);
471+
let who = T::Lookup::lookup(who)?;
472+
Account::<T>::mutate(id, &who, |a| a.is_frozen = true);
453473

454-
Self::deposit_event(Event::<T>::Frozen(id, who.1));
474+
Self::deposit_event(Event::<T>::Frozen(id, who));
455475
}
456476

457477
#[weight = 0]
@@ -461,10 +481,10 @@ decl_module! {
461481
let d = Details::<T>::get(id).ok_or(Error::<T>::Unknown)?;
462482
ensure!(&origin == &d.admin, Error::<T>::NoPermission);
463483

464-
let who = (id, T::Lookup::lookup(who)?);
465-
Account::<T>::mutate(&who, |a| a.is_frozen = false);
484+
let who = T::Lookup::lookup(who)?;
485+
Account::<T>::mutate(id, &who, |a| a.is_frozen = false);
466486

467-
Self::deposit_event(Event::<T>::Thawed(id, who.1));
487+
Self::deposit_event(Event::<T>::Thawed(id, who));
468488
}
469489

470490
#[weight = 0]
@@ -479,24 +499,24 @@ decl_module! {
479499
let d = Details::<T>::get(id).ok_or(Error::<T>::Unknown)?;
480500
ensure!(&origin == &d.admin, Error::<T>::NoPermission);
481501

482-
let source = (id, T::Lookup::lookup(source)?);
483-
let mut source_account = Account::<T>::get(&source);
502+
let source = T::Lookup::lookup(source)?;
503+
let mut source_account = Account::<T>::get(id, &source);
484504
let amount = amount.min(source_account.balance);
485505

486506
ensure!(!amount.is_zero(), Error::<T>::AmountZero);
487507

488-
let dest = (id, T::Lookup::lookup(dest)?);
508+
let dest = T::Lookup::lookup(dest)?;
489509

490510
source_account.balance -= amount;
491511
if source_account.balance.is_zero() {
492-
Account::<T>::remove(&source);
512+
Account::<T>::remove(id, &source);
493513
} else {
494-
Account::<T>::insert(&source, source_account);
514+
Account::<T>::insert(id, &source, source_account);
495515
}
496516

497-
Account::<T>::mutate(&dest, |a| a.balance = a.balance.saturating_add(amount));
517+
Account::<T>::mutate(id, &dest, |a| a.balance = a.balance.saturating_add(amount));
498518

499-
Self::deposit_event(RawEvent::ForceTransferred(id, source.1, dest.1, amount));
519+
Self::deposit_event(RawEvent::ForceTransferred(id, source, dest, amount));
500520
}
501521
}
502522
}
@@ -507,7 +527,7 @@ impl<T: Trait> Module<T> {
507527

508528
/// Get the asset `id` balance of `who`.
509529
pub fn balance(id: T::AssetId, who: T::AccountId) -> T::Balance {
510-
Account::<T>::get((id, who)).balance
530+
Account::<T>::get(id, who).balance
511531
}
512532

513533
/// Get the total supply of an asset `id`.
@@ -595,7 +615,7 @@ mod tests {
595615
#[test]
596616
fn issuing_asset_units_to_issuer_should_work() {
597617
new_test_ext().execute_with(|| {
598-
assert_ok!(Assets::create(Origin::signed(1), 1));
618+
assert_ok!(Assets::create(Origin::signed(1), 0, 1));
599619
assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100));
600620
assert_eq!(Assets::balance(0, 1), 100);
601621
});
@@ -604,7 +624,7 @@ mod tests {
604624
#[test]
605625
fn querying_total_supply_should_work() {
606626
new_test_ext().execute_with(|| {
607-
assert_ok!(Assets::create(Origin::signed(1), 1));
627+
assert_ok!(Assets::create(Origin::signed(1), 0, 1));
608628
assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100));
609629
assert_eq!(Assets::balance(0, 1), 100);
610630
assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50));
@@ -622,7 +642,7 @@ mod tests {
622642
#[test]
623643
fn transferring_amount_above_available_balance_should_work() {
624644
new_test_ext().execute_with(|| {
625-
assert_ok!(Assets::create(Origin::signed(1), 1));
645+
assert_ok!(Assets::create(Origin::signed(1), 0, 1));
626646
assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100));
627647
assert_eq!(Assets::balance(0, 1), 100);
628648
assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50));
@@ -634,7 +654,7 @@ mod tests {
634654
#[test]
635655
fn transferring_amount_more_than_available_balance_should_not_work() {
636656
new_test_ext().execute_with(|| {
637-
assert_ok!(Assets::create(Origin::signed(1), 1));
657+
assert_ok!(Assets::create(Origin::signed(1), 0, 1));
638658
assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100));
639659
assert_eq!(Assets::balance(0, 1), 100);
640660
assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50));
@@ -649,7 +669,7 @@ mod tests {
649669
#[test]
650670
fn transferring_less_than_one_unit_should_not_work() {
651671
new_test_ext().execute_with(|| {
652-
assert_ok!(Assets::create(Origin::signed(1), 1));
672+
assert_ok!(Assets::create(Origin::signed(1), 0, 1));
653673
assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100));
654674
assert_eq!(Assets::balance(0, 1), 100);
655675
assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 0), Error::<Test>::AmountZero);
@@ -659,7 +679,7 @@ mod tests {
659679
#[test]
660680
fn transferring_more_units_than_total_supply_should_not_work() {
661681
new_test_ext().execute_with(|| {
662-
assert_ok!(Assets::create(Origin::signed(1), 1));
682+
assert_ok!(Assets::create(Origin::signed(1), 0, 1));
663683
assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100));
664684
assert_eq!(Assets::balance(0, 1), 100);
665685
assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 101), Error::<Test>::BalanceLow);
@@ -669,7 +689,7 @@ mod tests {
669689
#[test]
670690
fn destroying_asset_balance_with_positive_balance_should_work() {
671691
new_test_ext().execute_with(|| {
672-
assert_ok!(Assets::create(Origin::signed(1), 1));
692+
assert_ok!(Assets::create(Origin::signed(1), 0, 1));
673693
assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100));
674694
assert_eq!(Assets::balance(0, 1), 100);
675695
assert_ok!(Assets::burn(Origin::signed(1), 0, 1, u64::max_value()));
@@ -679,7 +699,7 @@ mod tests {
679699
#[test]
680700
fn destroying_asset_balance_with_zero_balance_should_not_work() {
681701
new_test_ext().execute_with(|| {
682-
assert_ok!(Assets::create(Origin::signed(1), 1));
702+
assert_ok!(Assets::create(Origin::signed(1), 0, 1));
683703
assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100));
684704
assert_eq!(Assets::balance(0, 2), 0);
685705
assert_noop!(Assets::burn(Origin::signed(1), 0, 2, u64::max_value()), Error::<Test>::BalanceZero);

0 commit comments

Comments
 (0)