Skip to content

Instantly share code, notes, and snippets.

@zsfelfoldi
Last active April 26, 2022 23:59
Show Gist options
  • Save zsfelfoldi/9fa34934d9a695e6689ce56c4797c1a8 to your computer and use it in GitHub Desktop.
Save zsfelfoldi/9fa34934d9a695e6689ce56c4797c1a8 to your computer and use it in GitHub Desktop.

Notes on implementing uTP over the Geth DiscV5 implementation

The uTP-over-DiscV5 document specifies that all uTP traffic is encapsulated into TALKREQ packets while TALKRESP is not used. The problem is that the current DiscV5 implementation kind of insists on doing TALKREQ / TALKRESP packet exchanges and expects a response to every request. See the existing interface here:

type TalkRequestHandler func(enode.ID, *net.UDPAddr, []byte) []byte
func (t *UDPv5) RegisterTalkHandler(protocol string, handler TalkRequestHandler) {
func (t *UDPv5) TalkRequest(n *enode.Node, protocol string, request []byte) ([]byte, error) {

In order to interface uTP to DiscV5 we need to somehow circumvent the internal request/reply logic and just send and receive TALKREQ packets. I'd suggest modifying handleTalkRequest so that if the TalkRequestHandler returns a nil byte slice then it does not send a response at all. This way the uTP handler can register itself with RegisterTalkHandler('utp', handler) where the handler processes incoming messages and always returns nil. For sending messages without expecting a response I`d suggest adding an alternative send method:

func (t *UDPv5) TalkRequestNoResponse(n *enode.Node, protocol string, message []byte) error {
    _, err := t.send(n.ID(), &net.UDPAddr{IP: n.IP(), Port: n.UDP()}, &v5wire.TalkRequest{Protocol: protocol, Message: message})
    return err
}

The exported interface of the uTP logic should look something like this:

func (t *UTP) Send(n *enode.Node, connectionID, message []byte) error
func (t *UTP) Receive(n *enode.Node, connectionID []byte) ([]byte, error)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment