Skip to content

Commit b9b6287

Browse files
committed
staticaddr: serialize address creation with a channel
1 parent cef0fae commit b9b6287

File tree

1 file changed

+88
-3
lines changed

1 file changed

+88
-3
lines changed

staticaddr/address/manager.go

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,70 @@ 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+
addr *btcutil.AddressTaproot
71+
expiry int64
72+
err error
5773
}
5874

5975
// NewManager creates a new address manager.
6076
func NewManager(cfg *ManagerConfig, currentHeight int32) *Manager {
6177
m := &Manager{
62-
cfg: cfg,
78+
cfg: cfg,
79+
addrRequest: make(chan request),
6380
}
6481
m.currentHeight.Store(currentHeight)
6582

6683
return m
6784
}
6885

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

129+
// The address worker offloads the address creation with the server to a
130+
// separate go routine.
131+
go m.addrWorker(ctx)
132+
78133
// Communicate to the caller that the address manager has completed its
79134
// initialization.
80135
close(initChan)
@@ -95,10 +150,40 @@ func (m *Manager) Run(ctx context.Context, initChan chan struct{}) error {
95150
}
96151

97152
// NewAddress creates a new static address with the server or returns an
98-
// existing one.
153+
// existing one. It now sends a request to the manager's Run loop which
154+
// executes the actual address creation logic.
99155
func (m *Manager) NewAddress(ctx context.Context) (*btcutil.AddressTaproot,
100156
int64, error) {
101157

158+
respChan := make(chan response, 1)
159+
req := request{
160+
ctx: ctx,
161+
respChan: respChan,
162+
}
163+
164+
// Send the new address request to the manager run loop.
165+
select {
166+
case m.addrRequest <- req:
167+
168+
case <-ctx.Done():
169+
return nil, 0, ctx.Err()
170+
}
171+
172+
// Wait for the response from the manager run loop.
173+
select {
174+
case resp := <-respChan:
175+
return resp.addr, resp.expiry, resp.err
176+
177+
case <-ctx.Done():
178+
return nil, 0, ctx.Err()
179+
}
180+
}
181+
182+
// newAddress contains the body of the former NewAddress method and performs the
183+
// actual address creation/lookup according to the requested type.
184+
func (m *Manager) newAddress(ctx context.Context) (*btcutil.AddressTaproot,
185+
int64, error) {
186+
102187
// If there's already a static address in the database, we can return
103188
// it.
104189
m.Lock()

0 commit comments

Comments
 (0)