Уважаемые пользователи Голос!
Сайт доступен в режиме «чтение» до сентября 2020 года. Операции с токенами Golos, Cyber можно проводить, используя альтернативные клиенты или через эксплорер Cyberway. Подробности здесь: https://golos.io/@goloscore/operacii-s-tokenami-golos-cyber-1594822432061
С уважением, команда “Голос”
GOLOS
RU
EN
UA
ontofractal
7 лет назад

Разработка персональных ботов для Голоса. Урок 1.


В этом уроке мы научимся получать и обрабатывать информацию о новых блоках Голоса, генерируемых делегатами. Для этого мы напишем простой код на JavaScript, который будет выполняться на компьютере пользователя с помощью nodejs.

Предисловие

  • Требуется базовый уровень понимания JavaScript, веб технологий и командной строки
  • Задавайте вопросы в комментариях, если я что-то непонятно объясняю.
  • В этом уроке мы создадим основу для разных ботов. Учиться автоматически реагировать на события блокчейна мы будем в следующих уроках.
  • У меня минимальный опыт работы с русскоязычной терминологией в программировании, поэтому названия я буду оставлять на английском языке.
  • Несмотря на то, что на бекэнде я предпочитаю использовать Elixir, для первых уроков гораздо лучше подойдет JavaScript.
  • В этом уроке используется неоптимальный код, паттерны и структура, приоритизируется легкость для понимания и читаемость кода.

Зачем нужны боты?

В данном случае решается несколько целей, одна из них -- дать возможность аккаунтам следовать за голосами @academy без предоставления мне или кому-то другому постинг ключа.

Подготовка и выбор технологического стека

Что такое стек? Буквально "stack" означает стопка и используется для обозначения комплекса языков, технологий и приложений.
Разрабатывать программу бота будем на JavaScript. Если точнее, то на JavaScript 2016, а если еще точнее, то на версии JavaScript, которую поддерживает последняя версия nodejs.

Вначале была среда программирования. Для ее развертывания нам необходимо выполнить следующие действия:

  • установить последнюю версию node.js (изучите тут )
  • инициализировать новый проект с помощью npm init (показано в скринкасте)
  • установить мой форк npm модуля: "golos":"ontofractal/golosjs" в package.json ( в скринкасте ошибочная версия npm модуля golos)

Скринкаст подготовки нового проекта

asciicast

Первые строки

  • Для упрощения управлением асинхронным потоком данных используем Promises
  • node.js использует собственный формат модулей, в будущих релизах node.js (и браузеров) система импортирования модулей будет заменена на нативные EcmaScript 2016 модули, которые выглядят вот так: import golos from 'golos'
  • Библиотека golos использует вебсокеты и протокол JSONRPC для обмена данными с нодами Голоса. По умолчанию библиотека подключается к публичной ноде wss://ws.golos.io
// импортируем модуль голоса
const golos = require('golos')
// импортируем модуль Bluebird -- самую популярную имплементацию Promise
const Promise = require("bluebird") 
// аккаунт пользователя, который запускает бота
const accountName = '' 
// приватный постинг ключ пользователя, который запускает бота
const postingKey = '' 
// аккаунт пользователя за которым следим
const accountNameToFollow = 'academy' 

// создаем новый Promise c помощью обвертывания golos.api.getDynamicGlobalProperties
const dynamicGlobalProperties = new Promise((resolve, reject) => {
    golos.api.getDynamicGlobalProperties((err, result) => {
        if (err) {
            reject(err)
        }
        else {
            resolve(result)
        }
    })
})

// резолвим Promise
dynamicGlobalProperties 
    .then(x => console.log(x))
    .catch(e => console.log(e))

Создаем функцию, которая выдернет из полученного от ноды объекта глобальных свойств номер последнего блока
const pluckBlockHeight = x => x.head_block_number

Создаем функцию, которая запрашивает данные блока

const getBlockData = height => {
    golos.api.getBlock(height, (err, result) => {
        if (err) {
            console.log(err)
        }
        else {
            console.log(result)
        }
    })
}

Скринкаст результата

asciicast

Создаем функцию, которая будет запрашивать данные следующего блока с регулярным интервалом

const startFetchingBlocks = startingHeight => {
    let height = startingHeight
    setInterval(() => {
        getBlockData(height)
        height = height + 1 // брррр, мутация
        // у нас есть доступ к переменной height благодаря closure
    }, 3000) 
    // Задаем интервал в 3000 мс т.к. блок Голоса генерируется каждые три секунды
}

Сводим все вместе

const golos = require('golos') // импортируем модуль голоса
const Promise = require("bluebird") // импортируем модуль Bluebird -- самую популярную имплементацию Promise
const accountName = '' // аккаунт пользователя, который запускает бота
const postingKey = '' // приватный постинг ключ пользователя, который запускает бота
const accountNameToFollow = 'academy' // аккаунт пользователя за которым следим

// создаем новый Promise обворачивая golos.api.getDynamicGlobalProperties
const dynamicGlobalProperties = new Promise((resolve, reject) => {
    golos.api.getDynamicGlobalProperties((err, result) => {
        if (err) {
            reject(err)
        }
        else {
            resolve(result)
        }
    })
})

const pluckBlockHeight = x => x.head_block_number

const getBlockData = height => {
    golos.api.getBlock(height, (err, result) => {
        if (err) {
            console.log(err)
        }
        else {
            console.log('')
            console.log('============ НОВЫЙ БЛОК ============')
            console.log(result)
        }
    })
}

const startFetchingBlocks = startingHeight => {
    let height = startingHeight
    setInterval(() => {
        getBlockData(height)
        height = height + 1 // брррр, мутация
        // у нас есть доступ к переменной height благодаря closure
    }, 3000) 
    // Задаем интервал в 3000 мс т.к. блок Голоса генерируется каждые три секунды
}

// резолвим Promise
dynamicGlobalProperties
    .then(pluckBlockHeight)
    .then(startFetchingBlocks)
    .catch(e => console.log(e))

Получаем информацию о новых блоках Голоса

asciicast

В следующем уроке

  • Изучим структуру блоков и транзакций
  • Научимся отличать одни транзакции от других
  • Научимся обрабатывать поступающие данные о голосах пользователей

(つ◕౪◕)つ━☆゚.*・。゚

7
7208.832 GOLOS
Комментарии (30)
Сортировать по:
Сначала старые