# Прохождение академии Азоян
## 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]`, а то не успеваешь иногда прочитать ошибку.
Во многих заголовках искусствено переносится часть текста на новую строку