Skip to content

beacon: NotifyNode tells a node the registry holds a relayed handshake for it - #59

Merged
TeoSlayer merged 3 commits into
mainfrom
feat/notify-node
Oct 1, 2026
Merged

TeoSlayer merged 3 commits into
mainfrom
feat/notify-node

Conversation

@TeoSlayer

Copy link
Copy Markdown
Contributor

Summary

A trust handshake that cannot go directly (the requester cannot resolve a private node before trust exists) is relayed through the registry, and each side only finds it on its 60-second poll: about two minutes end to end. This gives the registry a way to tell the recipient to poll now.

Changes

  • Server.NotifyNode(nodeID) sends the node two bytes, [0x0A][0x01] (MsgNotify, kind handshake), at its registered UDP endpoint.
  • The message carries no node ID, address or payload. The node reacts by polling the registry over its own authenticated connection, which it would have done on its next tick anyway.
  • At most one notify per node per second.
  • Best effort: a node not registered with this beacon, on the compat (WSS) transport, or predating the message finds the handshake on its next poll, as before. Old daemons drop the message as an unknown beacon type.

Why not reuse a punch request as the wake-up: it would hand the requester the target's IP:port before trust (which the registry refuses), it does not work at all under -require-punch-token, and it would spend the punch budget.

Used by pilot-protocol/rendezvous (feat/handshake-notify) and handled by pilot-protocol/pilotprotocol (feat/fast-relayed-handshake). 0x0A is defined here and in the daemon rather than in common/protocol so each branch builds alone; it should move there.

Limits

  • Only reaches a node registered with the beacon that runs with the registry; nodes on another beacon in a mesh fall back to polling. Not tested with multiple beacons.
  • Beacon endpoint registrations are not authenticated, so a notify can be sent to whoever last claimed the node ID. It discloses only that something is waiting for that node.

Test Plan

  • go build ./..., go vet ./..., go test ./...
  • TestNotifyNode

🤖 Generated with Claude Code

…e for it

A trust handshake between two private nodes is parked at the registry until
each side polls for it, once a minute. NotifyNode sends the node a two-byte
MsgNotify ([0x0A][kind]) at the UDP endpoint it registered with this beacon,
so an updated daemon polls right away. The message carries no node ID,
address or payload. Notifies to one node are limited to one per second.
Best effort: daemons that predate it drop it as an unknown beacon message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@TeoSlayer

Copy link
Copy Markdown
Contributor Author

The failing test job is a data race reported by the race detector in TestEnableCompatWSS_HappyPath: EnableCompatWSS (server.go:304) writes a field that dispatchRelay (server.go:902) reads from the listener goroutine the test started first. Neither is touched by this PR, and NotifyNode is not called in that test. I could not reproduce it on main in 30 local -race runs (macOS/arm64), so it looks intermittent rather than new — but I have not proven it also occurs on main in CI. The job could not be re-run from the API; pushing an empty commit to retrigger.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@TeoSlayer
TeoSlayer merged commit 5ab5a37 into main Oct 1, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant