• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 21485572389

29 Jan 2026 04:09PM UTC coverage: 65.247% (+0.2%) from 65.074%
21485572389

Pull #10089

github

web-flow
Merge 22d34d15e into 19b2ad797
Pull Request #10089: Onion message forwarding

1152 of 1448 new or added lines in 23 files covered. (79.56%)

4109 existing lines in 29 files now uncovered.

139515 of 213825 relevant lines covered (65.25%)

20529.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.89
/onionmessage/actor.go
1
package onionmessage
2

3
import (
4
        "context"
5
        "encoding/hex"
6

7
        "github.com/lightningnetwork/lnd/actor"
8
        "github.com/lightningnetwork/lnd/fn/v2"
9
        "github.com/lightningnetwork/lnd/lnwire"
10
)
11

12
// Request 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.
16
type Request struct {
17
        // Embed BaseMessage to satisfy the actor package Message interface.
18
        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.
23
        msg lnwire.OnionMessage
24
}
25

26
// MessageType returns a string identifier for the Request message type.
NEW
27
func (m *Request) MessageType() string {
×
NEW
28
        return "OnionMessageRequest"
×
NEW
29
}
×
30

31
// Response is the response message sent back from an Onion Peer Actor.
32
type Response struct {
33
        actor.BaseMessage
34
        Success bool
35
}
36

37
// MessageType returns a string identifier for the Response message type.
NEW
38
func (m *Response) MessageType() string {
×
NEW
39
        return "OnionMessageResponse"
×
NEW
40
}
×
41

42
// OnionPeerActorRef is a reference to an Onion Peer Actor.
43
type OnionPeerActorRef actor.ActorRef[*Request, *Response]
44

45
// OnionPeerActor handles onion message delivery to a specific peer. It
46
// implements the actor.ActorBehavior interface and can be tested directly
47
// without the actor system.
48
type OnionPeerActor struct {
49
        sender func(msg *lnwire.OnionMessage)
50
}
51

52
// NewOnionPeerActor creates a new OnionPeerActor with the given sender
53
// function.
54
func NewOnionPeerActor(sender func(msg *lnwire.OnionMessage)) *OnionPeerActor {
10✔
55
        return &OnionPeerActor{sender: sender}
10✔
56
}
10✔
57

58
// Receive processes an incoming onion message request and sends it to the peer.
59
// This method implements the actor.ActorBehavior interface.
60
func (a *OnionPeerActor) Receive(ctx context.Context,
61
        req *Request) fn.Result[*Response] {
8✔
62

8✔
63
        select {
8✔
64
        case <-ctx.Done():
1✔
65
                log.DebugS(ctx, "OnionPeerActor context canceled, not sending")
1✔
66

1✔
67
                return fn.Err[*Response](ErrActorShuttingDown)
1✔
68
        default:
7✔
69
        }
70

71
        log.TraceS(ctx, "OnionPeerActor sending onion message")
7✔
72

7✔
73
        a.sender(&req.msg)
7✔
74

7✔
75
        return fn.Ok(&Response{Success: true})
7✔
76
}
77

78
// SpawnOnionPeerActor spawns a new Onion Peer Actor responsible for sending
79
// onion messages to a single peer identified by pubKey.
80
//
81
// Actor Lifecycle:
82
// - One actor per connected peer
83
// - Registered with receptionist using peer's public key as service key
84
// - Automatically cleaned up when peer disconnects
85
//
86
// The sender function is used to send the actual onion messages to the peer.
87
// This function should be provided by the brontide peer connection logic.
88
//
89
// Returns a reference to the spawned actor that can be used to send messages
90
// via Tell() or Ask() operations.
91
func SpawnOnionPeerActor(system *actor.ActorSystem,
92
        sender func(msg *lnwire.OnionMessage),
93
        pubKey [33]byte) OnionPeerActorRef {
8✔
94

8✔
95
        peerActor := NewOnionPeerActor(sender)
8✔
96

8✔
97
        pubKeyHex := hex.EncodeToString(pubKey[:])
8✔
98
        serviceKey := actor.NewServiceKey[*Request, *Response](pubKeyHex)
8✔
99
        actorRef := serviceKey.Spawn(
8✔
100
                system, "onion-peer-actor-"+pubKeyHex, peerActor,
8✔
101
        )
8✔
102

8✔
103
        log.Debugf("Spawned onion peer actor for peer %s", pubKeyHex)
8✔
104

8✔
105
        return actorRef
8✔
106
}
8✔
107

108
func findPeerActor(receptionist *actor.Receptionist, pubKey [33]byte,
109
) fn.Option[actor.ActorRef[*Request, *Response]] {
13✔
110

13✔
111
        pubKeyHex := hex.EncodeToString(pubKey[:])
13✔
112
        serviceKey := actor.NewServiceKey[*Request, *Response](pubKeyHex)
13✔
113
        refs := actor.FindInReceptionist(receptionist, serviceKey)
13✔
114

13✔
115
        return fn.Head(refs)
13✔
116
}
13✔
117

118
// StopPeerActor looks up the onion peer actor for the given public key and
119
// stops it. This should be called when a peer disconnects to clean up the
120
// actor. If no actor exists for the given public key, this is a no-op.
121
func StopPeerActor(system *actor.ActorSystem, pubKey [33]byte) {
5✔
122
        pubKeyHex := hex.EncodeToString(pubKey[:])
5✔
123
        serviceKey := actor.NewServiceKey[*Request, *Response](pubKeyHex)
5✔
124

5✔
125
        actorOpt := findPeerActor(system.Receptionist(), pubKey)
5✔
126
        actorOpt.WhenSome(func(ref actor.ActorRef[*Request, *Response]) {
8✔
127
                log.Debugf("Stopping onion peer actor for peer %s", pubKeyHex)
3✔
128

3✔
129
                serviceKey.Unregister(system, ref)
3✔
130
        })
3✔
131
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc