main.go
Обзор
Данный файл main.go реализует функциональность запуска и управления несколькими экземплярами процесса symbiotic_relay, взаимодействующих через gRPC API. Основная цель — запуск нескольких операторов (процессов), отправка им большого количества запросов на подпись сообщений и последующая проверка агрегированных доказательств подписей. Это позволяет нагрузочно протестировать систему на корректность и производительность распределённого протокола подписей с агрегацией.
Описание структуры и функционала
Типы и константы
type
process
Описывает один запущенный процессsymbiotic_relay.Поля:
args []string: аргументы запуска процессаcmd *exec.Cmd: объект команды процесса (если запущен)stdOut, stdErr *bytes.Buffer: буферы для stdout и stderr процессаapiAddr string: адрес API для gRPC подключенияrelayClient *v1.SymbioticClient: клиент для взаимодействия с API процессаrunSeparately bool: флаг, запущен ли процесс отдельно (не через exec.Command)
type
processes []process
Срез процессов, с удобными методами для управления всей группой.Константы:
operatorsCount = 3— количество операторов (процессов) для запускаnumberOfSignRequests = 1000— количество запросов подписи, которые будут отправленыsizeOfMessageBytes = 320— размер случайного сообщения в байтах для подписи
Функции и методы
func main()
Точка входа в программу.
Устанавливает уровень логирования на debug.
Запускает функцию
runс базовым контекстом.При ошибке завершает программу panic.
func run(ctx context.Context) error
Запускает процессы с помощью
runProcesses.Отправляет запросы на подпись и ждёт их агрегации через
sendRequestAndWait.Обрабатывает отмену контекста и корректно завершает работу.
Возвращает ошибку, если что-то пошло не так.
func runProcesses(ctx context.Context, runSeparately bool) (processes, error)
Запускает несколько экземпляров
symbiotic_relayс разными конфигурациями (ключи, порты, директории хранения).Если
runSeparately == false, процессы запускаются черезexec.Command, иначе предполагается, что процессы запущены отдельно.Для каждого процесса создаётся gRPC клиент для взаимодействия через API.
После запуска ожидает, что все процессы поднялись (метод
waitServerStarted).Возвращает срез запущенных процессов или ошибку при проблемах.
(prs processes) waitServerStarted(ctx context.Context)
Проверяет вывод
stdoutвсех процессов, ожидая сообщения"All missing epochs loaded", что сигнализирует об успешном запуске.Пытается сделать это до 100 раз с паузой в 1 секунду.
Если процессы не запускаются, выводит логи ошибок и завершает программу panic.
(prs processes) stopProcesses()
Для каждого процесса, если он запущен через
exec.Command, отправляет сигнал прерывания (os.Interrupt) для корректного завершения.Если сигнал не проходит, пытается убить процесс принудительно.
Логирует результат остановки.
func sendRequestAndWait(ctx context.Context, prs processes, nRequests int) *errors.Error
Получает текущую "эпоху" с первого процесса.
Отправляет
nRequestsзапросов на подпись сообщений параллельно (лимит 20 одновременных горутин).Хранит хэши отправленных запросов.
В цикле опрашивает агрегированные доказательства для каждого запроса, пока все не будут агрегированы или не произойдёт отмена контекста.
Логирует статус отправки и агрегации запросов.
(prs processes) sendMessageToAllRelays(ctx context.Context, epoch uint64) (string, error)
Генерирует случайное сообщение длиной
sizeOfMessageBytes.Отправляет запрос на подпись этому сообщению всем процессам через
sendSignMessageRequest.Возвращает хэш последнего запроса.
func sendSignMessageRequest(ctx context.Context, pr process, message []byte, epoch uint64) (string, error)
Использует gRPC клиент процесса для вызова метода
SignMessage.Передаёт сообщение, ключ и требуемую эпоху.
Возвращает хэш запроса, который используется для отслеживания агрегации.
func randomMessage(n int) []byte
Генерирует случайный слайс байт длиной
nс помощью криптографически стойкого генератора.В случае ошибки вызывает panic (т.к. генерация случайных байт критична).
(prs processes) printErrLogs()
Проходит по всем процессам.
Логирует содержимое stderr и stdout для каждого процесса, если там есть данные.
Важные детали реализации
Для параллелизма запросов используется
errgroupс лимитом параллельных горутин (20).Мониторинг запуска процессов основан на анализе их stdout (строка
"All missing epochs loaded").Отправка запросов и ожидание агрегации осуществляется через gRPC API первого процесса, который играет роль агрегатора.
Процессы запускаются с разными ключами и портами, чтобы имитировать распределённую среду.
Управление процессами происходит через стандартную библиотеку
os/exec, что позволяет контролировать жизненный цикл.
Взаимодействие с другими частями системы
Используются внутренние пакеты:
sum/internal/utils — для создания gRPC соединения.
Используются внешние библиотеки:
github.com/symbioticfi/relay/api/client/v1— gRPC клиент для API процессаsymbiotic_relay.github.com/ethereum/go-ethereum/common— для работы с хэшами и байтами.golang.org/x/sync/errgroup— для параллельного выполнения с контролем ошибок.
Этот файл является интеграционным тестом/нагрузочным инструментом для системы symbiotic_relay, запускающей несколько экземпляров и проверяющей корректность работы протокола подписей.
Пример использования
go run main.go
Программа запустит 3 процесса symbiotic_relay, отправит 1000 запросов на подпись случайных сообщений, дождётся агрегированных доказательств и завершит работу.
Диаграмма структуры и взаимодействия
flowchart TD
A[main()] --> B[run()]
B --> C[runProcesses()]
C --> D[process (symbiotic_relay instances)]
B --> E[sendRequestAndWait()]
E --> F[sendMessageToAllRelays()]
F --> G[sendSignMessageRequest()]
E --> H[GetAggregationProof (polling)]
C --> I[waitServerStarted()]
B --> J[stopProcesses()]
subgraph Processes
D
end
Описание диаграммы:
main()запускаетrun().run()вызываетrunProcesses()для запуска процессов.Каждый
process— отдельный экземплярsymbiotic_relay.Затем
sendRequestAndWait()отправляет запросы черезsendMessageToAllRelays(), которая вызываетsendSignMessageRequest()на каждом процессе.После отправки происходит опрос агрегированных доказательств через
GetAggregationProof.При завершении вызывается
stopProcesses()для корректного завершения.
Заключение
Файл main.go — это инструмент для запуска и тестирования системы symbiotic_relay с несколькими операторами, который автоматизирует процесс запуска, отправки нагрузки и проверки агрегированных ответов. Он демонстрирует эффективное использование горутин, gRPC клиентов и управления процессами в Go для создания комплексного интеграционного теста.