@@ -54,19 +54,91 @@ 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.
6076func 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+ // If processing this request panics, we want to recover to process
103+ // successive requests after we returned an error to the caller.
104+ defer func () {
105+ if r := recover (); r != nil {
106+ var err error
107+ if e , ok := r .(error ); ok {
108+ err = e
109+ } else {
110+ err = fmt .Errorf ("addrWorker panic: %v" , r )
111+ }
112+
113+ select {
114+ case req .respChan <- response {err : err }:
115+
116+ case <- req .ctx .Done ():
117+
118+ case <- managerCtx .Done ():
119+ }
120+ }
121+ }()
122+
123+ addr , expiry , e := m .newAddress (req .ctx )
124+
125+ resp := response {
126+ addr : addr ,
127+ expiry : expiry ,
128+ err : e ,
129+ }
130+
131+ select {
132+ case req .respChan <- resp :
133+
134+ case <- req .ctx .Done ():
135+
136+ case <- managerCtx .Done ():
137+ }
138+ }
139+
140+ // Run runs the address manager. It keeps track of the current block height and
141+ // creates new static addresses as needed.
70142func (m * Manager ) Run (ctx context.Context , initChan chan struct {}) error {
71143 newBlockChan , newBlockErrChan , err :=
72144 m .cfg .ChainNotifier .RegisterBlockEpochNtfn (ctx )
@@ -75,6 +147,10 @@ func (m *Manager) Run(ctx context.Context, initChan chan struct{}) error {
75147 return err
76148 }
77149
150+ // The address worker offloads the address creation with the server to a
151+ // separate go routine.
152+ go m .addrWorker (ctx )
153+
78154 // Communicate to the caller that the address manager has completed its
79155 // initialization.
80156 close (initChan )
@@ -95,10 +171,40 @@ func (m *Manager) Run(ctx context.Context, initChan chan struct{}) error {
95171}
96172
97173// NewAddress creates a new static address with the server or returns an
98- // existing one.
174+ // existing one. It now sends a request to the manager's Run loop which
175+ // executes the actual address creation logic.
99176func (m * Manager ) NewAddress (ctx context.Context ) (* btcutil.AddressTaproot ,
100177 int64 , error ) {
101178
179+ respChan := make (chan response , 1 )
180+ req := request {
181+ ctx : ctx ,
182+ respChan : respChan ,
183+ }
184+
185+ // Send the new address request to the manager run loop.
186+ select {
187+ case m .addrRequest <- req :
188+
189+ case <- ctx .Done ():
190+ return nil , 0 , ctx .Err ()
191+ }
192+
193+ // Wait for the response from the manager run loop.
194+ select {
195+ case resp := <- respChan :
196+ return resp .addr , resp .expiry , resp .err
197+
198+ case <- ctx .Done ():
199+ return nil , 0 , ctx .Err ()
200+ }
201+ }
202+
203+ // newAddress contains the body of the former NewAddress method and performs the
204+ // actual address creation/lookup according to the requested type.
205+ func (m * Manager ) newAddress (ctx context.Context ) (* btcutil.AddressTaproot ,
206+ int64 , error ) {
207+
102208 // If there's already a static address in the database, we can return
103209 // it.
104210 m .Lock ()
0 commit comments