NIP-95: Protocolo Híbrido Relay-P2P via WebRTC
- 1. Resumo Executivo
- 2. Taxonomia de Nós (Papéis)
- 3. Mensagens do Protocolo (Client <-> Relay)
- 4. Comunicação P2P (Peer <-> Peer via WebRTC)
- 5. Algoritmos e Lógica de Implementação (LLM Guide)
- 6. Segurança e Integridade
- 7. Extensão NIP-11 (Relay Information)
- 8. Pseudocódigo para Implementação em LLM
- 9. Fluxograma de Decisão (LLM Reasoning)
1. Resumo Executivo
A NIP-95 estende o protocolo Nostr (NIP-01) para permitir uma arquitetura de distribuição de eventos híbrida. O Relay deixa de ser a única fonte de verdade e entrega, passando a atuar também como um Seed Node e Signaling Server. Clientes estáveis tornam-se Super Peers, servindo eventos recentes via WebRTC Data Channels para outros peers, reduzindo drasticamente o consumo de banda e a carga de processamento do relay central.
2. Taxonomia de Nós (Papéis)
| Papel | Descrição | Requisitos Técnicos |
|---|---|---|
| Relay Seed | Nó de autoridade e coordenação. Armazena histórico completo. | Suporte a WebSocket + Lógica de Signaling + Indexação de Cache de Peers. |
| Super Peer | Cliente estável que atua como servidor P2P temporário. | Conexão >30min, Uptime alto, Cache Local (IndexedDB/LevelDB). |
| Casual Peer | Cliente padrão (mobile ou instável). Consumidor prioritário. | Suporte a WebRTC e fallback para WebSocket. |
3. Mensagens do Protocolo (Client <-> Relay)
As mensagens seguem o formato JSON padrão do Nostr: ["COMANDO", <payload>].
3.1 Registro e Gerenciamento de Peer
PEER_REGISTER (Client -> Relay)
Anuncia a intenção do cliente de participar da rede P2P.
[
"PEER_REGISTER",
{
"bandwidth": 10, // Mbps (opcional)
"storage": 500, // MB disponíveis para cache (opcional)
"publicKey": "hex", // Identidade para reputação/pagamentos
"lightningAddress": "user@domain.com" // Incentivos futuros
}
]
PEER_REGISTERED (Relay -> Client)
Confirmação de registro e atribuição de ID de sessão.
[
"PEER_REGISTERED",
{
"peer_id": "uuid-v4",
"heartbeat_interval": 30000,
"status": "registered"
}
]
3.2 Sincronização de Cache
PEER_CACHE_HAVE (Client -> Relay)
Informa ao relay quais eventos o cliente possui em seu cache local para que o relay possa rotear requisições.
[
"PEER_CACHE_HAVE",
{
"events": [
{ "id": "hex", "pubkey": "hex", "kind": 1, "created_at": 162... },
...
]
}
]
3.3 Descoberta e Signaling (Smart Routing)
PEER_OFFER (Relay -> Client)
Enviado pelo relay quando um cliente faz um REQ e o relay identifica que Super Peers possuem os dados.
[
"PEER_OFFER",
{
"subscription": "sub_id_123",
"offers": {
"event_id_abc": ["peer_id_1", "peer_id_2"],
"event_id_def": ["peer_id_3"]
},
"source": "smart_routing"
}
]
PEER_SIGNAL (Client -> Relay -> Client)
Encapsula o handshake WebRTC (SDP/ICE Candidates). O Relay apenas repassa.
[
"PEER_SIGNAL",
{
"target_peer": "uuid-do-outro-peer",
"signal_data": { "type": "offer/answer", "sdp": "..." } // ou ice candidate
}
]
4. Comunicação P2P (Peer <-> Peer via WebRTC)
Uma vez aberto o WebRTC Data Channel, os peers trocam mensagens binárias ou JSON diretamente.
4.1 Requisição de Evento (P2P_REQUEST)
{
"type": "P2P_REQUEST",
"event_id": "hex-id-do-evento"
}
4.2 Entrega de Evento (P2P_EVENTS)
{
"type": "P2P_EVENTS",
"event": {
"id": "...",
"pubkey": "...",
"sig": "...",
"content": "...",
...
}
}
5. Algoritmos e Lógica de Implementação (LLM Guide)
5.1 O Algoritmo de “Smart Routing” (No Relay)
Ao receber uma mensagem ["REQ", sub_id, filter]:
- Processamento Padrão: O relay deve buscar no banco de dados local e enviar eventos via WebSocket (compatibilidade NIP-01).
- Interseção de Cache: O relay consulta seu
CacheTracker(um mapa em memória deevent_id -> Set<peer_id>). - Seleção de Peers: Se o filtro do
REQbater com eventos indexados noCacheTracker:- Selecione até 3 Super Peers online para cada evento.
- Envie
PEER_OFFERao cliente solicitante.
5.2 O Processo de Promoção (Super Peer)
O Relay deve manter um loop de monitoramento (ex: a cada 1 min):
- Se
peer.uptime > 30minANDpeer.reputation > thresholdANDpeer.cache_size > 0:- Envie
["PEER_PROMOTED", { "peer_id": "..." }].
- Envie
- Se o peer desconectar ou falhar em responder heartbeats:
- Remova-o de todos os índices de
CacheTracker.
- Remova-o de todos os índices de
5.3 O Handshake WebRTC (Signaling)
- Peer B (Requester) recebe
PEER_OFFERcontendoPeer A. - Peer B gera um SDP Offer e envia ao Relay:
["PEER_SIGNAL", { target: "Peer A", signal: offer }]. - Relay localiza a conexão WebSocket de Peer A e repassa:
["PEER_SIGNAL_RELAY", { from: "Peer B", signal: offer }]. - Peer A gera um SDP Answer e envia ao Relay:
["PEER_SIGNAL", { target: "Peer B", signal: answer }]. - Relay repassa ao Peer B.
- Conexão P2P estabelecida via STUN/TURN.
6. Segurança e Integridade
- Assinaturas Schnorr: Clientes OBRIGATORIAMENTE devem validar a assinatura (
sig) de cada evento recebido via P2P usando a bibliotecanoble-curvesou similar. Se o ID do evento ou a assinatura forem inválidos, o peer remetente deve ser desconectado e reportado. - Reputação de Peer:
- O Relay deve manter um score de reputação no Redis/DB.
+1para cada evento validado e entregue (reportado viaPEER_STATS).-100(banimento) para envio de assinaturas falsas.- Decay temporal: Reputação diminui se o peer ficar offline.
- Privacidade: O uso de WebRTC expõe o endereço IP entre os peers. Clientes devem solicitar consentimento do usuário antes de ativar o modo P2P (“Enable P2P Acceleration”).
7. Extensão NIP-11 (Relay Information)
Relays compatíveis devem anunciar os limites do protocolo:
{
"supported_nips": [1, 11, 95],
"limitation": {
"p2p_enabled": true,
"p2p_max_connections_per_peer": 10,
"p2p_heartbeat_ms": 30000
}
}
8. Pseudocódigo para Implementação em LLM
Handler de Mensagem (Servidor)
function handleMessage(client, message) {
const [type, payload] = message;
switch(type) {
case "PEER_REGISTER":
return registerPeer(client, payload);
case "PEER_CACHE_HAVE":
return updateCacheTracker(client.id, payload.events);
case "PEER_SIGNAL":
const target = getClientById(payload.target_peer);
if (target) {
send(target, ["PEER_SIGNAL_RELAY", { from: client.id, signal: payload.signal_data }]);
}
break;
case "REQ":
handleStandardNip01(client, payload);
triggerSmartRouting(client, payload); // NIP-95 logic
break;
}
}
Handler de Recebimento P2P (Cliente)
peer.on('data', data => {
const msg = JSON.parse(data);
if (msg.type === 'P2P_EVENTS') {
if (nostr.verifySignature(msg.event)) {
displayEvent(msg.event);
localCache.save(msg.event);
} else {
reportMaliciousPeer(msg.peer_id);
}
}
});
9. Fluxograma de Decisão (LLM Reasoning)
- Input: Filtro Nostr (ex:
{ "kinds": [1], "limit": 10 }). - Relay Query: Busca no DB local (Fast).
- P2P Query: Verifica se algum Super Peer enviou
PEER_CACHE_HAVErecentemente comkind: 1. - Action: Envia resultados do DB via WebSocket +
PEER_OFFERpara conectar aos Super Peers que têm mais eventos do mesmo tipo, visando futuras atualizações. - Result: O cliente recebe os primeiros 10 eventos via WebSocket (baixa latência) e estabelece P2P para o fluxo contínuo (sustentabilidade).
- Reference: https://updatecachetracker(client.id/
- Reference: https://payload.signal/
- Reference: https://client.id/
- Reference: https://`peer.reputation/
- Reference: https://`peer.uptime/
- Reference: https://`peer.cache/
- Reference: https://peer.on/
- Reference: https://json.parse/
- Reference: https://displayevent(msg.event/
- Reference: https://getclientbyid(payload.target/
- Reference: https://reportmaliciouspeer(msg.peer/
- Reference: https://msg.type/
- Reference: https://msg.event/
- Reference: https://localcache.save/
- Reference: https://payload.events/
- Reference: https://nostr.verifysignature/
- Reference: https://"user@domain.com/
Write a comment