Слогер Создать блог
Разработка

Как интегрировать Python с Node API RustChain: разбор на реальных запросах

RustChain — блокчейн, где майнинг-награды зависят от возраста железа. У его ноды — обычный HTTPS JSON API. Показываем, как с ним работать из Python, и разбираем подводные камни.

RustChain — блокчейн, где майнинг-награды зависят от древности железа: чем старше компьютер, тем больше монет он приносит. У ноды — простой HTTPS JSON API, так что интеграция с любого языка — это просто HTTP-запросы. Покажу на Python, на реальных ответах, без моков.

Первое, обо что спотыкаются все: нода живёт по адресу https://50.28.86.131 и использует самоподписанный TLS-сертификат. Обычный urllib или requests такую ноду отвергнут. Для локального теста можно отключить проверку, но в проде закрепите сертификат.

import json, ssl, urllib.request BASE = "https://50.28.86.131" ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE # только для теста def get(path, params=None): url = BASE + path if params: url += "?" + "&".join(f"{k}={urllib.parse.quote(str(v))}" for k, v in params.items()) req = urllib.request.Request(url, headers={"User-Agent": "my-integration/0.1"}) with urllib.request.urlopen(req, timeout=20, context=ctx) as r: return json.loads(r.read().decode()) print(get("/health")) {"backup_age_hours": 18.18, "db_rw": true, "ok": true, "tip_age_slots": 0, "uptime_s": 77012, "version": "2.2.1-rip200"}

Что смотреть в ответе

db_rw: true — база доступна на запись, tip_age_slots: 0 — цепочка свежая. Если хоть одно не так, лучше подождать и повторить, чем строить интеграцию на устаревших данных.

Чтение состояния

Два эндпоинта закрывают почти все задачи — /epoch и /wallet/balance. Первый отдаёт общую картину сети:

{"blocks_per_epoch": 144, "enrolled_miners": 10, "epoch": 264, "epoch_pot": 1.5, "slot": 38022, "total_supply_rtc": 8388608}

Второй — баланс по miner_id:

print(get("/wallet/balance", {"miner_id": "Ivan-houzhiwen"})) # {"amount_i64": 45000000, "amount_rtc": 45.0, "miner_id": "Ivan-houzhiwen"}
ПолеЧто это
amount_i64Целое число во внутренних единицах — микро-RTC
amount_rtcЧеловекочитаемое значение, то же, но в RTC

Арифметику делайте только с целым полем, а форматируйте в самом конце. Плавающие балансы — как начинаются бухгалтерские баги.

Ловушка с нулём

Запрос несуществующего кошелька не возвращает ошибку. Вот реальный пример:

print(get("/wallet/balance", {"miner_id": "definitely-not-a-real-miner-xyz"})) # HTTP 200 -> {"amount_i64": 0, "amount_rtc": 0.0, "miner_id": "definitely-not-a-real-miner-xyz"}

HTTP 200, нулевой баланс. Если ваша интеграция считает ноль «валидным пустым аккаунтом», вы не отличите «у кошелька нет средств» от «такого кошелька никогда не существовало». Добавьте слой валидации: проверяйте miner_id по реестру, которому доверяете, прежде чем верить нулю. Это классический баг — успешный статус, но неверный эффект. Аудит API-клиентов обычно вылавливает такое.

Переводы

Переводы идут через /wallet/transfer/signed с подписью Ed25519. Полезная нагрузка выглядит так:

transfer = { "from_address": "RTCaaaa...", "to_address": "RTCbbbb...", "amount_rtc": 1.5, "nonce": 12345, "memo": "", "public_key": ed25519_pubkey_hex, "signature": ed25519_sig_hex, "chain_id": "rustchain-mainnet-v2", } # POST json=transfer в BASE + "/wallet/transfer/signed"

Три детали решают всё:

  1. Адреса — строки RTC..., а не miner_id и не адреса других сетей.
  2. Nonce защищает от повторов. Никогда не используйте один и тот же nonce дважды — храните последний использованный для каждого кошелька.
  3. chain_id не даёт переиспользовать подпись в другой сети. Для mainnet это ровно rustchain-mainnet-v2.

Правила подписи описаны в docs/API.md репозитория. Используйте их каноническую сериализацию, а не свой JSON — иначе подпись не пройдёт проверку.

Минимальный продакшн-клиент

Соберём всё вместе: ретраи, обработка ошибок, единая точка входа.

class RustChainClient: def __init__(self, base=BASE, retries=3): self.base, self.retries = base, retries self.ctx = ssl.create_default_context() self.ctx.check_hostname = False self.ctx.verify_mode = ssl.CERT_NONE def get(self, path, params=None): last = None for i in range(self.retries): try: return get(path, params) except Exception as e: last = e raise last def post(self, path, body): # аналогично, но с POST pass

Типичные ошибки

  • Отключать проверку сертификата в проде — обязательно закрепите сертификат.
  • Считать нулевой баланс за «пустой аккаунт» без доп. проверки.
  • Переиспользовать nonce.
  • Округлять amount_rtc при вычислениях — работайте с i64.
  • Не проверять /health перед операциями.

Вывод

Интеграция с RustChain — это базовые HTTP-запросы. Сложность не в самом API, а в мелочах: самоподписанный TLS, нулевые балансы несуществующих кошельков, аккуратность с nonce и подписью. Соберите тонкий слой-обёртку один раз — и дальше работайте как с обычной базой данных.

По материалам: blockchain. Текст переработан редакцией Слогера.

← На главную

Рекламное место — Конец поста
Реклама · Слогер

Комментарии (0)

Войдите, чтобы комментировать.

Пока нет комментариев. Будьте первым.