@@ -187,63 +187,108 @@ func (*environment) PrecommitEquivocation(
187187
188188// p2p network data for a round.
189189type BroadcastNetwork [M , N any ] struct {
190- receiver chan M
191- senders []chan M
192- history []M
193- routing bool
194- wg sync.WaitGroup
190+ receiver chan M
191+ stop chan struct {}
192+ mu sync.Mutex
193+ senders []chan M
194+ history []M
195+ routing bool
196+ stopped bool
197+ routeWG sync.WaitGroup
198+ forwarderWG sync.WaitGroup
195199}
196200
197201func NewBroadcastNetwork [M , N any ]() * BroadcastNetwork [M , N ] {
198202 bn := BroadcastNetwork [M , N ]{
199203 receiver : make (chan M , 10000 ),
204+ stop : make (chan struct {}),
200205 }
201206 return & bn
202207}
203208
204209func (bm * BroadcastNetwork [M , N ]) SendMessage (message M ) {
205- bm .receiver <- message
210+ select {
211+ case bm .receiver <- message :
212+ case <- bm .stop :
213+ }
206214}
207215
208216func (bm * BroadcastNetwork [M , N ]) AddNode (f func (N ) M , out chan N ) (in chan M ) {
209217 // buffer to 100 messages for now
210218 in = make (chan M , 10000 )
211219
220+ bm .mu .Lock ()
212221 // get history to the node.
213222 for _ , priorMessage := range bm .history {
214223 in <- priorMessage
215224 }
216-
217225 bm .senders = append (bm .senders , in )
218-
219- if ! bm . routing {
226+ startRoute := ! bm . routing
227+ if startRoute {
220228 bm .routing = true
221- bm .wg .Add (1 )
229+ bm .routeWG .Add (1 )
230+ }
231+ bm .mu .Unlock ()
232+
233+ if startRoute {
222234 go bm .route ()
223235 }
224236
237+ bm .forwarderWG .Add (1 )
225238 go func () {
226- for n := range out {
227- bm .receiver <- f (n )
239+ defer bm .forwarderWG .Done ()
240+ for {
241+ select {
242+ case n , ok := <- out :
243+ if ! ok {
244+ return
245+ }
246+ select {
247+ case bm .receiver <- f (n ):
248+ case <- bm .stop :
249+ return
250+ }
251+ case <- bm .stop :
252+ return
253+ }
228254 }
229255 }()
230256 return in
231257}
232258
233259func (bm * BroadcastNetwork [M , N ]) route () {
234- defer bm .wg .Done ()
260+ defer bm .routeWG .Done ()
235261 for msg := range bm .receiver {
262+ bm .mu .Lock ()
236263 bm .history = append (bm .history , msg )
237- for _ , sender := range bm .senders {
264+ senders := append ([]chan M (nil ), bm .senders ... )
265+ bm .mu .Unlock ()
266+ for _ , sender := range senders {
238267 sender <- msg
239268 }
240269 }
241270}
242271
243272func (bm * BroadcastNetwork [M , N ]) Stop () {
273+ bm .mu .Lock ()
274+ if bm .stopped {
275+ bm .mu .Unlock ()
276+ return
277+ }
278+ bm .stopped = true
279+ close (bm .stop )
280+ bm .mu .Unlock ()
281+
282+ // Order matters: drain forwarders first so they stop sending into receiver,
283+ // then close receiver so route can exit, then close per-node senders.
284+ bm .forwarderWG .Wait ()
244285 close (bm .receiver )
245- bm .wg .Wait ()
246- for _ , sender := range bm .senders {
286+ bm .routeWG .Wait ()
287+ bm .mu .Lock ()
288+ senders := bm .senders
289+ bm .senders = nil
290+ bm .mu .Unlock ()
291+ for _ , sender := range senders {
247292 close (sender )
248293 }
249294}
0 commit comments