1 { config, lib, pkgs, ... }:
7 eachBlockbook = config.services.blockbook-frontend;
9 blockbookOpts = { config, lib, name, ...}: {
13 enable = mkEnableOption (lib.mdDoc "blockbook-frontend application.");
17 default = pkgs.blockbook;
18 defaultText = literalExpression "pkgs.blockbook";
19 description = lib.mdDoc "Which blockbook package to use.";
24 default = "blockbook-frontend-${name}";
25 description = lib.mdDoc "The user as which to run blockbook-frontend-${name}.";
30 default = "${config.user}";
31 description = lib.mdDoc "The group as which to run blockbook-frontend-${name}.";
35 type = types.nullOr types.path;
37 example = "/etc/secrets/blockbook-frontend-${name}/certFile";
38 description = lib.mdDoc ''
39 To enable SSL, specify path to the name of certificate files without extension.
40 Expecting {file}`certFile.crt` and {file}`certFile.key`.
44 configFile = mkOption {
45 type = with types; nullOr path;
47 example = "${config.dataDir}/config.json";
48 description = lib.mdDoc "Location of the blockbook configuration file.";
54 description = lib.mdDoc ''
55 See <https://github.com/trezor/blockbook/blob/master/bchain/coins/blockchain.go#L61>
56 for current of coins supported in master (Note: may differ from release).
62 default = "${config.package}/share/css/";
63 defaultText = literalExpression ''"''${package}/share/css/"'';
64 example = literalExpression ''"''${dataDir}/static/css/"'';
65 description = lib.mdDoc ''
66 Location of the dir with {file}`main.css` CSS file.
67 By default, the one shipped with the package is used.
73 default = "/var/lib/blockbook-frontend-${name}";
74 description = lib.mdDoc "Location of blockbook-frontend-${name} data directory.";
80 description = lib.mdDoc "Debug mode, return more verbose errors, reload templates on each request.";
84 type = types.nullOr types.str;
86 description = lib.mdDoc "Internal http server binding `[address]:port`.";
89 messageQueueBinding = mkOption {
91 default = "tcp://127.0.0.1:38330";
92 description = lib.mdDoc "Message Queue Binding `address:port`.";
96 type = types.nullOr types.str;
98 description = lib.mdDoc "Public http server binding `[address]:port`.";
104 default = "http://127.0.0.1";
105 description = lib.mdDoc "URL for JSON-RPC connections.";
111 description = lib.mdDoc "Port for JSON-RPC connections.";
117 description = lib.mdDoc "Username for JSON-RPC connections.";
120 password = mkOption {
123 description = lib.mdDoc ''
124 RPC password for JSON-RPC connections.
125 Warning: this is stored in cleartext in the Nix store!!!
126 Use `configFile` or `passwordFile` if needed.
130 passwordFile = mkOption {
131 type = types.nullOr types.path;
133 description = lib.mdDoc ''
134 File containing password of the RPC user.
135 Note: This options is ignored when `configFile` is used.
143 description = lib.mdDoc "Synchronizes until tip, if together with zeromq, keeps index synchronized.";
146 templateDir = mkOption {
148 default = "${config.package}/share/templates/";
149 defaultText = literalExpression ''"''${package}/share/templates/"'';
150 example = literalExpression ''"''${dataDir}/templates/static/"'';
151 description = lib.mdDoc "Location of the HTML templates. By default, ones shipped with the package are used.";
154 extraConfig = mkOption {
157 example = literalExpression '' {
158 "alternative_estimate_fee" = "whatthefee-disabled";
159 "alternative_estimate_fee_params" = "{\"url\": \"https://whatthefee.io/data.json\", \"periodSeconds\": 60}";
160 "fiat_rates" = "coingecko";
161 "fiat_rates_params" = "{\"url\": \"https://api.coingecko.com/api/v3\", \"coin\": \"bitcoin\", \"periodSeconds\": 60}";
162 "coin_shortcut" = "BTC";
163 "coin_label" = "Bitcoin";
166 "address_format" = "";
167 "xpub_magic" = 76067358;
168 "xpub_magic_segwit_p2sh" = 77429938;
169 "xpub_magic_segwit_native" = 78792518;
170 "mempool_workers" = 8;
171 "mempool_sub_workers" = 2;
172 "block_addresses_to_keep" = 300;
174 description = lib.mdDoc ''
175 Additional configurations to be appended to {file}`coin.conf`.
176 Overrides any already defined configuration options.
177 See <https://github.com/trezor/blockbook/tree/master/configs/coins>
178 for current configuration options supported in master (Note: may differ from release).
182 extraCmdLineOptions = mkOption {
183 type = types.listOf types.str;
185 example = [ "-workers=1" "-dbcache=0" "-logtosderr" ];
186 description = lib.mdDoc ''
187 Extra command line options to pass to Blockbook.
188 Run blockbook --help to list all available options.
198 services.blockbook-frontend = mkOption {
199 type = types.attrsOf (types.submodule blockbookOpts);
201 description = lib.mdDoc "Specification of one or more blockbook-frontend instances.";
207 config = mkIf (eachBlockbook != {}) {
209 systemd.services = mapAttrs' (blockbookName: cfg: (
210 nameValuePair "blockbook-frontend-${blockbookName}" (
212 configFile = if cfg.configFile != null then cfg.configFile else
213 pkgs.writeText "config.conf" (builtins.toJSON ( {
214 coin_name = "${cfg.coinName}";
215 rpc_user = "${cfg.rpc.user}";
216 rpc_pass = "${cfg.rpc.password}";
217 rpc_url = "${cfg.rpc.url}:${toString cfg.rpc.port}";
218 message_queue_binding = "${cfg.messageQueueBinding}";
219 } // cfg.extraConfig)
222 description = "blockbook-frontend-${blockbookName} daemon";
223 after = [ "network.target" ];
224 wantedBy = [ "multi-user.target" ];
226 ln -sf ${cfg.templateDir} ${cfg.dataDir}/static/
227 ln -sf ${cfg.cssDir} ${cfg.dataDir}/static/
228 ${optionalString (cfg.rpc.passwordFile != null && cfg.configFile == null) ''
230 ${pkgs.jq}/bin/jq ".rpc_pass = \"$(cat ${cfg.rpc.passwordFile})\"" ${configFile} > $CONFIGTMP
231 mv $CONFIGTMP ${cfg.dataDir}/${blockbookName}-config.json
238 ${cfg.package}/bin/blockbook \
239 ${if (cfg.rpc.passwordFile != null && cfg.configFile == null) then
240 "-blockchaincfg=${cfg.dataDir}/${blockbookName}-config.json"
242 "-blockchaincfg=${configFile}"
244 -datadir=${cfg.dataDir} \
245 ${optionalString (cfg.sync != false) "-sync"} \
246 ${optionalString (cfg.certFile != null) "-certfile=${toString cfg.certFile}"} \
247 ${optionalString (cfg.debug != false) "-debug"} \
248 ${optionalString (cfg.internal != null) "-internal=${toString cfg.internal}"} \
249 ${optionalString (cfg.public != null) "-public=${toString cfg.public}"} \
250 ${toString cfg.extraCmdLineOptions}
252 Restart = "on-failure";
253 WorkingDirectory = cfg.dataDir;
259 systemd.tmpfiles.rules = flatten (mapAttrsToList (blockbookName: cfg: [
260 "d ${cfg.dataDir} 0750 ${cfg.user} ${cfg.group} - -"
261 "d ${cfg.dataDir}/static 0750 ${cfg.user} ${cfg.group} - -"
264 users.users = mapAttrs' (blockbookName: cfg: (
265 nameValuePair "blockbook-frontend-${blockbookName}" {
272 users.groups = mapAttrs' (instanceName: cfg: (
273 nameValuePair "${cfg.group}" { })) eachBlockbook;
276 meta.maintainers = with maintainers; [ _1000101 ];