@@ -54,19 +54,68 @@ type Manager struct {
54
54
cfg * ManagerConfig
55
55
56
56
currentHeight atomic.Int32
57
+
58
+ // addrRequest is a channel used to request new static addresses from
59
+ // the manager. The manager employs a go worker routine that handles the
60
+ // requests.
61
+ addrRequest chan request
62
+ }
63
+
64
+ type request struct {
65
+ ctx context.Context
66
+ respChan chan response
67
+ }
68
+
69
+ type response struct {
70
+ parameters * Parameters
71
+ err error
57
72
}
58
73
59
74
// NewManager creates a new address manager.
60
75
func NewManager (cfg * ManagerConfig , currentHeight int32 ) * Manager {
61
76
m := & Manager {
62
- cfg : cfg ,
77
+ cfg : cfg ,
78
+ addrRequest : make (chan request ),
63
79
}
64
80
m .currentHeight .Store (currentHeight )
65
81
66
82
return m
67
83
}
68
84
69
- // Run runs the address manager.
85
+ // addrWorker is a worker that handles address creation requests. It calls
86
+ // m.newAddress which blocks on server I/O and returns the address and expiry.
87
+ func (m * Manager ) addrWorker (ctx context.Context ) {
88
+ for {
89
+ select {
90
+ case req := <- m .addrRequest :
91
+ m .handleAddrRequest (ctx , req )
92
+
93
+ case <- ctx .Done ():
94
+ return
95
+ }
96
+ }
97
+ }
98
+
99
+ // handleAddrRequest is responsible for processing a single address request.
100
+ func (m * Manager ) handleAddrRequest (managerCtx context.Context , req request ) {
101
+ addrParams , err := m .newAddress (req .ctx )
102
+
103
+ resp := response {
104
+ parameters : addrParams ,
105
+ err : err ,
106
+ }
107
+
108
+ select {
109
+ case req .respChan <- resp :
110
+
111
+ case <- req .ctx .Done ():
112
+
113
+ case <- managerCtx .Done ():
114
+ }
115
+ }
116
+
117
+ // Run runs the address manager. It keeps track of the current block height and
118
+ // creates new static addresses as needed.
70
119
func (m * Manager ) Run (ctx context.Context , initChan chan struct {}) error {
71
120
newBlockChan , newBlockErrChan , err :=
72
121
m .cfg .ChainNotifier .RegisterBlockEpochNtfn (ctx )
@@ -75,6 +124,10 @@ func (m *Manager) Run(ctx context.Context, initChan chan struct{}) error {
75
124
return err
76
125
}
77
126
127
+ // The address worker offloads the address creation with the server to a
128
+ // separate go routine.
129
+ go m .addrWorker (ctx )
130
+
78
131
// Communicate to the caller that the address manager has completed its
79
132
// initialization.
80
133
close (initChan )
@@ -95,49 +148,64 @@ func (m *Manager) Run(ctx context.Context, initChan chan struct{}) error {
95
148
}
96
149
97
150
// NewAddress creates a new static address with the server or returns an
98
- // existing one.
99
- func (m * Manager ) NewAddress (ctx context.Context ) (* btcutil.AddressTaproot ,
100
- int64 , error ) {
151
+ // existing one. It now sends a request to the manager's Run loop which
152
+ // executes the actual address creation logic.
153
+ func (m * Manager ) NewAddress (ctx context.Context ) (* Parameters , error ) {
154
+ respChan := make (chan response , 1 )
155
+ req := request {
156
+ ctx : ctx ,
157
+ respChan : respChan ,
158
+ }
159
+
160
+ // Send the new address request to the manager run loop.
161
+ select {
162
+ case m .addrRequest <- req :
101
163
164
+ case <- ctx .Done ():
165
+ return nil , ctx .Err ()
166
+ }
167
+
168
+ // Wait for the response from the manager run loop.
169
+ select {
170
+ case resp := <- respChan :
171
+ return resp .parameters , resp .err
172
+
173
+ case <- ctx .Done ():
174
+ return nil , ctx .Err ()
175
+ }
176
+ }
177
+
178
+ // newAddress contains the body of the former NewAddress method and performs the
179
+ // actual address creation/lookup according to the requested type.
180
+ func (m * Manager ) newAddress (ctx context.Context ) (* Parameters , error ) {
102
181
// If there's already a static address in the database, we can return
103
182
// it.
104
183
m .Lock ()
105
184
addresses , err := m .cfg .Store .GetAllStaticAddresses (ctx )
106
185
if err != nil {
107
186
m .Unlock ()
108
187
109
- return nil , 0 , err
188
+ return nil , err
110
189
}
111
190
if len (addresses ) > 0 {
112
- clientPubKey := addresses [0 ].ClientPubkey
113
- serverPubKey := addresses [0 ].ServerPubkey
114
- expiry := int64 (addresses [0 ].Expiry )
115
-
116
- defer m .Unlock ()
117
-
118
- address , err := m .GetTaprootAddress (
119
- clientPubKey , serverPubKey , expiry ,
120
- )
121
- if err != nil {
122
- return nil , 0 , err
123
- }
191
+ m .Unlock ()
124
192
125
- return address , expiry , nil
193
+ return addresses [ 0 ] , nil
126
194
}
127
195
m .Unlock ()
128
196
129
197
// We are fetching a new L402 token from the server. There is one static
130
198
// address per L402 token allowed.
131
199
err = m .cfg .FetchL402 (ctx )
132
200
if err != nil {
133
- return nil , 0 , err
201
+ return nil , err
134
202
}
135
203
136
204
clientPubKey , err := m .cfg .WalletKit .DeriveNextKey (
137
205
ctx , swap .StaticAddressKeyFamily ,
138
206
)
139
207
if err != nil {
140
- return nil , 0 , err
208
+ return nil , err
141
209
}
142
210
143
211
// Send our clientPubKey to the server and wait for the server to
@@ -150,27 +218,27 @@ func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot,
150
218
},
151
219
)
152
220
if err != nil {
153
- return nil , 0 , err
221
+ return nil , err
154
222
}
155
223
156
224
serverParams := resp .GetParams ()
157
225
158
226
serverPubKey , err := btcec .ParsePubKey (serverParams .ServerKey )
159
227
if err != nil {
160
- return nil , 0 , err
228
+ return nil , err
161
229
}
162
230
163
231
staticAddress , err := script .NewStaticAddress (
164
232
input .MuSig2Version100RC2 , int64 (serverParams .Expiry ),
165
233
clientPubKey .PubKey , serverPubKey ,
166
234
)
167
235
if err != nil {
168
- return nil , 0 , err
236
+ return nil , err
169
237
}
170
238
171
239
pkScript , err := staticAddress .StaticAddressScript ()
172
240
if err != nil {
173
- return nil , 0 , err
241
+ return nil , err
174
242
}
175
243
176
244
// Create the static address from the parameters the server provided and
@@ -191,7 +259,7 @@ func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot,
191
259
}
192
260
err = m .cfg .Store .CreateStaticAddress (ctx , addrParams )
193
261
if err != nil {
194
- return nil , 0 , err
262
+ return nil , err
195
263
}
196
264
197
265
// Import the static address tapscript into our lnd wallet, so we can
@@ -201,20 +269,13 @@ func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot,
201
269
)
202
270
addr , err := m .cfg .WalletKit .ImportTaprootScript (ctx , tapScript )
203
271
if err != nil {
204
- return nil , 0 , err
272
+ return nil , err
205
273
}
206
274
207
275
log .Infof ("Imported static address taproot script to lnd wallet: %v" ,
208
276
addr )
209
277
210
- address , err := m .GetTaprootAddress (
211
- clientPubKey .PubKey , serverPubKey , int64 (serverParams .Expiry ),
212
- )
213
- if err != nil {
214
- return nil , 0 , err
215
- }
216
-
217
- return address , int64 (serverParams .Expiry ), nil
278
+ return addrParams , nil
218
279
}
219
280
220
281
// GetTaprootAddress returns a taproot address for the given client and server
0 commit comments