Нынешнее видение по организации сетевого (в т.ч. p2p) модуля
Несколько уровней внутри самого модуля
Для тестирования самое то. Код понятный, кусок логики не придется искать в других директориях. Снизу наверх:
- IO уровень: оперирует соединениями, сырыми байтами, реконнектами, таймаутами и асинхронностью (там поллинг самого общего плана)
- Peer уровень:
- протокол и сериализация,
- коллекция peers,
- броадкасты,
- персистентное хранилище, связанное с peers (пусть отдельно будет от хранилища блокчейна),
- ban/unban
- Dandelion (да, он здесь, а не в уровне 3)
- Integration layer:
- фильтр и cache (это множество хешей, которые позволят не отправлять TX или блок в узел, у которого он есть, а также не отсылать в другие модули то, что им уже известно)
- бридж с основной системой, т.е. формирование и трансляция запросов/ответов между ней (API модулей) и уровнем 2
- межпоточное взаимодействие
Основные моменты подробнее
- Один поток на все вышесказанное (сетевая логика, а также уровни 2 и 3)
- Тут логика, которая не требует вычислений, можно иметь очень много активных соединений, пределом может стать только сеть или память, но не cpu
- Исключение: может понадобиться отдельный поток, который зипует громоздкие ответы. Пусть они асинхронно формируются по мере надобности в них
- Взаимодействие с другими потоками или через очереди (если это запросы/ответы) или напрямую (явно сделать, чтоб было понятно, что это константный кусок памяти). Мьютексы ставить на небольшие кусочки обновляемых данных (ну например { total_difficulty, total_height }), которые можно быстро прочитать
- В очередях только что-то легко копируемое или immutable data, напр. { Type type; shared_ptr
и т.п.}
- Сетевое хозяйство и протокол
- Ограничиваемся TCP и IPv4. Потом успеем добавить если что понадобится, а так пусть меньше сначала кода будет
- В качестве библиотеки по сетевым вещам и асинхронности очень желаю libuv. Обоснование ниже.
- Можно взять за основу протокол из grin, что-то убрать/добавить проблем не составит
- Dandelion: надо определиться с одной из 2х схем, прописанных в документации по grin
- Peers
- Логику взять у grin, для начала
- Для хранилища (не блокчейн, только для peers, оно отдельное должно быть) взять sqlite как наиболее проверенную временем штуку. Она гибкая (индексы и т.д.). Кстати, in-memory sqlite тоже хорошо себя зарекомендовало как штука для работы с табличными данными и сложными индексами. Когда/если будут видны ограничения по performance или станет ясно, что не нужно индексирование, можно быдет подобрать key-value storage побыстрее
- Кэши и фильтры
- То же, что и у grin для начала. Можно будет какой-нибудь bloom filter попробовать, чтоб избежать ограничений, которые мы в этой части видим у grin
Доводы в пользу libuv
Оно здесь: http://docs.libuv.org/en/v1.x/, https://github.com/libuv/libuv
- Качественная и компактная вещь. На ней весь node.js и его асинхронность и много еще чего.
- Можно зафиксировать версию и исходники встроить в build system
- У меня с ней очень положительный опыт и не один. Вообще могу всю эту часть взять на себя и гарантировать хороший результат, и быстрый, т.к. изнутри знаю, что там
- Будет на несколько % медленнее самописного решения на epoll, но зато mature и не один линукс
- Туда же приделывается асинхронность и таймеры, API можно вывести приличное, на std::function, например
- Также можно приделать, когда понадобится, http и TLS