feat(wallet)_: add status proxy RPC urls for blockchain providers
Replace the status proxy URL for cryptocompare.
This commit is contained in:
parent
780e3e55f4
commit
b74d9e6b4e
5
Makefile
5
Makefile
|
@ -61,6 +61,11 @@ GIT_AUTHOR := $(shell git config user.email || echo $$USER)
|
|||
ENABLE_METRICS ?= true
|
||||
BUILD_TAGS ?= gowaku_no_rln
|
||||
|
||||
ifdef RELEASE
|
||||
BUILD_TAGS += release
|
||||
endif
|
||||
|
||||
|
||||
BUILD_FLAGS ?= -ldflags="-X github.com/status-im/status-go/params.Version=$(RELEASE_TAG:v%=%) \
|
||||
-X github.com/status-im/status-go/params.GitCommit=$(GIT_COMMIT) \
|
||||
-X github.com/status-im/status-go/params.IpfsGatewayURL=$(IPFS_GATEWAY_URL) \
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/status-im/status-go/buildinfo"
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/protocol/requests"
|
||||
)
|
||||
|
@ -27,6 +29,8 @@ var ganacheTokenAddress = common.HexToAddress("0x8571Ddc46b10d31EF963aF49b6C7799
|
|||
var mainnet = params.Network{
|
||||
ChainID: mainnetChainID,
|
||||
ChainName: "Mainnet",
|
||||
DefaultRPCURL: fmt.Sprintf("https://%s.api.status.im/grove/ethereum/mainnet/", buildinfo.ApiProxyStageName),
|
||||
DefaultFallbackURL: fmt.Sprintf("https://%s.api.status.im/infura/ethereum/mainnet/", buildinfo.ApiProxyStageName),
|
||||
RPCURL: "https://eth-archival.rpc.grove.city/v1/",
|
||||
FallbackURL: "https://mainnet.infura.io/v3/",
|
||||
BlockExplorerURL: "https://etherscan.io/",
|
||||
|
@ -63,6 +67,8 @@ var goerli = params.Network{
|
|||
var sepolia = params.Network{
|
||||
ChainID: sepoliaChainID,
|
||||
ChainName: "Mainnet",
|
||||
DefaultRPCURL: fmt.Sprintf("https://%s.api.status.im/grove/ethereum/sepolia/", buildinfo.ApiProxyStageName),
|
||||
DefaultFallbackURL: fmt.Sprintf("https://%s.api.status.im/infura/ethereum/sepolia/", buildinfo.ApiProxyStageName),
|
||||
RPCURL: "https://sepolia-archival.rpc.grove.city/v1/",
|
||||
FallbackURL: "https://sepolia.infura.io/v3/",
|
||||
BlockExplorerURL: "https://sepolia.etherscan.io/",
|
||||
|
@ -81,6 +87,8 @@ var sepolia = params.Network{
|
|||
var optimism = params.Network{
|
||||
ChainID: optimismChainID,
|
||||
ChainName: "Optimism",
|
||||
DefaultRPCURL: fmt.Sprintf("https://%s.api.status.im/grove/optimism/mainnet/", buildinfo.ApiProxyStageName),
|
||||
DefaultFallbackURL: fmt.Sprintf("https://%s.api.status.im/infura/optimism/mainnet/", buildinfo.ApiProxyStageName),
|
||||
RPCURL: "https://optimism-archival.rpc.grove.city/v1/",
|
||||
FallbackURL: "https://optimism-mainnet.infura.io/v3/",
|
||||
BlockExplorerURL: "https://optimistic.etherscan.io",
|
||||
|
@ -117,6 +125,8 @@ var optimismGoerli = params.Network{
|
|||
var optimismSepolia = params.Network{
|
||||
ChainID: optimismSepoliaChainID,
|
||||
ChainName: "Optimism",
|
||||
DefaultRPCURL: fmt.Sprintf("https://%s.api.status.im/grove/optimism/sepolia/", buildinfo.ApiProxyStageName),
|
||||
DefaultFallbackURL: fmt.Sprintf("https://%s.api.status.im/infura/optimism/sepolia/", buildinfo.ApiProxyStageName),
|
||||
RPCURL: "https://optimism-sepolia-archival.rpc.grove.city/v1/",
|
||||
FallbackURL: "https://optimism-sepolia.infura.io/v3/",
|
||||
BlockExplorerURL: "https://sepolia-optimism.etherscan.io/",
|
||||
|
@ -135,6 +145,8 @@ var optimismSepolia = params.Network{
|
|||
var arbitrum = params.Network{
|
||||
ChainID: arbitrumChainID,
|
||||
ChainName: "Arbitrum",
|
||||
DefaultRPCURL: fmt.Sprintf("https://%s.api.status.im/grove/arbitrum/mainnet/", buildinfo.ApiProxyStageName),
|
||||
DefaultFallbackURL: fmt.Sprintf("https://%s.api.status.im/infura/arbitrum/mainnet/", buildinfo.ApiProxyStageName),
|
||||
RPCURL: "https://arbitrum-one.rpc.grove.city/v1/",
|
||||
FallbackURL: "https://arbitrum-mainnet.infura.io/v3/",
|
||||
BlockExplorerURL: "https://arbiscan.io/",
|
||||
|
@ -171,6 +183,8 @@ var arbitrumGoerli = params.Network{
|
|||
var arbitrumSepolia = params.Network{
|
||||
ChainID: arbitrumSepoliaChainID,
|
||||
ChainName: "Arbitrum",
|
||||
DefaultRPCURL: fmt.Sprintf("https://%s.api.status.im/grove/arbitrum/sepolia/", buildinfo.ApiProxyStageName),
|
||||
DefaultFallbackURL: fmt.Sprintf("https://%s.api.status.im/infura/arbitrum/sepolia/", buildinfo.ApiProxyStageName),
|
||||
RPCURL: "https://arbitrum-sepolia-archival.rpc.grove.city/v1/",
|
||||
FallbackURL: "https://arbitrum-sepolia.infura.io/v3/",
|
||||
BlockExplorerURL: "https://sepolia-explorer.arbitrum.io/",
|
||||
|
|
|
@ -161,7 +161,7 @@ func SetFleet(fleet string, nodeConfig *params.NodeConfig) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func buildWalletConfig(request *requests.WalletSecretsConfig) params.WalletConfig {
|
||||
func buildWalletConfig(request *requests.WalletSecretsConfig, statusProxyEnabled bool) params.WalletConfig {
|
||||
walletConfig := params.WalletConfig{
|
||||
Enabled: true,
|
||||
AlchemyAPIKeys: make(map[uint64]string),
|
||||
|
@ -220,6 +220,14 @@ func buildWalletConfig(request *requests.WalletSecretsConfig) params.WalletConfi
|
|||
if request.StatusProxyMarketPassword != "" {
|
||||
walletConfig.StatusProxyMarketPassword = request.StatusProxyMarketPassword
|
||||
}
|
||||
if request.StatusProxyBlockchainUser != "" {
|
||||
walletConfig.StatusProxyBlockchainUser = request.StatusProxyBlockchainUser
|
||||
}
|
||||
if request.StatusProxyBlockchainPassword != "" {
|
||||
walletConfig.StatusProxyBlockchainPassword = request.StatusProxyBlockchainPassword
|
||||
}
|
||||
|
||||
walletConfig.StatusProxyEnabled = statusProxyEnabled
|
||||
|
||||
return walletConfig
|
||||
}
|
||||
|
@ -287,7 +295,7 @@ func defaultNodeConfig(installationID string, request *requests.CreateAccount, o
|
|||
nodeConfig.MaxPeers = DefaultMaxPeers
|
||||
nodeConfig.MaxPendingPeers = DefaultMaxPendingPeers
|
||||
|
||||
nodeConfig.WalletConfig = buildWalletConfig(&request.WalletSecretsConfig)
|
||||
nodeConfig.WalletConfig = buildWalletConfig(&request.WalletSecretsConfig, request.StatusProxyEnabled)
|
||||
|
||||
nodeConfig.LocalNotificationsConfig = params.LocalNotificationsConfig{Enabled: true}
|
||||
nodeConfig.BrowsersConfig = params.BrowsersConfig{Enabled: true}
|
||||
|
|
|
@ -601,7 +601,7 @@ func (b *GethStatusBackend) loginAccount(request *requests.Login) error {
|
|||
KeycardPairingDataFile: DefaultKeycardPairingDataFile,
|
||||
}
|
||||
|
||||
defaultCfg.WalletConfig = buildWalletConfig(&request.WalletSecretsConfig)
|
||||
defaultCfg.WalletConfig = buildWalletConfig(&request.WalletSecretsConfig, request.StatusProxyEnabled)
|
||||
|
||||
err = b.UpdateNodeConfigFleet(acc, request.Password, defaultCfg)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
//go:build !release
|
||||
|
||||
package buildinfo
|
||||
|
||||
var ApiProxyStageName = "test"
|
|
@ -0,0 +1,5 @@
|
|||
//go:build release
|
||||
|
||||
package buildinfo
|
||||
|
||||
var ApiProxyStageName = "prod"
|
|
@ -314,7 +314,20 @@ func (n *StatusNode) setupRPCClient() (err error) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
n.rpcClient, err = rpc.NewClient(gethNodeClient, n.config.NetworkID, n.config.UpstreamConfig, n.config.Networks, n.appDB)
|
||||
|
||||
// ProviderConfigs 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,
|
||||
},
|
||||
}
|
||||
|
||||
n.rpcClient, err = rpc.NewClient(gethNodeClient, n.config.NetworkID, n.config.UpstreamConfig, n.config.Networks, n.appDB, providerConfigs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -310,6 +310,21 @@ type UpstreamRPCConfig struct {
|
|||
URL string
|
||||
}
|
||||
|
||||
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
|
||||
// ----------
|
||||
|
@ -531,6 +546,8 @@ type TokenOverride struct {
|
|||
type Network struct {
|
||||
ChainID uint64 `json:"chainId"`
|
||||
ChainName string `json:"chainName"`
|
||||
DefaultRPCURL string `json:"defaultRpcUrl"` // proxy rpc url
|
||||
DefaultFallbackURL string `json:"defaultFallbackURL"` // proxy fallback url
|
||||
RPCURL string `json:"rpcUrl"`
|
||||
OriginalRPCURL string `json:"originalRpcUrl"`
|
||||
FallbackURL string `json:"fallbackURL"`
|
||||
|
@ -551,16 +568,19 @@ type Network struct {
|
|||
|
||||
// WalletConfig extra configuration for wallet.Service.
|
||||
type WalletConfig struct {
|
||||
Enabled bool
|
||||
OpenseaAPIKey string `json:"OpenseaAPIKey"`
|
||||
RaribleMainnetAPIKey string `json:"RaribleMainnetAPIKey"`
|
||||
RaribleTestnetAPIKey string `json:"RaribleTestnetAPIKey"`
|
||||
AlchemyAPIKeys map[uint64]string `json:"AlchemyAPIKeys"`
|
||||
InfuraAPIKey string `json:"InfuraAPIKey"`
|
||||
InfuraAPIKeySecret string `json:"InfuraAPIKeySecret"`
|
||||
StatusProxyMarketUser string `json:"StatusProxyMarketUser"`
|
||||
StatusProxyMarketPassword string `json:"StatusProxyMarketPassword"`
|
||||
EnableCelerBridge bool `json:"EnableCelerBridge"`
|
||||
Enabled bool
|
||||
OpenseaAPIKey string `json:"OpenseaAPIKey"`
|
||||
RaribleMainnetAPIKey string `json:"RaribleMainnetAPIKey"`
|
||||
RaribleTestnetAPIKey string `json:"RaribleTestnetAPIKey"`
|
||||
AlchemyAPIKeys map[uint64]string `json:"AlchemyAPIKeys"`
|
||||
InfuraAPIKey string `json:"InfuraAPIKey"`
|
||||
InfuraAPIKeySecret string `json:"InfuraAPIKeySecret"`
|
||||
StatusProxyMarketUser string `json:"StatusProxyMarketUser"`
|
||||
StatusProxyMarketPassword string `json:"StatusProxyMarketPassword"`
|
||||
StatusProxyBlockchainUser string `json:"StatusProxyBlockchainUser"`
|
||||
StatusProxyBlockchainPassword string `json:"StatusProxyBlockchainPassword"`
|
||||
StatusProxyEnabled bool `json:"StatusProxyEnabled"`
|
||||
EnableCelerBridge bool `json:"EnableCelerBridge"`
|
||||
}
|
||||
|
||||
// LocalNotificationsConfig extra configuration for localnotifications.Service.
|
||||
|
|
|
@ -86,6 +86,7 @@ type CreateAccount struct {
|
|||
|
||||
KeycardInstanceUID string `json:"keycardInstanceUID"`
|
||||
KeycardPairingDataFile *string `json:"keycardPairingDataFile"`
|
||||
StatusProxyEnabled bool `json:"statusProxyEnabled"`
|
||||
}
|
||||
|
||||
type WalletSecretsConfig struct {
|
||||
|
@ -96,17 +97,19 @@ type WalletSecretsConfig struct {
|
|||
RaribleMainnetAPIKey string `json:"raribleMainnetApiKey"`
|
||||
RaribleTestnetAPIKey string `json:"raribleTestnetApiKey"`
|
||||
|
||||
AlchemyEthereumMainnetToken string `json:"alchemyEthereumMainnetToken"`
|
||||
AlchemyEthereumGoerliToken string `json:"alchemyEthereumGoerliToken"`
|
||||
AlchemyEthereumSepoliaToken string `json:"alchemyEthereumSepoliaToken"`
|
||||
AlchemyArbitrumMainnetToken string `json:"alchemyArbitrumMainnetToken"`
|
||||
AlchemyArbitrumGoerliToken string `json:"alchemyArbitrumGoerliToken"`
|
||||
AlchemyArbitrumSepoliaToken string `json:"alchemyArbitrumSepoliaToken"`
|
||||
AlchemyOptimismMainnetToken string `json:"alchemyOptimismMainnetToken"`
|
||||
AlchemyOptimismGoerliToken string `json:"alchemyOptimismGoerliToken"`
|
||||
AlchemyOptimismSepoliaToken string `json:"alchemyOptimismSepoliaToken"`
|
||||
StatusProxyMarketUser string `json:"statusProxyMarketUser"`
|
||||
StatusProxyMarketPassword string `json:"statusProxyMarketPassword"`
|
||||
AlchemyEthereumMainnetToken string `json:"alchemyEthereumMainnetToken"`
|
||||
AlchemyEthereumGoerliToken string `json:"alchemyEthereumGoerliToken"`
|
||||
AlchemyEthereumSepoliaToken string `json:"alchemyEthereumSepoliaToken"`
|
||||
AlchemyArbitrumMainnetToken string `json:"alchemyArbitrumMainnetToken"`
|
||||
AlchemyArbitrumGoerliToken string `json:"alchemyArbitrumGoerliToken"`
|
||||
AlchemyArbitrumSepoliaToken string `json:"alchemyArbitrumSepoliaToken"`
|
||||
AlchemyOptimismMainnetToken string `json:"alchemyOptimismMainnetToken"`
|
||||
AlchemyOptimismGoerliToken string `json:"alchemyOptimismGoerliToken"`
|
||||
AlchemyOptimismSepoliaToken string `json:"alchemyOptimismSepoliaToken"`
|
||||
StatusProxyMarketUser string `json:"statusProxyMarketUser"`
|
||||
StatusProxyMarketPassword string `json:"statusProxyMarketPassword"`
|
||||
StatusProxyBlockchainUser string `json:"statusProxyBlockchainUser"`
|
||||
StatusProxyBlockchainPassword string `json:"statusProxyBlockchainPassword"`
|
||||
|
||||
// Testing
|
||||
GanacheURL string `json:"ganacheURL"`
|
||||
|
|
|
@ -35,7 +35,8 @@ type Login struct {
|
|||
|
||||
WalletSecretsConfig
|
||||
|
||||
APIConfig *APIConfig `json:"apiConfig"`
|
||||
APIConfig *APIConfig `json:"apiConfig"`
|
||||
StatusProxyEnabled bool `json:"statusProxyEnabled"`
|
||||
}
|
||||
|
||||
func (c *Login) Validate() error {
|
||||
|
|
149
rpc/client.go
149
rpc/client.go
|
@ -3,12 +3,12 @@ package rpc
|
|||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -26,6 +26,11 @@ import (
|
|||
const (
|
||||
// DefaultCallTimeout is a default timeout for an RPC call
|
||||
DefaultCallTimeout = time.Minute
|
||||
|
||||
// Names of providers
|
||||
providerGrove = "grove"
|
||||
providerInfura = "infura"
|
||||
ProviderStatusProxy = "status-proxy"
|
||||
)
|
||||
|
||||
// List of RPC client errors.
|
||||
|
@ -67,7 +72,8 @@ type Client struct {
|
|||
handlers map[string]Handler // locally registered handlers
|
||||
log log.Logger
|
||||
|
||||
walletNotifier func(chainID uint64, message string)
|
||||
walletNotifier func(chainID uint64, message string)
|
||||
providerConfigs []params.ProviderConfig
|
||||
}
|
||||
|
||||
// Is initialized in a build-tag-dependent module
|
||||
|
@ -78,7 +84,7 @@ var verifProxyInitFn func(c *Client)
|
|||
//
|
||||
// Client is safe for concurrent use and will automatically
|
||||
// reconnect to the server if connection is lost.
|
||||
func NewClient(client *gethrpc.Client, upstreamChainID uint64, upstream params.UpstreamRPCConfig, networks []params.Network, db *sql.DB) (*Client, error) {
|
||||
func NewClient(client *gethrpc.Client, upstreamChainID uint64, upstream params.UpstreamRPCConfig, networks []params.Network, db *sql.DB, providerConfigs []params.ProviderConfig) (*Client, error) {
|
||||
var err error
|
||||
|
||||
log := log.New("package", "status-go/rpc.Client")
|
||||
|
@ -99,6 +105,7 @@ func NewClient(client *gethrpc.Client, upstreamChainID uint64, upstream params.U
|
|||
rpcClients: make(map[uint64]chain.ClientInterface),
|
||||
limiterPerProvider: make(map[string]*chain.RPCRpsLimiter),
|
||||
log: log,
|
||||
providerConfigs: providerConfigs,
|
||||
}
|
||||
|
||||
if upstream.Enabled {
|
||||
|
@ -133,18 +140,6 @@ func (c *Client) SetWalletNotifier(notifier func(chainID uint64, message string)
|
|||
c.walletNotifier = notifier
|
||||
}
|
||||
|
||||
func extractLastParamFromURL(inputURL string) (string, error) {
|
||||
parsedURL, err := url.Parse(inputURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
pathSegments := strings.Split(parsedURL.Path, "/")
|
||||
lastSegment := pathSegments[len(pathSegments)-1]
|
||||
|
||||
return lastSegment, nil
|
||||
}
|
||||
|
||||
func extractHostAndPortFromURL(inputURL string) (string, error) {
|
||||
parsedURL, err := url.Parse(inputURL)
|
||||
if err != nil {
|
||||
|
@ -154,21 +149,26 @@ func extractHostAndPortFromURL(inputURL string) (string, error) {
|
|||
return parsedURL.Host, nil
|
||||
}
|
||||
|
||||
func (c *Client) getRPCRpsLimiter(URL string) (*chain.RPCRpsLimiter, error) {
|
||||
apiKey, err := extractLastParamFromURL(URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func (c *Client) getRPCRpsLimiter(key string) (*chain.RPCRpsLimiter, error) {
|
||||
c.rpsLimiterMutex.Lock()
|
||||
defer c.rpsLimiterMutex.Unlock()
|
||||
if limiter, ok := c.limiterPerProvider[apiKey]; ok {
|
||||
if limiter, ok := c.limiterPerProvider[key]; ok {
|
||||
return limiter, nil
|
||||
}
|
||||
limiter := chain.NewRPCRpsLimiter()
|
||||
c.limiterPerProvider[apiKey] = limiter
|
||||
c.limiterPerProvider[key] = limiter
|
||||
return limiter, nil
|
||||
}
|
||||
|
||||
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 (c *Client) getClientUsingCache(chainID uint64) (chain.ClientInterface, error) {
|
||||
c.rpcClientsMutex.Lock()
|
||||
defer c.rpcClientsMutex.Unlock()
|
||||
|
@ -187,45 +187,9 @@ func (c *Client) getClientUsingCache(chainID uint64) (chain.ClientInterface, err
|
|||
return nil, fmt.Errorf("could not find network: %d", chainID)
|
||||
}
|
||||
|
||||
rpcClient, err := gethrpc.Dial(network.RPCURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dial upstream server: %s", err)
|
||||
}
|
||||
|
||||
rpcLimiter, err := c.getRPCRpsLimiter(network.RPCURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get RPC limiter: %s", err)
|
||||
}
|
||||
|
||||
hostPortMain, err := extractHostAndPortFromURL(network.RPCURL)
|
||||
if err != nil {
|
||||
hostPortMain = "main"
|
||||
}
|
||||
|
||||
ethClients := []*chain.EthClient{
|
||||
chain.NewEthClient(ethclient.NewClient(rpcClient), rpcLimiter, rpcClient, hostPortMain),
|
||||
}
|
||||
|
||||
var (
|
||||
rpcFallbackClient *gethrpc.Client
|
||||
rpcFallbackLimiter *chain.RPCRpsLimiter
|
||||
)
|
||||
if len(network.FallbackURL) > 0 {
|
||||
rpcFallbackClient, err = gethrpc.Dial(network.FallbackURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dial upstream server: %s", err)
|
||||
}
|
||||
|
||||
rpcFallbackLimiter, err = c.getRPCRpsLimiter(network.FallbackURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get RPC fallback limiter: %s", err)
|
||||
}
|
||||
hostPortFallback, err := extractHostAndPortFromURL(network.FallbackURL)
|
||||
if err != nil {
|
||||
hostPortFallback = "fallback"
|
||||
}
|
||||
|
||||
ethClients = append(ethClients, chain.NewEthClient(ethclient.NewClient(rpcFallbackClient), rpcFallbackLimiter, rpcFallbackClient, hostPortFallback))
|
||||
ethClients := c.getEthClents(network)
|
||||
if len(ethClients) == 0 {
|
||||
return nil, fmt.Errorf("could not find any RPC URL for chain: %d", chainID)
|
||||
}
|
||||
|
||||
client := chain.NewClient(ethClients, chainID)
|
||||
|
@ -234,6 +198,69 @@ func (c *Client) getClientUsingCache(chainID uint64) (chain.ClientInterface, err
|
|||
return client, nil
|
||||
}
|
||||
|
||||
func (c *Client) getEthClents(network *params.Network) []*chain.EthClient {
|
||||
urls := make(map[string]string)
|
||||
keys := make([]string, 0)
|
||||
authMap := make(map[string]string)
|
||||
|
||||
// find proxy provider
|
||||
proxyProvider, err := getProviderConfig(c.providerConfigs, ProviderStatusProxy)
|
||||
if err != nil {
|
||||
c.log.Warn("could not find provider config for status-proxy", "error", err)
|
||||
}
|
||||
|
||||
if proxyProvider.Enabled {
|
||||
key := ProviderStatusProxy
|
||||
keyFallback := ProviderStatusProxy + "-fallback"
|
||||
urls[key] = network.DefaultRPCURL
|
||||
urls[keyFallback] = network.DefaultFallbackURL
|
||||
keys = []string{key, keyFallback}
|
||||
authMap[key] = proxyProvider.User + ":" + proxyProvider.Password
|
||||
authMap[keyFallback] = authMap[key]
|
||||
}
|
||||
keys = append(keys, []string{"main", "fallback"}...)
|
||||
urls["main"] = network.RPCURL
|
||||
urls["fallback"] = network.FallbackURL
|
||||
|
||||
ethClients := make([]*chain.EthClient, 0)
|
||||
for _, key := range keys {
|
||||
var rpcClient *gethrpc.Client
|
||||
var rpcLimiter *chain.RPCRpsLimiter
|
||||
var err error
|
||||
var hostPort string
|
||||
url := urls[key]
|
||||
|
||||
if len(url) > 0 {
|
||||
// For now we only support auth for status-proxy.
|
||||
authStr, ok := authMap[key]
|
||||
var opts []gethrpc.ClientOption
|
||||
if ok {
|
||||
authEncoded := base64.StdEncoding.EncodeToString([]byte(authStr))
|
||||
opts = append(opts, gethrpc.WithHeader("Authorization", "Basic "+authEncoded))
|
||||
}
|
||||
|
||||
rpcClient, err = gethrpc.DialOptions(context.Background(), url, opts...)
|
||||
if err != nil {
|
||||
c.log.Error("dial server "+key, "error", err)
|
||||
}
|
||||
|
||||
hostPort, err = extractHostAndPortFromURL(url)
|
||||
if err != nil {
|
||||
hostPort = key
|
||||
}
|
||||
|
||||
rpcLimiter, err = c.getRPCRpsLimiter(hostPort)
|
||||
if err != nil {
|
||||
c.log.Error("get RPC limiter "+key, "error", err)
|
||||
}
|
||||
|
||||
ethClients = append(ethClients, chain.NewEthClient(ethclient.NewClient(rpcClient), rpcLimiter, rpcClient, hostPort))
|
||||
}
|
||||
}
|
||||
|
||||
return ethClients
|
||||
}
|
||||
|
||||
// Ethclient returns ethclient.Client per chain
|
||||
func (c *Client) EthClient(chainID uint64) (chain.ClientInterface, error) {
|
||||
client, err := c.getClientUsingCache(chainID)
|
||||
|
|
|
@ -3,17 +3,22 @@ package rpc
|
|||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"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/t/helpers"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
gethrpc "github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
|
@ -39,7 +44,7 @@ func TestBlockedRoutesCall(t *testing.T) {
|
|||
gethRPCClient, err := gethrpc.Dial(ts.URL)
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := NewClient(gethRPCClient, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
|
||||
c, err := NewClient(gethRPCClient, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, m := range blockedMethods {
|
||||
|
@ -78,7 +83,7 @@ func TestBlockedRoutesRawCall(t *testing.T) {
|
|||
gethRPCClient, err := gethrpc.Dial(ts.URL)
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := NewClient(gethRPCClient, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
|
||||
c, err := NewClient(gethRPCClient, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, m := range blockedMethods {
|
||||
|
@ -105,7 +110,7 @@ func TestUpdateUpstreamURL(t *testing.T) {
|
|||
gethRPCClient, err := gethrpc.Dial(ts.URL)
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := NewClient(gethRPCClient, 1, params.UpstreamRPCConfig{Enabled: true, URL: ts.URL}, []params.Network{}, db)
|
||||
c, err := NewClient(gethRPCClient, 1, params.UpstreamRPCConfig{Enabled: true, URL: ts.URL}, []params.Network{}, db, nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, ts.URL, c.upstreamURL)
|
||||
|
||||
|
@ -132,3 +137,62 @@ func createTestServer(resp string) *httptest.Server {
|
|||
fmt.Fprintln(w, resp)
|
||||
}))
|
||||
}
|
||||
|
||||
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(2) // 2 providers
|
||||
|
||||
// Create a new ServeMux
|
||||
mux := http.NewServeMux()
|
||||
|
||||
path1 := "/foo"
|
||||
path2 := "/bar"
|
||||
// Register handlers for different URL paths
|
||||
mux.HandleFunc(path1, func(w http.ResponseWriter, r *http.Request) {
|
||||
authToken := base64.StdEncoding.EncodeToString([]byte(providerConfig.User + ":" + providerConfig.Password))
|
||||
require.Equal(t, fmt.Sprintf("Basic %s", authToken), r.Header.Get("Authorization"))
|
||||
wg.Done()
|
||||
})
|
||||
|
||||
mux.HandleFunc(path2, func(w http.ResponseWriter, r *http.Request) {
|
||||
authToken := base64.StdEncoding.EncodeToString([]byte(providerConfig.User + ":" + providerConfig.Password))
|
||||
require.Equal(t, fmt.Sprintf("Basic %s", authToken), r.Header.Get("Authorization"))
|
||||
wg.Done()
|
||||
})
|
||||
|
||||
// Create a new server with the mux as the handler
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
|
||||
networks := []params.Network{
|
||||
{
|
||||
ChainID: 1,
|
||||
DefaultRPCURL: server.URL + path1,
|
||||
DefaultFallbackURL: server.URL + path2,
|
||||
},
|
||||
}
|
||||
c, err := NewClient(nil, 1, params.UpstreamRPCConfig{}, networks, db, providerConfigs)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Networks from DB must pick up DefaultRPCURL and DefaultFallbackURL
|
||||
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.Nil(t, balance)
|
||||
wg.Wait()
|
||||
}
|
||||
|
|
|
@ -169,6 +169,7 @@ func (nm *Manager) Init(networks []params.Network) error {
|
|||
if err != nil {
|
||||
errors += fmt.Sprintf("error updating network original url for ChainID: %d, %s", currentNetworks[j].ChainID, err.Error())
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -230,12 +231,15 @@ func (nm *Manager) Find(chainID uint64) *params.Network {
|
|||
if len(networks) != 1 || err != nil {
|
||||
return nil
|
||||
}
|
||||
setDefaultRPCURL(networks, nm.configuredNetworks)
|
||||
return networks[0]
|
||||
}
|
||||
|
||||
func (nm *Manager) GetAll() ([]*params.Network, error) {
|
||||
query := newNetworksQuery()
|
||||
return query.exec(nm.db)
|
||||
networks, err := query.exec(nm.db)
|
||||
setDefaultRPCURL(networks, nm.configuredNetworks)
|
||||
return networks, err
|
||||
}
|
||||
|
||||
func (nm *Manager) Get(onlyEnabled bool) ([]*params.Network, error) {
|
||||
|
@ -282,6 +286,12 @@ func (nm *Manager) Get(onlyEnabled bool) ([]*params.Network, error) {
|
|||
continue
|
||||
}
|
||||
}
|
||||
|
||||
configuredNetwork, err := findNetwork(nm.configuredNetworks, network.ChainID)
|
||||
if err != nil {
|
||||
addDefaultRPCURL(network, configuredNetwork)
|
||||
}
|
||||
|
||||
results = append(results, network)
|
||||
}
|
||||
|
||||
|
@ -355,3 +365,28 @@ func (nm *Manager) GetActiveNetworks() ([]*params.Network, error) {
|
|||
|
||||
return availableNetworks, nil
|
||||
}
|
||||
|
||||
func findNetwork(networks []params.Network, chainID uint64) (params.Network, error) {
|
||||
for _, network := range networks {
|
||||
if network.ChainID == chainID {
|
||||
return network, nil
|
||||
}
|
||||
}
|
||||
return params.Network{}, fmt.Errorf("network not found")
|
||||
}
|
||||
|
||||
func addDefaultRPCURL(target *params.Network, source params.Network) {
|
||||
target.DefaultRPCURL = source.DefaultRPCURL
|
||||
target.DefaultFallbackURL = source.DefaultFallbackURL
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ func setupTestAPI(t *testing.T) (*API, func()) {
|
|||
}
|
||||
|
||||
client := gethrpc.DialInProc(server)
|
||||
rpcClient, err := statusRPC.NewClient(client, 1, upstreamConfig, nil, db)
|
||||
rpcClient, err := statusRPC.NewClient(client, 1, upstreamConfig, nil, db, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
service := NewService(db, rpcClient, nil)
|
||||
|
|
|
@ -28,7 +28,7 @@ func TestNewService(t *testing.T) {
|
|||
}
|
||||
|
||||
client := gethrpc.DialInProc(server)
|
||||
rpcClient, err := statusRPC.NewClient(client, 1, upstreamConfig, nil, db)
|
||||
rpcClient, err := statusRPC.NewClient(client, 1, upstreamConfig, nil, db, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
service := NewService(db, rpcClient, rpcClient.NetworkManager)
|
||||
|
|
|
@ -40,7 +40,7 @@ func setupTestAPI(t *testing.T) (*API, func()) {
|
|||
|
||||
_ = client
|
||||
|
||||
rpcClient, err := statusRPC.NewClient(nil, 1, upstreamConfig, nil, db)
|
||||
rpcClient, err := statusRPC.NewClient(nil, 1, upstreamConfig, nil, db, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// import account keys
|
||||
|
|
|
@ -405,7 +405,7 @@ func Test_removeBalanceHistoryOnEventAccountRemoved(t *testing.T) {
|
|||
txServiceMockCtrl := gomock.NewController(t)
|
||||
server, _ := fake.NewTestServer(txServiceMockCtrl)
|
||||
client := gethrpc.DialInProc(server)
|
||||
rpcClient, _ := rpc.NewClient(client, chainID, params.UpstreamRPCConfig{}, nil, appDB)
|
||||
rpcClient, _ := rpc.NewClient(client, chainID, params.UpstreamRPCConfig{}, nil, appDB, nil)
|
||||
rpcClient.UpstreamChainID = chainID
|
||||
|
||||
service := NewService(walletDB, accountsDB, &accountFeed, &walletFeed, rpcClient, nil, nil, nil)
|
||||
|
|
|
@ -90,7 +90,7 @@ func setupTestNetworkDB(t *testing.T) (*sql.DB, func()) {
|
|||
func setupRouter(t *testing.T) (*Router, func()) {
|
||||
db, cleanTmpDb := setupTestNetworkDB(t)
|
||||
|
||||
client, _ := rpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, defaultNetworks, db)
|
||||
client, _ := rpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, defaultNetworks, db, nil)
|
||||
|
||||
router := NewRouter(client, nil, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
|
|
|
@ -7,13 +7,15 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/status-im/status-go/buildinfo"
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty/utils"
|
||||
)
|
||||
|
||||
const baseURL = "https://min-api.cryptocompare.com"
|
||||
const CryptoCompareStatusProxyURL = "https://cryptocompare.test.api.status.im"
|
||||
const extraParamStatus = "Status.im"
|
||||
const baseURL = "https://min-api.cryptocompare.com"
|
||||
|
||||
var CryptoCompareStatusProxyURL = fmt.Sprintf("https://%s.api.status.im/cryptocompare/", buildinfo.ApiProxyStageName)
|
||||
|
||||
type HistoricalPricesContainer struct {
|
||||
Aggregated bool `json:"Aggregated"`
|
||||
|
|
|
@ -331,7 +331,7 @@ func Test_removeTokenBalanceOnEventAccountRemoved(t *testing.T) {
|
|||
txServiceMockCtrl := gomock.NewController(t)
|
||||
server, _ := fake.NewTestServer(txServiceMockCtrl)
|
||||
client := gethrpc.DialInProc(server)
|
||||
rpcClient, _ := rpc.NewClient(client, chainID, params.UpstreamRPCConfig{}, nil, appDB)
|
||||
rpcClient, _ := rpc.NewClient(client, chainID, params.UpstreamRPCConfig{}, nil, appDB, nil)
|
||||
rpcClient.UpstreamChainID = chainID
|
||||
nm := network.NewManager(appDB)
|
||||
mediaServer, err := mediaserver.NewMediaServer(appDB, nil, nil, walletDB)
|
||||
|
|
|
@ -1076,7 +1076,7 @@ func setupFindBlocksCommand(t *testing.T, accountAddress common.Address, fromBlo
|
|||
|
||||
return nil
|
||||
}
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db, nil)
|
||||
client.SetClient(tc.NetworkID(), tc)
|
||||
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil, nil, nil, token.NewPersistence(db))
|
||||
tokenManager.SetTokens([]*token.Token{
|
||||
|
@ -1339,7 +1339,7 @@ func TestFetchTransfersForLoadedBlocks(t *testing.T) {
|
|||
currentBlock: 100,
|
||||
}
|
||||
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db, nil)
|
||||
client.SetClient(tc.NetworkID(), tc)
|
||||
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil, nil, nil, token.NewPersistence(db))
|
||||
|
||||
|
@ -1463,7 +1463,7 @@ func TestFetchNewBlocksCommand_findBlocksWithEthTransfers(t *testing.T) {
|
|||
currentBlock: 100,
|
||||
}
|
||||
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db, nil)
|
||||
client.SetClient(tc.NetworkID(), tc)
|
||||
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil, nil, nil, token.NewPersistence(db))
|
||||
|
||||
|
@ -1543,7 +1543,7 @@ func TestFetchNewBlocksCommand_nonceDetection(t *testing.T) {
|
|||
mediaServer, err := server.NewMediaServer(appdb, nil, nil, db)
|
||||
require.NoError(t, err)
|
||||
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db, nil)
|
||||
client.SetClient(tc.NetworkID(), tc)
|
||||
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil, nil, nil, token.NewPersistence(db))
|
||||
|
||||
|
@ -1657,7 +1657,7 @@ func TestFetchNewBlocksCommand(t *testing.T) {
|
|||
}
|
||||
//tc.printPreparedData = true
|
||||
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db, nil)
|
||||
client.SetClient(tc.NetworkID(), tc)
|
||||
|
||||
tokenManager := token.NewTokenManager(db, client, community.NewManager(appdb, nil, nil), network.NewManager(appdb), appdb, mediaServer, nil, nil, nil, token.NewPersistence(db))
|
||||
|
@ -1796,7 +1796,7 @@ func TestLoadBlocksAndTransfersCommand_FiniteFinishedInfiniteRunning(t *testing.
|
|||
db, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
||||
require.NoError(t, err)
|
||||
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db)
|
||||
client, _ := statusRpc.NewClient(nil, 1, params.UpstreamRPCConfig{Enabled: false, URL: ""}, []params.Network{}, db, nil)
|
||||
maker, _ := contracts.NewContractMaker(client)
|
||||
|
||||
wdb := NewDB(db)
|
||||
|
|
|
@ -45,7 +45,7 @@ func setupTestAPI(t *testing.T) (*API, func()) {
|
|||
server, _ := fake.NewTestServer(txServiceMockCtrl)
|
||||
client := gethrpc.DialInProc(server)
|
||||
|
||||
rpcClient, err := statusRPC.NewClient(client, 1, upstreamConfig, nil, db)
|
||||
rpcClient, err := statusRPC.NewClient(client, 1, upstreamConfig, nil, db, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// import account keys
|
||||
|
|
|
@ -55,7 +55,7 @@ func (s *TransactorSuite) SetupTest() {
|
|||
chainID := gethparams.AllEthashProtocolChanges.ChainID.Uint64()
|
||||
db, err := sqlite.OpenUnecryptedDB(sqlite.InMemoryPath) // dummy to make rpc.Client happy
|
||||
s.Require().NoError(err)
|
||||
rpcClient, _ := rpc.NewClient(s.client, chainID, params.UpstreamRPCConfig{}, nil, db)
|
||||
rpcClient, _ := rpc.NewClient(s.client, chainID, params.UpstreamRPCConfig{}, nil, db, nil)
|
||||
rpcClient.UpstreamChainID = chainID
|
||||
nodeConfig, err := utils.MakeTestNodeConfigWithDataDir("", "/tmp", chainID)
|
||||
s.Require().NoError(err)
|
||||
|
|
Loading…
Reference in New Issue