python312Packages.aiohomeconnect: 0.10.0 -> 0.11.0 (#374011)
[NixPkgs.git] / nixos / modules / services / networking / quorum.nix
blobd86d32bc2de4282c852b3c2aeb08fb38ce9bac0f
2   config,
3   options,
4   pkgs,
5   lib,
6   ...
7 }:
8 let
10   inherit (lib)
11     mkEnableOption
12     mkIf
13     mkOption
14     literalExpression
15     types
16     optionalString
17     ;
19   cfg = config.services.quorum;
20   opt = options.services.quorum;
21   dataDir = "/var/lib/quorum";
22   genesisFile = pkgs.writeText "genesis.json" (builtins.toJSON cfg.genesis);
23   staticNodesFile = pkgs.writeText "static-nodes.json" (builtins.toJSON cfg.staticNodes);
27   options = {
29     services.quorum = {
30       enable = mkEnableOption "Quorum blockchain daemon";
32       user = mkOption {
33         type = types.str;
34         default = "quorum";
35         description = "The user as which to run quorum.";
36       };
38       group = mkOption {
39         type = types.str;
40         default = cfg.user;
41         defaultText = literalExpression "config.${opt.user}";
42         description = "The group as which to run quorum.";
43       };
45       port = mkOption {
46         type = types.port;
47         default = 21000;
48         description = "Override the default port on which to listen for connections.";
49       };
51       nodekeyFile = mkOption {
52         type = types.path;
53         default = "${dataDir}/nodekey";
54         description = "Path to the nodekey.";
55       };
57       staticNodes = mkOption {
58         type = types.listOf types.str;
59         default = [ ];
60         example = [
61           "enode://dd333ec28f0a8910c92eb4d336461eea1c20803eed9cf2c056557f986e720f8e693605bba2f4e8f289b1162e5ac7c80c914c7178130711e393ca76abc1d92f57@0.0.0.0:30303?discport=0"
62         ];
63         description = "List of validator nodes.";
64       };
66       privateconfig = mkOption {
67         type = types.str;
68         default = "ignore";
69         description = "Configuration of privacy transaction manager.";
70       };
72       syncmode = mkOption {
73         type = types.enum [
74           "fast"
75           "full"
76           "light"
77         ];
78         default = "full";
79         description = "Blockchain sync mode.";
80       };
82       blockperiod = mkOption {
83         type = types.int;
84         default = 5;
85         description = "Default minimum difference between two consecutive block's timestamps in seconds.";
86       };
88       permissioned = mkOption {
89         type = types.bool;
90         default = true;
91         description = "Allow only a defined list of nodes to connect.";
92       };
94       rpc = {
95         enable = mkOption {
96           type = types.bool;
97           default = true;
98           description = "Enable RPC interface.";
99         };
101         address = mkOption {
102           type = types.str;
103           default = "0.0.0.0";
104           description = "Listening address for RPC connections.";
105         };
107         port = mkOption {
108           type = types.port;
109           default = 22004;
110           description = "Override the default port on which to listen for RPC connections.";
111         };
113         api = mkOption {
114           type = types.str;
115           default = "admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,istanbul";
116           description = "API's offered over the HTTP-RPC interface.";
117         };
118       };
120       ws = {
121         enable = mkOption {
122           type = types.bool;
123           default = true;
124           description = "Enable WS-RPC interface.";
125         };
127         address = mkOption {
128           type = types.str;
129           default = "0.0.0.0";
130           description = "Listening address for WS-RPC connections.";
131         };
133         port = mkOption {
134           type = types.port;
135           default = 8546;
136           description = "Override the default port on which to listen for WS-RPC connections.";
137         };
139         api = mkOption {
140           type = types.str;
141           default = "admin,db,eth,debug,miner,net,shh,txpool,personal,web3,quorum,istanbul";
142           description = "API's offered over the WS-RPC interface.";
143         };
145         origins = mkOption {
146           type = types.str;
147           default = "*";
148           description = "Origins from which to accept websockets requests";
149         };
150       };
152       genesis = mkOption {
153         type = types.nullOr types.attrs;
154         default = null;
155         example = literalExpression ''
156           {
157                    alloc = {
158                      a47385db68718bdcbddc2d2bb7c54018066ec111 = {
159                        balance = "1000000000000000000000000000";
160                      };
161                    };
162                    coinbase = "0x0000000000000000000000000000000000000000";
163                    config = {
164                      byzantiumBlock = 4;
165                      chainId = 494702925;
166                      eip150Block = 2;
167                      eip155Block = 3;
168                      eip158Block = 3;
169                      homesteadBlock = 1;
170                      isQuorum = true;
171                      istanbul = {
172                        epoch = 30000;
173                        policy = 0;
174                      };
175                    };
176                    difficulty = "0x1";
177                    extraData = "0x0000000000000000000000000000000000000000000000000000000000000000f85ad59438f0508111273d8e482f49410ca4078afc86a961b8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0";
178                    gasLimit = "0x2FEFD800";
179                    mixHash = "0x63746963616c2062797a616e74696e65201111756c7420746f6c6572616e6365";
180                    nonce = "0x0";
181                    parentHash = "0x0000000000000000000000000000000000000000000000000000000000000000";
182                    timestamp = "0x00";
183                    }'';
184         description = "Blockchain genesis settings.";
185       };
186     };
187   };
189   config = mkIf cfg.enable {
190     environment.systemPackages = [ pkgs.quorum ];
191     systemd.tmpfiles.rules = [
192       "d '${dataDir}' 0770 '${cfg.user}' '${cfg.group}' - -"
193     ];
194     systemd.services.quorum = {
195       description = "Quorum daemon";
196       after = [ "network.target" ];
197       wantedBy = [ "multi-user.target" ];
198       environment = {
199         PRIVATE_CONFIG = "${cfg.privateconfig}";
200       };
201       preStart = ''
202         if [ ! -d ${dataDir}/geth ]; then
203           if [ ! -d ${dataDir}/keystore ]; then
204             echo ERROR: You need to create a wallet before initializing your genesis file, run:
205             echo   # su -s /bin/sh - quorum
206             echo   $ geth --datadir ${dataDir} account new
207             echo and configure your genesis file accordingly.
208             exit 1;
209           fi
210           ln -s ${staticNodesFile} ${dataDir}/static-nodes.json
211           ${pkgs.quorum}/bin/geth --datadir ${dataDir} init ${genesisFile}
212         fi
213       '';
214       serviceConfig = {
215         User = cfg.user;
216         Group = cfg.group;
217         ExecStart = ''
218           ${pkgs.quorum}/bin/geth \
219                       --nodiscover \
220                       --verbosity 5 \
221                       --nodekey ${cfg.nodekeyFile} \
222                       --istanbul.blockperiod ${toString cfg.blockperiod} \
223                       --syncmode ${cfg.syncmode} \
224                       ${optionalString (cfg.permissioned) "--permissioned"} \
225                       --mine --miner.threads 1 \
226                       ${optionalString (cfg.rpc.enable) "--rpc --rpcaddr ${cfg.rpc.address} --rpcport ${toString cfg.rpc.port} --rpcapi ${cfg.rpc.api}"} \
227                       ${optionalString (cfg.ws.enable) "--ws --ws.addr ${cfg.ws.address} --ws.port ${toString cfg.ws.port} --ws.api ${cfg.ws.api} --ws.origins ${cfg.ws.origins}"} \
228                       --emitcheckpoints \
229                       --datadir ${dataDir} \
230                       --port ${toString cfg.port}'';
231         Restart = "on-failure";
233         # Hardening measures
234         PrivateTmp = "true";
235         ProtectSystem = "full";
236         NoNewPrivileges = "true";
237         PrivateDevices = "true";
238         MemoryDenyWriteExecute = "true";
239       };
240     };
241     users.users.${cfg.user} = {
242       name = cfg.user;
243       group = cfg.group;
244       description = "Quorum daemon user";
245       home = dataDir;
246       isSystemUser = true;
247     };
248     users.groups.${cfg.group} = { };
249   };