# STAN. Модель процессинга **STAN** Итак - с UXTO все более менее устаканилось и стало ясно. Система разделена на две части, первая инкапсулирует торговую логику и выполнение заявок пользователей, вторая предоставляет систему обработки запросов авторизации и генерации ответов авторизации перевода средств внутри канала и между слоями. Все каналы используют модель UXTO. подробнее об этом ниже. На данном этапе - считаем что канал - это труба соеденяющая процессинг и трейдера. В дальнейшем это будет труба между любыми пользователями системы. Труба работает в два приема - (1)запрос, в котором передаются подготовленные для оформления транзакции артефакты и (2)ответ системы подготовленной и подписанной транзакцией. Такой дизайн обеспечит достижение трех целей: 1. сохранение асинхронный, высокопроизводительный дизайн **exchange_engine**, исключение блокировок между системами 2. сокрытие внутри системы интерфейсов **processing_engine**, смягчение его режима работы 3. гибкую модель расширения функционала как с точки зрения технологий работы с каналами, так и с точки зрения обработки типов заявок, отличных от market/limit order ![оригинал](https://paper-attachments.dropbox.com/s_EBC0F651BC125C9769DE7D0BB192980A833264473A3018FBDB6E908CA3F25CE5_1581139148655_file.png) Итак имеем ~~три~~ четыре системы, плохо осведомленные друг о друге: - `**execution_engine**` - это система обмена активами во втором слое, при которой продавец соглашается продать, а покупатель соглашается купить ценную бумагу в рамках транзакции. Расчет - это фактический обмен денег или какой-либо иной стоимости ценных бумаг. Работает в модели “учетной записи” в которой оперирует идентификатором канала(xpub реестра, инкапсулирующий все каналы пользователя в конкретном реестре), генерируемым для каждого реестра первого слоя - `user_ledger_id`. - `**clearing_engine**- UXTO **реестр второго слоя**, это процесс обновления счетов участников торгов, которые приводят к расчету - блокировка средств обеспечения постановленной заявки, создания транзакции нового состояния после матчинга заявки. Отвечает за работу внутри каналов для всех реестров первого слоя, вне зависимости от фактического количества каналов у пользователя - наружу он предлагает интерфейс управления абстрактным каналом, идентифицирующего пользователя/реестр первого слоя(`user_ledger_id`). - `**settlement_engine**` **-** служба поставки транзакций открытия, закрытия и рефинансирования каналов от имени биржи, также живет в мире UXTO, оперирует `user_channel_id` - `**revocation_engine**` **-** эта служба ****публикует ****транзакции отзыва в случае обнаружения в реестрах первого слоя транзакций установки устаревшего состояния, опубликованных трейдерами, оперирует `user_channel_id` оповещает `**clearing_engine**` > Важный момент - придерживаемся стратегии проверки структуры транзакций и подписей к ней в **execution и clearing** системах, это выглядит избыточным - но на данном этапе главная задача обойти возможные проблемы - после достижения функциональности системы оптимизируем эту часть. Вероятно придется распределить эти проверки между системами исходя из времени выполнения. **PS -** в случае достижения рабочей системы, следущая фаза будет нацелена на добавление функционала в торговую систему и апдейт механник работы каналов, также уже сейчас важно понимать, что я планирую использовать `**revocation_engine**` как часть инфраструктуры `**keyless_one**` в виде службы охраняющих интересы пользователей от попыток злоупотребления со стороны биржи **Важно учесть что биржевая система имеет компоненты критичные к задержкам:** - `**execution_engine**` - эта часть процессинга, включенная в exchange_engine // **Компоненты не критичные к задержкам:** - `**clearing_engine**` - отвечает за корректную смену состояния между пользователями(не забывая о комисии биржи) // - `**settlement_engine**` - отвечает за открытие/закрытие/ребалансировку каналов // - `**revocation_engine**` - система предотвращения публикации отмененных состояний Функционал биржи, который призван обеспечить STAN -> обмен между трейдерами актива А на актив Б, для обеспечения гибкости все средства обеспечивающие заявки в стакане - переходят на баланс `**clearing_engine**`, после исполнения(match) заявки средства обеспечивающие исполнения переходят на баланс трейдера. Для получения транзакции смены состояния трейдеру необходимо воспользоваться интерфейсом веб-терминала и запросить ее. В автоматическом режиме трейдер получает оповещение об исполнении в общем потоке. Процессы системы оптимальней всего воспринимать как конвейер трансформаций над заявкой. (Постановка, Исполнение, Запрос актуального состояния, Ре-балансировка канала, Перевод средств на холодные счета) **1. Процесс {регистрации | аутентификации} на бирже:** ![](https://paper-attachments.dropbox.com/s_EBC0F651BC125C9769DE7D0BB192980A833264473A3018FBDB6E908CA3F25CE5_1581187129737_auth.svg) **2. Процесс постановки заявки на обмен:** ![](https://paper-attachments.dropbox.com/s_EBC0F651BC125C9769DE7D0BB192980A833264473A3018FBDB6E908CA3F25CE5_1581153611017_place_order.svg) **** **2. Исполнение выставленной заявки**: **3. Запрос актуальных commit_tx на канал пользовтеля:** **4. Ре-балансировка(открытия/закрытия/изменения сальдо) канала:** **5. Внутренний процесс перевода средств биржи с горячих каналов на холодные:** **5. Процесс открытия канала** 6**. Процесс закрытия канала** ## Исходя из всего вышесказанного предлагаемые интерфейсы Типы данных: ``` - tx { inputs: [{ outpoint: { hash: "", // хеш транзакции index: 0 // индекс выхода транзакции }, ScriptSig: "", // подпись скрипта Sequence: 0xFFFFFFFF //дефолтное значение }, ... ], outputs: [{ ScriptPubKey: "", // redeem-script (multisig) Value: 90, // сумма для финансирования }, { ScriptPubKey: "", // дефолтный скрипт () Value: 10, // сдача } ] } - segwit_tx { inputs: [{ outpoint: { hash: "", // хеш транзакции (всегда транзакции финансирования) index: 1 // индекс выхода транзакции }, ScriptSig: "", // пустая строка Sequence: 0xFFFFFFFF, //дефолтное значение Witnessess: [ "", // пустая "", // подпись иницирующей стороны "", // подпись второй стороны "" // redeem скрипт (из транзакции финансирования) ] } // строго один ], outputs: [{ ScriptPubKey: "", // скрипт Value: 90, // сумма }, { ScriptPubKey: "", // скрипт Value: 10, // сумма } ] // строго 2 (в нашем случае) } ``` интерфейсы: | Вызывающая сторона | Вызываемая сторона | Интерфейс | Описание | | ------------------ | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | USER | **execution** | **login(**<br>string stan_public_master_key,<br>string[] exchange_public_master_keys) | Логин | | USER | **execution** | **open_channel(**<br>string trader_ledger_ID,<br>tx funding_tx,<br>segwit_tx init_commit_tx) | Открытие канала и создание транзакции финансирования | | **execution** | **settlement** | **open_channel(**<br>string trader_ledger_ID,<br>tx funding_tx,<br>segwit_tx init_commit_tx) | Открытие канала и создание транзакции финансирования (в response вся нужная инфа) | | **settlement** | **revocation** | **listen_tx(**<br>tx funding_tx,<br>channel_ID) | Указание revocation-демону слушать транзу | | **execution** | **clearing** | **hold_channe****l****(** <br>string trader_ledger_ID, <br>segwit_tx trader_signed_tx, <br>string trader_rev_secret) | Изменение состояния в пользу биржи, вызывается при блокировке средств, обеспечивающих выставленную заявку. | | **clearing** | **revocation** | **add_rev_key(**<br>segwit_tx commit_tx,<br>int channel_ID,<br>string rev_key) | Сообщение revocation с новым ключом отмены | | **execution** | **clearing** | **match_netting(**<br>string buyer_ledger_ID, <br>string seller_ledger_ID, <br>segwit_tx buyer_commit_tx, <br>segwit_tx seller_commit_tx**,** <br>string[] rev_secrets **)** | запрос на генерацию транзакций состояния, увеличивающих баланс пользователей | | **clearing** | **execution** | **block_channel**(<br>string user_ledger_ID,<br>int reason_code) | аварийное выключение канала пользователя | | **revocation** | **clearing** | **block_channel**(<br>int channel_ID, <br>int reason_code) | аварийное выключение канала пользователя | | USER | **execution** | **withdraw_request(**<br>int channel_ID,<br>segwit_tx close_tx) | Запрос на вывод средств с канала | | **execution** | **settlement** | **withdraw_request(**<br>int channel_ID,<br>segwit_tx close_tx) | Запрос на вывод средств с канала | | USER | **settlement** | **deposit_request(channel_ID)** | Запрос на пополнение канала | `**settlement**` **-** работа между первым и вторым слоем `**clearing**` - работа в канале(во втором слое) `**revocation**` **-** предохранитель, формирует транзакцию для первого слоя, оповещает второй о событии `**execution**` - предоставление сревиса обмена к активам, транзакции которых предоставляет первые три сервиса. ## STAN взгляд с обоих сторон Учитывая разные парадигмы построения архитектуры приложений, вкупе с разными моделями построения реестров, для исключения недопонимания нужно устаканить этот ньюанс: для otp_actors система выглядит так: **Внутренние****:** - `**order_processing_app**` - обработка заявок - `**trade_processing_app**` - обработка матчей - `**common_processing_app**` — обработка не связанных с торговлей сервисов авторизации(аутентификация пользователя на бирже, депонирования чат-а, депонирование торгового баланса для HFT) - `**exchange_app**` - двигатель сопоставления заявок **Внешние****:** - `**clearing_app**` - смена состояний в канале - `**settlement_app**` - открытие/закрытие/ре-финансирование каналов - `**revocation_app**` - обработка форс-мажорных ситуаций для micro_services система выглядит так: > `emitter` - тот, что испускает, `collector` - тот что принимает **Внутренние:** - `**offchain_tx_emmiter**` производитель транзакций смены состояния - `**offchain_tx_collector**` получатель запросов на производство транзакций смены состояния - `**blockchain_tx_emitter**` производитель транзакций открытия/закрытия каналов - `**blockchain_tx_collector**` получатель запросов на производство транзакций открытия/закрытия каналов **Внешние:** ****??? - ## Каналы реестров на основе учетной записи Для мимикрирования каналов состояний реестров построенных по модели учетной записи под модель UXTO мы используем механизм мета-транзакций, который позволяет определить пользовательский интерфейс контракта фиксации состояний, как атрибуты вызова методов контракта. Для устранения проблемы коммисий за публикацию в дорогих сетях - при открытии/закрытии канала необходимо взымать средства которых будет достаточно для публикации транзакции состояния, подписанной пользователем, но опубликованной с помощью оракла биржи. `TBA` ## Телеметрия Для решения задач отладки/профилирования/общего наблюдения за системой необходимо начать внедрять в обоих системах opentelemetry - стандарт сбора логов и метрик в едином формате, помимо наших систем также собирается телеметрия с ядрах хостовой ОС - этой информации должно быть достаточно для отлова узких мест при тестировании и наблюдением за производственным ландшафтом. С точки зрения golang - проблем не должно быть - основной вендор тут Uber, у них все на go. С точки зрения OTP - вроде уже все прояснили. ## API интеграциионной шины - [Глоссарий](#глоссарий) - [Общая информация](#общая-информация) - [Структуры (классы)](#структуры) - [Логин](#логин) - [Открытие канала](#открытие-канала) * [open_channel_user_execution](#open_channel_user_execution) * [open_channel_execution_settlement](#open_channel_execution_settlement) * [open_channel_settlement_revocation](#open_channel_settlement_revocation) * [Требования к транзакции финансирования](#требования-к-транзакции-финансирования) * [Требования к транзакции установки состояния](#требования-к-транзакции-установки-состояния) - [Создание ордера](#создание-ордера) * [create_order_user_execution](#create_order_user_execution) * [create_order_execution_clearing](#create_order_execution_clearing) - [Матчинг ордера](#матчинг-ордера) * [match_netting_execution_settlement](#match_netting_execution_settlement) - [Выключение канала](#выключение-канала) * [block_channel_revocation_execution](#block_channel_revocation_execution) - [Закрытие канала](#вывод-средств) * [withdraw_request_user_execution](#withdraw_request_user_execution) * [withdraw_request_execution_settlement](#withdraw_request_execution_settlement) * [withdraw_request_settlement_revocation](#withdraw_request_settlement_revocation) * [Требования к транзакции закрытия](#требования-к-транзакции-закрытия) - [ER-модель для clearing/settlement/revocation](#er-модель) ## Глоссарий * **user** - клиент на фронте * **execution** - движок биржи * **clearing** - установка состояний в каналах * **revocation** - наблюдение за транзакциями и отмена при необходимости * **settlement** - создание/закрытие каналов ## Общая информация Пока делаем общение между всеми через websocket (???) Имена методов содержатся в заголовках третьего уровня и обычно строятся по схеме `общее_название_метода_вызывающая_вызываемая` Пока предполагаю, что бинарный формат транзакций не используем, но можно впоследствии им воспользоваться. ## Структуры ### Request Для запросов предлагаю воспользоваться такой JSON - структурой ```javascript { method: string, // метод запроса id: variable, // id запроса, variable означает неопределенный тип, то есть пользоваться можно чем-угодно, можем туда nonce прикрутить потом params: variable[] // массив параметров произвольного типа. Не уверен насколько хорошая идея, так как усложняется валидация из-за такого подхода, но зато компактно } ``` ### Response Результат. Все далее описанные ошибки явялются значением поля `error` с этой структуры ```javascript { method: string, // метод запроса (тот же, что и в запросе) id: varibale, // id, указанный в запросе result: variable, // результат произвольного типа error: { // ошибка, null при отсутствии code: int, // код ошибки message: string // сообщение об ошибке } } ``` ### Transaction ```javascript { version: int, // обычно 2, но мало ли, лучше оставлю lockTime: long(int64), // segwit: bool, // использовался ли segwit inputs: { // входы hash: string, // хеш транзакции (с которой берется выход) index: int, // индекс выхода в исходной транзакции scriptSig: string, // подпись к скрипту sequence: int, // здесь либо дефолтное значение 0xFFFFFFFF, либо (в случае использования в скрипте CHECK_SEQUENCE_VERIFY) другое число witnesses: []string // подписи при segwit }[], outputs: { // выходы scriptPubKey: string, // скрипт value: long(int64) // сумма на выходе }[] } ``` ### Enum(coins) Поскольку enum'ы везде по-разному работают, пишу втупую (список еще дополню) ```javascript BTC = 1 LTC = 2 ``` ### Enum(reasonCode) ```javascript OK = 0 FAILED = 1 ``` ## Логин Клиент должен передать xpub мастер-ключ (ключи) от своего аккаунта. Если такого xpub не найдено, необходимо создать "учетную запись" и мастер-ключи, отвечающие этому пользователю (я думаю, что генерить отвечающие ключи лучше в сервисах(акторах)((микро-сервисах)), отвечающих за работу с криптой, чтобы **execution** знать не знал о каких-то ключах и мог оперировать аккаунтами и каналами без сложностей с ключами. С другой стороны, ключи нужно передавать только при создании канала, что вроде не очень сложно). Если учетка уже существует нужно проверить появление новых ключей для токенов и в случае наличия таковых запросить у settlement генерацию (или сгенерировать у себя) ### login_user_execution ##### Параметры |тип|описание|ограничения| |:-:|:------:|:---------:| |string|xpub биржи|соответствие структуре xpub (префикс, длина)| |string[]|xpub'ы для работы с различными токенами|соответствие структуре xpub| ##### Результат ##### Ошибки ### login_user_settlement ##### Параметры |тип|описание|ограничения| |:-:|:------:|:---------:| |string[]|xpub'ы для работы с различными токенами|соответствие структуре xpub| ##### Результат ```javascript { keys: string[] } ``` ##### Ошибки * неверный формат xpub ```json { "code": 400, "message": "wrong xpub" } ``` ## Открытие канала Для открытия канала **user** должен прислать xpub ключ соответствующей монеты для авторизации, подписанную транзакцию финансирования с корректными входами и скриптом в выходах, транзакцию установки начального состояния с корректным скриптом и своей подписью. **Execution** устанавливает номер нового канала и делает запрос в **settlement**. **settlement**, в свою очередь, посылает информацию о создании канала в **clearing** и **revocation**. ### open_channel_user_execution ##### Параметры |тип|описание|ограничения| |:-:|:------:|:---------:| |Coins(enum)|номер токена|-| |string|xpub (для конкретной монеты)|соответствие структуре xpub (префикс, длина)| |transaction(serialized)|транзакция финансирования|Описаны [здесь](#требования-к-транзакции-финансирования)| |transaction(serialized)|транзакция установки начального состояния|Описаны [здесь](#требования-к-транзакции-установки-состояния)| ##### Результат ```javascript { init: transaction (serialized) // подписанная init транзакция } ``` ##### Ошибки ### open_channel_execution_settlement ##### Параметры |тип|описание|ограничения| |:-:|:------:|:---------:| |int64|id клиента|-| |Coins(enum)|номер токена|-| |int|индекс канала (в пространстве клиент-монета)|номер строго следущий по порядку| |string|xpub (для конкретной монеты)|соответствие структуре xpub (префикс, длина)| |transaction(serialized)|транзакция финансирования|Описаны [здесь](#требования-к-транзакции-финансирования)| |transaction(serialized)|транзакция установки начального состояния|Описаны [здесь](#требования-к-транзакции-установки-состояния)| ##### Результат ```javascript { init: transaction (serialized) // подписанная init транзакция } ``` ##### Ошибки * неправильный скрипт в транзакции финансирования (установки начального состояния). Например, скрипт не той формы или не те public-ключи в нем ```json { "code": 400, "message": "wrong funding(init) script" } ``` * неправильная подпись в транзакции финансирования (установки начального состояния) ```json { "code": 400, "message": "wrong funding(init) signature" } ``` * входы не найдены ```json { "code": 400, "message": "wrong inputs funding(init) transaction" } ``` * все страшно сломалось ```json { "code": 500, "message": "internal error" } ``` ### open_channel_settlement_revocation ##### Параметры |тип|описание|ограничения| |:-:|:------:|:---------:| |string|xprv для канала|соответствие структуре xprv (префикс, длина)| |string|адрес redeem-скрипта|соответствие структуре адреса скрипта| ##### Результат ```javascript { success: true } ``` ##### Ошибки ```json { "code": 500, "message": "internal error" } ``` ### Требования к транзакции финансирования ##### Входы Все входы должны быть корректно подписаны ##### Выходы Должен быть ровно один выход со специальным multisig-скриптом ##### Скрипт `OP_2 <client_pub_key> <exchange_pub_ley> OP_2 OP_CHECKMULTISIG` ### Требования к транзакции установки состояния ##### Входы Все входы - выходы транзакций финансирования с multisig-скриптом ##### Выходы Один выход - на баланс биржи Второй выход - выход со специальным скриптом с замком ##### Скрипт `<exchange_pub_ley> OP_CHECKSIG OP_IF <revoke_pub_key> OP_CHECKSIG OP_ELSE OP_N OP_CHECKSEQUENCEVERIFY OP_DROP <client_public_key> OP_CHECKSIG OP_ENDIF` ## Создание ордера Пока (временно) будем считать, что ордер меняет состояние только одного канала. ### create_order_user_execution ##### Параметры |тип|описание|ограничения| |:-:|:------:|:---------:| |int64|сумма|-| |Coins(enum)|токен|-| |transaction(serialized)|транзакция установки следующего состояния|Описаны [здесь](#требования-к-транзакции-установки-состояния)| |string|ключ отмены предыдущей транзакции|hex private key| ##### Результат ##### Ошибки ### create_order_execution_clearing ##### Параметры |тип|описание|ограничения| |:-:|:------:|:---------:| |int64|id клиента|-| |Coins(enum)|токен|-| |int64|сумма|-| |transaction(serialized)|транзакция установки следующего состояния|Описаны [здесь](#требования-к-транзакции-установки-состояния)| |string|ключ отмены предыдущей транзакции|hex private key| ##### Результат ```javascript { commit: transaction (serialized) } ``` ##### Ошибки * неправильный ключ отмены предыдущей транзакции ```json { "code": 400, "message": "wrong revoke key" } ``` * неправильный скрипт в транзакции. Например, скрипт не той формы или не те public-ключи в нем ```json { "code": 400, "message": "wrong commit script" } ``` * неправильная подпись в транзакции ```json { "code": 400, "message": "wrong commit signature" } ``` * входы не найдены ```json { "code": 400, "message": "wrong inputs commit transaction" } ``` ## Матчинг ордера Для матчинга ордеров создается канал. Инициатор - биржа. Канал создается и тут же закрывается. Трейдер получит при следующем заходе эти транзакции, подпишет их и запушит в блокчейн. ### match_netting_execution_settlement ##### Параметры |тип|описание|ограничения| |:-:|:------:|:---------:| |string|xpub клиента|соответствие структуре xpub (префикс, длина)| |Coin(enum)|индекс токена|-| |long(int64)|сумма|-| ##### Результат ```javascript { funding: transaction, // транзакция финансирования init: transaction, // транзакция утсановки начального состояния close: transaction // транзакция закрытия канала } ``` ##### Ошибки * не нашлось баланса для финансирования ```json { "code": 400, "message": "insufficient funds" } ``` ## Выключение канала Аварийное выключение канала в случае жульничества со стороны трейдера или в результате пуша транзакции последнего состояния (что вполне нормально, просто теперь можно канал только закрыть) ### block_channel_revocation_execution ##### Параметры |тип|описание|ограничения| |:-:|:------:|:---------:| |int64|id клиента|-| |Coin(enum)|индекс токена|-| |int|индекс канала|-| |ReasonCode(enum)|reasonCode|-| ##### Результат ```json { "success": true } ``` ##### Ошибки * все поломалось ```json { "code": 500, "message": "internal error" } ``` ## Вывод средств Вывод средств - создание транзакции закрытия и ее подпись ### withdraw_request_user_execution ##### Параметры |тип|описание|ограничения| |:-:|:------:|:---------:| |Coin(enum)|индекс токена|-| |int|индекс канала|-| |transaction(serialized)|транзакция закрытия|Описаны [здесь](#требования-к-транзакции-закрытия)| ##### Результат ```javascript { close: transaction (serialized) } ``` ##### Ошибки ### withdraw_request_execution_settlement ##### Параметры |тип|описание|ограничения| |:-:|:------:|:---------:| |int|id клиента|-| |Coin(enum)|индекс токена|-| |int|индекс канала|-| |transaction(serialized)|транзакция закрытия|Описаны [здесь](#требования-к-транзакции-закрытия)| ##### Результат ```javascript { close: transaction } ``` ##### Ошибки * нет выхода на биржу ```json { "code": 400, "message": "missing exchange output" } ``` * неправильная подпись в транзакции ```json { "code": 400, "message": "wrong close signature" } ``` * неправильный вход ```json { "code": 400, "message": "wrong inputs close transaction" } ``` ### withdraw_request_settlement_revocation ##### Параметры |тип|описание|ограничения| |:-:|:------:|:---------:| |string|адрес redeem-скрипта|соответствие структуре адреса скрипта| ##### Результат ```json { "success": true } ``` ##### Ошибки * все поломалось ```json { "code": 500, "message": "internal error" } ``` ### Требования к транзакции закрытия ##### Входы Строго один - выход транзакции финансирования с multisig-скриптом ##### Выходы Один из них обязательно на адрес биржи ##### Скрипт Дополнительных требований нет ### ER модель ![](./img/er.png) ## Ландшафт В общем виде имеем `DEV → QA → QC → PRD` // QC для внешних аудиторов Для оптимизации комуникации в удаленной команде - предлагаю договорится и как можно быстрее подготовить прототип рабочей среды для DEV системы, дающей возможность запускать все компоненты всем участникам **DEV среда** Предлагаемая конфигурация среды на основе контейнеров, запускаемая и собираемая в соответствии со сценарием роя Network - 10.10.0.1/24 | **runtime_type** | **runtime_name** | **domain** | **runtime_adr** | **runtime_ports** | **runtime_env** | | ----------------- | ------------------------------ | ------------ | --------------- | ----------------- | --------------- | | state_less_nginx | {dash, handler, modal}.keyless | Keyless | 10.10.0.1 | | | | state_less_nginx | web.terminal.stan | Stan | 10.10.0.2 | | | | state_full_chains | regtest.chains.stan | Stan/Keyless | 10.10.0.3 | | | | state_less_erlang | pre_check.execution.stan | Stan | 10.10.0.4 | | | | state_less_erlang | matching.execution.stan | Stan | 10.10.0.5 | | | | state_less_erlang | common.stan | Stan | 10.10.0.6 | | | | state_less_erlang | api.stan | Stan | 10.10.0.7 | | | | state_less_golang | emitter.blockchain.stan | Stan | 10.10.0.8 | | | | state_less_golang | collector.blockchain.stan | Stan | 10.10.0.9 | | | | state_less_golang | emmiter.off_chain.stan | Stan | 10.10.0.10 | | | | state_less_golang | collector.off_chain.stan | Stan | 10.10.0.11 | | | | state_full_psql | accounts.storage.stan | Stan | 10.10.0.12 | | | | state_full_golang | regtest.blockbook.keyless | Stan/Keyless | 10.10.0.13 | | | | state_less_nginx | ui.portainer.stan | Stan/Keyless | 10.10.0.14 | | | | state_less_nginx | ui.admin.stan | Stan | 10.10.0.15 | | | **QA среда // задачи после устаканивания DEV** Внтреннее тестирование, в процессе интеграции и перед внешним аудитом. В данном ландшафте, в целях исключения досадных ошибок придерживаемся стратегии максимальной мимикрирования под QC/PRD Виртуальные машины для e_otp/базы, контейнерная среда для Golang микросервисов + единый контейнер для локальных тестовых блокчейн узлов - e2e, нагрузочное и интеграционного(с публичными тест-нетами) тестирование, выявление граничной производительности компонентов системы, составление плана на работы следующего этапа **QC среда** Среда для внешнего тестирования, интеграция системы оркестрации клиента - Внешний аудит, публичная тестовая среда **PRD среда** - Производство // **TBA**