Перейти к основному содержимому

Обнаружение пиров

Узел присоединяется, набирая точку входа, и находит остальную сеть сам. Обнаружение пиров (OFS-1100) обменивается известными пирами по тому же соединению, которое gossip уже использует, поэтому узел узнаёт пиров, которые ему никогда не давали, и анонсирует адреса, по которым он достижим.

Об этом стоит сказать прямо, потому что так было не всегда, а сбой был невидим: сервис обнаружения был полностью реализован и свёл пять узлов в своём собственном тесте, и ни один работающий узел никогда не создал ни одного. Узлы не анонсировали адрес и не узнавали пира, который не был бы дан им статически, при этом выглядя совершенно здоровыми для каждой локальной проверки. У узла один swarm libp2p, только одна вещь может управлять циклом событий этого swarm, и он был у gossip, — поэтому сервис, который не владел swarm, не получал ничего, навсегда. Оба теперь разделяют одно соединение, и сообщения маршрутизируются к одному или другому по собственному номеру спецификации OFS конверта.

Обнаружение — не флаг, и его нельзя выключить.

Первое соединение

Ничто не может найти сеть из ничего, поэтому --entrypoint всё ещё то, как узел запускается:

openfiat-node --entrypoint /dns4/openfiat.allenhark.com/udp/4001/quic-v1/p2p/12D3KooW...

Повторите для нескольких. Имя хоста работает и предпочтительно — узел разрешает его при запуске через собственный резолвер операционной системы, поэтому кластер переживает смену IP точки входа. Сохраняйте суффикс /p2p/<peer id>: DNS не аутентифицирован, а peer id — это то, что заставляет угнанную запись провалить рукопожатие, а не тихо стать вашим единственным пиром.

Точка входа, которая не разрешится, останавливает узел при запуске, а не пропускается. Узел, который тихо отбросил бы одну, поднялся бы вообще без пиров и выглядел бы совершенно здоровым, ни с кем не разговаривая, — что ровно тот сбой, с которого этот раздел открылся.

Запустите вообще без точки входа, и узел так и говорит, на уровне WARN. Это верно для первого узла нового кластера и неверно для всех остальных.

Что ваш узел анонсирует о себе

Каждый адрес, на котором узел знает, что слушает, за вычетом bind-маски. 0.0.0.0 и :: — инструкции прослушивания, означающие «каждый локальный интерфейс», а не назначения — и поскольку --gossip-bind-address по умолчанию ровно это, анонсировать его без фильтра — это ровно тот баг, который оставляет пиров без чего-либо для набора.

Loopback и приватные диапазоны намеренно не фильтруются. Процессы на одном хосте достигают друг друга по loopback, кластер docker-compose или LAN достигает своих пиров только по приватному адресу, а одно-хостовый кластер — это реальное развёртывание, а не тестовый артефакт.

За NAT, в контейнере или на облачном хосте с сопоставленным IP

Адрес, который ваш узел привязывает, — не тот адрес, по которому пиры могут его достичь, а публичный узел вычислить не может. Это не упущение — по построению только нечто с той стороны NAT может наблюдать публичный адрес. Поэтому оператор его объявляет:

--external-addr /ip4/203.0.113.7/udp/4001/quic-v1

Повторяемо. Объявленные адреса анонсируются раньше привязанных, поэтому пир, пробующий их по порядку, соединяется с первой попытки, а не истекает по времени на 172.17.0.2. Привязанные адреса всё же тоже анонсируются — отбрасывание их исправило бы удалённый случай, сломав локальный.

Опустите флаг, если ваш узел действительно на публичном интерфейсе. Его привязанный адрес уже его публичный.

Спрашивая узел, что он знает

curl -s -X POST http://localhost:7080/rpc -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"getPeers","params":{}}' | jq
{
"self_peer_id": "12D3KooWK9hQ7TwbfvFiaAxUbRFCkdhS7iEpAJDnewNL1anyREQ1",
"announced_addresses": ["/ip4/203.0.113.7/udp/4001/quic-v1"],
"peers": [
{
"peer_id": "12D3KooW...",
"addresses": ["/ip4/198.51.100.4/udp/4001/quic-v1"],
"node_version": "openfiat/0.1.0",
"supported_ofs": [1000, 1100, 1200, 1300, 1400, 1500, 2000, 2100, 2200, 2300, 2400, 3000, 4000, 4300, 6000, 7000, 8200],
"roles": ["MerchantGateway", "OracleProvider", "NotificationGateway", "RiskIntelligenceProvider"],
"last_seen": 1753800000000,
"latency_ms": 42,
"successes": 17,
"failures": 0
}
]
}

Три вещи стоит знать об этом ответе.

self_peer_id — это форма 12D3Koo…, которая идёт в точку входа, которую вы публикуете другим операторам. Узел, который не может назвать собственный peer id, нельзя присоединить, а сборка его из строки лога — это как он печатается неверно.

announced_addresses — это то, что вы говорите пирам набирать, в порядке, в котором они будут их пробовать. «Мой узел ничего не анонсирует» было невидимо снаружи, пока было правдой, а оператору, который проверяет, вступил ли в силу его --external-addr, больше некуда смотреть.

successes и failures — это собственный подсчёт этого узла обменов с тем пиром. Намеренно нет процента аптайма и нет оценки здоровья: свернуть два подсчёта в одно число представило бы локальный опыт одного узла как вердикт по всей сети, а два честных узла могут расходиться по обоим.