Skip to content

Commit 01b3143

Browse files
committed
staticaddr: serialize address creation with a channel
1 parent a1fb489 commit 01b3143

File tree

1 file changed

+74
-3
lines changed

1 file changed

+74
-3
lines changed

staticaddr/address/manager.go

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,56 @@ 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+
addr, expiry, err := m.newAddress(req.ctx)
93+
req.respChan <- response{
94+
addr: addr,
95+
expiry: expiry,
96+
err: err,
97+
}
98+
99+
case <-ctx.Done():
100+
return
101+
}
102+
}
103+
}
104+
105+
// Run runs the address manager. It keeps track of the current block height and
106+
// creates new static addresses as needed.
70107
func (m *Manager) Run(ctx context.Context, initChan chan struct{}) error {
71108
newBlockChan, newBlockErrChan, err :=
72109
m.cfg.ChainNotifier.RegisterBlockEpochNtfn(ctx)
@@ -75,6 +112,10 @@ func (m *Manager) Run(ctx context.Context, initChan chan struct{}) error {
75112
return err
76113
}
77114

115+
// The address worker offloads the I/O heavy address creation with the
116+
// server to a separate go routine.
117+
go m.addrWorker(ctx)
118+
78119
// Communicate to the caller that the address manager has completed its
79120
// initialization.
80121
close(initChan)
@@ -95,10 +136,40 @@ func (m *Manager) Run(ctx context.Context, initChan chan struct{}) error {
95136
}
96137

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

144+
respChan := make(chan response, 1)
145+
req := request{
146+
ctx: ctx,
147+
respChan: respChan,
148+
}
149+
150+
// Send the new address request to the manager run loop.
151+
select {
152+
case m.addrRequest <- req:
153+
154+
case <-ctx.Done():
155+
return nil, 0, ctx.Err()
156+
}
157+
158+
// Wait for the response from the manager run loop.
159+
select {
160+
case resp := <-respChan:
161+
return resp.addr, resp.expiry, resp.err
162+
163+
case <-ctx.Done():
164+
return nil, 0, ctx.Err()
165+
}
166+
}
167+
168+
// newAddress contains the body of the former NewAddress method and performs the
169+
// actual address creation/lookup according to the requested type.
170+
func (m *Manager) newAddress(ctx context.Context) (*btcutil.AddressTaproot,
171+
int64, error) {
172+
102173
// If there's already a static address in the database, we can return
103174
// it.
104175
m.Lock()

0 commit comments

Comments
 (0)