package mining import ( "context" "time" ) const ( HighResolutionDuration = 5 * time.Minute HighResolutionInterval = 10 * time.Second LowResolutionInterval = 1 * time.Minute LowResHistoryRetention = 24 * time.Hour ) // miner, err := factory.Create("xmrig") // if err := miner.Install(); err != nil { return err } // if err := miner.Start(&Config{Algo: "rx/0", Pool: "stratum+tcp://pool.example.com:3333"}); err != nil { return err } // stats, err := miner.GetStats(ctx) // defer miner.Stop() type Miner interface { // Lifecycle operations Install() error Uninstall() error Start(config *Config) error Stop() error // Stats operations GetStats(ctx context.Context) (*PerformanceMetrics, error) // Info operations GetType() string // switch miner.GetType() { case "xmrig": ...; case "tt-miner": ... } GetName() string GetPath() string GetBinaryPath() string CheckInstallation() (*InstallationDetails, error) GetLatestVersion() (string, error) // History operations GetHashrateHistory() []HashratePoint AddHashratePoint(point HashratePoint) ReduceHashrateHistory(now time.Time) // IO operations GetLogs() []string WriteStdin(input string) error } // details, err := miner.CheckInstallation() // if details.IsInstalled { logging.Info("installed", logging.Fields{"version": details.Version}) } type InstallationDetails struct { IsInstalled bool `json:"is_installed"` Version string `json:"version"` Path string `json:"path"` MinerBinary string `json:"miner_binary"` ConfigPath string `json:"config_path,omitempty"` // Add path to the miner-specific config } // info := SystemInfo{OS: "linux", Architecture: "amd64", AvailableCPUCores: 8} type SystemInfo struct { Timestamp time.Time `json:"timestamp"` OS string `json:"os"` Architecture string `json:"architecture"` GoVersion string `json:"go_version"` AvailableCPUCores int `json:"available_cpu_cores"` TotalSystemRAMGB float64 `json:"total_system_ram_gb"` InstalledMinersInfo []*InstallationDetails `json:"installed_miners_info"` } // Config{Miner: "xmrig", Pool: "stratum+tcp://pool.example.com:3333", Wallet: "4ABC...", Threads: 4} type Config struct { Miner string `json:"miner"` Pool string `json:"pool"` Wallet string `json:"wallet"` Threads int `json:"threads"` TLS bool `json:"tls"` HugePages bool `json:"hugePages"` Algo string `json:"algo,omitempty"` Coin string `json:"coin,omitempty"` Password string `json:"password,omitempty"` UserPass string `json:"userPass,omitempty"` Proxy string `json:"proxy,omitempty"` Keepalive bool `json:"keepalive,omitempty"` Nicehash bool `json:"nicehash,omitempty"` RigID string `json:"rigId,omitempty"` TLSFingerprint string `json:"tlsFingerprint,omitempty"` Retries int `json:"retries,omitempty"` RetryPause int `json:"retryPause,omitempty"` UserAgent string `json:"userAgent,omitempty"` DonateLevel int `json:"donateLevel,omitempty"` DonateOverProxy bool `json:"donateOverProxy,omitempty"` NoCPU bool `json:"noCpu,omitempty"` CPUAffinity string `json:"cpuAffinity,omitempty"` AV int `json:"av,omitempty"` CPUPriority int `json:"cpuPriority,omitempty"` CPUMaxThreadsHint int `json:"cpuMaxThreadsHint,omitempty"` CPUMemoryPool int `json:"cpuMemoryPool,omitempty"` CPUNoYield bool `json:"cpuNoYield,omitempty"` HugepageSize int `json:"hugepageSize,omitempty"` HugePagesJIT bool `json:"hugePagesJIT,omitempty"` ASM string `json:"asm,omitempty"` Argon2Impl string `json:"argon2Impl,omitempty"` RandomXInit int `json:"randomXInit,omitempty"` RandomXNoNUMA bool `json:"randomXNoNuma,omitempty"` RandomXMode string `json:"randomXMode,omitempty"` RandomX1GBPages bool `json:"randomX1GBPages,omitempty"` RandomXWrmsr string `json:"randomXWrmsr,omitempty"` RandomXNoRdmsr bool `json:"randomXNoRdmsr,omitempty"` RandomXCacheQoS bool `json:"randomXCacheQoS,omitempty"` APIWorkerID string `json:"apiWorkerId,omitempty"` APIID string `json:"apiId,omitempty"` HTTPHost string `json:"httpHost,omitempty"` HTTPPort int `json:"httpPort,omitempty"` HTTPAccessToken string `json:"httpAccessToken,omitempty"` HTTPNoRestricted bool `json:"httpNoRestricted,omitempty"` Syslog bool `json:"syslog,omitempty"` LogFile string `json:"logFile,omitempty"` PrintTime int `json:"printTime,omitempty"` HealthPrintTime int `json:"healthPrintTime,omitempty"` NoColor bool `json:"noColor,omitempty"` Verbose bool `json:"verbose,omitempty"` LogOutput bool `json:"logOutput,omitempty"` Background bool `json:"background,omitempty"` Title string `json:"title,omitempty"` NoTitle bool `json:"noTitle,omitempty"` PauseOnBattery bool `json:"pauseOnBattery,omitempty"` PauseOnActive int `json:"pauseOnActive,omitempty"` Stress bool `json:"stress,omitempty"` Bench string `json:"bench,omitempty"` Submit bool `json:"submit,omitempty"` Verify string `json:"verify,omitempty"` Seed string `json:"seed,omitempty"` Hash string `json:"hash,omitempty"` NoDMI bool `json:"noDMI,omitempty"` // GPU-specific options (for XMRig dual CPU+GPU mining) GPUEnabled bool `json:"gpuEnabled,omitempty"` // Enable GPU mining GPUPool string `json:"gpuPool,omitempty"` // Separate pool for GPU (can differ from CPU) GPUWallet string `json:"gpuWallet,omitempty"` // Wallet for GPU pool (defaults to main Wallet) GPUAlgo string `json:"gpuAlgo,omitempty"` // Algorithm for GPU (e.g., "kawpow", "ethash") GPUPassword string `json:"gpuPassword,omitempty"` // Password for GPU pool GPUIntensity int `json:"gpuIntensity,omitempty"` // GPU mining intensity (0-100) GPUThreads int `json:"gpuThreads,omitempty"` // GPU threads per card Devices string `json:"devices,omitempty"` // GPU device selection (e.g., "0,1,2") OpenCL bool `json:"opencl,omitempty"` // Enable OpenCL (AMD/Intel GPUs) CUDA bool `json:"cuda,omitempty"` // Enable CUDA (NVIDIA GPUs) Intensity int `json:"intensity,omitempty"` // Mining intensity for GPU miners CLIArgs string `json:"cliArgs,omitempty"` // Additional CLI arguments } // if err := config.Validate(); err != nil { return err } func (c *Config) Validate() error { // Pool URL validation if c.Pool != "" { // Block shell metacharacters in pool URL if containsShellChars(c.Pool) { return ErrInvalidConfig("pool URL contains invalid characters") } } // Wallet validation (basic alphanumeric + special chars allowed in addresses) if c.Wallet != "" { if containsShellChars(c.Wallet) { return ErrInvalidConfig("wallet address contains invalid characters") } // Most wallet addresses are 40-128 chars if len(c.Wallet) > 256 { return ErrInvalidConfig("wallet address too long (max 256 chars)") } } // Thread count validation if c.Threads < 0 { return ErrInvalidConfig("threads cannot be negative") } if c.Threads > 1024 { return ErrInvalidConfig("threads value too high (max 1024)") } // Algorithm validation (alphanumeric, dash, slash) if c.Algo != "" { if !isValidAlgo(c.Algo) { return ErrInvalidConfig("algorithm name contains invalid characters") } } // Intensity validation if c.Intensity < 0 || c.Intensity > 100 { return ErrInvalidConfig("intensity must be between 0 and 100") } if c.GPUIntensity < 0 || c.GPUIntensity > 100 { return ErrInvalidConfig("GPU intensity must be between 0 and 100") } // Donate level validation if c.DonateLevel < 0 || c.DonateLevel > 100 { return ErrInvalidConfig("donate level must be between 0 and 100") } // CLIArgs validation - check for shell metacharacters if c.CLIArgs != "" { if containsShellChars(c.CLIArgs) { return ErrInvalidConfig("CLI arguments contain invalid characters") } // Limit length to prevent abuse if len(c.CLIArgs) > 1024 { return ErrInvalidConfig("CLI arguments too long (max 1024 chars)") } } return nil } // containsShellChars(";echo bad") == true // containsShellChars("stratum+tcp://pool.example.com:3333") == false func containsShellChars(input string) bool { for _, character := range input { switch character { case ';', '|', '&', '`', '$', '(', ')', '{', '}', '<', '>', '\n', '\r', '\\', '\'', '"', '!': return true } } return false } // isValidAlgo("rx/0") == true // isValidAlgo("rx/0;rm -rf /") == false func isValidAlgo(algo string) bool { for _, character := range algo { if !((character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z') || (character >= '0' && character <= '9') || character == '-' || character == '/' || character == '_') { return false } } return true } // metrics, err := miner.GetStats(ctx) // if metrics.Hashrate > 0 { logging.Info("mining", logging.Fields{"hashrate": metrics.Hashrate}) } type PerformanceMetrics struct { Hashrate int `json:"hashrate"` Shares int `json:"shares"` Rejected int `json:"rejected"` Uptime int `json:"uptime"` LastShare int64 `json:"lastShare"` Algorithm string `json:"algorithm"` AvgDifficulty int `json:"avgDifficulty"` // Average difficulty per accepted share (HashesTotal/SharesGood) DiffCurrent int `json:"diffCurrent"` // Current job difficulty from pool ExtraData map[string]interface{} `json:"extraData,omitempty"` } // point := HashratePoint{Timestamp: time.Now(), Hashrate: 1500} type HashratePoint struct { Timestamp time.Time `json:"timestamp"` Hashrate int `json:"hashrate"` } // api := API{Enabled: true, ListenHost: "127.0.0.1", ListenPort: 18080} type API struct { Enabled bool `json:"enabled"` ListenHost string `json:"listenHost"` ListenPort int `json:"listenPort"` } // var summary XMRigSummary; UnmarshalJSON(body, &summary); _ = summary.Hashrate.Highest type XMRigSummary struct { ID string `json:"id"` WorkerID string `json:"worker_id"` Uptime int `json:"uptime"` Restricted bool `json:"restricted"` Resources struct { Memory struct { Free int64 `json:"free"` Total int64 `json:"total"` ResidentSetMemory int64 `json:"resident_set_memory"` } `json:"memory"` LoadAverage []float64 `json:"load_average"` HardwareConcurrency int `json:"hardware_concurrency"` } `json:"resources"` Features []string `json:"features"` Results struct { DiffCurrent int `json:"diff_current"` SharesGood int `json:"shares_good"` SharesTotal int `json:"shares_total"` AvgTime int `json:"avg_time"` AvgTimeMS int `json:"avg_time_ms"` HashesTotal int `json:"hashes_total"` Best []int `json:"best"` } `json:"results"` Algo string `json:"algo"` Connection struct { Pool string `json:"pool"` IP string `json:"ip"` Uptime int `json:"uptime"` UptimeMS int `json:"uptime_ms"` Ping int `json:"ping"` Failures int `json:"failures"` TLS string `json:"tls"` TLSFingerprint string `json:"tls-fingerprint"` Algo string `json:"algo"` Diff int `json:"diff"` Accepted int `json:"accepted"` Rejected int `json:"rejected"` AvgTime int `json:"avg_time"` AvgTimeMS int `json:"avg_time_ms"` HashesTotal int `json:"hashes_total"` } `json:"connection"` Version string `json:"version"` Kind string `json:"kind"` UA string `json:"ua"` CPU struct { Brand string `json:"brand"` Family int `json:"family"` Model int `json:"model"` Stepping int `json:"stepping"` ProcInfo int `json:"proc_info"` AES bool `json:"aes"` AVX2 bool `json:"avx2"` X64 bool `json:"x64"` Is64Bit bool `json:"64_bit"` L2 int `json:"l2"` L3 int `json:"l3"` Cores int `json:"cores"` Threads int `json:"threads"` Packages int `json:"packages"` Nodes int `json:"nodes"` Backend string `json:"backend"` MSR string `json:"msr"` Assembly string `json:"assembly"` Arch string `json:"arch"` Flags []string `json:"flags"` } `json:"cpu"` DonateLevel int `json:"donate_level"` Paused bool `json:"paused"` Algorithms []string `json:"algorithms"` Hashrate struct { Total []float64 `json:"total"` Highest float64 `json:"highest"` } `json:"hashrate"` Hugepages []int `json:"hugepages"` } // miner := AvailableMiner{Name: "xmrig", Description: "CPU/GPU miner for RandomX"} type AvailableMiner struct { Name string `json:"name"` Description string `json:"description"` }