Vitajte na bonusovom cvičení zameranom na využitie jazyka Rust v Blockchaine
- Rust:
curl –proto ’=https’ –tlsv1.2 -sSf https://sh.rustup.rs | sh
- Rust: verzia nightly
rustup default nightly
- Rust wasm
rustup target add wasm32-unknown-unknown
- OS specific moduly ktoré vypíše pri kompilácii (Treba inštalovať dodatočne keďže každé OS má rôzne prerequizity)
- 60gb úložisko a 8gb ram
Máte predpripravenú šablónu Parachainu. Doplnte paletu voting o funkciu ktorá umožní vytvárať referendá pre kvadratické hlasovanie. Riešenie otestujte v Runtime.
-
Alice hlasuje aye s
1000
hlasovacou silou. Musí rezervovať1000000
tokenov -
Bob hlasuje nay s hlasovacou silou
30
. Musí rezervovať900
tokenov -
Bob zahlasuje nay s ďalšou hlasovacou silou
70
. Musí rezervovať ďalších9910
tokenov (Dokopy má Bob hlasovaciu silu100
a rezervovaných10000
tokenov)
Celková hlasovacia sila na referendu je teda:
Aye - 1000
Nay - 100
Referendum úspešne ukončí v prospech tvorcu.
- Krok 1. Naviguj do palety voting
cd cumulus/parachain-template/pallets/voting
- Krok 2. Doplň funkciu "create_proposal" podľa komentárov v kóde
- Krok 2.1 Otestovanie doplnenej funkcie cez
cargo build
- Krok 2.2 Otestovanie doplnenej funkcie cez testy
cargo test --package pallet-voting --lib -- tests --nocapture
- Krok 3. Skompilovanie Polkadotu -
cd Polkadot
acargo build --release
- Krok 4. Skompilovanie Parachain šablóny -
cargo b -r -p parachain-template-node
- Krok 5. Prejsť do zložky binaries
cd binaries
- Krok 6. Stiahnuť si zombienet binárku pre špecifický OS (Linux a Mac only)
https://github.com/paritytech/zombienet/releases/tag/v1.3.90
(Windows buď cez virtuálnu mašinu alebo manuálne spustiť sieťhttps://docs.substrate.io/tutorials/build-a-parachain/connect-a-local-parachain/
) - Krok 7. Spustiť zombienet binárku cez
./zombienet-macos -p native -c 1 spawn config.toml
- Krok 8. Otvoriť PolkadotJS link ktorú poskytol Zombienet
- Krok 9. Extrinsics tab (Otestuj si voting paletku) vytvor proposal
Práve si sa naučil základy interakcie s Blockchainom ✅.
- Všimol si si niektoré limitácie ktoré táto paleta obsahuje? Aké?
- Rozšír paletu o žiadosti a poplatky za registráciu
- Rozšír referendá o možnosť žiadať o prostriedky. Keď referendum skončí úspešne (AYE>NAY) prostriedky užívateľovi vyplať z Pokladnice (Vytvor špeciálny účet ktorý na to bude slúžiť a depozituj mu aktíva)
Ak som stratený mám dostupných nasledovných žolíkov ktoré využívam postupne.
- ChatGPT?
- Ťahák?
- Cvičiaci?
- Riešenie?
-
register_voter (origin: OriginFor<T>, who: T::AccountId)
Funkcia registruje hlasujúceho (Registruje jeho entitu - hlasovať môžu len registrovaný voliči). Potrebné sudo. -
unregister_voter (origin: OriginFor<T>, who: T::AccountId)
Funkcia na deregistráciu hlasujúceho. Potrebné sudo. -
create_proposal (origin: OriginFor<T>, text: T::Hash, end_block: T::BlockNumber )
Funkcia na vytvorenie referenda, môžu ho vytvoriť aj normálny užívatelia. (Text si zahashuj!) -
create_vote (origin: OriginFor<T>, id: u32, vote: Vote, vote_powers: BalanceOf<T>)
Funkcia na hlasovanie - len registrovaný používateľ môže hlasovať -
deposit_token (origin: OriginFor<T>, who: T::AccountId, amount: BalanceOf<T>)
Testovacia funkcia na pridanie aktív. Potrebné sudo -
close_proposal(origin: OriginFor<T>, id: u32)
Funkcia na uzavretie referenda, referendum je možné uzavrieť po čase na ktorý bolo aktivované. Zavrieť ho môže ktokoľvek (Aby sa proposaly nekopili a nezahltili úložisko).
- TokensDeposited {who: T::AccountId, amount: BalanceOf}: Informuje používateľa o pridaných aktívach na účet
- VoterRegistered {who: T::AccountId}: Informuje používateľa o registrácii entity
- VoterDeregistered {who: T::AccountId}: Informuje používateľa o deregistrácii entity
- ProposalCreated {who: T::AccountId, proposal_id: u32}: Informuje používateľa o úspešnom vytvorení referenda
- ProposalVoted {who: T::AccountId, proposal_id: u32, vote: Vote, vote_power: BalanceOf}: Informuje používateľa o úspešnom hlasovaní
- ProposalClosed {who: T::AccountId, proposal_id: u32, status: ProposalStatus}: Informuje používateľa o úspešnom uzavretí hlasovania
- NotEnoughTokenToReserve: Používateľ chce hlasovať s viac aktívami než disponuje
- NonExistentProposal: Referendum neexistuje (Buď bolo uzavreté alebo nebolo nikdy vytvorené)
- NonExistentIdentity: Používateľ nie je registrovaný
- TooFarInTheFuture: Používateľ chce vytvoriť referendum na príliš ďalekú budúcnosť (Limit 1000blokov do budúcna - možné zmeniť v mock.rs)
- ProposalNotOverYet: Používateľ chce uzatvoriť referendum keď ešte stále nie je rozhodnuté
- AlreadyRegistered: Identita nového používateľa už existuje
- NotMatchingVote: Používateľ chce na referendum hlasovať znovu s opozíciou proti jeho pôvodnému hlasu (nedovolené striedať AYE a NAY na rovnakom referende)
//Returns proposal for specific id
pub type Proposals<T: Config> = StorageMap<_, Blake2_128Concat, u32, Proposal<T>>;
Úložisko vráti objekt referenda so špecifickou ID.
//Returns user ids in vector for specific proposal
pub type ProposalVotes<T: Config> = StorageMap<_, Blake2_128Concat, u32, BoundedVec<T::AccountId, T::MaxVoters>>;
Úložisko vráti vektor účtov ktoré hlasovali na špecifické referendum.
//Returns id of last proposal
pub type LastProposalId<T: Config> = StorageValue<_, u32>;
Úložisko ktoré informuje o poslednej ID referenda.
//Map accountid onto user_vote structure
pub type UserVotes<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountId, BoundedVec<UserVote, T::MaxVotes>>;
Úložisko ktoré vráti hlasy ktoré účet použil.
Ak sa ti nepodarilo vyriešiť funkciu tak si pozri riadok s ktorým sa pasuješ a potom sa vráť a skús zvyšok dokončiť sám.
#[pallet::call_index(3)]
#[pallet::weight(Weight::from_parts(10_000, 0) + T::DbWeight::get().reads_writes(1,1))]
pub fn create_proposal(
origin: OriginFor<T>,
text: T::Hash,
end_block: U256,
) -> DispatchResult {
let who = ensure_signed(origin)?;
//We check if block is not too far in the future
//We get current block and add x blocks and check if end block is not bigger than that
let current_block = frame_system::Pallet::<T>::block_number();
//Get max future block configurable max future block
let max_block = current_block + T::MaxFutureBlock::get().into();
//Check if block is not too far in the future
ensure!(end_block < max_block.into(), Error::<T>::TooFarInTheFuture);
//Query latest proposal id
let id = LastProposalId::<T>::get().unwrap_or(0);
// Bounded vector for proposals and change storage map to storage value
Proposals::<T>::insert(
id + 1,
Proposal {
id: id + 1,
text,
vote_count_aye: 0u32.into(),
vote_count_nay: 0u32.into(),
end_block,
status: ProposalStatus::InProgress,
},
);
//Update last proposal id
LastProposalId::<T>::put(id + 1);
//Emit event proposal created
Self::deposit_event(Event::ProposalCreated { who, proposal_id: id + 1 });
Ok(())
}