Skip to content

Commit 0f23670

Browse files
committed
fix: switch to next client only if the connection is successful
1 parent 7fa4863 commit 0f23670

File tree

2 files changed

+53
-16
lines changed

2 files changed

+53
-16
lines changed

RPC/rpc.go

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,17 @@ import (
66
"errors"
77
"fmt"
88
"github.com/ethereum/go-ethereum/ethclient"
9+
"github.com/ethereum/go-ethereum/log"
10+
"github.com/sirupsen/logrus"
911
"os"
1012
"path/filepath"
11-
"razor/logger"
1213
"razor/path"
1314
"sort"
1415
"strings"
1516
"sync"
1617
"time"
1718
)
1819

19-
var log = logger.NewLogger()
20-
2120
func (m *RPCManager) calculateMetrics(endpoint *RPCEndpoint) error {
2221
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
2322
defer cancel()
@@ -39,7 +38,7 @@ func (m *RPCManager) calculateMetrics(endpoint *RPCEndpoint) error {
3938

4039
endpoint.BlockNumber = blockNumber
4140
endpoint.Latency = latency
42-
endpoint.Client = client // Store the client for future use
41+
endpoint.Client = client
4342

4443
return nil
4544
}
@@ -51,14 +50,14 @@ func (m *RPCManager) updateAndSortEndpoints() error {
5150
}
5251

5352
var wg sync.WaitGroup
54-
log.Debug("Starting concurrent metrics calculation for all endpoints...")
53+
logrus.Debug("Starting concurrent metrics calculation for all endpoints...")
5554

5655
for _, endpoint := range m.Endpoints {
5756
wg.Add(1)
5857
go func(ep *RPCEndpoint) {
5958
defer wg.Done()
6059
if err := m.calculateMetrics(ep); err != nil {
61-
log.Printf("Error calculating metrics for endpoint %s: %v", ep.URL, err)
60+
logrus.Errorf("Error calculating metrics for endpoint %s: %v", ep.URL, err)
6261
}
6362
}(endpoint)
6463
}
@@ -76,8 +75,12 @@ func (m *RPCManager) updateAndSortEndpoints() error {
7675
return m.Endpoints[i].BlockNumber > m.Endpoints[j].BlockNumber
7776
})
7877

79-
// Update the best RPC client after sorting
78+
// Update the best RPC client and endpoint after sorting
8079
m.BestRPCClient = m.Endpoints[0].Client
80+
m.BestEndpoint = m.Endpoints[0]
81+
82+
logrus.Infof("Best RPC endpoint updated: %s (BlockNumber: %d, Latency: %.2f)",
83+
m.BestEndpoint.URL, m.BestEndpoint.BlockNumber, m.BestEndpoint.Latency)
8184

8285
return nil
8386
}
@@ -87,7 +90,7 @@ func (m *RPCManager) RefreshEndpoints() error {
8790
if err := m.updateAndSortEndpoints(); err != nil {
8891
return fmt.Errorf("failed to refresh endpoints: %w", err)
8992
}
90-
log.Infof("Endpoints refreshed successfully")
93+
logrus.Infof("Endpoints refreshed successfully")
9194
return nil
9295
}
9396

@@ -122,7 +125,7 @@ func InitializeRPCManager(provider string) (*RPCManager, error) {
122125

123126
// If the provider is not found, add it to the list
124127
if !providerFound && provider != "" {
125-
log.Infof("Adding user-provided endpoint: %s", provider)
128+
logrus.Infof("Adding user-provided endpoint: %s", provider)
126129
rpcEndpointsList = append(rpcEndpointsList, provider)
127130
}
128131

@@ -154,14 +157,27 @@ func (m *RPCManager) GetBestRPCClient() (*ethclient.Client, error) {
154157
return m.BestRPCClient, nil
155158
}
156159

160+
// GetBestEndpointURL returns the URL of the best endpoint
161+
func (m *RPCManager) GetBestEndpointURL() (string, error) {
162+
m.mutex.RLock()
163+
defer m.mutex.RUnlock()
164+
165+
if m.BestEndpoint == nil {
166+
return "", fmt.Errorf("no best endpoint available")
167+
}
168+
return m.BestEndpoint.URL, nil
169+
}
170+
157171
// SwitchToNextBestRPCClient switches to the next best available client after the current best client.
172+
// If no valid next best client is found, it retains the current best client.
158173
func (m *RPCManager) SwitchToNextBestRPCClient() error {
159174
m.mutex.Lock()
160175
defer m.mutex.Unlock()
161176

162177
// If there are fewer than 2 endpoints, there are no alternate clients to switch to.
163178
if len(m.Endpoints) < 2 {
164-
return fmt.Errorf("no other RPC clients to switch to")
179+
logrus.Warn("No alternate RPC clients available. Retaining the current best client.")
180+
return nil
165181
}
166182

167183
// Find the index of the current best client
@@ -173,16 +189,36 @@ func (m *RPCManager) SwitchToNextBestRPCClient() error {
173189
}
174190
}
175191

176-
// If current client is not found (which is rare), return an error
192+
// If the current client is not found (which is rare), return an error
177193
if currentIndex == -1 {
178194
return fmt.Errorf("current best client not found in the list of endpoints")
179195
}
180196

181-
// Calculate the next index by wrapping around if necessary
182-
nextIndex := (currentIndex + 1) % len(m.Endpoints)
197+
// Iterate through the remaining endpoints to find a valid next best client
198+
for i := 1; i < len(m.Endpoints); i++ {
199+
nextIndex := (currentIndex + i) % len(m.Endpoints)
200+
nextEndpoint := m.Endpoints[nextIndex]
201+
202+
// Check if we can connect to the next endpoint
203+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
204+
defer cancel()
205+
206+
client, err := ethclient.DialContext(ctx, nextEndpoint.URL)
207+
if err != nil {
208+
logrus.Errorf("Failed to connect to RPC endpoint %s: %v", nextEndpoint.URL, err)
209+
continue
210+
}
211+
212+
// Successfully connected, update the best client and endpoint
213+
m.BestRPCClient = client
214+
m.BestEndpoint = nextEndpoint
215+
216+
logrus.Infof("Switched to the next best RPC endpoint: %s (BlockNumber: %d, Latency: %.2f)",
217+
m.BestEndpoint.URL, m.BestEndpoint.BlockNumber, m.BestEndpoint.Latency)
218+
return nil
219+
}
183220

184-
// Switch to the next client in the list
185-
m.BestRPCClient = m.Endpoints[nextIndex].Client
186-
log.Infof("Switched to the next best RPC client: %s", m.Endpoints[nextIndex].URL)
221+
// If no valid endpoint is found, retain the current best client
222+
logrus.Warn("No valid next-best RPC client found. Retaining the current best client.")
187223
return nil
188224
}

RPC/rpc_struct.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type RPCManager struct {
1717
Endpoints []*RPCEndpoint
1818
mutex sync.RWMutex
1919
BestRPCClient *ethclient.Client // Holds the current best RPC client
20+
BestEndpoint *RPCEndpoint // Holds the URL to current best RPC client
2021
}
2122

2223
type RPCParameters struct {

0 commit comments

Comments
 (0)