# Прохождение академии Азоян ## hello-world ### Hello world Нужно ли говорить что нужен nightly toolchain? Нужно ли уточнить где создать файл `build.rs` что в корне проекта, не в `src/` ? При сборки примера с пустым `handle()` возникают предупреждения что не используются `use gstd::{msg, prelude::*};` Но я думаю это нормально. ### Testing smart contract with gtest library На странице с тестами если копировать код из примера файл `hello_world_test.rs` создастся прям в корне. Нужно поменять пример на такой: ```sh mkdir tests touch tests/hello_world_test.rs ``` либо на: ```sh mkdir tests cd tests touch hello_world_test.rs ``` Где показываются два варианта инициализации программы нужно убрать цифру 1, либо добавить цифру 2 для следующего примера (также, я бы показал примеры создания системы прям в функции): 1. Program can be initialized from file: ```rs fn hello_test() { let program = Program::from_file(&sys, "./target/wasm32-unknown-unknown/release/hello_world.wasm"); } ``` 2. Or you may use Program::current() function to load the current program: ```rs fn hello_test() { let program = Program::current(&sys); } ``` После запуска теста у меня такой вывод (с нулём перед сообщением): ``` running 1 test [DEBUG hello_test] Program was initialized with message "0INIT MESSAGE" test hello_test ... ok ``` Дальше в примерах где assert'ы если скопировать их, то переменная `res` нигде не объявлена перед этим. Я бы сделал так: > For example we can check the init message processing result: > + contains empty log (the program doesn’t reply and does not send any messages); > ```rs > let res = program.send(2, String::from("INIT MESSAGE")); > assert!(!res.main_failed()); > ``` > + was successful: > ```rs > assert!(!res.main_failed()); > ``` ### More advanced hello world Если просто копировать enum с этой страницы в `lib.rs` будут ошибки компиляции. Надо добавить `use gstd::ActorId;` и сделать `enum` публичным: ```rs #![no_std] use gstd::{msg, prelude::*, debug, ActorId}; #[derive(Encode, Decode, TypeInfo)] pub enum InputMessages { SendHelloTo(ActorId), SendHelloReply, } ``` Eсли копировать последний на странице тест, попросит закрыть фигурную скобку. Её нужно добавить в пример. Если запустить тест, он не пройдёт: нужно при инициализации отправлять то же сообщение, которое ожидаем получить ответом на `InputMessages::SendHelloTo` ### Program state Вроде всё ок ### Upload the program to the blockchain Я бы писал workshop node с большой буквы Workshop node, чтобы при беглом просмотре сразу была ассоциация при выборе Workshop в idea. При загрузке контракта после подсчёта газа возникает ошибка: ``` 8000: Runtime error: Application, Execution, AbortedDueToTrap, MessageWithBacktrace { message: "wasm trap: wasm unreachable instruction executed", backtrace: Some, Backtrace { backtrace_string: "\n 0: 0x43c2 - <unknown>!rust_begin_unwind\n 1: 0x195b - <unknown>!core… ``` Нужно добавить в корневом Cargo.toml и в `hello-world-io/` к `gstd` ветку `branch = "stable"` ```toml gstd = { git = "https://github.com/gear-tech/gear.git", features = ["debug"], branch = "stable" } ``` ### Homework "Hello world" У многих может быть не установлен `yarn` (и, соответственно `npm`). Сначала надо установить `npm` затем `yarn`: ```sh npm install --global yarn ``` При запуске команды `yarn` возникают следующие ошибки: ``` yarn install v1.22.19 [1/4] Resolving packages... [2/4] Fetching packages... error @polkadot/api@9.13.2: The engine "node" is incompatible with this module. Expected version ">=14.0.0". Got "12.22.9" error Found incompatible module. info Visit https://yarnpkg.com/en/docs/cli/install for documentation about this command. ``` Чтобы исправить или чтобы их не вознкало нужно предупредить чтобы установили последнюю версию nodejs В домашнем задании написано: > When initializing, set its name and date of birth and send a reply about the successful initialization. но в примере метадаты: ```rs type Init = InOut<String,()>; ``` передаётся только строка, а как же возвраст? Тогда нужно указать, что передаётся только имя, а возраст создаётся в самом контракте `date_of_birth: gstd::exec::block_timestamp()`. Также можно вместо `InOut<String, ()>` использовать `In<String>` Если ошибиться при вводе ID программы, то больше нельзя будет переотправить ID программы, будет ошибка `8000: Runtime error: "Get active program error: DoesNotExist, 0x1e9c9f9a228cdc9370d552c93b50b4eb2075d4c8` чтобы этого избежать надо переконнектить аккаунт либо тестировать в приватной вкладке, которая не кеширует ничего. В примере Тамагочи нужно сделать публичными поля `name`, `date_of_birth`: ```rs #[derive(Default, Encode, Decode, TypeInfo)] pub struct Tamagotchi { pub name: String, pub date_of_birth: u64, } ``` ## Escrow ### Escrow tutorail Нет замечания ### Escrow Project Coding Practice Я бы выделял моноширинным шрифтом код в подсказках типа: > (For that we have to add `#[derive(Debug, PartialEq, Eq)]` above the EscrowState enum) В конце в блоке Finally я бы привёл пример функции целиком (причём, для туториала можно в одну строчку, игнорирая оригинальное форматирование из кода): ```rs fn deposit(&mut self) { assert_eq!(self.state, EscrowState::AwaitingPayment, "State must be `AwaitingPayment"); assert_eq!(msg::source(), self.buyer, "The message sender must be a buyer"); assert_eq!(msg::value(), self.price, "The attached value must be equal to set price"); self.state = EscrowState::AwaitingDelivery; msg::reply(EscrowEvent::FundsDeposited, 0) .expect("Error in reply `EscrowEvent::FundsDeposited"); } ``` ### Reading program state using your own function Надо добавить `branch = "stable"` в секцию к `gstd` ```toml gstd = { git = "https://github.com/gear-tech/gear.git", branch = "stable" } ``` На странице с тестами если копировать код из примера файл `escrow_test.rs` создастся прям в корне. Нужно поменять пример на такой: ```sh mkdir tests touch tests/escrow_test.rs ``` либо на: ```sh mkdir tests cd tests touch escrow_test.rs ``` В примере теста надо поправить заголовок на ```rs use escrow_io::{InitEscrow, EscrowAction, EscrowEvent}; ``` Не проходит `assert!(res.log().is_empty());` в конце `init_escrow()` ### Coding Странно, что смешаны задания по Escrow и тамагочи Текст где описываются константы выглядит неопрятно: кое-где используется "=", где-то ":=", где-то ":", а где-то сразу стоит число. Также плохо улавливается связь что нужно **правильно** инициализировать так: ```rs fed_block: exec::block_timestamp(), entertained_block: exec::block_timestamp(), rested_block: exec::block_timestamp(), ``` а не **неправильно** так: ```rs fed_block: HUNGER_PER_BLOCK, entertained_block: ENERGY_PER_BLOCK, rested_block: BOREDOM_PER_BLOCK, ``` Дальше не совсем очевидно как это использовать в расчётах. В коде где `impl Metadata` для тамагочи надо исправить на: ```rs type Init = InOut<String, ()>; ``` ### Homework "Escrow tutorial" Почему-то отображается всё по 10, хотя в контракте 10000 ## Fungible/Non-fungible token ### Fungible tokens Всё ок ### Non-Fungible token Всё ок ### Asynchronous communication between programs Я бы слово drastically заменил на cardinally или radically чтоб не гуглить ### Distributed transactions Всё ок ### Implementation of fungible token on Gear Нужен пробел между предложениями > (Maintaining idempotency).There are two possible risks when sending a transaction: ### Homework "Fungible/Non-fungible token" Вроде ок. Задание лёгкое. ## Tamagotchi shop ### Tamagotchi shop Непонятно что делать со `store contract` создавать его в отдельном репизотрии или в этом же? Я бы называл его не Store, а Shop, как и название главы. Также получается, что ученик должен из кода контракта самостоятельно понять каким должен быть крейт io и закодировать его. Может быть привести пример `StoreAction` и `StoreEvent`? Надо чтобы в примере был указан макрос `Default` ```rs #[derive(Default)] pub struct AttributeStore { /* ... */ } ``` А также `Clone` для `Metadata` ```rs #[derive(Clone)] pub struct Metadata { /* ... */ } ``` Кстати, почему здесь `Metadata` своя, а не используется `gmeta::Metadata` для `ProgramMetadata`? Нужно импортировать `use gstd::exec`, `enum`'ы и многое другое c крейта `io`, `ft_logic_io`, `ft_main_io` ну либо ученик догадается сам, компилятор подскажет А вот что точно нужно показать это как импортировать `shared-fungible-token` в корневой `Cargo.toml` крейт ```toml ft-main-io = { git = "https://github.com/gear-dapps/sharded-fungible-token.git", tag = "0.1.3" } ft-logic-io = { git = "https://github.com/gear-dapps/sharded-fungible-token.git", tag = "0.1.3" } ``` ### Homework "Tamagochi shop" Нужно сказать, что если мы собираемся отправлять асинхронные сообщения, то нужно заменить ```rs #[no_mangle] unsafe extern "C" fn handle() ``` на ```rs #[gstd::async_main] async fn main() ``` Также наверное нужно показать как правильно готовить сообщение для отправки на контракт shared-fungible-token: ```rs let action = Action::Approve { approved_account: account, amount, } .encode(); let payload = FTokenAction::Message { transaction_id: 1, payload: action, }.encode(); msg::send_for_reply(ft_address, payload, 0) .expect("Can't send message") .await .expect("Can't receive reply"); ``` Так же нужно сказать, что надо использовать контракт Store (Tamagochi shop) локально, который он делал в этом уроке. И соответственно в контракте Store во всех наших крейтах Cargo.toml поменять ветку на `branch = "testnet"` Судя по следующему домашнему заданию `Auction` структура `Tamagochi` содержит не опциональный адрес `ft_contract_id` тогда возникает вопрос, чем его иницализировать? При создании Tamagochi в `init` добавить? Значением по умолчанию? Судя по тому, что существует `TmgAction::SetFTokenContract(ft_address)` значением по умолчанию и потому что во фронтенде `frontend/src/assets/meta/meta4.txt` только имя передаётся. Но это не очевидно. ## Auction ### Adding gas reservation and system signals ### Homework "Auction" Непонятно что отвечать если с Тамагочи всё хорошо и он не нуждается в еде, сне и развлечениях. Также не понятно в чём измеряется `duration` секунды, милисекунды ил что-то другое? А оно измеряется в блоках ## Program factory ### Program factory Описание вроде ок ### Coding Возможно лучше перенести в `io/lib.rs` код `pub type EscrowId = u64;` и enum'ов `FactoryAction`, `FactoryEvent` хотя это не обязательно. Но, например ученик будет пользоваться предыдущим шаблоном с метадатой, надо написать чтобы самостоятельно реализовал трейт `Metadata` иначе не соберётся из-за `build.rs` Но обязательно надо показать, что нужно добавить крейт с самим Escrow контрактом. В моём случае это ```toml escrow-io = { path = "../escrow/io" } ``` Также непонятно откуда брать `GAS_FOR_CREATION`, нужно добавить это в начале. В уроке по Escrow `EscrowAction::Deposit` и `EscrowAction::ConfirmDelivery` не принимали ActorId, теперь принимает. Надо указать, что необходимо добавить в Escorw это контракт ```rs pub enum EscrowAction { Deposit(ActorId), ConfirmDelivery(ActorId), } ``` и добавить какой-то логики на этот счёт, а то в академии написано: _Other methods are implemented easily since all logic and all checks are included into the Escrow contract_ ### Testing Возможно путь до `wasm`'a Escrow контракта другой, я бы обратил на это внимание в тексте. Тест приведённый в примере не проходит, фейлится на первом `assert`'e ### Homework "Program factory" Вроде не трудно. ## Tamagotchi battle ### Tamagotchi battle Кажется в коде опечатка ```rs TmgEvent::Owner(ActorId) { owner: ActorId, energy: u32, power: u32, } ``` Нужно убрать (ActorId) Надо в примере `const` написать в нижнем регистре: ```rs CONST MAX_POWER: u16 = 10_000; CONST MIN_POWER: u16 = 3_000; ``` Поправить на u16 возвращаемый тип: ```rs pub fn generate_power() -> 16 { // ... ``` Дальше скорее всего имеется ввиду создать число из массива размером два байта, поэтому код ```rs let bytes: [u8; 32] = [random[0], random[1]]; let random_power: u16 = 16::from_be_bytes % MAX_POWER; ``` надо заменить на ```rs let bytes: [u8; 2] = [random[0], random[1]]; let random_power: u16 = u16::from_be_bytes(bytes) % MAX_POWER; ``` Функции `get_trun()` и `generate_power()` не аккуратно написаны в примере, нужно убрать две точки при переносе строк и оставть одну ```rs let (random, _) = exec::random(random_input). .expect("Error during getting the random number"); // ... let (random, _) = exec::random(random_input). .expect("Error during getting the random number"); ``` Нужно переименовать функцию в примере *where get_owner:* ```rs async fn get_tmg_info(tmg_id: &TamagotchiId) ``` на `get_owner()` так как в остальном коде используется `get_owner()` Так как `Player` клонируется нужно добавить ему макрос `Clone` ```rs #[derive(Default, Clone)] pub struct Player { // ... ``` Возможно нужно по-прежнему напоминать, что надо добавить крейт с `io` для `Store` и `Tamagotchi` Непонятно чему равны константы `SWORD_POWER` и `SWORD_ID` Также я бы для удобства привёл пример кода enum'ов `BattleAction` и `BattleEvent` ### Coursework Непонятно ссылку на какой контракт надо загрузить. Также получается надо добавить `TmgAction::Owner` и `TmgEvent::Owner` в контракт Tamagotchi Непонятно какие значения `power`, `energy` во время регистрации при создании Игрока. Точнее в тексте описано, что они случайные из диапазона, но если копировать код не будет понятно. Может лучше написать сразу так: ```rs let player = Player { owner, tmg_id: *tmg_id, energy: generate_power(), power: generate_power(), attributes, }; ``` Если копировать код ```rs self.players[next_turn] = opponent; // check if opponent lost if opponent.energy == 0 ``` будет ошибка компиляции, т.к. `opponent` перемещается. Можно заменить на: ```rs self.players[next_turn] = opponent; // check if opponent lost if self.players[next_turn].energy == 0 ``` ______________ # Общие замечания Я бы во все примеры с кодом добавил кнопку "Копировать". Все обозначения файлов и директорий выделял бы либо моноширинным текстом `lib.rs`, либо жирным текстом **lib.rs**, и все директории писал бы со слешем `src/` или **src/** Во всех примерах Cargo.toml надо поменять версии крейтов gear с `branch = "stable"` на `branch = "testnet"` В idea я бы сделал, чтобы сообщения исчезали по нажатию на `[x]`, а то не успеваешь иногда прочитать ошибку. Во многих заголовках искусствено переносится часть текста на новую строку