2022-05-05 00:51:24 +03:00
|
|
|
package proxyd
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2023-07-19 23:21:00 +03:00
|
|
|
"math/big"
|
2022-05-05 00:51:24 +03:00
|
|
|
"os"
|
|
|
|
"strings"
|
2022-09-15 11:46:11 +03:00
|
|
|
"time"
|
2024-07-23 00:44:27 +03:00
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/log"
|
2022-05-05 00:51:24 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
type ServerConfig struct {
|
|
|
|
RPCHost string `toml:"rpc_host"`
|
|
|
|
RPCPort int `toml:"rpc_port"`
|
|
|
|
WSHost string `toml:"ws_host"`
|
|
|
|
WSPort int `toml:"ws_port"`
|
|
|
|
MaxBodySizeBytes int64 `toml:"max_body_size_bytes"`
|
|
|
|
MaxConcurrentRPCs int64 `toml:"max_concurrent_rpcs"`
|
2022-10-14 21:56:27 +03:00
|
|
|
LogLevel string `toml:"log_level"`
|
2022-05-05 00:51:24 +03:00
|
|
|
|
|
|
|
// TimeoutSeconds specifies the maximum time spent serving an HTTP request. Note that isn't used for websocket connections
|
|
|
|
TimeoutSeconds int `toml:"timeout_seconds"`
|
|
|
|
|
|
|
|
MaxUpstreamBatchSize int `toml:"max_upstream_batch_size"`
|
2022-07-27 20:12:47 +03:00
|
|
|
|
2023-11-02 22:38:04 +03:00
|
|
|
EnableRequestLog bool `toml:"enable_request_log"`
|
|
|
|
MaxRequestBodyLogLen int `toml:"max_request_body_log_len"`
|
|
|
|
EnablePprof bool `toml:"enable_pprof"`
|
2023-10-19 22:48:03 +03:00
|
|
|
EnableXServedByHeader bool `toml:"enable_served_by_header"`
|
2024-04-12 01:07:16 +03:00
|
|
|
AllowAllOrigins bool `toml:"allow_all_origins"`
|
2022-05-05 00:51:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type CacheConfig struct {
|
2024-02-24 00:58:00 +03:00
|
|
|
Enabled bool `toml:"enabled"`
|
|
|
|
TTL TOMLDuration `toml:"ttl"`
|
2022-05-05 00:51:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type RedisConfig struct {
|
2023-05-14 08:33:09 +03:00
|
|
|
URL string `toml:"url"`
|
|
|
|
Namespace string `toml:"namespace"`
|
2024-08-19 23:23:09 +03:00
|
|
|
ReadURL string `toml:"read_url"`
|
2022-05-05 00:51:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type MetricsConfig struct {
|
|
|
|
Enabled bool `toml:"enabled"`
|
|
|
|
Host string `toml:"host"`
|
|
|
|
Port int `toml:"port"`
|
|
|
|
}
|
|
|
|
|
2022-08-04 20:34:43 +03:00
|
|
|
type RateLimitConfig struct {
|
2023-05-15 22:28:41 +03:00
|
|
|
UseRedis bool `toml:"use_redis"`
|
|
|
|
BaseRate int `toml:"base_rate"`
|
|
|
|
BaseInterval TOMLDuration `toml:"base_interval"`
|
|
|
|
ExemptOrigins []string `toml:"exempt_origins"`
|
|
|
|
ExemptUserAgents []string `toml:"exempt_user_agents"`
|
|
|
|
ErrorMessage string `toml:"error_message"`
|
|
|
|
MethodOverrides map[string]*RateLimitMethodOverride `toml:"method_overrides"`
|
2023-11-02 22:38:04 +03:00
|
|
|
IPHeaderOverride string `toml:"ip_header_override"`
|
2022-09-15 11:46:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type RateLimitMethodOverride struct {
|
|
|
|
Limit int `toml:"limit"`
|
|
|
|
Interval TOMLDuration `toml:"interval"`
|
2023-02-15 10:42:44 +03:00
|
|
|
Global bool `toml:"global"`
|
2022-09-15 11:46:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type TOMLDuration time.Duration
|
|
|
|
|
|
|
|
func (t *TOMLDuration) UnmarshalText(b []byte) error {
|
|
|
|
d, err := time.ParseDuration(string(b))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
*t = TOMLDuration(d)
|
|
|
|
return nil
|
2022-08-04 20:34:43 +03:00
|
|
|
}
|
|
|
|
|
2022-05-05 00:51:24 +03:00
|
|
|
type BackendOptions struct {
|
2023-05-04 02:23:43 +03:00
|
|
|
ResponseTimeoutSeconds int `toml:"response_timeout_seconds"`
|
|
|
|
MaxResponseSizeBytes int64 `toml:"max_response_size_bytes"`
|
|
|
|
MaxRetries int `toml:"max_retries"`
|
|
|
|
OutOfServiceSeconds int `toml:"out_of_service_seconds"`
|
|
|
|
MaxDegradedLatencyThreshold TOMLDuration `toml:"max_degraded_latency_threshold"`
|
|
|
|
MaxLatencyThreshold TOMLDuration `toml:"max_latency_threshold"`
|
|
|
|
MaxErrorRateThreshold float64 `toml:"max_error_rate_threshold"`
|
2022-05-05 00:51:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type BackendConfig struct {
|
2023-11-11 12:52:09 +03:00
|
|
|
Username string `toml:"username"`
|
|
|
|
Password string `toml:"password"`
|
|
|
|
RPCURL string `toml:"rpc_url"`
|
|
|
|
WSURL string `toml:"ws_url"`
|
|
|
|
WSPort int `toml:"ws_port"`
|
|
|
|
MaxRPS int `toml:"max_rps"`
|
|
|
|
MaxWSConns int `toml:"max_ws_conns"`
|
|
|
|
CAFile string `toml:"ca_file"`
|
|
|
|
ClientCertFile string `toml:"client_cert_file"`
|
|
|
|
ClientKeyFile string `toml:"client_key_file"`
|
|
|
|
StripTrailingXFF bool `toml:"strip_trailing_xff"`
|
|
|
|
Headers map[string]string `toml:"headers"`
|
2023-06-01 23:16:40 +03:00
|
|
|
|
2023-11-01 23:01:02 +03:00
|
|
|
Weight int `toml:"weight"`
|
|
|
|
|
2023-06-01 23:16:40 +03:00
|
|
|
ConsensusSkipPeerCountCheck bool `toml:"consensus_skip_peer_count"`
|
2023-08-19 02:38:03 +03:00
|
|
|
ConsensusForcedCandidate bool `toml:"consensus_forced_candidate"`
|
2023-06-01 23:16:40 +03:00
|
|
|
ConsensusReceiptsTarget string `toml:"consensus_receipts_target"`
|
2022-05-05 00:51:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type BackendsConfig map[string]*BackendConfig
|
|
|
|
|
2024-07-23 00:44:27 +03:00
|
|
|
type RoutingStrategy string
|
|
|
|
|
|
|
|
func (b *BackendGroupConfig) ValidateRoutingStrategy(bgName string) bool {
|
|
|
|
|
|
|
|
// If Consensus Aware is Set and Routing RoutingStrategy is populated fail
|
|
|
|
if b.ConsensusAware && b.RoutingStrategy != "" {
|
|
|
|
log.Warn("consensus_aware is now deprecated, please use routing_strategy = consensus_aware")
|
|
|
|
log.Crit("Exiting consensus_aware and routing strategy are mutually exclusive, they cannot both be defined")
|
|
|
|
}
|
|
|
|
|
|
|
|
// If Consensus Aware is Set set RoutingStrategy to consensus_aware
|
|
|
|
if b.ConsensusAware {
|
|
|
|
b.RoutingStrategy = ConsensusAwareRoutingStrategy
|
|
|
|
log.Info("consensus_aware is now deprecated, please use routing_strategy = consenus_aware in the future")
|
|
|
|
}
|
|
|
|
|
|
|
|
switch b.RoutingStrategy {
|
|
|
|
case ConsensusAwareRoutingStrategy:
|
|
|
|
return true
|
|
|
|
case MulticallRoutingStrategy:
|
|
|
|
return true
|
|
|
|
case FallbackRoutingStrategy:
|
|
|
|
return true
|
|
|
|
case "":
|
|
|
|
log.Info("Empty routing strategy provided for backend_group, using fallback strategy ", "name", bgName)
|
|
|
|
b.RoutingStrategy = FallbackRoutingStrategy
|
|
|
|
return true
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
ConsensusAwareRoutingStrategy RoutingStrategy = "consensus_aware"
|
|
|
|
MulticallRoutingStrategy RoutingStrategy = "multicall"
|
|
|
|
FallbackRoutingStrategy RoutingStrategy = "fallback"
|
|
|
|
)
|
|
|
|
|
2022-05-05 00:51:24 +03:00
|
|
|
type BackendGroupConfig struct {
|
2023-05-04 02:23:43 +03:00
|
|
|
Backends []string `toml:"backends"`
|
|
|
|
|
2023-11-01 23:01:02 +03:00
|
|
|
WeightedRouting bool `toml:"weighted_routing"`
|
2023-11-01 04:41:55 +03:00
|
|
|
|
2024-07-23 00:44:27 +03:00
|
|
|
RoutingStrategy RoutingStrategy `toml:"routing_strategy"`
|
|
|
|
|
|
|
|
/*
|
|
|
|
Deprecated: Use routing_strategy config to create a consensus_aware proxyd instance
|
|
|
|
*/
|
2024-04-12 01:07:16 +03:00
|
|
|
ConsensusAware bool `toml:"consensus_aware"`
|
|
|
|
ConsensusAsyncHandler string `toml:"consensus_handler"`
|
|
|
|
ConsensusPollerInterval TOMLDuration `toml:"consensus_poller_interval"`
|
2023-05-04 02:23:43 +03:00
|
|
|
|
|
|
|
ConsensusBanPeriod TOMLDuration `toml:"consensus_ban_period"`
|
|
|
|
ConsensusMaxUpdateThreshold TOMLDuration `toml:"consensus_max_update_threshold"`
|
2023-05-09 02:29:05 +03:00
|
|
|
ConsensusMaxBlockLag uint64 `toml:"consensus_max_block_lag"`
|
2023-08-19 02:38:03 +03:00
|
|
|
ConsensusMaxBlockRange uint64 `toml:"consensus_max_block_range"`
|
2023-05-04 02:23:43 +03:00
|
|
|
ConsensusMinPeerCount int `toml:"consensus_min_peer_count"`
|
2023-09-14 22:36:24 +03:00
|
|
|
|
|
|
|
ConsensusHA bool `toml:"consensus_ha"`
|
|
|
|
ConsensusHAHeartbeatInterval TOMLDuration `toml:"consensus_ha_heartbeat_interval"`
|
|
|
|
ConsensusHALockPeriod TOMLDuration `toml:"consensus_ha_lock_period"`
|
2024-03-18 21:26:39 +03:00
|
|
|
ConsensusHARedis RedisConfig `toml:"consensus_ha_redis"`
|
2024-06-05 02:19:54 +03:00
|
|
|
|
|
|
|
Fallbacks []string `toml:"fallbacks"`
|
2022-05-05 00:51:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type BackendGroupsConfig map[string]*BackendGroupConfig
|
|
|
|
|
|
|
|
type MethodMappingsConfig map[string]string
|
|
|
|
|
2022-09-24 00:06:02 +03:00
|
|
|
type BatchConfig struct {
|
|
|
|
MaxSize int `toml:"max_size"`
|
|
|
|
ErrorMessage string `toml:"error_message"`
|
|
|
|
}
|
|
|
|
|
2023-01-23 02:40:26 +03:00
|
|
|
// SenderRateLimitConfig configures the sender-based rate limiter
|
|
|
|
// for eth_sendRawTransaction requests.
|
2023-12-12 21:04:52 +03:00
|
|
|
// To enable pre-eip155 transactions, add '0' to allowed_chain_ids.
|
2023-01-23 02:40:26 +03:00
|
|
|
type SenderRateLimitConfig struct {
|
2023-07-19 23:21:00 +03:00
|
|
|
Enabled bool
|
|
|
|
Interval TOMLDuration
|
|
|
|
Limit int
|
|
|
|
AllowedChainIds []*big.Int `toml:"allowed_chain_ids"`
|
2023-01-23 02:40:26 +03:00
|
|
|
}
|
|
|
|
|
2022-05-05 00:51:24 +03:00
|
|
|
type Config struct {
|
2023-01-23 02:40:26 +03:00
|
|
|
WSBackendGroup string `toml:"ws_backend_group"`
|
|
|
|
Server ServerConfig `toml:"server"`
|
|
|
|
Cache CacheConfig `toml:"cache"`
|
|
|
|
Redis RedisConfig `toml:"redis"`
|
|
|
|
Metrics MetricsConfig `toml:"metrics"`
|
|
|
|
RateLimit RateLimitConfig `toml:"rate_limit"`
|
|
|
|
BackendOptions BackendOptions `toml:"backend"`
|
|
|
|
Backends BackendsConfig `toml:"backends"`
|
|
|
|
BatchConfig BatchConfig `toml:"batch"`
|
|
|
|
Authentication map[string]string `toml:"authentication"`
|
|
|
|
BackendGroups BackendGroupsConfig `toml:"backend_groups"`
|
|
|
|
RPCMethodMappings map[string]string `toml:"rpc_method_mappings"`
|
|
|
|
WSMethodWhitelist []string `toml:"ws_method_whitelist"`
|
|
|
|
WhitelistErrorMessage string `toml:"whitelist_error_message"`
|
|
|
|
SenderRateLimit SenderRateLimitConfig `toml:"sender_rate_limit"`
|
2022-05-05 00:51:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func ReadFromEnvOrConfig(value string) (string, error) {
|
|
|
|
if strings.HasPrefix(value, "$") {
|
|
|
|
envValue := os.Getenv(strings.TrimPrefix(value, "$"))
|
|
|
|
if envValue == "" {
|
|
|
|
return "", fmt.Errorf("config env var %s not found", value)
|
|
|
|
}
|
|
|
|
return envValue, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.HasPrefix(value, "\\") {
|
|
|
|
return strings.TrimPrefix(value, "\\"), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return value, nil
|
|
|
|
}
|