Skip to content

Commit e25d3a6

Browse files
committed
wip: cleanup
1 parent 99d7816 commit e25d3a6

File tree

5 files changed

+258
-187
lines changed

5 files changed

+258
-187
lines changed

onionmessage/actor.go

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@ import (
99
"github.com/lightningnetwork/lnd/lnwire"
1010
)
1111

12-
// OMRequest is a message sent to an Onion Peer Actor to send an onion message
13-
// to the peer for which the actor is responsible.
12+
// OMRequest is a message sent to an Onion Peer Actor to request sending an
13+
// onion message to a specific peer. Each actor is responsible for a single
14+
// peer connection, and this message is used to queue onion messages for
15+
// delivery to that peer.
1416
type OMRequest struct {
1517
// Embed BaseMessage to satisfy the actor package Message interface.
1618
actor.BaseMessage
19+
20+
// msg is the onion message to send. This field is unexported as it's an
21+
// implementation detail of the actor system and should not be accessed
22+
// directly by external code.
1723
msg lnwire.OnionMessage
1824
}
1925

@@ -37,9 +43,18 @@ func (m *OMResponse) MessageType() string {
3743
type OnionPeerActorRef actor.ActorRef[*OMRequest, *OMResponse]
3844

3945
// SpawnOnionPeerActor spawns a new Onion Peer Actor responsible for sending
40-
// onion messages to a single peer identified by pubKey. The sender function
41-
// is used to send the actual onion messages. The function returns a reference
42-
// to the spawned actor.
46+
// onion messages to a single peer identified by pubKey.
47+
//
48+
// Actor Lifecycle:
49+
// - One actor per connected peer
50+
// - Registered with receptionist using peer's public key as service key
51+
// - Automatically cleaned up when peer disconnects
52+
//
53+
// The sender function is used to send the actual onion messages to the peer.
54+
// This function should be provided by the brontide peer connection logic.
55+
//
56+
// Returns a reference to the spawned actor that can be used to send messages
57+
// via Tell() or Ask() operations.
4358
func SpawnOnionPeerActor(system *actor.ActorSystem,
4459
sender func(msg *lnwire.OnionMessage),
4560
pubKey [33]byte) OnionPeerActorRef {
@@ -73,3 +88,12 @@ func SpawnOnionPeerActor(system *actor.ActorSystem,
7388

7489
return actorRef
7590
}
91+
92+
func findPeerActor(receptionist *actor.Receptionist, pubKey [33]byte,
93+
) fn.Option[actor.ActorRef[*OMRequest, *OMResponse]] {
94+
95+
pubKeyHex := hex.EncodeToString(pubKey[:])
96+
serviceKey := actor.NewServiceKey[*OMRequest, *OMResponse](pubKeyHex)
97+
refs := actor.FindInReceptionist(receptionist, serviceKey)
98+
return fn.Head(refs)
99+
}

onionmessage/endpoint.go

Lines changed: 73 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,17 @@ type OnionMessageUpdate struct {
3434
// blinded routes by default.
3535
OnionBlob []byte
3636

37+
// CustomRecords contains any custom TLV records included in the
38+
// payload.
3739
CustomRecords record.CustomSet
3840

41+
// ReplyPath contains the reply path information for the onion message.
3942
ReplyPath *lnwire.ReplyPath
4043

44+
// EncryptedRecipientData contains the encrypted recipient data for the
45+
// onion message, created by the creator of the blinded route. This is
46+
// the receiver for the last leg of the route, and the sender for the
47+
// first leg uyp to the introduction point.
4148
EncryptedRecipientData []byte
4249
}
4350

@@ -72,7 +79,14 @@ var _ msgmux.Endpoint = (*OnionEndpoint)(nil)
7279

7380
// NewOnionEndpoint creates a new OnionEndpoint with the given options.
7481
func NewOnionEndpoint(receptionist *actor.Receptionist, router *sphinx.Router,
75-
opts ...OnionEndpointOption) *OnionEndpoint {
82+
opts ...OnionEndpointOption) (*OnionEndpoint, error) {
83+
84+
if receptionist == nil {
85+
return nil, ErrNilReceptionist
86+
}
87+
if router == nil {
88+
return nil, ErrNilRouter
89+
}
7690

7791
o := &OnionEndpoint{
7892
receptionist: receptionist,
@@ -82,7 +96,7 @@ func NewOnionEndpoint(receptionist *actor.Receptionist, router *sphinx.Router,
8296
opt(o)
8397
}
8498

85-
return o
99+
return o, nil
86100
}
87101

88102
// Name returns the unique name of the endpoint.
@@ -118,49 +132,62 @@ func (o *OnionEndpoint) SendMessage(ctx context.Context,
118132
btclog.HexN("onion_blob", onionMsg.OnionBlob, 10),
119133
slog.Int("blob_length", len(onionMsg.OnionBlob)))
120134

121-
routingDecisionResult := processOnionMessage(o.router, onionMsg)
135+
routingActionResult := processOnionMessage(o.router, onionMsg)
122136

123-
routingDecision, err := routingDecisionResult.Unpack()
137+
routingAction, err := routingActionResult.Unpack()
124138
if err != nil {
125139
log.ErrorS(logCtx, "Failed to handle onion message", err)
126140
return false
127141
}
128142

129-
var payload *lnwire.OnionMessagePayload
130-
131-
routingDecision.WhenLeft(func(forwardAction ForwardAction) {
132-
err = o.forwardMessage(
133-
ctx, forwardAction.NextNodeID,
134-
forwardAction.NextPathKey,
135-
forwardAction.NextPacket,
136-
)
137-
payload = forwardAction.Payload
138-
})
139-
140-
if err != nil {
141-
log.ErrorS(logCtx, "Failed to forward onion message", err)
142-
return false
143-
}
144-
145-
routingDecision.WhenRight(func(deliverAction DeliverAction) {
146-
payload = deliverAction.Payload
147-
})
148-
143+
var isProcessedSuccessful bool = false
144+
145+
// Handle the routing action.
146+
payload := fn.ElimEither(routingAction,
147+
func(forwardAction forwardAction) *lnwire.OnionMessagePayload {
148+
log.DebugS(logCtx, "Forwarding onion message",
149+
lnutils.LogPubKey("next_node_id",
150+
forwardAction.nextNodeID),
151+
)
152+
153+
err := o.forwardMessage(
154+
ctx, forwardAction.nextNodeID,
155+
forwardAction.nextPathKey,
156+
forwardAction.nextPacket,
157+
)
158+
159+
if err != nil {
160+
log.ErrorS(logCtx, "Failed to forward onion "+
161+
"message", err)
162+
isProcessedSuccessful = false
163+
}
164+
165+
isProcessedSuccessful = true
166+
167+
return forwardAction.payload
168+
},
169+
func(deliverAction deliverAction) *lnwire.OnionMessagePayload {
170+
log.DebugS(logCtx, "Delivering onion message to self")
171+
isProcessedSuccessful = true
172+
return deliverAction.payload
173+
})
174+
175+
// Convert peer []byte to [33]byte.
149176
var peerArr [33]byte
150177
copy(peerArr[:], peer)
151178

152179
// Convert path key []byte to [33]byte.
153-
pathKey := onionMsg.PathKey.SerializeCompressed()
154180
var pathKeyArr [33]byte
155-
copy(pathKeyArr[:], pathKey)
181+
copy(pathKeyArr[:], onionMsg.PathKey.SerializeCompressed())
156182

183+
// Create the onion message update to send to subscribers.
157184
update := &OnionMessageUpdate{
158185
Peer: peerArr,
159186
PathKey: pathKeyArr,
160187
OnionBlob: onionMsg.OnionBlob,
161188
}
162189

163-
// If we have a payload (no error), add its contents to our update.
190+
// If we have a payload, add its contents to our update.
164191
if payload != nil {
165192
customRecords := make(record.CustomSet)
166193
for _, v := range payload.FinalHopPayloads {
@@ -173,18 +200,17 @@ func (o *OnionEndpoint) SendMessage(ctx context.Context,
173200

174201
// Send the update to any subscribers.
175202
if sendErr := o.onionMessageServer.SendUpdate(update); sendErr != nil {
176-
log.Errorf("Failed to send onion message update: %v", sendErr)
177-
return false
178-
}
203+
log.ErrorS(logCtx, "Failed to send onion message update",
204+
sendErr)
179205

180-
// If we failed to handle the onion message, we return false.
181-
if err != nil {
182206
return false
183207
}
184208

185-
return true
209+
return isProcessedSuccessful
186210
}
187211

212+
// forwardMessage forwards the onion message to the next node using the peer
213+
// actor that was spawned for that node.
188214
func (o *OnionEndpoint) forwardMessage(ctx context.Context,
189215
nextNodeID *btcec.PublicKey, nextBlindingPoint *btcec.PublicKey,
190216
nextPacket []byte) error {
@@ -195,25 +221,24 @@ func (o *OnionEndpoint) forwardMessage(ctx context.Context,
195221
// Find the onion peer actor for the next node ID.
196222
actorRefOpt := findPeerActor(o.receptionist, nextNodeIDBytes)
197223

224+
// If no actor found, return an error.
198225
if actorRefOpt.IsNone() {
199-
return fmt.Errorf("no actors found for nextNodeId: %v",
226+
return fmt.Errorf("failed to forward onion message: no peer "+
227+
"actor found for node %v (peer may be disconnected)",
200228
nextNodeID)
201229
}
202230

203-
onionMsg := lnwire.NewOnionMessage(
204-
nextBlindingPoint, nextPacket,
205-
)
206-
req := &OMRequest{msg: *onionMsg}
207-
actorRefOpt.UnsafeFromSome().Tell(ctx, req)
231+
// Send the onion message to the peer actor.
232+
actorRefOpt.WhenSome(func(actorRef actor.ActorRef[*OMRequest,
233+
*OMResponse]) {
208234

209-
return nil
210-
}
211-
212-
func findPeerActor(receptionist *actor.Receptionist, pubKey [33]byte,
213-
) fn.Option[actor.ActorRef[*OMRequest, *OMResponse]] {
235+
onionMsg := lnwire.NewOnionMessage(
236+
nextBlindingPoint, nextPacket,
237+
)
238+
req := &OMRequest{msg: *onionMsg}
239+
actorRef.Tell(ctx, req)
240+
})
214241

215-
pubKeyHex := hex.EncodeToString(pubKey[:])
216-
serviceKey := actor.NewServiceKey[*OMRequest, *OMResponse](pubKeyHex)
217-
refs := actor.FindInReceptionist(receptionist, serviceKey)
218-
return fn.Head(refs)
242+
// Successfully forwarded the message.
243+
return nil
219244
}

onionmessage/errors.go

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,17 @@ package onionmessage
33
import "errors"
44

55
var (
6-
// ErrBadMessage is returned when we can't process an onion message.
7-
ErrBadMessage = errors.New("onion message processing failed")
8-
9-
// ErrBadOnionMsg is returned when we receive a bad onion message.
10-
ErrBadOnionMsg = errors.New("invalid onion message")
11-
12-
// ErrBadOnionBlob is returned when we receive a bad onion blob within
13-
// our onion message.
14-
ErrBadOnionBlob = errors.New("invalid onion blob")
15-
16-
// ErrNoForwardingOnion is returned when we try to forward an onion
17-
// message but no next onion is provided.
18-
ErrNoForwardingOnion = errors.New("no next onion provided to forward")
19-
20-
// ErrNoEncryptedData is returned when the encrypted data TLV is not
21-
// present when it is required.
22-
ErrNoEncryptedData = errors.New("encrypted data blob required")
23-
24-
// ErrNoForwardingPayload is returned when no onion message payload
25-
// is provided to allow forwarding messages.
26-
ErrNoForwardingPayload = errors.New("no payload provided for " +
27-
"forwarding")
28-
29-
// ErrNoNextNodeID is returned when we require a next node id in our
30-
// encrypted data blob and one was not provided.
31-
ErrNoNextNodeID = errors.New("next node ID required")
32-
336
// ErrActortShuttingDown is returned by the actor logic when its context
347
// is cancelled.
358
ErrActorShuttingDown = errors.New("actor shutting down")
369

3710
// ErrNextNodeIdEmpty is returned when the next node ID is missing from
3811
// the route data.
3912
ErrNextNodeIdEmpty = errors.New("next node ID empty")
13+
14+
// ErrNilReceptionist is returned when a nil receptionist is provided.
15+
ErrNilReceptionist = errors.New("receptionist cannot be nil")
16+
17+
// ErrNilRouter is returned when a nil router is provided.
18+
ErrNilRouter = errors.New("router cannot be nil")
4019
)

0 commit comments

Comments
 (0)