Skip to content

Commit 1732892

Browse files
claudeSertug17
authored andcommitted
fix(aggregator): guard nil subscription in SubscribeToNewTasksV3 error goroutine
When the primary RPC WebSocket subscription fails on startup but the fallback succeeds, the error-handling goroutine called sub.Err() on a nil event.Subscription interface, causing an immediate nil pointer dereference panic. Introduce nilSafeErrCh() which returns a never-sending channel when the subscription is nil, so the select statement in the goroutine degrades gracefully instead of panicking. Resubscription after a recovered error now also updates the local channel variable (subErrCh / subFallbackErrCh) so the fix stays effective throughout the lifetime of the goroutine. Fixes #2293
1 parent ca40ffa commit 1732892

1 file changed

Lines changed: 21 additions & 2 deletions

File tree

‎core/chainio/avs_subscriber.go‎

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,22 +120,31 @@ func (s *AvsSubscriber) SubscribeToNewTasksV3(newTaskCreatedChan chan *servicema
120120
s.logger.Info("Starting error handling goroutine")
121121
var errMain, errFallback error
122122
var auxSub, auxSubFallback event.Subscription
123+
124+
// Guard against nil subscriptions: if a subscription failed on startup,
125+
// replace its Err() channel with a never-sending channel so the select
126+
// below never blocks on a nil interface (which would panic).
127+
subErrCh := nilSafeErrCh(sub)
128+
subFallbackErrCh := nilSafeErrCh(subFallback)
129+
123130
for errMain == nil || errFallback == nil { //while one is active
124131
select {
125-
case err := <-sub.Err():
132+
case err := <-subErrCh:
126133
s.logger.Warn("Error in new task subscription of main connection", "err", err)
127134

128135
auxSub, errMain = SubscribeToNewTasksV3Retryable(&bind.WatchOpts{}, s.AvsContractBindings.ServiceManager, internalChannel, nil, retry.NetworkRetryParams())
129136
if errMain == nil {
130137
sub = auxSub // update the subscription only if it was successful
138+
subErrCh = nilSafeErrCh(sub)
131139
s.logger.Info("Resubscribed to fallback new task subscription")
132140
}
133-
case err := <-subFallback.Err():
141+
case err := <-subFallbackErrCh:
134142
s.logger.Warn("Error in new task subscription of fallback connection", "err", err)
135143

136144
auxSubFallback, errFallback = SubscribeToNewTasksV3Retryable(&bind.WatchOpts{}, s.AvsContractBindings.ServiceManagerFallback, internalChannel, nil, retry.NetworkRetryParams())
137145
if errFallback == nil {
138146
subFallback = auxSubFallback // update the subscription only if it was successful
147+
subFallbackErrCh = nilSafeErrCh(subFallback)
139148
s.logger.Info("Resubscribed to fallback new task subscription")
140149
}
141150
}
@@ -221,6 +230,16 @@ func (s *AvsSubscriber) getLatestNotRespondedTaskFromEthereumV3() (*servicemanag
221230
return lastLog, nil
222231
}
223232

233+
// nilSafeErrCh returns sub.Err() if sub is non-nil, otherwise a channel that
234+
// never sends. This prevents a nil-interface method call panic in the
235+
// error-handling goroutine when one of the two subscriptions failed on startup.
236+
func nilSafeErrCh(sub event.Subscription) <-chan error {
237+
if sub == nil {
238+
return make(chan error) // never sends; effectively disables this case
239+
}
240+
return sub.Err()
241+
}
242+
224243
func (s *AvsSubscriber) WaitForOneBlock(startBlock uint64) error {
225244
currentBlock, err := s.BlockNumberRetryable(context.Background(), retry.NetworkRetryParams())
226245
if err != nil {

0 commit comments

Comments
 (0)