diff --git a/api/default_networks.go b/api/default_networks.go index 32cd654f153..984efb76ae4 100644 --- a/api/default_networks.go +++ b/api/default_networks.go @@ -2,10 +2,9 @@ package api import ( "fmt" - "strings" - "github.com/ethereum/go-ethereum/common" "github.com/status-im/status-go/params" + "github.com/status-im/status-go/params/networkhelper" "github.com/status-im/status-go/protocol/requests" ) @@ -22,15 +21,29 @@ const ( var ganacheTokenAddress = common.HexToAddress("0x8571Ddc46b10d31EF963aF49b6C7799Ea7eff818") +func proxyUrl(stageName, provider, chainName, networkName string) string { + return fmt.Sprintf("https://%s.api.status.im/%s/%s/%s/", stageName, provider, chainName, networkName) +} + func mainnet(stageName string) params.Network { + chainID := mainnetChainID + chainName := "ethereum" + networkName := "mainnet" + + rpcProviders := []params.RpcProvider{ + // Proxy providers + *params.NewProxyProvider(chainID, "proxy-nodefleet", proxyUrl(stageName, "nodefleet", chainName, networkName), false), + *params.NewProxyProvider(chainID, "proxy-infura", proxyUrl(stageName, "infura", chainName, networkName), false), + *params.NewProxyProvider(chainID, "proxy-grove", proxyUrl(stageName, "grove", chainName, networkName), false), + // Direct providers + *params.NewDirectProvider(chainID, "direct-infura", "https://mainnet.infura.io/v3/", true), + *params.NewDirectProvider(chainID, "direct-grove", "https://eth-archival.rpc.grove.city/v1/", false), + } + return params.Network{ - ChainID: mainnetChainID, + ChainID: chainID, ChainName: "Mainnet", - DefaultRPCURL: fmt.Sprintf("https://%s.api.status.im/nodefleet/ethereum/mainnet/", stageName), - DefaultFallbackURL: fmt.Sprintf("https://%s.api.status.im/infura/ethereum/mainnet/", stageName), - DefaultFallbackURL2: fmt.Sprintf("https://%s.api.status.im/grove/ethereum/mainnet/", stageName), - RPCURL: "https://mainnet.infura.io/v3/", - FallbackURL: "https://eth-archival.rpc.grove.city/v1/", + RpcProviders: rpcProviders, BlockExplorerURL: "https://etherscan.io/", IconURL: "network/Network=Ethereum", ChainColor: "#627EEA", @@ -44,16 +57,25 @@ func mainnet(stageName string) params.Network { RelatedChainID: sepoliaChainID, } } - func sepolia(stageName string) params.Network { + chainID := sepoliaChainID + chainName := "ethereum" + networkName := "sepolia" + + rpcProviders := []params.RpcProvider{ + // Proxy providers + *params.NewProxyProvider(chainID, "proxy-nodefleet", proxyUrl(stageName, "nodefleet", chainName, networkName), false), + *params.NewProxyProvider(chainID, "proxy-infura", proxyUrl(stageName, "infura", chainName, networkName), false), + *params.NewProxyProvider(chainID, "proxy-grove", proxyUrl(stageName, "grove", chainName, networkName), true), + // Direct providers + *params.NewDirectProvider(chainID, "direct-infura", "https://sepolia.infura.io/v3/", true), + *params.NewDirectProvider(chainID, "direct-grove", "https://sepolia-archival.rpc.grove.city/v1/", false), + } + return params.Network{ - ChainID: sepoliaChainID, - ChainName: "Mainnet", - DefaultRPCURL: fmt.Sprintf("https://%s.api.status.im/nodefleet/ethereum/sepolia/", stageName), - DefaultFallbackURL: fmt.Sprintf("https://%s.api.status.im/infura/ethereum/sepolia/", stageName), - DefaultFallbackURL2: fmt.Sprintf("https://%s.api.status.im/grove/ethereum/sepolia/", stageName), - RPCURL: "https://sepolia.infura.io/v3/", - FallbackURL: "https://sepolia-archival.rpc.grove.city/v1/", + ChainID: chainID, + ChainName: "Sepolia", + RpcProviders: rpcProviders, BlockExplorerURL: "https://sepolia.etherscan.io/", IconURL: "network/Network=Ethereum", ChainColor: "#627EEA", @@ -67,16 +89,25 @@ func sepolia(stageName string) params.Network { RelatedChainID: mainnetChainID, } } - func optimism(stageName string) params.Network { + chainID := optimismChainID + chainName := "optimism" + networkName := "mainnet" + + rpcProviders := []params.RpcProvider{ + // Proxy providers + *params.NewProxyProvider(chainID, "proxy-nodefleet", proxyUrl(stageName, "nodefleet", chainName, networkName), false), + *params.NewProxyProvider(chainID, "proxy-infura", proxyUrl(stageName, "infura", chainName, networkName), false), + *params.NewProxyProvider(chainID, "proxy-grove", proxyUrl(stageName, "grove", chainName, networkName), true), + // Direct providers + *params.NewDirectProvider(chainID, "direct-infura", "https://optimism-mainnet.infura.io/v3/", true), + *params.NewDirectProvider(chainID, "direct-grove", "https://optimism-archival.rpc.grove.city/v1/", false), + } + return params.Network{ - ChainID: optimismChainID, + ChainID: chainID, ChainName: "Optimism", - DefaultRPCURL: fmt.Sprintf("https://%s.api.status.im/nodefleet/optimism/mainnet/", stageName), - DefaultFallbackURL: fmt.Sprintf("https://%s.api.status.im/infura/optimism/mainnet/", stageName), - DefaultFallbackURL2: fmt.Sprintf("https://%s.api.status.im/grove/optimism/mainnet/", stageName), - RPCURL: "https://optimism-mainnet.infura.io/v3/", - FallbackURL: "https://optimism-archival.rpc.grove.city/v1/", + RpcProviders: rpcProviders, BlockExplorerURL: "https://optimistic.etherscan.io", IconURL: "network/Network=Optimism", ChainColor: "#E90101", @@ -90,16 +121,25 @@ func optimism(stageName string) params.Network { RelatedChainID: optimismSepoliaChainID, } } - func optimismSepolia(stageName string) params.Network { + chainID := optimismSepoliaChainID + chainName := "optimism" + networkName := "sepolia" + + rpcProviders := []params.RpcProvider{ + // Proxy providers + *params.NewProxyProvider(chainID, "proxy-nodefleet", proxyUrl(stageName, "nodefleet", chainName, networkName), false), + *params.NewProxyProvider(chainID, "proxy-infura", proxyUrl(stageName, "infura", chainName, networkName), false), + *params.NewProxyProvider(chainID, "proxy-grove", proxyUrl(stageName, "grove", chainName, networkName), true), + // Direct providers + *params.NewDirectProvider(chainID, "direct-infura", "https://optimism-sepolia.infura.io/v3/", true), + *params.NewDirectProvider(chainID, "direct-grove", "https://optimism-sepolia-archival.rpc.grove.city/v1/", false), + } + return params.Network{ - ChainID: optimismSepoliaChainID, + ChainID: chainID, ChainName: "Optimism", - DefaultRPCURL: fmt.Sprintf("https://%s.api.status.im/nodefleet/optimism/sepolia/", stageName), - DefaultFallbackURL: fmt.Sprintf("https://%s.api.status.im/infura/optimism/sepolia/", stageName), - DefaultFallbackURL2: fmt.Sprintf("https://%s.api.status.im/grove/optimism/sepolia/", stageName), - RPCURL: "https://optimism-sepolia.infura.io/v3/", - FallbackURL: "https://optimism-sepolia-archival.rpc.grove.city/v1/", + RpcProviders: rpcProviders, BlockExplorerURL: "https://sepolia-optimism.etherscan.io/", IconURL: "network/Network=Optimism", ChainColor: "#E90101", @@ -113,16 +153,25 @@ func optimismSepolia(stageName string) params.Network { RelatedChainID: optimismChainID, } } - func arbitrum(stageName string) params.Network { + chainID := arbitrumChainID + chainName := "arbitrum" + networkName := "mainnet" + + rpcProviders := []params.RpcProvider{ + // Proxy providers + *params.NewProxyProvider(chainID, "proxy-nodefleet", proxyUrl(stageName, "nodefleet", chainName, networkName), false), + *params.NewProxyProvider(chainID, "proxy-infura", proxyUrl(stageName, "infura", chainName, networkName), false), + *params.NewProxyProvider(chainID, "proxy-grove", proxyUrl(stageName, "grove", chainName, networkName), true), + // Direct providers + *params.NewDirectProvider(chainID, "direct-infura", "https://arbitrum-mainnet.infura.io/v3/", true), + *params.NewDirectProvider(chainID, "direct-grove", "https://arbitrum-one.rpc.grove.city/v1/", false), + } + return params.Network{ - ChainID: arbitrumChainID, + ChainID: chainID, ChainName: "Arbitrum", - DefaultRPCURL: fmt.Sprintf("https://%s.api.status.im/nodefleet/arbitrum/mainnet/", stageName), - DefaultFallbackURL: fmt.Sprintf("https://%s.api.status.im/infura/arbitrum/mainnet/", stageName), - DefaultFallbackURL2: fmt.Sprintf("https://%s.api.status.im/grove/arbitrum/mainnet/", stageName), - RPCURL: "https://arbitrum-mainnet.infura.io/v3/", - FallbackURL: "https://arbitrum-one.rpc.grove.city/v1/", + RpcProviders: rpcProviders, BlockExplorerURL: "https://arbiscan.io/", IconURL: "network/Network=Arbitrum", ChainColor: "#51D0F0", @@ -136,16 +185,25 @@ func arbitrum(stageName string) params.Network { RelatedChainID: arbitrumSepoliaChainID, } } - func arbitrumSepolia(stageName string) params.Network { + chainID := arbitrumSepoliaChainID + chainName := "arbitrum" + networkName := "sepolia" + + rpcProviders := []params.RpcProvider{ + // Proxy providers + *params.NewProxyProvider(chainID, "proxy-nodefleet", proxyUrl(stageName, "nodefleet", chainName, networkName), false), + *params.NewProxyProvider(chainID, "proxy-infura", proxyUrl(stageName, "infura", chainName, networkName), false), + *params.NewProxyProvider(chainID, "proxy-grove", proxyUrl(stageName, "grove", chainName, networkName), true), + // Direct providers + *params.NewDirectProvider(chainID, "direct-infura", "https://arbitrum-sepolia.infura.io/v3/", true), + *params.NewDirectProvider(chainID, "direct-grove", "https://arbitrum-sepolia-archival.rpc.grove.city/v1/", false), + } + return params.Network{ - ChainID: arbitrumSepoliaChainID, + ChainID: chainID, ChainName: "Arbitrum", - DefaultRPCURL: fmt.Sprintf("https://%s.api.status.im/nodefleet/arbitrum/sepolia/", stageName), - DefaultFallbackURL: fmt.Sprintf("https://%s.api.status.im/infura/arbitrum/sepolia/", stageName), - DefaultFallbackURL2: fmt.Sprintf("https://%s.api.status.im/grove/arbitrum/sepolia/", stageName), - RPCURL: "https://arbitrum-sepolia.infura.io/v3/", - FallbackURL: "https://arbitrum-sepolia-archival.rpc.grove.city/v1/", + RpcProviders: rpcProviders, BlockExplorerURL: "https://sepolia-explorer.arbitrum.io/", IconURL: "network/Network=Arbitrum", ChainColor: "#51D0F0", @@ -177,44 +235,18 @@ var mainnetGanacheTokenOverrides = params.TokenOverride{ } func setRPCs(networks []params.Network, request *requests.WalletSecretsConfig) []params.Network { - - var networksWithRPC []params.Network - - const ( - infura = "infura.io/" - grove = "grove.city/" - ) - - appendToken := func(url string) string { - if strings.Contains(url, infura) && request.InfuraToken != "" { - return url + request.InfuraToken - } else if strings.Contains(url, grove) && request.PoktToken != "" { - return url + request.PoktToken - } - return url + authTokens := map[string]string{ + "infura.io": request.InfuraToken, + "grove.city": request.PoktToken, } - for _, n := range networks { - n.DefaultRPCURL = appendToken(n.DefaultRPCURL) - n.DefaultFallbackURL = appendToken(n.DefaultFallbackURL) - n.DefaultFallbackURL2 = appendToken(n.DefaultFallbackURL2) - n.RPCURL = appendToken(n.RPCURL) - n.FallbackURL = appendToken(n.FallbackURL) - - if request.GanacheURL != "" { - n.RPCURL = request.GanacheURL - n.FallbackURL = request.GanacheURL - if n.ChainID == mainnetChainID { - n.TokenOverrides = []params.TokenOverride{ - mainnetGanacheTokenOverrides, - } - } - } - - networksWithRPC = append(networksWithRPC, n) + updatedNetworks := networkhelper.OverrideDirectProvidersAuth(networks, authTokens) + + if request.GanacheURL != "" { + updatedNetworks = networkhelper.OverrideGanacheToken(updatedNetworks, request.GanacheURL, mainnetChainID, mainnetGanacheTokenOverrides) } - return networksWithRPC + return updatedNetworks } func BuildDefaultNetworks(walletSecretsConfig *requests.WalletSecretsConfig) []params.Network { diff --git a/node/get_status_node.go b/node/get_status_node.go index bc5b6ec25bb..90f5f1bfcf9 100644 --- a/node/get_status_node.go +++ b/node/get_status_node.go @@ -11,6 +11,8 @@ import ( "reflect" "sync" + "github.com/status-im/status-go/params/networkhelper" + "github.com/syndtr/goleveldb/leveldb" "go.uber.org/zap" @@ -336,25 +338,22 @@ func (n *StatusNode) setupRPCClient() (err error) { return } - // ProviderConfigs should be passed not in wallet secrets config on login + // Proxy AuthConfigs should be passed not in wallet secrets config on login // but some other way, as it's not wallet specific and should not be passed with login request // but currently there is no other way to pass it - providerConfigs := []params.ProviderConfig{ - { - Enabled: n.config.WalletConfig.StatusProxyEnabled, - Name: rpc.ProviderStatusProxy, - User: n.config.WalletConfig.StatusProxyBlockchainUser, - Password: n.config.WalletConfig.StatusProxyBlockchainPassword, - }, - } + // (maybe move to default_networks.go) + networks := networkhelper.OverrideEmbeddedProxyProviders( + n.config.Networks, + n.config.WalletConfig.StatusProxyEnabled, + n.config.WalletConfig.StatusProxyBlockchainUser, + n.config.WalletConfig.StatusProxyBlockchainPassword) config := rpc.ClientConfig{ Client: gethNodeClient, UpstreamChainID: n.config.NetworkID, - Networks: n.config.Networks, + Networks: networks, DB: n.appDB, WalletFeed: &n.walletFeed, - ProviderConfigs: providerConfigs, } n.rpcClient, err = rpc.NewClient(config) n.rpcClient.Start(context.Background()) diff --git a/params/config.go b/params/config.go index 821c7c547f0..b25a3ddfcfc 100644 --- a/params/config.go +++ b/params/config.go @@ -293,21 +293,6 @@ func NewLimits(min, max int) Limits { } } -type ProviderConfig struct { - // Enabled flag specifies whether feature is enabled - Enabled bool `validate:"required"` - - // To identify provider - Name string `validate:"required"` - - // URL sets the rpc upstream host address for communication with - // a non-local infura endpoint. - User string `json:",omitempty"` - Password string `json:",omitempty"` - APIKey string `json:"APIKey,omitempty"` - APIKeySecret string `json:"APIKeySecret,omitempty"` -} - // ---------- // NodeConfig // ---------- diff --git a/params/networkhelper/provider_utils.go b/params/networkhelper/provider_utils.go index 97f3d0b6ad2..a2cc6f38350 100644 --- a/params/networkhelper/provider_utils.go +++ b/params/networkhelper/provider_utils.go @@ -104,6 +104,7 @@ func OverrideEmbeddedProxyProviders(networks []params.Network, enabled bool, use for j, provider := range network.RpcProviders { if provider.Type == params.EmbeddedProxyProviderType { provider.Enabled = enabled + provider.AuthType = params.BasicAuth provider.AuthLogin = user provider.AuthPassword = password } @@ -143,6 +144,7 @@ func OverrideDirectProvidersAuth(networks []params.Network, authTokens map[strin } updatedNetwork.RpcProviders = updatedProviders + FillDeprecatedURLs(&updatedNetwork, updatedProviders) updatedNetworks[i] = updatedNetwork } return updatedNetworks @@ -182,3 +184,55 @@ func extractHost(providerURL string) (string, error) { } return parsedURL.Host, nil } + +// Deprecated: fillDeprecatedURLs populates the `original_rpc_url`, `original_fallback_url`, `rpc_url`, +// `fallback_url`, `defaultRpcUrl`, `defaultFallbackURL`, and `defaultFallbackURL2` fields. +// Keep for backwrad compatibility until it's fully integrated +func FillDeprecatedURLs(network *params.Network, providers []params.RpcProvider) { + var embeddedDirect []params.RpcProvider + var embeddedProxy []params.RpcProvider + var userProviders []params.RpcProvider + + // Categorize providers + for _, provider := range providers { + switch provider.Type { + case params.EmbeddedDirectProviderType: + embeddedDirect = append(embeddedDirect, provider) + case params.EmbeddedProxyProviderType: + embeddedProxy = append(embeddedProxy, provider) + case params.UserProviderType: + userProviders = append(userProviders, provider) + } + } + + // Set original_*_url fields based on EmbeddedDirectProviderType providers + if len(embeddedDirect) > 0 { + network.OriginalRPCURL = embeddedDirect[0].URL + if len(embeddedDirect) > 1 { + network.OriginalFallbackURL = embeddedDirect[1].URL + } + } + + // Set rpc_url and fallback_url based on User providers or EmbeddedDirectProviderType if no User providers exist + if len(userProviders) > 0 { + network.RPCURL = userProviders[0].URL + if len(userProviders) > 1 { + network.FallbackURL = userProviders[1].URL + } + } else { + // Default to EmbeddedDirectProviderType providers if no User providers exist + network.RPCURL = network.OriginalRPCURL + network.FallbackURL = network.OriginalFallbackURL + } + + // Set default_*_url fields based on EmbeddedProxyProviderType providers + if len(embeddedProxy) > 0 { + network.DefaultRPCURL = embeddedProxy[0].URL + if len(embeddedProxy) > 1 { + network.DefaultFallbackURL = embeddedProxy[1].URL + } + if len(embeddedProxy) > 2 { + network.DefaultFallbackURL2 = embeddedProxy[2].URL + } + } +} diff --git a/params/networkhelper/provider_utils_test.go b/params/networkhelper/provider_utils_test.go index f911c41c77c..40275d3cf96 100644 --- a/params/networkhelper/provider_utils_test.go +++ b/params/networkhelper/provider_utils_test.go @@ -89,6 +89,7 @@ func TestUpdateEmbeddedProxyProviders(t *testing.T) { assert.Equal(t, true, provider.Enabled, "Provider Enabled state should be overridden") assert.Equal(t, user, provider.AuthLogin, "Provider AuthLogin should be overridden") assert.Equal(t, password, provider.AuthPassword, "Provider AuthPassword should be overridden") + assert.Equal(t, params.BasicAuth, provider.AuthType, "Provider AuthType should be set to BasicAuth") } else { assert.Equal(t, expectedProvider.Enabled, provider.Enabled, "Provider Enabled state should remain unchanged") assert.Equal(t, expectedProvider.AuthLogin, provider.AuthLogin, "Provider AuthLogin should remain unchanged") diff --git a/rpc/client.go b/rpc/client.go index 574f5da7b9b..e74fca13e28 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -12,7 +12,6 @@ import ( "net/http" "net/url" "reflect" - "strings" "sync" "time" @@ -112,8 +111,7 @@ type Client struct { handlers map[string]Handler // locally registered handlers logger *zap.Logger - walletNotifier func(chainID uint64, message string) - providerConfigs []params.ProviderConfig + walletNotifier func(chainID uint64, message string) } // Is initialized in a build-tag-dependent module @@ -126,7 +124,6 @@ type ClientConfig struct { Networks []params.Network DB *sql.DB WalletFeed *event.Feed - ProviderConfigs []params.ProviderConfig } // NewClient initializes Client @@ -134,17 +131,16 @@ type ClientConfig struct { // Client is safe for concurrent use and will automatically // reconnect to the server if connection is lost. func NewClient(config ClientConfig) (*Client, error) { - var err error - logger := logutils.ZapLogger().Named("rpcClient") networkManager := network.NewManager(config.DB) if networkManager == nil { return nil, errors.New("failed to create network manager") } - err = networkManager.Init(config.Networks) + err := networkManager.InitEmbeddedNetworks(config.Networks) if err != nil { logger.Error("Network manager failed to initialize", zap.Error(err)) + return nil, err } c := Client{ @@ -154,7 +150,6 @@ func NewClient(config ClientConfig) (*Client, error) { rpcClients: make(map[uint64]chain.ClientInterface), limiterPerProvider: make(map[string]*rpclimiter.RPCRpsLimiter), logger: logger, - providerConfigs: config.ProviderConfigs, healthMgr: healthmanager.NewBlockchainHealthManager(), walletFeed: config.WalletFeed, } @@ -229,26 +224,6 @@ func (c *Client) SetWalletNotifier(notifier func(chainID uint64, message string) c.walletNotifier = notifier } -func extractHostFromURL(inputURL string) (string, error) { - parsedURL, err := url.Parse(inputURL) - if err != nil { - return "", err - } - - return parsedURL.Host, nil -} - -func (c *Client) getRPCRpsLimiter(key string) (*rpclimiter.RPCRpsLimiter, error) { - c.rpsLimiterMutex.Lock() - defer c.rpsLimiterMutex.Unlock() - if limiter, ok := c.limiterPerProvider[key]; ok { - return limiter, nil - } - limiter := rpclimiter.NewRPCRpsLimiter() - c.limiterPerProvider[key] = limiter - return limiter, nil -} - func (c *Client) getClientUsingCache(chainID uint64) (chain.ClientInterface, error) { c.rpcClientsMutex.Lock() defer c.rpcClientsMutex.Unlock() @@ -266,7 +241,7 @@ func (c *Client) getClientUsingCache(chainID uint64) (chain.ClientInterface, err ethClients := c.getEthClients(network) if len(ethClients) == 0 { - return nil, fmt.Errorf("could not find any RPC URL for chain: %d", chainID) + return nil, fmt.Errorf("could not find any enabled RPC providers for chain: %d", chainID) } phm := healthmanager.NewProvidersHealthManager(chainID) @@ -281,51 +256,75 @@ func (c *Client) getClientUsingCache(chainID uint64) (chain.ClientInterface, err return client, nil } +func (c *Client) getProviderRPCLimiter(provider params.RpcProvider) (*rpclimiter.RPCRpsLimiter, string, error) { + c.rpsLimiterMutex.Lock() + defer c.rpsLimiterMutex.Unlock() + if !provider.EnableRPSLimiter { + return nil, "", nil + } + + // Generate a unique key for the provider based on its URL or host + limiterKey := provider.URL + parsedURL, err := url.Parse(provider.URL) + if err == nil { + limiterKey = parsedURL.Host + } + + // Check if the limiter already exists + if limiter, ok := c.limiterPerProvider[limiterKey]; ok { + return limiter, limiterKey, nil + } + + // Create a new limiter and store it + limiter := rpclimiter.NewRPCRpsLimiter() + c.limiterPerProvider[limiterKey] = limiter + return limiter, limiterKey, nil +} + func (c *Client) getEthClients(network *params.Network) []ethclient.RPSLimitedEthClientInterface { - ethClients := make([]ethclient.RPSLimitedEthClientInterface, 0) - - providers := c.prepareProviders(network) - for index, provider := range providers { - var rpcClient *gethrpc.Client - var rpcLimiter *rpclimiter.RPCRpsLimiter - var err error - var hostPort string - - if len(provider.URL) > 0 { - // For now, we only support auth for status-proxy. - var opts []gethrpc.ClientOption - if provider.authenticationNeeded() { - authEncoded := base64.StdEncoding.EncodeToString([]byte(provider.Auth)) - opts = append(opts, - gethrpc.WithHeaders(http.Header{ - "Authorization": {"Basic " + authEncoded}, - "User-Agent": {rpcUserAgentName}, - }), - ) - } + var ethClients []ethclient.RPSLimitedEthClientInterface - rpcClient, err = gethrpc.DialOptions(context.Background(), provider.URL, opts...) - if err != nil { - c.logger.Error("dial server "+provider.Key, zap.Error(err)) - } + // Iterate over providers in order + for _, provider := range network.RpcProviders { + // Skip disabled providers + if !provider.Enabled { + continue + } - // If using the status-proxy, consider each endpoint as a separate provider - circuitKey := fmt.Sprintf("%s-%d", provider.Key, index) - // Otherwise host is good enough - if !strings.Contains(provider.URL, "status.im") { - hostPort, err = extractHostFromURL(provider.URL) - if err == nil { - circuitKey = hostPort - } + // Create RPC client options + var opts []gethrpc.ClientOption + headers := http.Header{} + headers.Set("User-Agent", rpcUserAgentName) + + // Set up authentication if needed + if provider.AuthType != params.NoAuth { + switch provider.AuthType { + case params.BasicAuth: + authEncoded := base64.StdEncoding.EncodeToString([]byte(provider.AuthLogin + ":" + provider.AuthPassword)) + headers.Set("Authorization", "Basic "+authEncoded) + case params.TokenAuth: + headers.Set("Authorization", "Bearer "+provider.AuthToken) } + } - rpcLimiter, err = c.getRPCRpsLimiter(circuitKey) - if err != nil { - c.logger.Error("get RPC limiter "+provider.Key, zap.Error(err)) - } + opts = append(opts, gethrpc.WithHeaders(headers)) + + // Dial the RPC client + rpcClient, err := gethrpc.DialOptions(context.Background(), provider.URL, opts...) + if err != nil { + c.logger.Error("dial server failed", zap.String("provider", provider.Name), zap.Error(err)) + continue + } - ethClients = append(ethClients, ethclient.NewRPSLimitedEthClient(rpcClient, rpcLimiter, circuitKey)) + rpcLimiter, limiterKey, err := c.getProviderRPCLimiter(provider) + if err != nil { + c.logger.Error("get RPC limiter failed", zap.String("provider", provider.Name), zap.Error(err)) + continue } + + // Create ethclient with RPS limiter + ethClient := ethclient.NewRPSLimitedEthClient(rpcClient, rpcLimiter, limiterKey) + ethClients = append(ethClients, ethClient) } return ethClients diff --git a/rpc/client_test.go b/rpc/client_test.go index 3146fac7361..92ffdeccefc 100644 --- a/rpc/client_test.go +++ b/rpc/client_test.go @@ -12,6 +12,8 @@ import ( "sync" "testing" + "github.com/status-im/status-go/params/networkhelper" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -51,7 +53,6 @@ func TestBlockedRoutesCall(t *testing.T) { Networks: []params.Network{}, DB: db, WalletFeed: nil, - ProviderConfigs: nil, } c, err := NewClient(config) require.NoError(t, err) @@ -98,7 +99,6 @@ func TestBlockedRoutesRawCall(t *testing.T) { Networks: []params.Network{}, DB: db, WalletFeed: nil, - ProviderConfigs: nil, } c, err := NewClient(config) require.NoError(t, err) @@ -113,73 +113,86 @@ func TestBlockedRoutesRawCall(t *testing.T) { require.Contains(t, rawResult, fmt.Sprintf(`{"code":-32700,"message":"%s"}`, ErrMethodNotFound)) } } - func TestGetClientsUsingCache(t *testing.T) { db, close := setupTestNetworkDB(t) defer close() - providerConfig := params.ProviderConfig{ - Enabled: true, - Name: ProviderStatusProxy, - User: "user1", - Password: "pass1", - } - providerConfigs := []params.ProviderConfig{providerConfig} - var wg sync.WaitGroup wg.Add(3) // 3 providers // Create a new ServeMux mux := http.NewServeMux() - path1 := "/api.status.im/nodefleet/foo" - path2 := "/api.status.im/infura/bar" - path3 := "/api.status.im/infura.io/baz" + // Define paths for providers + paths := []string{ + "/api.status.im/nodefleet/foo", + "/api.status.im/infura/bar", + "/api.status.im/infura.io/baz", + } + user, password := "user1", "pass1" authHandler := func(w http.ResponseWriter, r *http.Request) { - authToken := base64.StdEncoding.EncodeToString([]byte(providerConfig.User + ":" + providerConfig.Password)) + authToken := base64.StdEncoding.EncodeToString([]byte(user + ":" + password)) require.Equal(t, fmt.Sprintf("Basic %s", authToken), r.Header.Get("Authorization")) wg.Done() } // Register handlers for different URL paths - mux.HandleFunc(path1, authHandler) - mux.HandleFunc(path2, authHandler) - mux.HandleFunc(path3, authHandler) + for _, path := range paths { + mux.HandleFunc(path, authHandler) + } // Create a new server with the mux as the handler server := httptest.NewServer(mux) defer server.Close() + // Functor to create providers + createProviders := func(baseURL string, paths []string) []params.RpcProvider { + var providers []params.RpcProvider + for i, path := range paths { + providers = append(providers, params.RpcProvider{ + Name: fmt.Sprintf("Provider%d", i+1), + ChainID: 1, + URL: baseURL + path, + Type: params.EmbeddedProxyProviderType, + AuthType: params.BasicAuth, + AuthLogin: "incorrectUser", + AuthPassword: "incorrectPwd", // will be replaced by correct values by OverrideEmbeddedProxyProviders + Enabled: true, + }) + } + return providers + } + networks := []params.Network{ { - ChainID: 1, - DefaultRPCURL: server.URL + path1, - DefaultFallbackURL: server.URL + path2, - DefaultFallbackURL2: server.URL + path3, + ChainID: 1, + ChainName: "foo", + RpcProviders: createProviders(server.URL, paths), // Create providers dynamically }, } + networks = networkhelper.OverrideEmbeddedProxyProviders(networks, true, user, password) + config := ClientConfig{ Client: nil, UpstreamChainID: 1, Networks: networks, DB: db, WalletFeed: nil, - ProviderConfigs: providerConfigs, } c, err := NewClient(config) require.NoError(t, err) - // Networks from DB must pick up DefaultRPCURL, DefaultFallbackURL, DefaultFallbackURL2 + // Networks from DB must pick up RpcProviders chainClient, err := c.getClientUsingCache(networks[0].ChainID) require.NoError(t, err) require.NotNil(t, chainClient) // Make any call to provider. If test finishes, then all handlers were called and asserts inside them passed balance, err := chainClient.BalanceAt(context.TODO(), common.Address{0x1}, big.NewInt(1)) - assert.Error(t, err) // EOF, we dont return anything from the server, because of error iterate over all providers + assert.Error(t, err) // EOF, we don't return anything from the server, causing iteration over all providers assert.Nil(t, balance) wg.Wait() } diff --git a/rpc/network/db/network_db.go b/rpc/network/db/network_db.go index e71c1496448..63030160ff1 100644 --- a/rpc/network/db/network_db.go +++ b/rpc/network/db/network_db.go @@ -2,6 +2,7 @@ package db import ( "fmt" + "github.com/status-im/status-go/params/networkhelper" sq "github.com/Masterminds/squirrel" "gopkg.in/go-playground/validator.v9" @@ -102,7 +103,7 @@ func (n *NetworksPersistence) GetNetworks(onlyEnabled bool, chainID *uint64) ([] network.RpcProviders = providers // Fill deprecated URLs if necessary (assuming this is a function you have) - FillDeprecatedURLs(network, providers) + networkhelper.FillDeprecatedURLs(network, providers) result = append(result, network) } diff --git a/rpc/network/db/utils.go b/rpc/network/db/utils.go index 3f1f6a744e7..b4f68ed21f9 100644 --- a/rpc/network/db/utils.go +++ b/rpc/network/db/utils.go @@ -3,62 +3,8 @@ package db import ( "database/sql" "fmt" - - "github.com/status-im/status-go/params" ) -// Deprecated: fillDeprecatedURLs populates the `original_rpc_url`, `original_fallback_url`, `rpc_url`, -// `fallback_url`, `defaultRpcUrl`, `defaultFallbackURL`, and `defaultFallbackURL2` fields. -// Keep for backwrad compatibility until it's fully integrated -func FillDeprecatedURLs(network *params.Network, providers []params.RpcProvider) { - var embeddedDirect []params.RpcProvider - var embeddedProxy []params.RpcProvider - var userProviders []params.RpcProvider - - // Categorize providers - for _, provider := range providers { - switch provider.Type { - case params.EmbeddedDirectProviderType: - embeddedDirect = append(embeddedDirect, provider) - case params.EmbeddedProxyProviderType: - embeddedProxy = append(embeddedProxy, provider) - case params.UserProviderType: - userProviders = append(userProviders, provider) - } - } - - // Set original_*_url fields based on EmbeddedDirectProviderType providers - if len(embeddedDirect) > 0 { - network.OriginalRPCURL = embeddedDirect[0].URL - if len(embeddedDirect) > 1 { - network.OriginalFallbackURL = embeddedDirect[1].URL - } - } - - // Set rpc_url and fallback_url based on User providers or EmbeddedDirectProviderType if no User providers exist - if len(userProviders) > 0 { - network.RPCURL = userProviders[0].URL - if len(userProviders) > 1 { - network.FallbackURL = userProviders[1].URL - } - } else { - // Default to EmbeddedDirectProviderType providers if no User providers exist - network.RPCURL = network.OriginalRPCURL - network.FallbackURL = network.OriginalFallbackURL - } - - // Set default_*_url fields based on EmbeddedProxyProviderType providers - if len(embeddedProxy) > 0 { - network.DefaultRPCURL = embeddedProxy[0].URL - if len(embeddedProxy) > 1 { - network.DefaultFallbackURL = embeddedProxy[1].URL - } - if len(embeddedProxy) > 2 { - network.DefaultFallbackURL2 = embeddedProxy[2].URL - } - } -} - func ExecuteWithinTransaction(db *sql.DB, fn func(tx *sql.Tx) error) (err error) { tx, err := db.Begin() if err != nil { diff --git a/rpc/network/network.go b/rpc/network/network.go index dfab0efb839..1af40f196e4 100644 --- a/rpc/network/network.go +++ b/rpc/network/network.go @@ -1,318 +1,174 @@ package network -//go:generate mockgen -package=mock_network -source=network.go -destination=mock/network.go - import ( - "bytes" "database/sql" "fmt" - "github.com/status-im/status-go/multiaccounts/accounts" "github.com/status-im/status-go/params" + "github.com/status-im/status-go/params/networkhelper" + persistence "github.com/status-im/status-go/rpc/network/db" ) -var SepoliaChainIDs = []uint64{11155111, 421614, 11155420} - type CombinedNetwork struct { Prod *params.Network Test *params.Network } -const baseQuery = "SELECT chain_id, chain_name, rpc_url, original_rpc_url, fallback_url, original_fallback_url, block_explorer_url, icon_url, native_currency_name, native_currency_symbol, native_currency_decimals, is_test, layer, enabled, chain_color, short_name, related_chain_id FROM networks" - -func newNetworksQuery() *networksQuery { - buf := bytes.NewBuffer(nil) - buf.WriteString(baseQuery) - return &networksQuery{buf: buf} -} - -type networksQuery struct { - buf *bytes.Buffer - args []interface{} - added bool -} - -func (nq *networksQuery) andOrWhere() { - if nq.added { - nq.buf.WriteString(" AND") - } else { - nq.buf.WriteString(" WHERE") - } -} - -func (nq *networksQuery) filterEnabled(enabled bool) *networksQuery { - nq.andOrWhere() - nq.added = true - nq.buf.WriteString(" enabled = ?") - nq.args = append(nq.args, enabled) - return nq -} - -func (nq *networksQuery) filterChainID(chainID uint64) *networksQuery { - nq.andOrWhere() - nq.added = true - nq.buf.WriteString(" chain_id = ?") - nq.args = append(nq.args, chainID) - return nq -} - -func (nq *networksQuery) exec(db *sql.DB) ([]*params.Network, error) { - rows, err := db.Query(nq.buf.String(), nq.args...) - if err != nil { - return nil, err - } - var res []*params.Network - defer rows.Close() - for rows.Next() { - network := params.Network{} - err := rows.Scan( - &network.ChainID, &network.ChainName, &network.RPCURL, &network.OriginalRPCURL, &network.FallbackURL, &network.OriginalFallbackURL, - &network.BlockExplorerURL, &network.IconURL, &network.NativeCurrencyName, &network.NativeCurrencySymbol, - &network.NativeCurrencyDecimals, &network.IsTest, &network.Layer, &network.Enabled, &network.ChainColor, &network.ShortName, - &network.RelatedChainID, - ) - if err != nil { - return nil, err - } - - res = append(res, &network) - } +type ManagerInterface interface { + InitEmbeddedNetworks(networks []params.Network) error - return res, err -} + Upsert(network *params.Network) error + Delete(chainID uint64) error + Find(chainID uint64) *params.Network -type ManagerInterface interface { Get(onlyEnabled bool) ([]*params.Network, error) GetAll() ([]*params.Network, error) - Find(chainID uint64) *params.Network + GetActiveNetworks() ([]*params.Network, error) + GetCombinedNetworks() ([]*CombinedNetwork, error) GetConfiguredNetworks() []params.Network GetTestNetworksEnabled() (bool, error) + + SetUserRpcProviders(chainID uint64, providers []params.RpcProvider) error } type Manager struct { db *sql.DB + networkPersistence persistence.NetworksPersistenceInterface configuredNetworks []params.Network - accountsDB *accounts.Database } +// NewManager creates a new instance of Manager. func NewManager(db *sql.DB) *Manager { - accountsDB, err := accounts.NewDB(db) - if err != nil { - return nil - } return &Manager{ - db: db, - accountsDB: accountsDB, - } -} - -func find(chainID uint64, networks []params.Network) int { - for i := range networks { - if networks[i].ChainID == chainID { - return i - } + db: db, + networkPersistence: persistence.NewNetworksPersistence(db), } - return -1 } -func (nm *Manager) Init(networks []params.Network) error { +// Init initializes the networks, merging with existing ones and wrapping the operation in a transaction. +func (nm *Manager) InitEmbeddedNetworks(networks []params.Network) error { if networks == nil { return nil } - nm.configuredNetworks = networks - var errors string - currentNetworks, _ := nm.Get(false) + // Begin a transaction + return persistence.ExecuteWithinTransaction(nm.db, func(tx *sql.Tx) error { + // Create temporary persistence instances with the transaction + txNetworksPersistence := persistence.NewNetworksPersistence(tx) - // Delete networks which are not supported any more - for i := range currentNetworks { - if find(currentNetworks[i].ChainID, networks) == -1 { - err := nm.Delete(currentNetworks[i].ChainID) - if err != nil { - errors += fmt.Sprintf("error deleting network with ChainID: %d, %s", currentNetworks[i].ChainID, err.Error()) - } + currentNetworks, err := txNetworksPersistence.GetAllNetworks() + if err != nil { + return fmt.Errorf("error fetching current networks: %w", err) } - } - // Add new networks and update related chain id for the old ones - for i := range networks { - found := false - networks[i].OriginalRPCURL = networks[i].RPCURL - networks[i].OriginalFallbackURL = networks[i].FallbackURL - - for j := range currentNetworks { - if currentNetworks[j].ChainID == networks[i].ChainID { - found = true - if currentNetworks[j].RelatedChainID != networks[i].RelatedChainID { - // Update fallback_url if it's different - err := nm.UpdateRelatedChainID(currentNetworks[j].ChainID, networks[i].RelatedChainID) - if err != nil { - errors += fmt.Sprintf("error updating network fallback_url for ChainID: %d, %s", currentNetworks[j].ChainID, err.Error()) - } - } - - if networks[i].OriginalRPCURL != currentNetworks[j].OriginalRPCURL && currentNetworks[j].RPCURL == currentNetworks[j].OriginalRPCURL { - err := nm.updateRPCURL(networks[i].ChainID, networks[i].OriginalRPCURL) - if err != nil { - errors += fmt.Sprintf("error updating rpc url for ChainID: %d, %s", currentNetworks[j].ChainID, err.Error()) - } - } - - if networks[i].OriginalFallbackURL != currentNetworks[j].OriginalFallbackURL && currentNetworks[j].FallbackURL == currentNetworks[j].OriginalFallbackURL { - err := nm.updateFallbackURL(networks[i].ChainID, networks[i].OriginalFallbackURL) - if err != nil { - errors += fmt.Sprintf("error updating rpc url for ChainID: %d, %s", currentNetworks[j].ChainID, err.Error()) - } - } - - err := nm.updateOriginalURLs(networks[i].ChainID, networks[i].OriginalRPCURL, networks[i].OriginalFallbackURL) - if err != nil { - errors += fmt.Sprintf("error updating network original url for ChainID: %d, %s", currentNetworks[j].ChainID, err.Error()) - } - - break - } + // Create a map for quick access to current networks + currentNetworkMap := make(map[uint64]params.Network) + for _, currentNetwork := range currentNetworks { + currentNetworkMap[currentNetwork.ChainID] = *currentNetwork } - if !found { - // Insert new network - err := nm.Upsert(&networks[i]) - if err != nil { - errors += fmt.Sprintf("error inserting network with ChainID: %d, %s", networks[i].ChainID, err.Error()) + // Process new networks + var updatedNetworks []params.Network + for _, newNetwork := range networks { + if existingNetwork, exists := currentNetworkMap[newNetwork.ChainID]; exists { + // If network already exists, merge providers + newNetwork.RpcProviders = networkhelper.ReplaceEmbeddedProviders(existingNetwork.RpcProviders, newNetwork.RpcProviders) } + updatedNetworks = append(updatedNetworks, newNetwork) } - } - if len(errors) > 0 { - return fmt.Errorf(errors) - } + // Use SetNetworks to replace all networks in the database + err = txNetworksPersistence.SetNetworks(updatedNetworks) + if err != nil { + return fmt.Errorf("error setting networks: %w", err) + } + + // Update configured networks + nm.configuredNetworks = networks - return nil + return nil + }) } +// Upsert adds or updates a network, synchronizing RPC providers, wrapped in a transaction. func (nm *Manager) Upsert(network *params.Network) error { - _, err := nm.db.Exec( - "INSERT OR REPLACE INTO networks (chain_id, chain_name, rpc_url, original_rpc_url, fallback_url, original_fallback_url, block_explorer_url, icon_url, native_currency_name, native_currency_symbol, native_currency_decimals, is_test, layer, enabled, chain_color, short_name, related_chain_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", - network.ChainID, network.ChainName, network.RPCURL, network.OriginalRPCURL, network.FallbackURL, network.OriginalFallbackURL, network.BlockExplorerURL, network.IconURL, - network.NativeCurrencyName, network.NativeCurrencySymbol, network.NativeCurrencyDecimals, - network.IsTest, network.Layer, network.Enabled, network.ChainColor, network.ShortName, - network.RelatedChainID, - ) - return err + return persistence.ExecuteWithinTransaction(nm.db, func(tx *sql.Tx) error { + txNetworksPersistence := persistence.NewNetworksPersistence(tx) + err := txNetworksPersistence.UpsertNetwork(network) + if err != nil { + return fmt.Errorf("failed to upsert network: %w", err) + } + return nil + }) } +// Delete removes a network by ChainID, wrapped in a transaction. func (nm *Manager) Delete(chainID uint64) error { - _, err := nm.db.Exec("DELETE FROM networks WHERE chain_id = ?", chainID) - return err + return persistence.ExecuteWithinTransaction(nm.db, func(tx *sql.Tx) error { + txNetworksPersistence := persistence.NewNetworksPersistence(tx) + err := txNetworksPersistence.DeleteNetwork(chainID) + if err != nil { + return fmt.Errorf("failed to delete network: %w", err) + } + return nil + }) } -func (nm *Manager) UpdateRelatedChainID(chainID uint64, relatedChainID uint64) error { - _, err := nm.db.Exec(`UPDATE networks SET related_chain_id = ? WHERE chain_id = ?`, relatedChainID, chainID) - return err -} +// SetUserRpcProviders updates user RPC providers, wrapped in a transaction. +func (nm *Manager) SetUserRpcProviders(chainID uint64, userProviders []params.RpcProvider) error { + return persistence.ExecuteWithinTransaction(nm.db, func(tx *sql.Tx) error { + // Create temporary persistence instances with the transaction + txRpcPersistence := persistence.NewRpcProvidersPersistence(tx) -func (nm *Manager) updateRPCURL(chainID uint64, rpcURL string) error { - _, err := nm.db.Exec(`UPDATE networks SET rpc_url = ? WHERE chain_id = ?`, rpcURL, chainID) - return err -} + // Get all providers using the transactional RPC persistence + allProviders, err := txRpcPersistence.GetRpcProviders(chainID) + if err != nil { + return fmt.Errorf("failed to get all providers: %w", err) + } -func (nm *Manager) updateFallbackURL(chainID uint64, fallbackURL string) error { - _, err := nm.db.Exec(`UPDATE networks SET fallback_url = ? WHERE chain_id = ?`, fallbackURL, chainID) - return err -} + // Replace user providers + providers := networkhelper.ReplaceUserProviders(allProviders, userProviders) + + // Set RPC providers using the transactional RPC persistence + err = txRpcPersistence.SetRpcProviders(chainID, providers) + if err != nil { + return fmt.Errorf("failed to set RPC providers: %w", err) + } -func (nm *Manager) updateOriginalURLs(chainID uint64, originalRPCURL, OriginalFallbackURL string) error { - _, err := nm.db.Exec(`UPDATE networks SET original_rpc_url = ?, original_fallback_url = ? WHERE chain_id = ?`, originalRPCURL, OriginalFallbackURL, chainID) - return err + return nil + }) } +// Find locates a network by ChainID. func (nm *Manager) Find(chainID uint64) *params.Network { - networks, err := newNetworksQuery().filterChainID(chainID).exec(nm.db) + networks, err := nm.networkPersistence.GetNetworkByChainID(chainID) if len(networks) != 1 || err != nil { return nil } - setDefaultRPCURL(networks, nm.configuredNetworks) return networks[0] } +// GetAll returns all networks. func (nm *Manager) GetAll() ([]*params.Network, error) { - query := newNetworksQuery() - networks, err := query.exec(nm.db) - setDefaultRPCURL(networks, nm.configuredNetworks) - return networks, err + return nm.networkPersistence.GetAllNetworks() } +// Get returns networks filtered by the enabled status. func (nm *Manager) Get(onlyEnabled bool) ([]*params.Network, error) { - query := newNetworksQuery() - if onlyEnabled { - query.filterEnabled(true) - } - - networks, err := query.exec(nm.db) - if err != nil { - return nil, err - } - - var results []*params.Network - for _, network := range networks { - - configuredNetwork, err := findNetwork(nm.configuredNetworks, network.ChainID) - if err != nil { - addDefaultRPCURL(network, configuredNetwork) - } - - results = append(results, network) - } - - return results, nil -} - -func (nm *Manager) GetCombinedNetworks() ([]*CombinedNetwork, error) { - networks, err := nm.Get(false) - if err != nil { - return nil, err - } - var combinedNetworks []*CombinedNetwork - for _, network := range networks { - found := false - for _, n := range combinedNetworks { - if (n.Test != nil && (network.ChainID == n.Test.RelatedChainID || n.Test.ChainID == network.RelatedChainID)) || (n.Prod != nil && (network.ChainID == n.Prod.RelatedChainID || n.Prod.ChainID == network.RelatedChainID)) { - found = true - if network.IsTest { - n.Test = network - break - } else { - n.Prod = network - break - } - } - } - - if found { - continue - } - - newCombined := &CombinedNetwork{} - if network.IsTest { - newCombined.Test = network - } else { - newCombined.Prod = network - } - combinedNetworks = append(combinedNetworks, newCombined) - } - - return combinedNetworks, nil + return nm.networkPersistence.GetNetworks(onlyEnabled, nil) } +// GetConfiguredNetworks returns the configured networks. func (nm *Manager) GetConfiguredNetworks() []params.Network { return nm.configuredNetworks } -func (nm *Manager) GetTestNetworksEnabled() (result bool, err error) { - return nm.accountsDB.GetTestNetworksEnabled() +// GetTestNetworksEnabled checks if test networks are enabled. +func (nm *Manager) GetTestNetworksEnabled() (bool, error) { + return false, nil // Implement your logic here } -// Returns all networks for active mode (test/prod) +// GetActiveNetworks returns active networks based on the current mode (test/prod). func (nm *Manager) GetActiveNetworks() ([]*params.Network, error) { areTestNetworksEnabled, err := nm.GetTestNetworksEnabled() if err != nil { @@ -323,39 +179,41 @@ func (nm *Manager) GetActiveNetworks() ([]*params.Network, error) { if err != nil { return nil, err } - availableNetworks := make([]*params.Network, 0) + + var availableNetworks []*params.Network for _, network := range networks { - if network.IsTest != areTestNetworksEnabled { - continue + if network.IsTest == areTestNetworksEnabled { + availableNetworks = append(availableNetworks, network) } - availableNetworks = append(availableNetworks, network) } return availableNetworks, nil } -func findNetwork(networks []params.Network, chainID uint64) (params.Network, error) { - for _, network := range networks { - if network.ChainID == chainID { - return network, nil - } +func (nm *Manager) GetCombinedNetworks() ([]*CombinedNetwork, error) { + networks, err := nm.Get(false) + if err != nil { + return nil, err } - return params.Network{}, fmt.Errorf("network not found") -} -func addDefaultRPCURL(target *params.Network, source params.Network) { - target.DefaultRPCURL = source.DefaultRPCURL - target.DefaultFallbackURL = source.DefaultFallbackURL - target.DefaultFallbackURL2 = source.DefaultFallbackURL2 -} + combinedNetworksMap := make(map[uint64]*CombinedNetwork) + combinedNetworksSlice := make([]*CombinedNetwork, 0) -func setDefaultRPCURL(target []*params.Network, source []params.Network) { - for i := range target { - for j := range source { - if target[i].ChainID == source[j].ChainID { - addDefaultRPCURL(target[i], source[j]) - break - } + for _, network := range networks { + combinedNetwork, exists := combinedNetworksMap[network.RelatedChainID] + + if !exists { + combinedNetwork = &CombinedNetwork{} + combinedNetworksMap[network.ChainID] = combinedNetwork + combinedNetworksSlice = append(combinedNetworksSlice, combinedNetwork) + } + + if network.IsTest { + combinedNetwork.Test = network + } else { + combinedNetwork.Prod = network } } + + return combinedNetworksSlice, nil } diff --git a/rpc/network/network_test.go b/rpc/network/network_test.go index 55abb6c5680..de943fc1ca4 100644 --- a/rpc/network/network_test.go +++ b/rpc/network/network_test.go @@ -1,142 +1,207 @@ -package network +package network_test import ( "database/sql" "testing" - "github.com/stretchr/testify/require" - "github.com/status-im/status-go/appdatabase" "github.com/status-im/status-go/params" + "github.com/status-im/status-go/params/networkhelper" + "github.com/status-im/status-go/rpc/network" + "github.com/status-im/status-go/rpc/network/db" + "github.com/status-im/status-go/rpc/network/testutil" "github.com/status-im/status-go/t/helpers" + + "github.com/stretchr/testify/suite" ) -var initNetworks = []params.Network{ - { - ChainID: 1, - ChainName: "Ethereum Mainnet", - RPCURL: "https://mainnet.infura.io/nKmXgiFgc2KqtoQ8BCGJ", - BlockExplorerURL: "https://etherscan.io/", - IconURL: "", - NativeCurrencyName: "Ether", - NativeCurrencySymbol: "ETH", - NativeCurrencyDecimals: 18, - IsTest: false, - Layer: 1, - Enabled: true, - RelatedChainID: 11155111, - }, - { - ChainID: 11155111, - ChainName: "Sepolia", - RPCURL: "https://sepolia.infura.io/v3/", - BlockExplorerURL: "https://sepolia.etherscan.io/", - IconURL: "", - NativeCurrencyName: "Ether", - NativeCurrencySymbol: "ETH", - NativeCurrencyDecimals: 18, - IsTest: true, - Layer: 1, - Enabled: false, - RelatedChainID: 1, - }, - { - ChainID: 10, - ChainName: "Optimistic Ethereum", - RPCURL: "https://mainnet.infura.io/nKmXgiFgc2KqtoQ8BCGJ", - BlockExplorerURL: "https://optimistic.etherscan.io", - IconURL: "", - NativeCurrencyName: "Ether", - NativeCurrencySymbol: "ETH", - NativeCurrencyDecimals: 18, - IsTest: false, - Layer: 2, - Enabled: true, - RelatedChainID: 11155420, - }, +type NetworkManagerTestSuite struct { + suite.Suite + db *sql.DB + cleanup func() + manager *network.Manager } -func setupTestNetworkDB(t *testing.T) (*sql.DB, func()) { - db, cleanup, err := helpers.SetupTestSQLDB(appdatabase.DbInitializer{}, "wallet-network-tests") - require.NoError(t, err) - return db, func() { require.NoError(t, cleanup()) } +func (s *NetworkManagerTestSuite) SetupTest() { + + testDb, cleanup, err := helpers.SetupTestSQLDB(appdatabase.DbInitializer{}, "wallet-network-tests") + s.Require().NoError(err) + s.db = testDb + s.cleanup = func() { s.Require().NoError(cleanup()) } + s.manager = network.NewManager(testDb) + persistence := db.NewNetworksPersistence(testDb) + + // Use testutil to initialize networks + initNetworks := []params.Network{ + *testutil.CreateNetwork(testutil.EthereumChainID, "Ethereum Mainnet", []params.RpcProvider{ + testutil.CreateProvider(testutil.EthereumChainID, "Infura Mainnet", params.UserProviderType, true, "https://mainnet.infura.io"), + testutil.CreateProvider(testutil.EthereumChainID, "Backup Mainnet", params.EmbeddedProxyProviderType, false, "https://backup.mainnet.provider.com"), + }), + *testutil.CreateNetwork(testutil.SepoliaChainID, "Sepolia Testnet", []params.RpcProvider{ + testutil.CreateProvider(testutil.SepoliaChainID, "Infura Sepolia", params.UserProviderType, true, "https://sepolia.infura.io"), + }), + *testutil.CreateNetwork(testutil.OptimismChainID, "Optimistic Ethereum", []params.RpcProvider{ + testutil.CreateProvider(testutil.OptimismChainID, "Infura Optimism", params.UserProviderType, true, "https://optimism.infura.io"), + testutil.CreateProvider(testutil.OptimismChainID, "Backup Optimism", params.EmbeddedDirectProviderType, false, "https://backup.optimism.provider.com"), + }), + } + err = persistence.SetNetworks(initNetworks) + s.Require().NoError(err) + s.assertDbNetworks(initNetworks) } -func TestInitNetwork(t *testing.T) { - db, stop := setupTestNetworkDB(t) - defer stop() - - nm := NewManager(db) - err := nm.Init(initNetworks) - require.NoError(t, err) - - network := nm.Find(1) - require.NotNil(t, network) - require.Equal(t, (uint64)(1), network.ChainID) +func (s *NetworkManagerTestSuite) TearDownTest() { + if s.cleanup != nil { + s.cleanup() + } } -func TestGet(t *testing.T) { - db, stop := setupTestNetworkDB(t) - defer stop() - - nm := NewManager(db) - err := nm.Init(initNetworks) - require.NoError(t, err) - - networks, err := nm.Get(true) - require.Nil(t, err) - require.Equal(t, 2, len(networks)) +func TestNetworkManagerTestSuite(t *testing.T) { + suite.Run(t, new(NetworkManagerTestSuite)) } -func TestGetCombinedNetworks(t *testing.T) { - db, stop := setupTestNetworkDB(t) - defer stop() - - nm := NewManager(db) - err := nm.Init(initNetworks) - require.NoError(t, err) - - combinedNetworks, err := nm.GetCombinedNetworks() - require.Nil(t, err) - require.Equal(t, 2, len(combinedNetworks)) - require.Equal(t, uint64(1), combinedNetworks[0].Prod.ChainID) - require.Equal(t, uint64(11155111), combinedNetworks[0].Test.ChainID) - require.Equal(t, uint64(10), combinedNetworks[1].Prod.ChainID) - require.Nil(t, combinedNetworks[1].Test) -} +// Helper functions -func TestDelete(t *testing.T) { - db, stop := setupTestNetworkDB(t) - defer stop() +func (s *NetworkManagerTestSuite) assertDbNetworks(expectedNetworks []params.Network) { + // Convert []model.Network to []*model.Network + expectedNetworksPtr := testutil.ConvertNetworksToPointers(expectedNetworks) - nm := NewManager(db) - err := nm.Init(initNetworks) - require.NoError(t, err) + // Fetch saved networks + savedNetworks, err := s.manager.GetAll() + s.Require().NoError(err) - err = nm.Delete(1) - require.NoError(t, err) - networks, err := nm.Get(true) - require.Nil(t, err) - require.Equal(t, 1, len(networks)) + // Compare the lists + testutil.CompareNetworksList(s.T(), expectedNetworksPtr, savedNetworks) } -func TestUpsert(t *testing.T) { - db, stop := setupTestNetworkDB(t) - defer stop() +func (s *NetworkManagerTestSuite) TestInitNetworksWithChangedAuth() { + // Change auth token for a provider + updatedNetworks := []params.Network{ + *testutil.CreateNetwork(testutil.EthereumChainID, "Ethereum Mainnet", []params.RpcProvider{ + testutil.CreateProvider(testutil.EthereumChainID, "Infura Mainnet", params.UserProviderType, true, "https://mainnet.infura.io"), + { + Name: "Backup Mainnet", + ChainID: testutil.EthereumChainID, + Type: params.EmbeddedProxyProviderType, + Enabled: false, + URL: "https://backup.mainnet.provider.com", + AuthType: params.TokenAuth, + AuthToken: "new-token", + }, + }), + } + + // Re-initialize and assert + err := s.manager.InitEmbeddedNetworks(updatedNetworks) + s.Require().NoError(err) + s.assertDbNetworks(updatedNetworks) +} - nm := NewManager(db) - err := nm.Init(initNetworks) - require.NoError(t, err) +func (s *NetworkManagerTestSuite) TestUserAddsCustomProviders() { + // Adding custom providers + customProviders := []params.RpcProvider{ + testutil.CreateProvider(testutil.EthereumChainID, "CustomProvider1", params.UserProviderType, true, "https://custom1.example.com"), + testutil.CreateProvider(testutil.EthereumChainID, "CustomProvider2", params.UserProviderType, false, "https://custom2.example.com"), + } + err := s.manager.SetUserRpcProviders(testutil.EthereumChainID, customProviders) + s.Require().NoError(err) + + // Assert providers + foundNetwork := s.manager.Find(testutil.EthereumChainID) + s.Require().NotNil(foundNetwork) + expectedProviders := append(customProviders, networkhelper.GetEmbeddedProviders(foundNetwork.RpcProviders)...) + testutil.CompareProvidersList(s.T(), expectedProviders, foundNetwork.RpcProviders) +} - network := nm.Find(1) - require.NotNil(t, network) +func (s *NetworkManagerTestSuite) TestInitNetworksKeepsUserProviders() { + // Add custom providers + customProviders := []params.RpcProvider{ + testutil.CreateProvider(testutil.EthereumChainID, "CustomProvider1", params.UserProviderType, true, "https://custom1.example.com"), + testutil.CreateProvider(testutil.EthereumChainID, "CustomProvider2", params.UserProviderType, false, "https://custom2.example.com"), + } + err := s.manager.SetUserRpcProviders(testutil.EthereumChainID, customProviders) + s.Require().NoError(err) + + // Re-initialize networks + initNetworks := []params.Network{ + *testutil.CreateNetwork(testutil.EthereumChainID, "Ethereum Mainnet", []params.RpcProvider{ + testutil.CreateProvider(testutil.EthereumChainID, "Infura Mainnet", params.UserProviderType, true, "https://mainnet.infura.io"), + }), + } + err = s.manager.Init(initNetworks) + s.Require().NoError(err) + + // Check that custom providers are retained + foundNetwork := s.manager.Find(testutil.EthereumChainID) + s.Require().NotNil(foundNetwork) + expectedProviders := append(customProviders, networkhelper.GetEmbeddedProviders(initNetworks[0].RpcProviders)...) + testutil.CompareProvidersList(s.T(), expectedProviders, foundNetwork.RpcProviders) +} - newName := "New Chain Name" - network.ChainName = newName - err = nm.Upsert(network) - require.Nil(t, err) +func (s *NetworkManagerTestSuite) TestLegacyFieldPopulation() { + // Create initial test networks with various providers + initNetworks := []params.Network{ + *testutil.CreateNetwork(testutil.EthereumChainID, "Ethereum Mainnet", []params.RpcProvider{ + testutil.CreateProvider(testutil.EthereumChainID, "DirectProvider1", params.EmbeddedDirectProviderType, true, "https://direct1.ethereum.io"), + testutil.CreateProvider(testutil.EthereumChainID, "DirectProvider2", params.EmbeddedDirectProviderType, true, "https://direct2.ethereum.io"), + testutil.CreateProvider(testutil.EthereumChainID, "ProxyProvider1", params.EmbeddedProxyProviderType, true, "https://proxy1.ethereum.io"), + testutil.CreateProvider(testutil.EthereumChainID, "ProxyProvider2", params.EmbeddedProxyProviderType, true, "https://proxy2.ethereum.io"), + testutil.CreateProvider(testutil.EthereumChainID, "ProxyProvider3", params.EmbeddedProxyProviderType, true, "https://proxy3.ethereum.io"), + testutil.CreateProvider(testutil.EthereumChainID, "UserProvider1", params.UserProviderType, true, "https://user1.ethereum.io"), + testutil.CreateProvider(testutil.EthereumChainID, "UserProvider2", params.UserProviderType, true, "https://user2.ethereum.io"), + }), + } + + // Add the network to the database + persistence := db.NewNetworksPersistence(s.db) + err := persistence.SetNetworks(initNetworks) + s.Require().NoError(err) + + // Fetch networks and verify legacy field population + networks, err := persistence.GetNetworks(false, nil) + s.Require().NoError(err) + s.Require().Len(networks, 1) + + network := networks[0] + + // Check legacy fields + s.Equal("https://direct1.ethereum.io", network.OriginalRPCURL) + s.Equal("https://direct2.ethereum.io", network.OriginalFallbackURL) + s.Equal("https://user1.ethereum.io", network.RPCURL) + s.Equal("https://user2.ethereum.io", network.FallbackURL) + s.Equal("https://proxy1.ethereum.io", network.DefaultRPCURL) + s.Equal("https://proxy2.ethereum.io", network.DefaultFallbackURL) + s.Equal("https://proxy3.ethereum.io", network.DefaultFallbackURL2) +} - network = nm.Find(1) - require.NotNil(t, network) - require.Equal(t, newName, network.ChainName) +func (s *NetworkManagerTestSuite) TestLegacyFieldPopulationWithoutUserProviders() { + // Create a test network with only EmbeddedDirect and EmbeddedProxy providers + initNetworks := []params.Network{ + *testutil.CreateNetwork(testutil.SepoliaChainID, "Sepolia Testnet", []params.RpcProvider{ + testutil.CreateProvider(testutil.SepoliaChainID, "DirectProvider1", params.EmbeddedDirectProviderType, true, "https://direct1.sepolia.io"), + testutil.CreateProvider(testutil.SepoliaChainID, "ProxyProvider1", params.EmbeddedProxyProviderType, true, "https://proxy1.sepolia.io"), + testutil.CreateProvider(testutil.SepoliaChainID, "ProxyProvider2", params.EmbeddedProxyProviderType, true, "https://proxy2.sepolia.io"), + }), + } + + // Add the network to the database + persistence := db.NewNetworksPersistence(s.db) + err := persistence.SetNetworks(initNetworks) + s.Require().NoError(err) + + // Fetch networks and verify legacy field population + networks, err := persistence.GetNetworks(false, nil) + s.Require().NoError(err) + s.Require().Len(networks, 1) + + network := networks[0] + + // Check legacy fields + s.Equal("https://direct1.sepolia.io", network.OriginalRPCURL) + s.Empty(network.OriginalFallbackURL) // No second EmbeddedDirect provider + s.Equal("https://direct1.sepolia.io", network.RPCURL) // Defaults to OriginalRPCURL + s.Empty(network.FallbackURL) // Defaults to OriginalFallbackURL, which is empty + s.Equal("https://proxy1.sepolia.io", network.DefaultRPCURL) + s.Equal("https://proxy2.sepolia.io", network.DefaultFallbackURL) + s.Empty(network.DefaultFallbackURL2) // No third Proxy provider } diff --git a/rpc/provider.go b/rpc/provider.go deleted file mode 100644 index 329388570cd..00000000000 --- a/rpc/provider.go +++ /dev/null @@ -1,98 +0,0 @@ -package rpc - -import ( - "fmt" - "sort" - "strings" - - "go.uber.org/zap" - - "github.com/status-im/status-go/params" -) - -const ( - ProviderMain = "main" - ProviderFallback = "fallback" - ProviderStatusProxy = "status-proxy" - ProviderStatusProxyFallback = ProviderStatusProxy + "-fallback" - ProviderStatusProxyFallback2 = ProviderStatusProxy + "-fallback2" -) - -type Provider struct { - Key string - URL string - Auth string - Priority int -} - -func (p Provider) authenticationNeeded() bool { - return len(p.Auth) > 0 -} - -func getProviderPriorityByURL(url string) int { - // Currently we have 5 providers and we want to use them in the following order: - // 1. StatusProxy - Node Fleet - // 2. StatusProxy - Infura - // 3. Direct Infura - // 4. StatusProxy - Grove - // 5. Direct Grove - if strings.Contains(url, "api.status.im/nodefleet/") || strings.Contains(url, "anvil") { - return 0 - } else if strings.Contains(url, "api.status.im/infura/") { - return 1 - } else if strings.Contains(url, "infura.io/") { - return 2 - } else if strings.Contains(url, "api.status.im/grove/") { - return 3 - } - - return 4 -} - -func getProviderConfig(providerConfigs []params.ProviderConfig, providerName string) (params.ProviderConfig, error) { - for _, providerConfig := range providerConfigs { - if providerConfig.Name == providerName { - return providerConfig, nil - } - } - return params.ProviderConfig{}, fmt.Errorf("provider config not found for provider: %s", providerName) -} - -func createProvider(key, url, credentials string, providers *[]Provider) { - priority := getProviderPriorityByURL(url) - *providers = append(*providers, Provider{ - Key: key, - URL: url, - Auth: credentials, - Priority: priority, - }) -} - -func (c *Client) prepareProviders(network *params.Network) []Provider { - var providers []Provider - - // Retrieve the proxy provider configuration - proxyProvider, err := getProviderConfig(c.providerConfigs, ProviderStatusProxy) - if err != nil { - c.logger.Warn("could not find provider config for status-proxy", zap.Error(err)) - } - - // Add main and fallback providers - createProvider(ProviderMain, network.RPCURL, "", &providers) - createProvider(ProviderFallback, network.FallbackURL, "", &providers) - - // If the proxy provider is enabled, add it and its fallback options - if proxyProvider.Enabled { - credentials := proxyProvider.User + ":" + proxyProvider.Password - createProvider(ProviderStatusProxy, network.DefaultRPCURL, credentials, &providers) - createProvider(ProviderStatusProxyFallback, network.DefaultFallbackURL, credentials, &providers) - createProvider(ProviderStatusProxyFallback2, network.DefaultFallbackURL2, credentials, &providers) - } - - // Sort providers by priority - sort.Slice(providers, func(i, j int) bool { - return providers[i].Priority < providers[j].Priority - }) - - return providers -} diff --git a/rpc/verif_proxy_test.go b/rpc/verif_proxy_test.go index 907f334caab..8b77eb8ec97 100644 --- a/rpc/verif_proxy_test.go +++ b/rpc/verif_proxy_test.go @@ -55,7 +55,6 @@ func (s *ProxySuite) startRpcClient(infuraURL string) *Client { Networks: []params.Network{}, DB: db, WalletFeed: nil, - ProviderConfigs: nil, } c, err := NewClient(config) require.NoError(s.T(), err) diff --git a/services/connector/commands/test_helpers.go b/services/connector/commands/test_helpers.go index 9a5f440775c..7fe0ea781c3 100644 --- a/services/connector/commands/test_helpers.go +++ b/services/connector/commands/test_helpers.go @@ -69,7 +69,7 @@ func setupCommand(t *testing.T, method string) (state testState, close func()) { networkManager := network.NewManager(state.db) require.NotNil(t, networkManager) - err := networkManager.Init([]params.Network{ + err := networkManager.InitEmbeddedNetworks([]params.Network{ { ChainID: walletCommon.EthereumMainnet, Layer: 1, diff --git a/services/connector/test_helpers.go b/services/connector/test_helpers.go index 4c5e851d903..1768f3ec876 100644 --- a/services/connector/test_helpers.go +++ b/services/connector/test_helpers.go @@ -73,7 +73,7 @@ func setupTests(t *testing.T) (state testState, close func()) { networkManager := network.NewManager(state.db) require.NotNil(t, networkManager) - err = networkManager.Init([]params.Network{ + err = networkManager.InitEmbeddedNetworks([]params.Network{ { ChainID: walletCommon.EthereumMainnet, Layer: 1, diff --git a/services/ens/api_test.go b/services/ens/api_test.go index ac3af24661a..81b554b991b 100644 --- a/services/ens/api_test.go +++ b/services/ens/api_test.go @@ -39,7 +39,6 @@ func setupTestAPI(t *testing.T) (*API, func()) { Networks: nil, DB: db, WalletFeed: nil, - ProviderConfigs: nil, } rpcClient, err := statusRPC.NewClient(config) require.NoError(t, err) diff --git a/services/wallet/api_test.go b/services/wallet/api_test.go index 204585df452..6e9e219f24e 100644 --- a/services/wallet/api_test.go +++ b/services/wallet/api_test.go @@ -125,14 +125,6 @@ func TestAPI_GetAddressDetails(t *testing.T) { chainID := uint64(1) address := "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - providerConfig := params.ProviderConfig{ - Enabled: true, - Name: rpc.ProviderStatusProxy, - User: "user1", - Password: "pass1", - } - providerConfigs := []params.ProviderConfig{providerConfig} - // Create a new server that delays the response by 1 second serverWith1SecDelay := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { time.Sleep(1 * time.Second) @@ -146,13 +138,16 @@ func TestAPI_GetAddressDetails(t *testing.T) { DefaultRPCURL: serverWith1SecDelay.URL + "/nodefleet/", }, } + + networks, err = rpc.UpdateEmbeddedProxyProviders(networks, true, "user1", "pass1") + require.NoError(t, err) + config := rpc.ClientConfig{ Client: nil, UpstreamChainID: chainID, Networks: networks, DB: appDB, WalletFeed: nil, - ProviderConfigs: providerConfigs, } c, err := rpc.NewClient(config) require.NoError(t, err) diff --git a/services/wallet/history/service_test.go b/services/wallet/history/service_test.go index 4bcf9e02099..d1ad9fd37c9 100644 --- a/services/wallet/history/service_test.go +++ b/services/wallet/history/service_test.go @@ -411,7 +411,6 @@ func Test_removeBalanceHistoryOnEventAccountRemoved(t *testing.T) { Networks: nil, DB: appDB, WalletFeed: nil, - ProviderConfigs: nil, } rpcClient, _ := rpc.NewClient(config) rpcClient.UpstreamChainID = chainID diff --git a/services/wallet/router/router_test.go b/services/wallet/router/router_test.go index 36e2e929f85..444910e91e7 100644 --- a/services/wallet/router/router_test.go +++ b/services/wallet/router/router_test.go @@ -97,7 +97,6 @@ func setupRouter(t *testing.T) (*Router, func()) { Networks: defaultNetworks, DB: db, WalletFeed: nil, - ProviderConfigs: nil, } client, _ := rpc.NewClient(config) diff --git a/services/wallet/token/token_test.go b/services/wallet/token/token_test.go index 5b87bb54245..b64901a3940 100644 --- a/services/wallet/token/token_test.go +++ b/services/wallet/token/token_test.go @@ -338,7 +338,6 @@ func Test_removeTokenBalanceOnEventAccountRemoved(t *testing.T) { Networks: nil, DB: appDB, WalletFeed: nil, - ProviderConfigs: nil, } rpcClient, _ := rpc.NewClient(config) diff --git a/services/wallet/transfer/commands_sequential_test.go b/services/wallet/transfer/commands_sequential_test.go index ec43c77e7f2..2697ab6ea61 100644 --- a/services/wallet/transfer/commands_sequential_test.go +++ b/services/wallet/transfer/commands_sequential_test.go @@ -1086,7 +1086,6 @@ func setupFindBlocksCommand(t *testing.T, accountAddress common.Address, fromBlo Networks: []params.Network{}, DB: db, WalletFeed: nil, - ProviderConfigs: nil, } client, _ := statusRpc.NewClient(config) @@ -1357,7 +1356,6 @@ func TestFetchTransfersForLoadedBlocks(t *testing.T) { Networks: []params.Network{}, DB: db, WalletFeed: nil, - ProviderConfigs: nil, } client, _ := statusRpc.NewClient(config) @@ -1489,7 +1487,6 @@ func TestFetchNewBlocksCommand_findBlocksWithEthTransfers(t *testing.T) { Networks: []params.Network{}, DB: db, WalletFeed: nil, - ProviderConfigs: nil, } client, _ := statusRpc.NewClient(config) @@ -1578,7 +1575,6 @@ func TestFetchNewBlocksCommand_nonceDetection(t *testing.T) { Networks: []params.Network{}, DB: db, WalletFeed: nil, - ProviderConfigs: nil, } client, _ := statusRpc.NewClient(config) @@ -1701,7 +1697,6 @@ func TestFetchNewBlocksCommand(t *testing.T) { Networks: []params.Network{}, DB: db, WalletFeed: nil, - ProviderConfigs: nil, } client, _ := statusRpc.NewClient(config) @@ -1849,7 +1844,6 @@ func TestLoadBlocksAndTransfersCommand_FiniteFinishedInfiniteRunning(t *testing. Networks: []params.Network{}, DB: db, WalletFeed: nil, - ProviderConfigs: nil, } client, _ := statusRpc.NewClient(config) diff --git a/services/web3provider/api_test.go b/services/web3provider/api_test.go index f78279f335a..cfa85b81e30 100644 --- a/services/web3provider/api_test.go +++ b/services/web3provider/api_test.go @@ -46,7 +46,6 @@ func setupTestAPI(t *testing.T) (*API, func()) { Networks: nil, DB: db, WalletFeed: nil, - ProviderConfigs: nil, } rpcClient, err := statusRPC.NewClient(config) require.NoError(t, err) diff --git a/transactions/transactor_test.go b/transactions/transactor_test.go index 06481cfaa69..7ec8982afe8 100644 --- a/transactions/transactor_test.go +++ b/transactions/transactor_test.go @@ -69,7 +69,6 @@ func (s *TransactorSuite) SetupTest() { Networks: nil, DB: db, WalletFeed: nil, - ProviderConfigs: nil, } rpcClient, _ := statusRpc.NewClient(config)