Monero — пробная интеграция

Posted: 2017-07-31 in IT, Networks, Security
Метки:,

Всем привет. Сегодня мы попробуем прикрутить оплату криптовалютой к какому-нибудь сервису, а точнее — обозначить основные пути, как это можно сделать.

Торговать наш сервис будет именно тем, о чём вы сразу и подумали — oрyжием и нaркoтиками.
Есть масса онлайн-игр, во внутриигровых мирах которых есть и то, и другое. А также ещё масса всяких виртуальных шмоток, монет, цацок для перса и прочего.

Сама идея продажи виртуальных вещей за виртуальные деньги очень забавна. Если же вы подумали о закупках колумбийского кокаина и поставках автоматов Калашникова африканским диктаторам — то вы, вероятно, очень испорченный человек, и явно ошиблись адресом в браузере. И вообще, что вы делаете с такими запросами в неприватном интернете… 😀 😀

Независимо от используемой платёжной системы, донатное приобретение (вполне годный вариант применения криптовалют) проходит в несколько крупных этапов:

1) клиент выбирает на сайте, что он хочет купить — это может быть меч, зелье, магический жезл или бронированные труселя.
2) сайт пишет отметку в базе, формирует некий iD будущей покупки, и переправляет клиента на платёжную систему, вместе с этим iD.
3). Увидев при проверке, что пришёл платёж с заданным iD на требуемую сумму, скрипты пополняют аккаунт игрового персонажа нужным предметом.

В классических криптовалютах автоматическое формирование этого iD есть изрядная головная боль. Проблема в том, что для отличения одной покупки от другой, и даже для различения платежей от разных клиентов (его достаточно в более простом случае, когда есть просто покупка единственной сущности — например, внутриигровых монет) потребуется каждый раз генерировать новую ключевую пару строго под этого клиента или даже под каждую покупку.

Без этого автоматика работать не будет, а разгребать платёжи вручную — нафиг не уперлось. Однако в этом случае требуется крайне скрупулезный учёт и безопасное/надёжное хранение таких ключей, или как минимум постоянный авто-перевод средств на более защищенные аккаунты.
В случае сбоя такие приватные ключи могут быть утрачены (их слишком много) вместе с перечисленными средствами, а синхронизация состояний для каждого ключа потребует массу ресурсов. Не исключено, что потребуется отдельный сервер, который будет заниматься только ключами, отвечая через своё апи на ряд команд типа «сгенерить ключ, выдать паблик-кей» и «проверить баланс». Получается громоздко, криво, не очень секурно и геморно.

Но прогресс не стоит на месте, и есть криптовалюта, которая позволяет изящно решить эту задачу.

Встречаем — Monero.

Монеро содержит одно крайне удобное нововведение — Payment_ID, который позволяет в рамках одного кошелька (одной основной пары ключей) принимать кучу разных платежей под разными iD, и легко проверять их, вообще не размещая никаких приватных ключей на игровых серверах ! Но перед тем, как начать пробовать это настроить, надо немного разобраться с типами ключей в системе Monero.

Большинство криптовалют опирается в каждом аккаунте только на одну пара ключей — открытая часть позволяет осуществить оплату на заданный аккаунт (аналог номера счёта), а закрытая — провести расходование средств (аналог банковского токена).

В монеро всё намного интересней и гораздо веселей — есть 7 типов разных строчек =)

Роль классической пары — spend-пара.
* Spend-Private-Key — это важнейший приватный ключ, он нужен для расходования средств на балансе. Его мы будем хранить максимально приватно, и только у владельца проекта, в ячейке швейцарского банка.
* Spend-Public-Key — по этому адресу будет понятно, что оплата именно вам. Это первая часть публичной информации, нужная клиенту, чтобы перевести нам донатные средства.

В силу параноидальных криптографических фич монеро есть ещё View-пара ключей.
* View-Public-Key — вторая часть открытого ключа, позволяющая сообщить, сколько именно монет вам пришло. Это вторая часть публичной информации, нужная клиенту.
* View-Private-Key — полу-секретный ключ, позволяющий просматривать платежи, но не позволяющий делать переводы средств. Такой вот доступ к кошельку только на чтение. Это совершенно потрясающая особенность — имея только паблик-ключи, невозможно даже сказать, есть ли на балансе средства. Именно этот ключ мы поставим на сервер. Он позволяет увидеть, что и сколько пришло, но не позволяет потратить. Его раскрытие снизит приватность аккаунта до уровня классических криптовалют, но не позволит похитить средства (для этого нужен private-spend) — то, что доктор прописал.

* Payment_ID — дополнительное поле размером в 16 шестнадцатеричных цифр. Это довольно много — 18446744073709551616 вариантов. Изначально задумывалось как случайно генерируемое значение во имя приватности, но нам оно подойдёт в качестве идентификатора платежа. Тут возможен как вариант последовательного увеличения на единицу (когда пространство общее на всех клиентов и все транзакции к нашему кошельку), так и выделения части цифр под фиксированые поля. Например, выделив первые 7 цифр под номер транзакции, и оставшиеся 9 — под номер клиента, мы получим возможность разделить все поступившие платежи для базы в 68 млрд клиентов, каждый из которых сможет провести 268 млн транзакций =).

* Standard XMR Address — обычный адрес без PaymentID. Это по сути два паблик-ключа (spend+view паблики), номер сети и контрольная сумма для защиты от опечаток и сбоев. Платежи на такой адрес приходят с Payment_ID = 000000000000000. Получив такой платёж, в силу приватных особенностей монеро, вы даже не сможете сказать, от кого он, и средства придётся принять как пожертвование на цели достижения мира во всём мире.

* Integrated Address — более длинный адрес, включающий в себя то же, что и обычный адрес, плюс Payment_ID. Именно интеграция Payment_ID делает такие адреса идеальными для автоматизации.

Для проверки всех этих адресов есть такой сервис:
https://xmr.llcoins.net/addresstests.html

И Java-Script библиотека, если вам потребуется как-то обрабатывать адреса монеро на своём сайте:
https://xmr.llcoins.net/js/site.js

Важное предупреждение: Никогда, ни при каких обстоятельствах не вводите свои приватные ключи куда-либо !! Для проверки сгенерите тестовые прямо на сайте.

Разобравшись с типами ключей, перейдем к настройке всего этого счастья.

Сперва делается генерация основного кошелька на машине владельца. Это должен быть очень хорошо защищенный компьютер.

Качаем кошелек нужного нам типа: https://getmonero.org/downloads/
Важный момент — нода. Полновесный блокчейн монеро весит 23 Гб, и качать его — дело долгое и муторное. Конечно, не настолько муторное, как у какого-нить полудохлого некро-форка битка, но достаточно долгое даже на широком канале. Поэтому имеет смысл найти ближайшую полновесную ноду и прописать её в качестве хоста, чтобы запустить кошелек в режиме «тонкого клиента». Можно поднять и свою ноду на отдельной виртуалке — для этого просто от имени отдельного пользователя выполняем такой скрипт:

#!/bin/bash

ipaddr=`ip a | grep 'inet ' | grep -v '127.0.0' | cut -d ' ' -f 6 | cut -d '/' -f 1 | head -n 1`;

screen -dmS Monero ~/monero-v0.10.3.1/monerod --rpc-bind-ip $ipaddr --rpc-bind-port 18089 --restricted-rpc --confirm-external-bind

В каталоге ~/.bitmonero/lmdb будет создан файл data.mdb размером под 23 Гб — это и есть полный блокчейн монеро.

Если свою полновесную ноду поднимать влом — можно получить адрес готовой уже существующей ноды вот тут:
https://moneroworld.com/pages/nodes.html

Бэкапим начальную фразу (25 слов), приватные ключи, файл кошелька так, чтобы обеспечить конфиденциальность и доступность. Постарайтесь не забыть пароль. То есть основные приватные ключи и контрольные слова не должны быть утрачены или попасть в чужие руки.

Потом мы экспортируем две строчки — основной Standard Address (команда address) и Private-View-Key (команда viewkey), и копируем их на наш игровой сервер.

Настройка на сервере потребует создания рид-онли кошелька.

Сперва качаем с официального сайта «Command-Line Tools Only» под линукс, распаковываем его куда-нить в /opt и не забываем добавить в бэкап. Проверить права доступа тоже не помешает.

Сперва запускаем утилиту создания кошелька c опцией —generate-from-view-key. Не забываем также указать ноду (желательно свою, запущенную на отдельной машине), чтобы не качать локально 45 Гб блокчейна:

./monero-wallet-cli --daemon-host NODE:PORT --generate-from-view-key ro-wallet.dat

Утилита запросит стандартный адрес, Private-View ключ и новый пароль для кошелька. При желании этот рид-онли кошелёк (т.н. аудиторский) всегда можно пересоздать, заново выгрузив адреса и View-ключ от владельца главного кошелька.

Вывод будет примерно такой:

Monero 'Wolfram Warptangent' (v0.10.3.1-release)
Logging to ./monero-wallet-cli.log
Standard address: 4StdXMR...addr
View key: 5priv..view..key
Enter new wallet password:
Confirm Password:
Generated new wallet: 4StdXMR...addr
Restore from specific blockchain height (optional, default 0),
or alternatively from specific date (YYYY-MM-DD):
Starting refresh...
Refresh done, blocks received: 5984
Balance: 0.000000000000, unlocked balance: 0.000000000000

Для проверки попробуем зайти в наш аудиторский кошелек:

$ ./monero-wallet-cli --daemon-host NODE:PORT --wallet-file ro-wallet.dat --password ""
Monero 'Wolfram Warptangent' (v0.10.3.1-release)
Logging to ./monero-wallet-cli.log
Opened watch-only wallet: 4StdXMR...addr
**********************************************************************
Use "help" command to see the list of available commands.
**********************************************************************
Starting refresh...
Refresh done, blocks received: 225
Balance: 0.000000000000, unlocked balance: 0.000000000000
Background refresh thread started

Пробуем такие команды:
balance — возвращает общий баланс. Должно быть для нового кошелька вот так:
Balance: 0.000000000000, unlocked balance: 0.000000000000
spendkey — должна написать такое:
Error: wallet is watch-only and has no spend key
integrated_address 0000012000000035 — должна вернуть новый адрес, который на сервисе проверки должен приниматься как Integrated.

Если всё ок, выходим командой exit;

Попробуем некоторые базовые команды. Обратите внимание, для Payment_ID надо указывать все 16 цифр!

Генерация Integrated-адреса с заданным Payment_ID 0000001234567890:

./monero-wallet-cli --daemon-host NODE:PORT --wallet-file ro-wallet.dat --password "" integrated_address 0000001234567890 | tail -n 1

Поиск платежей для заданного payment_id 0000001234567890:
./monero-wallet-cli --daemon-host NODE:PORT --wallet-file ro-wallet.dat --password "" payment 0000001234567890

Примеры вывода команд:

Список платежей с номером блока, направлением, датой, суммой и Payment_ID:
[wallet 4StdXM]: show_transfers
13..089 in 2017-07-27 0.005000000000 8b...3a 0000000000000000 -
13..500 in 2017-07-29 0.002000000000 5d...5f 0000001234567890 -

Только входящие платежи с инфой о типах подписей:
[wallet 4StdXM]: incoming_transfers
amount spent unlocked ringct global index tx id
0.005000000000 F unlocked RingCT 1746600
0.002000000000 F unlocked RingCT 1771723

И ещё немного команд ручной проверки платежей:

[wallet 4StdXM]: show_transfer
Error: usage: show_transfer

[wallet 4StdXM]: show_transfer 5d...5f
Incoming transaction found
txid:
Height: 13..089
Timestamp: 2017-07-27
Amount: 0.002000000000
Payment ID: 0000001234567890
Note:

[wallet 4StdXM]: payments
Error: expected at least one payment_id

[wallet 4StdXM]: payments 0000001234567890
payment transaction height amount unlock time

13..500 0.002000000000 0

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

./monero-wallet-rpc --daemon-host NODE --daemon-port NODE-PORT --rpc-bind-port 18082 --restricted-rpc --wallet-file ro-wallet.dat

Порт мы выбрали 18082, как в официальном мануале. Чтобы не вводить пароль каждый раз при старте, дописываем опцию —password или —password-file. Запустить имеет смысл от отдельного пользователя в screen-сессии.

Видим, что порт 18082 слушается локально:
$ netstat -nltp | grep monero
tcp 0 0 127.0.0.1:18082 0.0.0.0:* LISTEN 3974/./monero-walle

После чего интеграция с запущенным rpc-сервером настраивается вот по этому мануалу:

https://getmonero.org/resources/developer-guides/wallet-rpc.html

Увидев платёж, наши скрипты уже могут что-то поменять персонажу, пометить платёж в базе как уже окончательно завершенный, и так далее.

Для генерации QR-кодов можно использовать пакет qrencode, приблуды на php-gd или сторонние сервисы. Выдывать лучше сразу Integrated address, а не связку из стандартного + payment-id отдельно, ибо без Payment-ID надёжно верифицировать платёж не получится. Формат строки на вход qr-генератора указан в мануале:

http://monero.wikia.com/wiki/URI_formatting

Вот такая вот классная системка. Пусть будет больше криптовалют, хороших и разных, как и сервисов, их использующих.

Реклама
- комментарии
  1. Олег:

    Клево:-) спс