Files
lnd/onionmessage/onion_endpoint.go
T
Gijs van Dam 07dc74e198 multi: endpoints for onion messages
This commit creates the necessary endpoints for onion messages.
Specifically, it adds the following:

- `SendOnionMessage` endpoint to send onion messages.
- `SubscribeOnionMessages` endpoint to subscribe to incoming onion
  messages.

It uses the `msgmux` package to handle the onion messages.
2025-11-12 22:54:04 +08:00

102 lines
2.7 KiB
Go

package onionmessage
import (
"context"
"encoding/hex"
"log/slog"
"github.com/btcsuite/btclog/v2"
"github.com/lightningnetwork/lnd/lnutils"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/msgmux"
"github.com/lightningnetwork/lnd/subscribe"
)
// OnionMessageUpdate is onion message update dispatched to any potential
// subscriber.
type OnionMessageUpdate struct {
// Peer is the peer pubkey
Peer [33]byte
// PathKey is the route blinding ephemeral pubkey to be used for
// the onion message.
PathKey [33]byte
// OnionBlob is the raw serialized mix header used to relay messages in
// a privacy-preserving manner. This blob should be handled in the same
// manner as onions used to route HTLCs, with the exception that it uses
// blinded routes by default.
OnionBlob []byte
}
// OnionEndpoint handles incoming onion messages.
type OnionEndpoint struct {
// subscribe.Server is used for subscriptions to onion messages.
onionMessageServer *subscribe.Server
}
// A compile-time check to ensure OnionEndpoint implements the Endpoint
// interface.
var _ msgmux.Endpoint = (*OnionEndpoint)(nil)
// NewOnionEndpoint creates a new OnionEndpoint.
func NewOnionEndpoint(messageServer *subscribe.Server) *OnionEndpoint {
return &OnionEndpoint{
onionMessageServer: messageServer,
}
}
// Name returns the unique name of the endpoint.
func (o *OnionEndpoint) Name() string {
return "OnionMessageHandler"
}
// CanHandle checks if the endpoint can handle the incoming message.
// It returns true if the message is an lnwire.OnionMessage.
func (o *OnionEndpoint) CanHandle(msg msgmux.PeerMsg) bool {
_, ok := msg.Message.(*lnwire.OnionMessage)
return ok
}
// SendMessage processes the incoming onion message.
// It returns true if the message was successfully processed.
func (o *OnionEndpoint) SendMessage(ctx context.Context,
msg msgmux.PeerMsg) bool {
onionMsg, ok := msg.Message.(*lnwire.OnionMessage)
if !ok {
return false
}
peer := msg.PeerPub.SerializeCompressed()
logCtx := btclog.WithCtx(ctx,
slog.String("peer", hex.EncodeToString(peer)),
lnutils.LogPubKey("path_key", onionMsg.PathKey),
)
log.DebugS(logCtx, "OnionEndpoint received OnionMessage",
btclog.HexN("onion_blob", onionMsg.OnionBlob, 10),
slog.Int("blob_length", len(onionMsg.OnionBlob)))
var peerArr [33]byte
copy(peerArr[:], peer)
// Convert path key []byte to [33]byte.
pathKey := onionMsg.PathKey.SerializeCompressed()
var pathKeyArr [33]byte
copy(pathKeyArr[:], pathKey)
err := o.onionMessageServer.SendUpdate(&OnionMessageUpdate{
Peer: peerArr,
PathKey: pathKeyArr,
OnionBlob: onionMsg.OnionBlob,
})
if err != nil {
log.ErrorS(logCtx, "Failed to send onion message update", err)
return false
}
return true
}