1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.cgminer;
7
8 convType = with builtins;
9 v: if isBool v then boolToString v else toString v;
10 mergedHwConfig =
11 mapAttrsToList (n: v: ''"${n}": "${(concatStringsSep "," (map convType v))}"'')
12 (foldAttrs (n: a: [n] ++ a) [] cfg.hardware);
13 mergedConfig = with builtins;
14 mapAttrsToList (n: v: ''"${n}": ${if isBool v then convType v else ''"${convType v}"''}'')
15 cfg.config;
16
17 cgminerConfig = pkgs.writeText "cgminer.conf" ''
18 {
19 ${concatStringsSep ",\n" mergedHwConfig},
20 ${concatStringsSep ",\n" mergedConfig},
21 "pools": [
22 ${concatStringsSep ",\n"
23 (map (v: ''{"url": "${v.url}", "user": "${v.user}", "pass": "${v.pass}"}'')
24 cfg.pools)}]
25 }
26 '';
27in
28{
29 ###### interface
30 options = {
31
32 services.cgminer = {
33
34 enable = mkEnableOption "cgminer, an ASIC/FPGA/GPU miner for bitcoin and litecoin";
35
36 package = mkPackageOption pkgs "cgminer" { };
37
38 user = mkOption {
39 type = types.str;
40 default = "cgminer";
41 description = "User account under which cgminer runs";
42 };
43
44 pools = mkOption {
45 default = []; # Run benchmark
46 type = types.listOf (types.attrsOf types.str);
47 description = "List of pools where to mine";
48 example = [{
49 url = "http://p2pool.org:9332";
50 username = "17EUZxTvs9uRmPsjPZSYUU3zCz9iwstudk";
51 password="X";
52 }];
53 };
54
55 hardware = mkOption {
56 default = []; # Run without options
57 type = types.listOf (types.attrsOf (types.either types.str types.int));
58 description= "List of config options for every GPU";
59 example = [
60 {
61 intensity = 9;
62 gpu-engine = "0-985";
63 gpu-fan = "0-85";
64 gpu-memclock = 860;
65 gpu-powertune = 20;
66 temp-cutoff = 95;
67 temp-overheat = 85;
68 temp-target = 75;
69 }
70 {
71 intensity = 9;
72 gpu-engine = "0-950";
73 gpu-fan = "0-85";
74 gpu-memclock = 825;
75 gpu-powertune = 20;
76 temp-cutoff = 95;
77 temp-overheat = 85;
78 temp-target = 75;
79 }];
80 };
81
82 config = mkOption {
83 default = {};
84 type = types.attrsOf (types.either types.bool types.int);
85 description = "Additional config";
86 example = {
87 auto-fan = true;
88 auto-gpu = true;
89 expiry = 120;
90 failover-only = true;
91 gpu-threads = 2;
92 log = 5;
93 queue = 1;
94 scan-time = 60;
95 temp-histeresys = 3;
96 };
97 };
98 };
99 };
100
101
102 ###### implementation
103
104 config = mkIf config.services.cgminer.enable {
105
106 users.users = optionalAttrs (cfg.user == "cgminer") {
107 cgminer = {
108 isSystemUser = true;
109 group = "cgminer";
110 description = "Cgminer user";
111 };
112 };
113 users.groups = optionalAttrs (cfg.user == "cgminer") {
114 cgminer = {};
115 };
116
117 environment.systemPackages = [ cfg.package ];
118
119 systemd.services.cgminer = {
120 path = [ pkgs.cgminer ];
121
122 after = [ "network.target" "display-manager.service" ];
123 wantedBy = [ "multi-user.target" ];
124
125 environment = {
126 LD_LIBRARY_PATH = "/run/opengl-driver/lib:/run/opengl-driver-32/lib";
127 DISPLAY = ":${toString config.services.xserver.display}";
128 GPU_MAX_ALLOC_PERCENT = "100";
129 GPU_USE_SYNC_OBJECTS = "1";
130 };
131
132 startLimitIntervalSec = 60; # 1 min
133 serviceConfig = {
134 ExecStart = "${pkgs.cgminer}/bin/cgminer --syslog --text-only --config ${cgminerConfig}";
135 User = cfg.user;
136 RestartSec = "30s";
137 Restart = "always";
138 };
139 };
140
141 };
142
143}