【Substrate Collectables教程】【第2章Kitties】4 擁有多個 Kitties
阿新 • • 發佈:2022-05-13
擁有多個 Kitties
4.1 使用 Tuples 去模擬高階陣列
我們需要引入一些更復雜的儲存項來表示多個使用者對多個專案的所有權。
幸運的是,根據我們的需求,使用一個由 AccountId
和 Index
組成的 tuple 幾乎就可以解決我們的問題了。
以下是我們如何使用這樣的結構構造每個人獨有的 "friends list":
MyFriendsArray get(my_friends_array): map (T::AccountId, u32) => T::AccountId; MyFriendsCount get(my_friends_count): map T::AccountId => u32;
這模擬了一個標準的二維陣列,如:
MyFriendsArray[AccountId][Index] -> AccountId
我們也可以獲取使用者的朋友數量:
MyFriendsArray[AccountId].length()
4.2 相對索引
與以前一樣,我們可以通過索引專案的位置來優化 runtime 需要執行的計算工作。一般的方法是反轉 MyFriendsArray
的對映,並建立一個這樣的儲存項:
MyFriendsIndex: map (T::AccountId, T::AccountId) => u32;
如果 AccountId
代表使用者和他們的朋友, 那麼返回值將是 MyFriendsArray
但是,由於我們的 kitty 都具有唯一識別符號作為 Hash
,並且不能被多個使用者所擁有,所以我們實際上可以簡化此結構
MyKittiesIndex: map T::Hash => u32;
這個索引告訴了我們對於一個給定的 kitty,可以在哪裡檢視該項的 所有者 陣列。
4.3 示例
use support::{decl_storage, decl_module, StorageValue, StorageMap, dispatch::Result, ensure, decl_event}; use system::ensure_signed; use runtime_primitives::traits::{As, Hash}; use parity_codec::{Encode, Decode}; #[derive(Encode, Decode, Default, Clone, PartialEq)] #[cfg_attr(feature= "std", derive(Debug))] pub struct Kitty<Hash, Balance> { id: Hash, dna: Hash, price: Balance, gen: u64, } pub trait Trait: balances::Trait { type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>; } decl_event!( pub enum Event<T> where <T as system::Trait>::AccountId, <T as system::Trait>::Hash { Created(AccountId, Hash), } ); decl_storage! { trait Store for Module<T: Trait> as KittyStorage { Kitties get(kitty): map T::Hash => Kitty<T::Hash, T::Balance>; KittyOwner get(owner_of): map T::Hash => Option<T::AccountId>; AllKittiesArray get(kitty_by_index): map u64 => T::Hash; AllKittiesCount get(all_kitties_count): u64; AllKittiesIndex: map T::Hash => u64; OwnedKittiesArray get(kitty_of_owner_by_index): map (T::AccountId, u64) => T::Hash; OwnedKittiesCount get(owned_kitty_count): map T::AccountId => u64; OwnedKittiesIndex: map T::Hash => u64; Nonce: u64; } } decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin { fn deposit_event<T>() = default; fn create_kitty(origin) -> Result { let sender = ensure_signed(origin)?; let owned_kitty_count = Self::owned_kitty_count(&sender); let new_owned_kitty_count = owned_kitty_count.checked_add(1) .ok_or("Overflow adding a new kitty to account balance")?; let all_kitties_count = Self::all_kitties_count(); let new_all_kitties_count = all_kitties_count.checked_add(1) .ok_or("Overflow adding a new kitty to total supply")?; let nonce = <Nonce<T>>::get(); let random_hash = (<system::Module<T>>::random_seed(), &sender, nonce) .using_encoded(<T as system::Trait>::Hashing::hash); ensure!(!<KittyOwner<T>>::exists(random_hash), "Kitty already exists"); let new_kitty = Kitty { id: random_hash, dna: random_hash, price: <T::Balance as As<u64>>::sa(0), gen: 0, }; <Kitties<T>>::insert(random_hash, new_kitty); <KittyOwner<T>>::insert(random_hash, &sender); <AllKittiesArray<T>>::insert(all_kitties_count, random_hash); <AllKittiesCount<T>>::put(new_all_kitties_count); <AllKittiesIndex<T>>::insert(random_hash, all_kitties_count); <OwnedKittiesArray<T>>::insert((sender.clone(), owned_kitty_count), random_hash); <OwnedKittiesCount<T>>::insert(&sender, new_owned_kitty_count); <OwnedKittiesIndex<T>>::insert(random_hash, owned_kitty_count); <Nonce<T>>::mutate(|n| *n += 1); Self::deposit_event(RawEvent::Created(sender, random_hash)); Ok(()) } } }