November 8, 2021

SubQuery | Module 1, 2, 4

🔹 У SubQuery есть Academy для Developer.

В этой академии будет 6 модулей:

Module 1 - есть в этом гайде
Module 2 - есть в этом гайде
Module 3 - пропустили задание
Module 4 - Актуально для выполнения. Сдача задания до 24 января (01:00 Киев).
Module 5 - скоро будет
Module 6 - скоро будет

• Чтобы стать SubQuery Spartan нужно выполнить только 1 и 2 модули.

Читайте полную инструкцию как стать Spartan проекта:
teletype.in/@elrmcfteam/SubQuerySpartan


Чтобы выполнить этот модуль нам нужно: • Акааунт на github.com
• Арендовать сервер, можете прочитать наш гайд как арендовать сервера.

По мощности подойдет любой
я выбрал 1 CPU, 1 GB RAM, 20 GB SSD, Ubuntu-20.04.

Запуск

• У вашего сервера есть IP-адрес сервера - Пользователь - Пароль эти данные мы будем использовать.

  • Для Windows скачиваем приложение https://www.putty.org/
  • на MacOS/ Linux открываем встроенный "Терминал"

В putty вписываем ваш IP-адрес,в "Терминал" нужно ввести команду ssh root@ваш IP-адрес

В открытом терминале Windows

root

В открытом терминале MacOS (то что на скрине выше)

 ssh root@ваш IP-адрес

Дальше просит вписать пароль, копируем его, но командой Control+V его не вставить, вставка пароля осуществляться правой кнопкой мыши и Enter. Сам пароль при этом не будет отображен, это сделано в целях безопасности.
⚠️ Если после ввода пароля произошел сбой значит нужно: вписать пароль вручную.

Module 1


• Обновляем пакеты:

sudo apt update


• Устанавливаем нужные элементы:

apt install npm
npm install -g yarn
npm install -g @subql/cli
apt install docker-compose

• Обновим ноду до последней версии:

npm install -g n
n latest


• Создаем и входим в директорию:

mkdir SubQl
cd SubQl


• Создаем проект:

subql init --starter subqlHelloWorld

Попунктно будет появлятся каждая строчка, нам нужно заполнить только Authors:

Git repository: Enter RPC endpoint: Enter Authors: ваш ник
Description: Enter Version: [1.0.0]: Enter License: [Apache-2.0]: Enter

• Заходим в проект:

cd subqlHelloWorld


• Устанавливаем зависимости и собираем код:

npm install
npm run-script codegen
npm run-script build


• Запускаем докер:

docker-compose pull && docker-compose up


Через несколько минут должный пойти логи, они могут быть с ошибками, это нормально, в целом будет подобная картина:

• Дальше в строке браузера пишем:

Ваш_ip_адрес_серваера:3000

• У нас откроется приложение где мы сможем протестировать то что запустили.

Туда вписываем:

{
 query{
   starterEntities(last:10, orderBy:FIELD1_ASC ){
     nodes{
       field1
     }
   }
 }
}

Жмем на кнопку по центру и в правой колонке будет отображаться нумерация блока, с каждым нажатием, будет все больше пройденных блоков.

• Если всё окей, в терминале нужно остановить докер чтобы работать дальше нажимаем Control + C и вписываем команду:

docker-compose stop

• Теперь нам нужно сдать задание, для этого нужно загрузить наш проект на https://github.com/ если вы не зарегестрировались в начале гайда делаем это сейчас, не забудьте подтвердить почту.


• Теперь нужно вписать несколько команд
(вписываем переменные не удаляя 👉" 👈):

sudo apt install git
git config --global user.name "ник_гитхаб"
git config --global user.email "ваш_email"
eval ssh-agent -s
ssh-keygen -t rsa -b 4096 -C "ваш_email" -f ~/.ssh/id_rsa


• Три раза вписываем:

cat ~/.ssh/id_rsa.pub

Высветился длинный ключ, мы его копируем целиком и переходим в github.com

• Создаем новый репозиторий:

Вписываем название, я вписал название проекта:

Дальше нужно перейти с настройки:

И добавить ключ который мы скопировали с терминала в поле SSH key:

Вставляем ключ и жмём Add SSH key:

Так же нам нужно создать свой Personal access tokens:

Settings -> Developer Settings -> Personal Access Token -> Generate new token

Даем название своему токену (паролю), выбираем период который он будет действовать, выбираем галочки как на скрине и создаем его.

• Этот access tokens нам скоро понадобится:
(сохраняем его и не теряем, он показывается один раз)

• Возвращаемся в терминал и вписываем несколько команд:

git init
git remote add origin https://github.com/ник_гитхаб/название_репозитория.git
такая строка у вас есть на этом экране

• Дальше:

git add .
git commit -m 'create project'
git push origin master


В поле Username for 'https://github.com': вписываем ник гитхаб.

В поле Password for 'https://ник_гитхаб@github.com': вписываем access tokens который мы создавали

Если видите эту строку, значит вы всё правильно подключили
* [new branch] master -> master.

• Переходим на сайт https://project.subquery.network/ и логинимся через github.
Создаем новый проект- Create Project.

• Заполняем Project Name и вставляем ссылку на свой репозиторий + Create Project:

• Будут такие два поля, жмем Deploy и внутри еще одна кнопка Deploy update%

Поздравляю, вы выполнили задание.

Module 2

Продолжим ставить всё на том же сервере.
Подключаемся к серверу.

Входим в существующую директорию:

cd SubQl


Дальше очень интересно, можете ознакомиться с официальным гайдом, но спасибо команде nodes.guru они для нас все упростили:

git clone https://github.com/subquery/tutorials-account-balances.git


• Заходим в папку:

cd tutorials-account-balances


• Устанавливаем зависимости и собираем код:

npm install
npm run-script codegen
npm run-script build


Запускаем докер:

docker-compose pull && docker-compose up


Стоит подождать несколько минут пока не пойдут подобные логи, могут проскакивать ошибки, это нормально.

• Дальше в строке браузера пишем:

Ваш_ip_адрес_серваера:3000

• У нас откроется приложение где мы сможем протестировать то что запустили.

Туда вписываем:

query {
  accounts(first:15, orderBy:BALANCE_ASC){
    nodes{
      account
      balance
    }
  }
}

Жмем на кнопку по центру и в правой колонке будет так:

• Возвращаемся в терминал, жмем Соntrol+C чтобы остановить все процессы и можно было дальше вводить команды.


Осталось загрузить наш проект на https://github.com/ делаем этого точно так же как выгружали модуль 1

• Нужно вписать несколько команд
(вписываем переменные не удаляя 👉" 👈):

sudo apt install git
git config --global user.name "ник_гитхаб"
git config --global user.email "ваш_email"
eval ssh-agent -s
ssh-keygen -t rsa -b 4096 -C "ваш_email" -f ~/.ssh/id_rsa


• Три раза вписываем чтобы получить длинный ключ:

cat ~/.ssh/id_rsa.pub


• Переходим в github.com, создаем новый репозиторий, все абсолютно так же как с модулем один
(только название самого репозитория меняем).

• Добавляем SSH key
(ключ который мы скопировали с терминала).

• Создать новый access tokens не нужно, используем тот который создали при прохождении первого модуля.
• Возвращаемся в терминал и вписываем несколько команд:

git init
git remote set-url origin https://github.com/ник_гитхаб/название_репозитория
такая строка у вас есть на этом экране, только не добавляем git.

• Дальше:

git add .
git commit -m 'create project'
git push origin master


В поле Username for 'https://github.com': вписываем ник гитхаб.

В поле Password for 'https://ник_гитхаб@github.com': вписываем access tokens

Если видите эту строку, значит вы всё правильно подключили
* [new branch] master -> master.

• Переходим на сайт https://project.subquery.network/ и логинимся через github.
Создаем новый проект- Create Project.

• Заполняем Project Name и вставляем ссылку на свой репозиторий + Create Project:

• Будут такие два поля, жмем Deploy и внутри еще одна кнопка Deploy update%

Module 4

В этом задании нам нужно будет работать с файловой системой, скачайте программы:

Для Windows - mobaxterm
для MacOS - cyberduck (подключение к серверу через SSH)

Если вы делаете модули в-первые

• Обновляем пакеты:

sudo apt update


• Устанавливаем нужные элементы:

apt install npm
npm install -g yarn
npm install -g @subql/cli
apt install docker-compose

• Обновим ноду до последней версии:

npm install -g n
n latest

Если вы делали предыдущие модули подключайтесь к серверу

• Обновим ноду до последней версии (навсякий случай):

npm install -g n
n latest

Задание 1

• Создаем новый проект:

subql init

с названием:

staking-rewards

(Project name [subql-starter]: staking-rewards)

• Заходим в программу которую скачивали и подключаемся к серверу, я буду использовать с cyberduck так как работаю с MacOS.

• В документе schema.graphql меняем содержимое на:

type StakingReward @entity{
id: ID! #blockHeight-eventIdx
account: String!
balance: BigInt!
date: Date!
blockHeight: Int!
}


• В документе project.yaml заменим некоторые значения, меняем содержимое на:

specVersion: 0.2.0
name: sashabnk
version: 1.0.0
description: ''
repository: ''
schema:
  file: ./schema.graphql
network:
  genesisHash: '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3'
  endpoint: wss://polkadot.api.onfinality.io/public-ws
dataSources:
  - kind: substrate/Runtime
    startBlock: 7000000
    mapping:
      file: ./dist/index.js
      handlers:
      - handler: handleStakingRewarded
        kind: substrate/EventHandler
        filter:
          module: staking 
          method: Rewarded


• По пути src- mappings- mappingHandlers.ts меняем содержимое на:

import {SubstrateEvent} from "@subql/types";
import {StakingReward} from "../types";
import {Balance} from "@polkadot/types/interfaces";

export async function handleStakingRewarded(event: SubstrateEvent):
Promise<void> {
    const {event: {data: [account, newReward]}} = event;
    const entity = new StakingReward(`${event.block.block.header.number}-${event.idx.toString()}`);
    entity.account = account.toString();
    entity.balance = (newReward as Balance).toBigInt();
    entity.date = event.block.timestamp;
    entity.blockHeight = event.block.block.header.number.toNumber();
    await entity.save();
}

• Так же из-за докера могут быть ошибки, чтобы их избежать заменим в документе docker-compose.yml содержимое на:

version: '3'

services:
  postgres:
    image: postgres:12-alpine
    ports:
      - 5432:5432
    volumes:
      - .data/postgres:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: postgres

  subquery-node:
    image: onfinality/subql-node:v0.25.3
    depends_on:
      - "postgres"
    restart: always
    environment:
      DB_USER: postgres
      DB_PASS: postgres
      DB_DATABASE: postgres
      DB_HOST: postgres
      DB_PORT: 5432
    volumes:
      - ./:/app
    command:
      - -f=/app
      - --local

  graphql-engine:
    image: onfinality/subql-query:v0.8.0
    ports:
      - 3000:3000
    depends_on:
      - "postgres"
      - "subquery-node"
    restart: always
    environment:
      DB_USER: postgres
      DB_PASS: postgres
      DB_DATABASE: postgres
      DB_HOST: postgres
      DB_PORT: 5432
    command:
      - --name=app
      - --playground
      - --indexer=http://subquery-node:3000

• Возвращаемся в терминал

Заходим в проект:

cd staking-rewards
yarn install
yarn codegen
yarn build

• Запускаем докер:

docker-compose pull && docker-compose up

такими будут логи:


• Дальше в строке браузера пишем:

Ваш_ip_адрес_серваера:3000

• У нас откроется приложение где мы сможем протестировать то что запустили.

Туда вписываем:

query{
stakingRewards(first: 3 orderBy:BLOCK_HEIGHT_ASC){
nodes{
blockHeight
account
date
balance
}
}
}

• Если всё окей, в терминале нужно остановить докер чтобы работать дальше

нажимаем Control + C и вписываем команду:

docker-compose stop

Задание 2

• В документе schema.graphql меняем содержимое на:

type StakingReward @entity{
id: ID! #blockHeight-eventIdx
account: String!
balance: BigInt!
date: Date!
blockHeight: Int!
}

type SumReward @entity{
id: ID! # AccountId
totalReward: BigInt!
blockheight: Int!
}


• В документе project.yaml меняем содержимое на:

specVersion: 0.2.0
name: sashabnk
version: 1.0.0
description: ''
repository: ''
schema:
  file: ./schema.graphql
network:
  genesisHash: '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3'
  endpoint: wss://polkadot.api.onfinality.io/public-ws
dataSources:
  - kind: substrate/Runtime
    startBlock: 7000000
    mapping:
      file: ./dist/index.js
      handlers:
      - handler: handleSumRewarded
        kind: substrate/EventHandler
        filter:
          module: staking
          method: Rewarded
      - handler: handleStakingRewarded
        kind: substrate/EventHandler
        filter:
          module: staking
          method: Rewarded


• По пути src- mappings- mappingHandlers.ts меняем содержимое на:

import {SubstrateEvent} from "@subql/types";
import {StakingReward, SumReward} from "../types";
import {Balance} from "@polkadot/types/interfaces";

export async function handleStakingRewarded(event: SubstrateEvent):
Promise<void> {
    const {event: {data: [account, newReward]}} = event;
    const entity = new
StakingReward(`${event.block.block.header.number}-${event.idx.toString()
}`);
    entity.account = account.toString();
    entity.balance = (newReward as Balance).toBigInt();
    entity.date = event.block.timestamp;
    entity.blockHeight = event.block.block.header.number.toNumber();
    await entity.save();
}

function createSumReward(accountId: string): SumReward {
    const entity = new SumReward(accountId);
    entity.totalReward = BigInt(0);
    return entity;
}
export async function handleSumRewarded(event: SubstrateEvent):
Promise<void> {
    const {event: {data: [account, newReward]}} = event;
    let entity = await SumReward.get(account.toString());
    if (entity === undefined){
    entity = createSumReward(account.toString());
}
    entity.totalReward = entity.totalReward + (newReward as Balance).toBigInt();
    entity.blockheight = event.block.block.header.number.toNumber();
    await entity.save();
}


• Возвращаемся в терминал

Обновим данные:

yarn codegen
yarn build

• Запускаем докер:

docker-compose pull && docker-compose up


• Дальше в строке браузера пишем:

Ваш_ip_адрес_серваера:3000

• У нас откроется приложение где мы сможем протестировать то что запустили.

Туда вписываем:

query{
sumRewards(first:3 orderBy:BLOCKHEIGHT_ASC){
nodes{
blockheight
id
totalReward
}
}
}

• Если всё окей, в терминале нужно остановить докер чтобы работать дальше

нажимаем Control + C и вписываем команду:

docker-compose stop

Задание 3

• В документе schema.graphql меняем содержимое на:

type StakingReward @entity{
id: ID! #blockHeight-eventIdx
account: SumReward!
balance: BigInt!
date: Date!
blockheight: Int
}

type SumReward @entity{
id: ID! # AccountId
totalReward: BigInt!
blockheight: Int!
}


• В документе project.yaml меняем содержимое на:

specVersion: 0.2.0
name: sashabnk
version: 1.0.0
description: ''
repository: ''
schema:
  file: ./schema.graphql
network:
  genesisHash: '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3'
  endpoint: wss://polkadot.api.onfinality.io/public-ws
dataSources:
  - kind: substrate/Runtime
    startBlock: 7000000
    mapping:
      file: ./dist/index.js
      handlers:
      - handler: handleSumRewarded
        kind: substrate/EventHandler
        filter:
          module: staking
          method: Rewarded
      - handler: handleStakingRewarded
        kind: substrate/EventHandler
        filter:
          module: staking
          method: Rewarded


• По пути src- mappings- mappingHandlers.ts меняем содержимое на:

import {SubstrateEvent} from "@subql/types";
import {StakingReward, SumReward} from "../types";
import {Balance} from "@polkadot/types/interfaces";

export async function handleStakingRewarded(event: SubstrateEvent):
Promise<void> {
    const {event: {data: [account, newReward]}} = event;
    const entity = new
StakingReward(`${event.block.block.header.number}-${event.idx.toString()
}`);
    entity.accountId = account.toString();
    entity.balance = (newReward as Balance).toBigInt();
    entity.date = event.block.timestamp;
    await entity.save();
}

function createSumReward(accountId: string): SumReward {
    const entity = new SumReward(accountId);
    entity.totalReward = BigInt(0);
    return entity;
}
export async function handleSumRewarded(event: SubstrateEvent):
Promise<void> {
    const {event: {data: [account, newReward]}} = event;
    let entity = await SumReward.get(account.toString());
    if (entity === undefined){
    entity = createSumReward(account.toString());
}
    entity.totalReward = entity.totalReward + (newReward as Balance).toBigInt();
    entity.blockheight = event.block.block.header.number.toNumber();
    await entity.save();
}


• Возвращаемся в терминал

Обновим данные:

yarn codegen
yarn build

• Запускаем докер:

docker-compose pull && docker-compose up


• Дальше в строке браузера пишем:

Ваш_ip_адрес_серваера:3000

• У нас откроется приложение где мы сможем протестировать то что запустили.

Туда вписываем:

query{
sumRewards(filter:
{id:{equalTo:"16jWQMBXZNxfgXJmVL61gMX4uqtc9WTXV3c8DGx6DUKejm7"}}){
nodes{
blockheight
id
totalReward
stakingRewardsByAccountId{
nodes{
balance
}
}
}
}
}

Кому интересно:
в результатах должно быть две строки "balance", как в оригинальном документе

Чтобы увидеть обе строки подождите 15 минут с запущенным докером. Так что одна строка с балансом это не проблема.

• Если всё окей, в терминале нужно остановить докер чтобы работать дальше

нажимаем Control + C и вписываем команду:

docker-compose stop

Задание 4

• В документе schema.graphql меняем содержимое на:

type StakingReward @entity{
id: ID! #blockHeight-eventIdx
account: SumReward!
balance: BigInt!
date: Date!
blockheight: Int
}

type SumReward @entity{
id: ID! # AccountId
totalReward: BigInt!
blockheight: Int
}


• В документе project.yaml меняем содержимое на:

specVersion: 0.2.0
name: sashabnk
version: 1.0.0
description: ''
repository: ''
schema:
  file: ./schema.graphql
network:
  genesisHash: '0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3'
  endpoint: wss://polkadot.api.onfinality.io/public-ws
dataSources:
  - kind: substrate/Runtime
    startBlock: 6000000
    mapping:
      file: ./dist/index.js
      handlers:
      - handler: handleSumReward
        kind: substrate/EventHandler
        filter:
          module: staking
          method: Reward
      - handler: handleStakingReward
        kind: substrate/EventHandler
        filter:
          module: staking
          method: Reward


• По пути src- mappings- mappingHandlers.ts меняем содержимое на:

import {SubstrateEvent} from "@subql/types";
import {StakingReward, SumReward} from "../types";
import {Balance} from "@polkadot/types/interfaces";

export async function handleStakingReward(event: SubstrateEvent):
Promise<void> {
    const {event: {data: [account, newReward]}} = event;
    const entity = new
StakingReward(`${event.block.block.header.number}-${event.idx.toString()
}`);
    entity.accountId = account.toString();
    entity.balance = (newReward as Balance).toBigInt();
    entity.date = event.block.timestamp;
    await entity.save();
}

function createSumReward(accountId: string): SumReward {
    const entity = new SumReward(accountId);
    entity.totalReward = BigInt(0);
    return entity;
}
export async function handleSumReward(event: SubstrateEvent):
Promise<void> {
    const {event: {data: [account, newReward]}} = event;
    let entity = await SumReward.get(account.toString());
    if (entity === undefined){
    entity = createSumReward(account.toString());
}
    entity.totalReward = entity.totalReward + (newReward as Balance).toBigInt();
    entity.blockheight = event.block.block.header.number.toNumber();
    await entity.save();
}


• Возвращаемся в терминал

Обновим данные:

yarn codegen
yarn build

• Запускаем докер:

docker-compose pull && docker-compose up


• Дальше в строке браузера пишем:

Ваш_ip_адрес_серваера:3000

• У нас откроется приложение где мы сможем протестировать то что запустили.

Туда вписываем:

query{
sumRewards(first:3 orderBy:BLOCKHEIGHT_ASC){
nodes{
blockheight
id
totalReward
}
}
}

• Если всё окей, в терминале нужно остановить докер чтобы работать дальше

нажимаем Control + C и вписываем команду:

docker-compose stop

• Теперь нам нужно сдать задание, для этого нужно загрузить наш проект на https://github.com/ если вы не зарегестрировались в начале гайда делаем это сейчас, не забудьте подтвердить почту.

Как это сделать смотрите с картинками в первом модуле.

В форму для сдачи задания нужно отправлять ссылки на репозиторий в гитхаб.

Полная инструкция по SubQuery Spartan :
teletype.in/@elrmcfteam/SubQuerySpartan

Ссылки проекта: Discord: https://discord.gg/subquery
Сайт проекта: https://subquery.network/
Канал TG: https://t.me/subquerynetwork
Получить поддержку лучше в: #🇺🇦ukraine или #🇷🇺russian чат Discord.

Наши ссылки:
Чат ELRMCF: https://t.me/joinchat/cXa3BtZytS8wNWU8

| Автор: sasha.bnk Inst