//go:build validation // +build validation package main import ( "fmt" "os" "regexp" "strings" "github.com/fraktal/mev-beta/internal/config" ) func main() { if len(os.Args) != 2 { fmt.Fprintf(os.Stderr, "Usage: %s \n", os.Args[0]) os.Exit(1) } configFile := os.Args[1] // Load configuration cfg, err := config.Load(configFile) if err != nil { fmt.Fprintf(os.Stderr, "Failed to load config: %v\n", err) os.Exit(1) } // Validate configuration if err := validateConfig(cfg); err != nil { fmt.Fprintf(os.Stderr, "Configuration validation failed: %v\n", err) os.Exit(1) } fmt.Println("Configuration validation successful") } func validateConfig(cfg *config.Config) error { // Validate Arbitrum configuration if err := validateArbitrumConfig(&cfg.Arbitrum); err != nil { return fmt.Errorf("arbitrum config: %w", err) } // Validate bot configuration if err := validateBotConfig(&cfg.Bot); err != nil { return fmt.Errorf("bot config: %w", err) } // Validate other configurations... return nil } func validateArbitrumConfig(cfg *config.ArbitrumConfig) error { // Validate RPC endpoint format if cfg.RPCEndpoint == "" { return fmt.Errorf("rpc_endpoint is required") } if !isValidEndpoint(cfg.RPCEndpoint) { return fmt.Errorf("invalid rpc_endpoint format: %s", cfg.RPCEndpoint) } // Validate chain ID if cfg.ChainID != 42161 { return fmt.Errorf("chain_id must be 42161 for Arbitrum mainnet, got: %d", cfg.ChainID) } // Validate rate limits if cfg.RateLimit.RequestsPerSecond <= 0 { return fmt.Errorf("requests_per_second must be positive, got: %d", cfg.RateLimit.RequestsPerSecond) } if cfg.RateLimit.MaxConcurrent <= 0 { return fmt.Errorf("max_concurrent must be positive, got: %d", cfg.RateLimit.MaxConcurrent) } // Validate fallback endpoints for i, endpoint := range cfg.FallbackEndpoints { if !isValidEndpoint(endpoint.URL) { return fmt.Errorf("invalid fallback endpoint %d: %s", i, endpoint.URL) } } return nil } func validateBotConfig(cfg *config.BotConfig) error { // Validate worker count if cfg.MaxWorkers <= 0 { return fmt.Errorf("max_workers must be positive, got: %d", cfg.MaxWorkers) } if cfg.MaxWorkers > 100 { return fmt.Errorf("max_workers should not exceed 100 for stability, got: %d", cfg.MaxWorkers) } // Validate buffer size if cfg.ChannelBufferSize <= 0 { return fmt.Errorf("channel_buffer_size must be positive, got: %d", cfg.ChannelBufferSize) } return nil } func isValidEndpoint(endpoint string) bool { // Remove environment variable syntax if present endpoint = strings.TrimSpace(endpoint) if strings.Contains(endpoint, "${") { // Skip validation for environment variables return true } // Check if it's a valid HTTP/HTTPS/WS/WSS URL httpRegex := regexp.MustCompile(`^https?://[a-zA-Z0-9.-]+[a-zA-Z0-9.-]*[a-zA-Z0-9]/?(.*)?$`) wsRegex := regexp.MustCompile(`^wss?://[a-zA-Z0-9.-]+[a-zA-Z0-9.-]*[a-zA-Z0-9]/?(.*)?$`) return httpRegex.MatchString(endpoint) || wsRegex.MatchString(endpoint) }