Skip to content

Commit f75f351

Browse files
committed
staticaddr: serialize address creation with a channel
1 parent 5b3fb0a commit f75f351

3 files changed

Lines changed: 114 additions & 41 deletions

File tree

loopd/swapclient_server.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,14 +1632,21 @@ func (s *swapClientServer) NewStaticAddress(ctx context.Context,
16321632
_ *looprpc.NewStaticAddressRequest) (
16331633
*looprpc.NewStaticAddressResponse, error) {
16341634

1635-
staticAddress, expiry, err := s.staticAddressManager.NewAddress(ctx)
1635+
params, err := s.staticAddressManager.NewAddress(ctx)
1636+
if err != nil {
1637+
return nil, err
1638+
}
1639+
1640+
address, err := s.staticAddressManager.GetTaprootAddress(
1641+
params.ClientPubkey, params.ServerPubkey, int64(params.Expiry),
1642+
)
16361643
if err != nil {
16371644
return nil, err
16381645
}
16391646

16401647
return &looprpc.NewStaticAddressResponse{
1641-
Address: staticAddress.String(),
1642-
Expiry: uint32(expiry),
1648+
Address: address.String(),
1649+
Expiry: params.Expiry,
16431650
}, nil
16441651
}
16451652

staticaddr/address/manager.go

Lines changed: 96 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,21 @@ type Manager struct {
5454
cfg *ManagerConfig
5555

5656
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
5772
}
5873

5974
// NewManager creates a new address manager.
@@ -64,14 +79,48 @@ func NewManager(cfg *ManagerConfig, currentHeight int32) (*Manager, error) {
6479
}
6580

6681
m := &Manager{
67-
cfg: cfg,
82+
cfg: cfg,
83+
addrRequest: make(chan request),
6884
}
6985
m.currentHeight.Store(currentHeight)
7086

7187
return m, nil
7288
}
7389

74-
// Run runs the address manager.
90+
// addrWorker is a worker that handles address creation requests. It calls
91+
// m.newAddress which blocks on server I/O and returns the address and expiry.
92+
func (m *Manager) addrWorker(ctx context.Context) {
93+
for {
94+
select {
95+
case req := <-m.addrRequest:
96+
m.handleAddrRequest(ctx, req)
97+
98+
case <-ctx.Done():
99+
return
100+
}
101+
}
102+
}
103+
104+
// handleAddrRequest is responsible for processing a single address request.
105+
func (m *Manager) handleAddrRequest(managerCtx context.Context, req request) {
106+
addrParams, err := m.newAddress(req.ctx)
107+
108+
resp := response{
109+
parameters: addrParams,
110+
err: err,
111+
}
112+
113+
select {
114+
case req.respChan <- resp:
115+
116+
case <-req.ctx.Done():
117+
118+
case <-managerCtx.Done():
119+
}
120+
}
121+
122+
// Run runs the address manager. It keeps track of the current block height and
123+
// creates new static addresses as needed.
75124
func (m *Manager) Run(ctx context.Context, initChan chan struct{}) error {
76125
newBlockChan, newBlockErrChan, err :=
77126
m.cfg.ChainNotifier.RegisterBlockEpochNtfn(ctx)
@@ -80,6 +129,10 @@ func (m *Manager) Run(ctx context.Context, initChan chan struct{}) error {
80129
return err
81130
}
82131

132+
// The address worker offloads the address creation with the server to a
133+
// separate go routine.
134+
go m.addrWorker(ctx)
135+
83136
// Communicate to the caller that the address manager has completed its
84137
// initialization.
85138
close(initChan)
@@ -100,49 +153,64 @@ func (m *Manager) Run(ctx context.Context, initChan chan struct{}) error {
100153
}
101154

102155
// NewAddress creates a new static address with the server or returns an
103-
// existing one.
104-
func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot,
105-
int64, error) {
156+
// existing one. It now sends a request to the manager's Run loop which
157+
// executes the actual address creation logic.
158+
func (m *Manager) NewAddress(ctx context.Context) (*Parameters, error) {
159+
respChan := make(chan response, 1)
160+
req := request{
161+
ctx: ctx,
162+
respChan: respChan,
163+
}
164+
165+
// Send the new address request to the manager run loop.
166+
select {
167+
case m.addrRequest <- req:
106168

169+
case <-ctx.Done():
170+
return nil, ctx.Err()
171+
}
172+
173+
// Wait for the response from the manager run loop.
174+
select {
175+
case resp := <-respChan:
176+
return resp.parameters, resp.err
177+
178+
case <-ctx.Done():
179+
return nil, ctx.Err()
180+
}
181+
}
182+
183+
// newAddress contains the body of the former NewAddress method and performs the
184+
// actual address creation/lookup according to the requested type.
185+
func (m *Manager) newAddress(ctx context.Context) (*Parameters, error) {
107186
// If there's already a static address in the database, we can return
108187
// it.
109188
m.Lock()
110189
addresses, err := m.cfg.Store.GetAllStaticAddresses(ctx)
111190
if err != nil {
112191
m.Unlock()
113192

114-
return nil, 0, err
193+
return nil, err
115194
}
116195
if len(addresses) > 0 {
117-
clientPubKey := addresses[0].ClientPubkey
118-
serverPubKey := addresses[0].ServerPubkey
119-
expiry := int64(addresses[0].Expiry)
120-
121-
defer m.Unlock()
122-
123-
address, err := m.GetTaprootAddress(
124-
clientPubKey, serverPubKey, expiry,
125-
)
126-
if err != nil {
127-
return nil, 0, err
128-
}
196+
m.Unlock()
129197

130-
return address, expiry, nil
198+
return addresses[0], nil
131199
}
132200
m.Unlock()
133201

134202
// We are fetching a new L402 token from the server. There is one static
135203
// address per L402 token allowed.
136204
err = m.cfg.FetchL402(ctx)
137205
if err != nil {
138-
return nil, 0, err
206+
return nil, err
139207
}
140208

141209
clientPubKey, err := m.cfg.WalletKit.DeriveNextKey(
142210
ctx, swap.StaticAddressKeyFamily,
143211
)
144212
if err != nil {
145-
return nil, 0, err
213+
return nil, err
146214
}
147215

148216
// Send our clientPubKey to the server and wait for the server to
@@ -155,27 +223,27 @@ func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot,
155223
},
156224
)
157225
if err != nil {
158-
return nil, 0, err
226+
return nil, err
159227
}
160228

161229
serverParams := resp.GetParams()
162230

163231
serverPubKey, err := btcec.ParsePubKey(serverParams.ServerKey)
164232
if err != nil {
165-
return nil, 0, err
233+
return nil, err
166234
}
167235

168236
staticAddress, err := script.NewStaticAddress(
169237
input.MuSig2Version100RC2, int64(serverParams.Expiry),
170238
clientPubKey.PubKey, serverPubKey,
171239
)
172240
if err != nil {
173-
return nil, 0, err
241+
return nil, err
174242
}
175243

176244
pkScript, err := staticAddress.StaticAddressScript()
177245
if err != nil {
178-
return nil, 0, err
246+
return nil, err
179247
}
180248

181249
// Create the static address from the parameters the server provided and
@@ -196,7 +264,7 @@ func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot,
196264
}
197265
err = m.cfg.Store.CreateStaticAddress(ctx, addrParams)
198266
if err != nil {
199-
return nil, 0, err
267+
return nil, err
200268
}
201269

202270
// Import the static address tapscript into our lnd wallet, so we can
@@ -206,20 +274,13 @@ func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot,
206274
)
207275
addr, err := m.cfg.WalletKit.ImportTaprootScript(ctx, tapScript)
208276
if err != nil {
209-
return nil, 0, err
277+
return nil, err
210278
}
211279

212280
log.Infof("Imported static address taproot script to lnd wallet: %v",
213281
addr)
214282

215-
address, err := m.GetTaprootAddress(
216-
clientPubKey.PubKey, serverPubKey, int64(serverParams.Expiry),
217-
)
218-
if err != nil {
219-
return nil, 0, err
220-
}
221-
222-
return address, int64(serverParams.Expiry), nil
283+
return addrParams, nil
223284
}
224285

225286
// GetTaprootAddress returns a taproot address for the given client and server

staticaddr/address/manager_test.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,19 @@ func TestManager(t *testing.T) {
118118
require.NoError(t, err)
119119

120120
// Create a new static address.
121-
taprootAddress, expiry, err := testContext.manager.NewAddress(ctxb)
121+
params, err := testContext.manager.NewAddress(ctxb)
122+
require.NoError(t, err)
123+
124+
address, err := testContext.manager.GetTaprootAddress(
125+
params.ClientPubkey, params.ServerPubkey, int64(params.Expiry),
126+
)
122127
require.NoError(t, err)
123128

124129
// The addresses have to match.
125-
require.Equal(t, expectedAddress.String(), taprootAddress.String())
130+
require.Equal(t, expectedAddress.String(), address.String())
126131

127132
// The expiry has to match.
128-
require.EqualValues(t, defaultExpiry, expiry)
133+
require.EqualValues(t, defaultExpiry, params.Expiry)
129134
}
130135

131136
// GenerateExpectedTaprootAddress generates the expected taproot address that

0 commit comments

Comments
 (0)