Аналитика для дроп-хантера
Дисклеймер: данный текст не является подробной инструкцией! Подразумевается, что вы обладаете достаточными знаниями и общими представлениями о той сфере, которой посвящена эта статья. Чмоки!
Если я еще не выключил демо-стенд, то можно посмотреть, как это выгляди тут -> http://109.199.102.66:3111/d/ef2c7fab-276d-4d5a-9eac-9a9bcf658f7d/zenno-demo?orgId=1 login:zennoposter, password: a$Ai&#t8.
Свои исследования в области аналиики для дроп-хантинга я начал еще весной 2023, о чем писал в этой статье https://whiteigel.ru/yJS6tL1Mr9j. Решение проработало какое-то время, с его помощью я неплохо вынес Arkham, о котором тоже писал ранее (хо-хо).
Однако, творческая мысль не стоит на месте, появились новые инструменты, а с ними и возможности. Сегодня поговорим, как можно увязать блокчейны, ZennoPoster(ЗП), PostgreSQL, Grafana чтобы получать информацию из одного источника, в удобном виде, пригодной для анализа и принятия решений.
Мой подход традиционен: если есть информация-она должна быть обработана, структурирована, представлена в удобном виде, чтобы на основе ее анализа можно было принимать какие-то решения.
Данная связка позволяет анализировать информацию, полученную как в ходе активностей, проводимых в ЗП, так и данных, получаемых непосредственно из блокчейна.
В основе всего лежит база данных (БД), построенная на PostgreSQL, но можно использовать любую реляционную СУБД (Новые слова? ChatGPT в помощь!).
База данных позволяет хранить всю информацию, которую мы получаем в ходе работы шаблона в ЗП, то, что мы пишем в таблицу. Чем плоха таблица? Таблица дает плоское представление и собрать в одной таблице информацию из разных источников достаточно проблематично. Я не говорю, что это невозможно, есть гении Excel, которые такие связки ваяют, что закачаешься.
- Создание схемы данных
- Выбор инструментов и установка
- Создание прототипа
- Внесение данных
- Тест и доводка
- Внесение изменений для сбора данных в ЗП
- CI/CD (Continuous Improvement/Continuous Development). Проект всегда развивается, появляются новые идеи, новые реализации. Все по Agile.
Сначала поставим задачу: нужна аналитическая система, которая позволяет собирать данные автоматически, хранить их и организовывать представление в удобном виде. На одной странице должны быть видны ключевые показатели (стоимость основных токенов: ВТС, ЕТН), стоимость "газа" в Ethereum, количество профилей в работе, количество ведущихся проектов, количество активностей, таблицы, показывающие завершенные активности, таблица ошибок, таблица отображения балансов в нужных сетях, таблица активностей, таблица с информацией о профиле (номер, адрес, пароль, прокси, ip-адрес прокси и др.). Проще говоря, нужен "рабочий кабинет абузера", "система единого окна". Готово! Половина дела, считай, сделана!
Готовим схему данных
Тут вам даже думать не нужно, вот готовый простенький пример.
Для того чтобы понять, как это работает, нужно разобраться в основах управления БД. Что такое таблицы, что такое primary key/foreign key, какие связи бывают (один к одному, один ко многим). Вот очень хороший курс по основам СУБД https://www.youtube.com/watch?v=HVQNxdI6fqY&list=PLBheEHDcG7-k1Y_Uy04Dj2ylWhcfSfqoF
В основе структуры лежат три сущности: профиль, проект, активность. Некоторые сущности имеют зависимые сущности, например, таблица profileinfo и balances зависят от таблицы profile и связаны с ней через foreign key "profile_id". Это позволяет соединять данные из разных таблиц. Например, взять номер из таблицы profile, взять адрес кошелька из таблицы profileinfo, взять баланс из balances и создать на основе этих данных новую таблицу, связав эти поля по ключу profile_id.
SELECT b.profile_id, pi.wallet, b.eth_native, b.zksync_native, b.date
FROM balances b
JOIN profile p ON b.profile_id = p.id
JOIN profileinfo pi ON p.id = pi.profile_id
WHERE b.date = (SELECT MAX(date) FROM balances WHERE profile_id = b.profile_id);
Согласен, выглядит жутковато, но вам не нужно писать самим этот запрос. За вас это сделает ChatGPT, вам достаточно представлять. что вы хотите получить и дать ему промпт. Вот как выглядел промпт:
"запрос на получения данных из таблизы balances, profile_id refers to id in profile, date is latest date"
"добавь получение поля wallet из таблицы profileinfo, таблица profileinfo связана с таблицей profile через поле profile_id"
"поставь поле wallet вторым после profile_id"
Как видите, настройка идет поэтапно, пока не будет получен нужный результат.
Такие сущности как transaction, error связаны со всеми главными сущностями, думаю понятно, почему это происходит.
Выбор инструментов
- СУБД PostgreSQL https://www.postgresql.org/download/ выбираете нужную платформу, версию, скачиваете и устанавливаете.
- DBeaver. https://dbeaver.io/ Очень удобный инструмент для работы с СУБД. В postgres есть встроенный pgadmin, но он не всегда удобен.
- Grafana. https://grafana.com/ Инструмент для визуализации.
- ODBC драйвер для подключения ЗП к СУБД. В этой гениальной статье описано все и даны все ссылки. Автору огромный респект. https://zennolab.com/discussion/threads/postgresql-subd-i-zennoposter-podkljuchenie-cherez-odbc.43320/
Все эти инстументы имеют бесплатные версии, используйте их. Решение будет стоить вам 0, кроме затраченного времени и нервов.
Создание прототипа
После того как вы установили все нужные инструменты, необходимо создать базу данных. Как это сделать в PostgreSQL очень подробно рассказано в этих уроках. Вообще, это очень хороший курс по основам управления СУБД - https://www.youtube.com/watch?v=HVQNxdI6fqY&list=PLBheEHDcG7-k1Y_Uy04Dj2ylWhcfSfqoF
После того как вы написали все запросы для создания БД (сами или через чат) и скормили СУБД(лучше это делать через DBeaver, он удобнее), у вас должна получиться, примерно, такая же схема, как выше, с похожими связями. Отлично! Вы на верном пути!
Примеры запросов к чату и результаты:
"Запрос SQL на создание таблицы в БД. table= balances, fields: (id(primary key), profile_id(foreign key to profile), eth_native, zksync_native, date = date)"
CREATE TABLE balances (
id SERIAL PRIMARY KEY,
profile_id INTEGER REFERENCES profile(id),
eth_native DECIMAL,
zksync_native DECIMAL,
date DATE
);
После этого необходимо настроить передачу данных в БД из активностей ЗП.
Для этого в шаблоне создаем кубик "Добавить действие" - "Данные" - "Базы данных" и настраиваем его так, как рассказано в статье https://zennolab.com/discussion/threads/postgresql-subd-i-zennoposter-podkljuchenie-cherez-odbc.43320/
Если вы все сделали правильно, то результат теста у вас должен выглядеть так:
Настраиваем запрос для записи активностей.
"Поместить запись в таблицу transaction. Поля: hash, project_id, action_id, profile_id, date".
Краткое пояснение: хэш вы получите из запроса к блокчейну, когда будете проверять, прошла ли транзакция - научитесь это делать, project_id и action_id - соотвествующие индексы для данной активности из таблиц project и action. Не имя активности и проекта, а именно цифровой индекс, потом по этим индексам вы будете соединять данные из разных таблиц. Номер профиля ставится из переменной проекта, тут все понятно.
Скрин таблицы action. Здесь видна связь данной таблицы с предыдущей через project_id. Связь через индекс, а не имя проекта.
Запрос на добавление данных в БД:
INSERT INTO transaction
(hash, project_id, action_id, profile_id, date)
VALUES ('{-Variable.transaction_hash-}', 4, 3, {-Variable.profile-}, CURRENT_DATE);
Запрос вставляется в окно запроса кубика ЗП.
Результат выполнения запроса. Как видите, нет никаких имен только отсылки к соответствующим полям других таблиц.
Такие кубики для записи нужно настроить для каждой активности, с указанием соответствующих полей проекта и активности. Постарайтесь не перепутать.
Если хотите отслеживать ошибки, то можно настроить и их запись
Код для кубика Setup Error Logging for DB. В нем мы настраиваем индекс активностей для передачи в БД.
Код для записи ошибки. Все переменнные получены из проекта, только индекс проекта указан вручную. Если хотите запариться, можете придумать, как его передавать автоматически. Это несложно.
INSERT INTO error
(profile_id, project_id, action_id, text, date)
VALUES
({-Variable.profile-}, 4, {-Variable.action_id-}, '{-Variable.error_msg-}', CURRENT_DATE);
Поздравляю вас, вы научились записывать данные в базу данных автоматически!
Подключени БД к Grafana
После установки Grafana и наполнения первичными данными БД, можно начинать строить ваш первый дашборд.
В браузере вводите адрес http://localhost:3000/ или http://127.0.0.1:3000/ это одно и тоже. Сервис запущен на вашей локальной машине и доступено по 3000 порту.
Логин и пароль на вход в панель управления - admin:admin. Поменяйте его на нужный вам.
В левом верхнем меню выбираем пункт Connections-Add new connection.
В поиске набираем Postgres. Выбирайте первый. Устанавливаем его.
После этого переходим Connections-Data source. Жмем Add new data source в правом верхнем углу.
Заполняем данные для подключения. База у вас находится, скорее всего по адресу localhost:5432 (локальная машина: стандартный порт), указываете имя вашей базы данных, имя пользоваателя и его пароль.
Внизу страницы кликаете на Save&Test. Если все сделали правильно, то результат выглядит так. Отлично! Мы подключили источник данных и теперь можем получать их из нашей таблицы.
Создание и настройка дашборда
Home-Dashboards. New в правом верхнем углу. New dashboard.
Появляется окно создания и настройки представления. Выбирем нужый источник данных в поле Data source ( если не выбрали ранее).
Надежнее всего сразу вставить код для запроса выбрав кнопку Code в правой стороне поля. Код пишите либо сами, либо просите чат.
Вставляем код для получения данных (он начинается с SELECT). Например,
SELECT b.profile_id, pi.wallet, b.eth_native, b.zksync_native, b.dateFROM balances bJOIN profile p ON b.profile_id = p.idJOIN profileinfo pi ON p.id = pi.profile_idWHERE b.date = (SELECT MAX(date) FROM balances WHERE profile_id = b.profile_id);
Нажимем Run query. У вас должен получиться, примерно, такой результат. Поздравляю! Вы получили первую таблицу с данными из разных таблиц вашей БД!
Внимание! Интерпретатор выполняет все команды, которые вы ему дадите! Если вы напишите:
DROP TABLE IF EXISTS balances; -
он снесет вам таблицу балансов со всеми записями без возможности восстановления. Ну разве только из бекапа.
Если после запроса результат выгляди так, то вам нужно поменятьт представление на табличное в правом верхнем углу. Visualizations>Table.
Жмем синюю кнопку Apply в правом верхне углу. Ваша таблица добавлена в дашборд.
Кликаем по трем точкам в правом верхнем углу новой таблицы и выбираем Edit.
Слева в поле вы можете настраивать ваш запрос, справа в колонке настраивать внешний вид таблицы. Все очень просто!
По аналогии добавляте нужные вам таблицы на основе данных: активности, ошибки, балансы, данные профилей - все что угодно! На дашборде таблицы можно растягивать, перемещать в любое место, организовывать так, как вам нравится.
С таблицами разобрались. Остались API.
Получаем стоимость газа в Ethereum
Переходим на страницу добавления источников данных, пишем в поиске JSON, выбираем вторую опцию (круглая иконка), устанавливаем пакет.
Заполняем название, поле адреса: https://api.etherscan.io Проверяем и сохраняем.
Добавляем новую визуализацию. Выбирам наш новый источник данных.
Возвращаемся на закладку Fields. Вводим $. и получаем результаты запроса!
Выбираем нужные ключи через точку:
Иногда работает такой вариант:
Справа выбираем представление типа Gauge. Кликаем Apply. Индикатор газа добавлен.
Для получения цены BTC, ETH достаточно просто ввести нужные ссылки на api CoinGecko в поле url источника данных JSON. Создайте новый источник данных типа JSON и вставьте эти ссылки:
BTC - https://api.coingecko.com/api/v3/coins/bitcoin/tickers
ETH - https://api.coingecko.com/api/v3/coins/ethereum/tickers
В поле Field введите ключи для получения данных:
ВТС - $.tickers[*].converted_last.usd
ЕТН - $.tickers[*].converted_last.usd
Можете попробовать получить их сами - это несложно.
Итак, друзья, мы создали с вами основу для аналитической системы! Настроить и "причесать" ее под свои нужды вы сможете сами. Помните, это не пошаговая инструкция, как получить нужный результат. Скорее, это путеводитель, который поможет вам ориентироваться, но путь придется пройти самим.
Как перенести все данные из "горячей" таблицы в БД.
- Устанавливаем занчение переменной number = 1
- Берем из "горячей" таблицы строку и все данные назначаем переменным.
- Отправляем в БД запрос на внесение с переменными, полученными в прошлом шаге.
- Проверка условия и вывод сообщения.
- Увеличиваем счетчик +1.
- Повторяем, пока цикл не закончится.
INSERT INTO profileInfo (profile_id, wallet, password, proxy, proxy_ip, name) VALUES ({-Variable.number-}, '{-Variable.address-}', '{-Variable.password-}', '{-Variable.proxy-}', '{-Variable.proxy_ip-}', '{-Variable.name-}');
Как получить балансы из нужной сети для всех адресов и положить их в базу данных
- Устанавливаем значение переменной для инкремента = 1.
- Отправляем запрос к БД для получения данных профиля и кладем их в переменные. *Запрос будет ниже.
- Получаем баланс (return My.GetBalance(project, My.BlockchainBalance.zksync, My.TokenBalance.ETH);) и кладем его в переменную.
- Меняем запятую на точку.
- Отправляем запрос в БД.
- Увеличиваем инкремент на 1.
Здесь вам понадобится "универсальный чекер баланса", который умеет получать данные из любой сети для любого токена. Его вы напишите сами. Так же, в полученном балансе вам нужно будет заменить запятую на точку. Для этого используется кубик обработки регулярных выражений.
SELECT p.*, pi.wallet, pi.password, pi.proxy, pi.proxy_ip, pi.name
FROM profile p
JOIN profileInfo pi ON p.id = pi.profile_id
WHERE p.id = {-Variable.number-};
INSERT INTO balances
(profile_id, zksync_native, date)
VALUES
({-Variable.profile-}, {-Variable.balance-}, CURRENT_DATE);