From 731cf647ff10b8d7ab15336069ed812025cd1946 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Mon, 13 Sep 2021 13:40:46 +0200 Subject: [PATCH 1/5] modules: remove unneeded use of `options` module arg Needed by the following commit. --- modules/charge-lnd.nix | 4 ++-- modules/operator.nix | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/charge-lnd.nix b/modules/charge-lnd.nix index c3d4580..32aef1e 100644 --- a/modules/charge-lnd.nix +++ b/modules/charge-lnd.nix @@ -1,4 +1,4 @@ -{ config, options, lib, pkgs, ... }: +{ config, lib, pkgs, ... }: with lib; @@ -6,7 +6,7 @@ let cfg = config.services.charge-lnd; nbLib = config.nix-bitcoin.lib; lnd = config.services.lnd; - electrs = if (options ? services.electrs) && config.services.electrs.enable + electrs = if (config.services ? electrs) && config.services.electrs.enable then config.services.electrs else null; diff --git a/modules/operator.nix b/modules/operator.nix index 4be5eb9..f336f82 100644 --- a/modules/operator.nix +++ b/modules/operator.nix @@ -4,7 +4,7 @@ # When using nix-bitcoin as part of a larger system config, set # `nix-bitcoin.operator.name` to your main user name. -{ config, lib, pkgs, options, ... }: +{ config, lib, pkgs, ... }: with lib; let From 27c45b82cc3e6e785795e682ee3bf4d6ef65ca90 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Mon, 13 Sep 2021 13:40:47 +0200 Subject: [PATCH 2/5] modules: move options to the top This greatly improves readability and makes it easier to discover options. This commit was genereated by running the following script inside the repo root dir: #!/usr/bin/env ruby def transform(src) return false if src.include?('inherit options;') success = false options = nil src.sub!(/^ options.*?^ }.*?;/m) do |match| options = match " inherit options;" end return false if !options src.sub!(/^with lib;\s*let\n+/m) do |match| success = true <<~EOF with lib; let #{options} EOF end success end Dir['modules/**/*.nix'].each do |f| src = File.read(f) if transform(src) puts "Changed file #{f}" File.write(f, src) end end --- modules/backups.nix | 67 ++++----- modules/bitcoind.nix | 113 +++++++-------- modules/btcpayserver.nix | 11 +- modules/charge-lnd.nix | 39 ++--- modules/clightning-plugins/default.nix | 12 +- modules/clightning-plugins/zmq.nix | 8 +- modules/clightning.nix | 37 ++--- modules/electrs.nix | 12 +- modules/hardware-wallets.nix | 11 +- modules/joinmarket-ob-watcher.nix | 68 ++++----- modules/joinmarket.nix | 191 +++++++++++++------------ modules/lightning-loop.nix | 55 +++---- modules/lightning-pool.nix | 41 +++--- modules/liquid.nix | 133 ++++++++--------- modules/lnd-rest-onion-service.nix | 35 ++--- modules/lnd.nix | 71 ++++----- modules/netns-isolation.nix | 87 +++++------ modules/nodeinfo.nix | 20 +-- modules/onion-addresses.nix | 9 +- modules/onion-services.nix | 25 ++-- modules/operator.nix | 6 +- modules/recurring-donations.nix | 65 ++++----- modules/spark-wallet.nix | 41 +++--- modules/versioning.nix | 30 ++-- 24 files changed, 609 insertions(+), 578 deletions(-) diff --git a/modules/backups.nix b/modules/backups.nix index 7a95eb3..4febc98 100644 --- a/modules/backups.nix +++ b/modules/backups.nix @@ -1,40 +1,7 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.services.backups; - - filelist = pkgs.writeText "filelist.txt" '' - ${optionalString (!cfg.with-bulk-data) "- ${config.services.bitcoind.dataDir}/blocks"} - ${optionalString (!cfg.with-bulk-data) "- ${config.services.bitcoind.dataDir}/chainstate"} - ${config.services.bitcoind.dataDir} - ${config.services.clightning.dataDir} - ${config.services.lnd.dataDir} - ${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/blocks"} - ${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/chainstate"} - ${config.services.liquidd.dataDir} - ${optionalString cfg.with-bulk-data "${config.services.electrs.dataDir}"} - ${config.services.nbxplorer.dataDir} - ${config.services.btcpayserver.dataDir} - ${config.services.joinmarket.dataDir} - ${optionalString config.nix-bitcoin.generateSecrets "${config.nix-bitcoin.secretsDir}"} - /var/lib/tor - /var/lib/nixos - - ${builtins.concatStringsSep "\n" postgresqlBackupPaths} - - # Extra files - ${cfg.extraFiles} - - # Exclude all unspecified files and directories - - / - ''; - - postgresqlBackupDir = config.services.postgresqlBackup.location; - postgresqlBackupPaths = map (db: "${postgresqlBackupDir}/${db}.sql.gz") cfg.postgresqlDatabases; - postgresqlBackupServices = map (db: "postgresqlBackup-${db}.service") cfg.postgresqlDatabases; -in { options.services.backups = { enable = mkEnableOption "Backups service"; with-bulk-data = mkOption { @@ -73,6 +40,40 @@ in { }; }; + cfg = config.services.backups; + + filelist = pkgs.writeText "filelist.txt" '' + ${optionalString (!cfg.with-bulk-data) "- ${config.services.bitcoind.dataDir}/blocks"} + ${optionalString (!cfg.with-bulk-data) "- ${config.services.bitcoind.dataDir}/chainstate"} + ${config.services.bitcoind.dataDir} + ${config.services.clightning.dataDir} + ${config.services.lnd.dataDir} + ${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/blocks"} + ${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/chainstate"} + ${config.services.liquidd.dataDir} + ${optionalString cfg.with-bulk-data "${config.services.electrs.dataDir}"} + ${config.services.nbxplorer.dataDir} + ${config.services.btcpayserver.dataDir} + ${config.services.joinmarket.dataDir} + ${optionalString config.nix-bitcoin.generateSecrets "${config.nix-bitcoin.secretsDir}"} + /var/lib/tor + /var/lib/nixos + + ${builtins.concatStringsSep "\n" postgresqlBackupPaths} + + # Extra files + ${cfg.extraFiles} + + # Exclude all unspecified files and directories + - / + ''; + + postgresqlBackupDir = config.services.postgresqlBackup.location; + postgresqlBackupPaths = map (db: "${postgresqlBackupDir}/${db}.sql.gz") cfg.postgresqlDatabases; + postgresqlBackupServices = map (db: "postgresqlBackup-${db}.service") cfg.postgresqlDatabases; +in { + inherit options; + config = mkIf cfg.enable { environment.systemPackages = [ pkgs.duplicity ]; diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index 117f4d9..50f1a88 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -1,63 +1,7 @@ { config, pkgs, lib, ... }: with lib; - let - cfg = config.services.bitcoind; - nbLib = config.nix-bitcoin.lib; - secretsDir = config.nix-bitcoin.secretsDir; - - configFile = builtins.toFile "bitcoin.conf" '' - # We're already logging via journald - nodebuglogfile=1 - - startupnotify=/run/current-system/systemd/bin/systemd-notify --ready - - ${optionalString cfg.regtest '' - regtest=1 - [regtest] - ''} - ${optionalString (cfg.dbCache != null) "dbcache=${toString cfg.dbCache}"} - prune=${toString cfg.prune} - ${optionalString (cfg.sysperms != null) "sysperms=${if cfg.sysperms then "1" else "0"}"} - ${optionalString (cfg.disablewallet != null) "disablewallet=${if cfg.disablewallet then "1" else "0"}"} - ${optionalString (cfg.assumevalid != null) "assumevalid=${cfg.assumevalid}"} - - # Connection options - ${optionalString cfg.listen "bind=${cfg.address}${optionalString cfg.enforceTor "=onion"}"} - port=${toString cfg.port} - ${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"} - listen=${if cfg.listen then "1" else "0"} - ${optionalString (cfg.discover != null) "discover=${if cfg.discover then "1" else "0"}"} - ${lib.concatMapStrings (node: "addnode=${node}\n") cfg.addnodes} - - # RPC server options - rpcbind=${cfg.rpc.address} - rpcport=${toString cfg.rpc.port} - rpcconnect=${cfg.rpc.address} - ${optionalString (cfg.rpc.threads != null) "rpcthreads=${toString cfg.rpc.threads}"} - rpcwhitelistdefault=0 - ${concatMapStrings (user: '' - ${optionalString (!user.passwordHMACFromFile) "rpcauth=${user.name}:${passwordHMAC}"} - ${optionalString (user.rpcwhitelist != []) - "rpcwhitelist=${user.name}:${lib.strings.concatStringsSep "," user.rpcwhitelist}"} - '') (builtins.attrValues cfg.rpc.users) - } - ${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpc.allowip} - - # Wallet options - ${optionalString (cfg.addresstype != null) "addresstype=${cfg.addresstype}"} - - # ZMQ options - ${optionalString (cfg.zmqpubrawblock != null) "zmqpubrawblock=${cfg.zmqpubrawblock}"} - ${optionalString (cfg.zmqpubrawtx != null) "zmqpubrawtx=${cfg.zmqpubrawtx}"} - - # Extra options - ${cfg.extraConfig} - ''; - - zmqServerEnabled = (cfg.zmqpubrawblock != null) || (cfg.zmqpubrawtx != null); -in { options = { services.bitcoind = { enable = mkEnableOption "Bitcoin daemon"; @@ -289,6 +233,63 @@ in { }; }; + cfg = config.services.bitcoind; + nbLib = config.nix-bitcoin.lib; + secretsDir = config.nix-bitcoin.secretsDir; + + configFile = builtins.toFile "bitcoin.conf" '' + # We're already logging via journald + nodebuglogfile=1 + + startupnotify=/run/current-system/systemd/bin/systemd-notify --ready + + ${optionalString cfg.regtest '' + regtest=1 + [regtest] + ''} + ${optionalString (cfg.dbCache != null) "dbcache=${toString cfg.dbCache}"} + prune=${toString cfg.prune} + ${optionalString (cfg.sysperms != null) "sysperms=${if cfg.sysperms then "1" else "0"}"} + ${optionalString (cfg.disablewallet != null) "disablewallet=${if cfg.disablewallet then "1" else "0"}"} + ${optionalString (cfg.assumevalid != null) "assumevalid=${cfg.assumevalid}"} + + # Connection options + ${optionalString cfg.listen "bind=${cfg.address}${optionalString cfg.enforceTor "=onion"}"} + port=${toString cfg.port} + ${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"} + listen=${if cfg.listen then "1" else "0"} + ${optionalString (cfg.discover != null) "discover=${if cfg.discover then "1" else "0"}"} + ${lib.concatMapStrings (node: "addnode=${node}\n") cfg.addnodes} + + # RPC server options + rpcbind=${cfg.rpc.address} + rpcport=${toString cfg.rpc.port} + rpcconnect=${cfg.rpc.address} + ${optionalString (cfg.rpc.threads != null) "rpcthreads=${toString cfg.rpc.threads}"} + rpcwhitelistdefault=0 + ${concatMapStrings (user: '' + ${optionalString (!user.passwordHMACFromFile) "rpcauth=${user.name}:${passwordHMAC}"} + ${optionalString (user.rpcwhitelist != []) + "rpcwhitelist=${user.name}:${lib.strings.concatStringsSep "," user.rpcwhitelist}"} + '') (builtins.attrValues cfg.rpc.users) + } + ${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpc.allowip} + + # Wallet options + ${optionalString (cfg.addresstype != null) "addresstype=${cfg.addresstype}"} + + # ZMQ options + ${optionalString (cfg.zmqpubrawblock != null) "zmqpubrawblock=${cfg.zmqpubrawblock}"} + ${optionalString (cfg.zmqpubrawtx != null) "zmqpubrawtx=${cfg.zmqpubrawtx}"} + + # Extra options + ${cfg.extraConfig} + ''; + + zmqServerEnabled = (cfg.zmqpubrawblock != null) || (cfg.zmqpubrawtx != null); +in { + inherit options; + config = mkIf cfg.enable { environment.systemPackages = [ cfg.package (hiPrio cfg.cli) ]; diff --git a/modules/btcpayserver.nix b/modules/btcpayserver.nix index f38b6ee..f35b7f6 100644 --- a/modules/btcpayserver.nix +++ b/modules/btcpayserver.nix @@ -1,12 +1,7 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.services; - nbLib = config.nix-bitcoin.lib; - nbPkgs = config.nix-bitcoin.pkgs; -in { options.services = { nbxplorer = { package = mkOption { @@ -102,6 +97,12 @@ in { }; }; + cfg = config.services; + nbLib = config.nix-bitcoin.lib; + nbPkgs = config.nix-bitcoin.pkgs; +in { + inherit options; + config = mkIf cfg.btcpayserver.enable { services.bitcoind.enable = true; services.clightning.enable = mkIf (cfg.btcpayserver.lightningBackend == "clightning") true; diff --git a/modules/charge-lnd.nix b/modules/charge-lnd.nix index 32aef1e..8e72478 100644 --- a/modules/charge-lnd.nix +++ b/modules/charge-lnd.nix @@ -1,26 +1,7 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.services.charge-lnd; - nbLib = config.nix-bitcoin.lib; - lnd = config.services.lnd; - electrs = if (config.services ? electrs) && config.services.electrs.enable - then config.services.electrs - else null; - - user = "charge-lnd"; - group = user; - dataDir = "/var/lib/charge-lnd"; - - configFile = builtins.toFile "charge-lnd.config" cfg.policies; - checkedConfig = pkgs.runCommandNoCC "charge-lnd-checked.config" { } '' - ${config.nix-bitcoin.pkgs.charge-lnd}/bin/charge-lnd --check --config ${configFile} - cp ${configFile} $out - ''; -in -{ options.services.charge-lnd = with types; { enable = mkEnableOption "charge-lnd, policy-based fee manager"; @@ -86,6 +67,26 @@ in }; }; + cfg = config.services.charge-lnd; + nbLib = config.nix-bitcoin.lib; + lnd = config.services.lnd; + electrs = if (config.services ? electrs) && config.services.electrs.enable + then config.services.electrs + else null; + + user = "charge-lnd"; + group = user; + dataDir = "/var/lib/charge-lnd"; + + configFile = builtins.toFile "charge-lnd.config" cfg.policies; + checkedConfig = pkgs.runCommandNoCC "charge-lnd-checked.config" { } '' + ${config.nix-bitcoin.pkgs.charge-lnd}/bin/charge-lnd --check --config ${configFile} + cp ${configFile} $out + ''; +in +{ + inherit options; + config = mkIf cfg.enable { services.lnd = { enable = true; diff --git a/modules/clightning-plugins/default.nix b/modules/clightning-plugins/default.nix index 4de6bb1..9a39782 100644 --- a/modules/clightning-plugins/default.nix +++ b/modules/clightning-plugins/default.nix @@ -2,6 +2,12 @@ with lib; let + options.services.clightning.plugins = { + helpme.enable = mkEnableOption "Help me (clightning plugin)"; + monitor.enable = mkEnableOption "Monitor (clightning plugin)"; + rebalance.enable = mkEnableOption "Rebalance (clightning plugin)"; + }; + cfg = config.services.clightning.plugins; pluginPkgs = config.nix-bitcoin.pkgs.clightning-plugins; in { @@ -12,11 +18,7 @@ in { ./zmq.nix ]; - options.services.clightning.plugins = { - helpme.enable = mkEnableOption "Help me (clightning plugin)"; - monitor.enable = mkEnableOption "Monitor (clightning plugin)"; - rebalance.enable = mkEnableOption "Rebalance (clightning plugin)"; - }; + inherit options; config = { services.clightning.extraConfig = mkMerge [ diff --git a/modules/clightning-plugins/zmq.nix b/modules/clightning-plugins/zmq.nix index 5ba2ece..f2e7627 100644 --- a/modules/clightning-plugins/zmq.nix +++ b/modules/clightning-plugins/zmq.nix @@ -2,6 +2,10 @@ with lib; let + options.services.clightning.plugins.zmq = { + enable = mkEnableOption "ZMQ (clightning plugin)"; + } // lib.genAttrs endpoints mkEndpointOption; + cfg = config.services.clightning.plugins.zmq; nbLib = config.nix-bitcoin.lib; @@ -31,9 +35,7 @@ let ''; in { - options.services.clightning.plugins.zmq = { - enable = mkEnableOption "ZMQ (clightning plugin)"; - } // lib.genAttrs endpoints mkEndpointOption; + inherit options; config = mkIf cfg.enable { services.clightning.extraConfig = '' diff --git a/modules/clightning.nix b/modules/clightning.nix index 93a3b5a..6aea551 100644 --- a/modules/clightning.nix +++ b/modules/clightning.nix @@ -1,25 +1,7 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.services.clightning; - nbLib = config.nix-bitcoin.lib; - nbPkgs = config.nix-bitcoin.pkgs; - network = config.services.bitcoind.makeNetworkName "bitcoin" "regtest"; - configFile = pkgs.writeText "config" '' - network=${network} - bitcoin-datadir=${config.services.bitcoind.dataDir} - ${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"} - always-use-proxy=${boolToString cfg.always-use-proxy} - bind-addr=${cfg.address}:${toString cfg.port} - bitcoin-rpcconnect=${config.services.bitcoind.rpc.address} - bitcoin-rpcport=${toString config.services.bitcoind.rpc.port} - bitcoin-rpcuser=${config.services.bitcoind.rpc.users.public.name} - rpc-file-mode=0660 - ${cfg.extraConfig} - ''; -in { options.services.clightning = { enable = mkEnableOption "clightning"; address = mkOption { @@ -91,6 +73,25 @@ in { inherit (nbLib) enforceTor; }; + cfg = config.services.clightning; + nbLib = config.nix-bitcoin.lib; + nbPkgs = config.nix-bitcoin.pkgs; + network = config.services.bitcoind.makeNetworkName "bitcoin" "regtest"; + configFile = pkgs.writeText "config" '' + network=${network} + bitcoin-datadir=${config.services.bitcoind.dataDir} + ${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"} + always-use-proxy=${boolToString cfg.always-use-proxy} + bind-addr=${cfg.address}:${toString cfg.port} + bitcoin-rpcconnect=${config.services.bitcoind.rpc.address} + bitcoin-rpcport=${toString config.services.bitcoind.rpc.port} + bitcoin-rpcuser=${config.services.bitcoind.rpc.users.public.name} + rpc-file-mode=0660 + ${cfg.extraConfig} + ''; +in { + inherit options; + config = mkIf cfg.enable { services.bitcoind = { enable = true; diff --git a/modules/electrs.nix b/modules/electrs.nix index 880cc1a..f650954 100644 --- a/modules/electrs.nix +++ b/modules/electrs.nix @@ -2,11 +2,6 @@ with lib; let - cfg = config.services.electrs; - nbLib = config.nix-bitcoin.lib; - secretsDir = config.nix-bitcoin.secretsDir; - bitcoind = config.services.bitcoind; -in { options.services.electrs = { enable = mkEnableOption "electrs"; address = mkOption { @@ -54,6 +49,13 @@ in { enforceTor = nbLib.enforceTor; }; + cfg = config.services.electrs; + nbLib = config.nix-bitcoin.lib; + secretsDir = config.nix-bitcoin.secretsDir; + bitcoind = config.services.bitcoind; +in { + inherit options; + config = mkIf cfg.enable { assertions = [ { assertion = bitcoind.prune == 0; diff --git a/modules/hardware-wallets.nix b/modules/hardware-wallets.nix index b2e9352..cf95dc4 100644 --- a/modules/hardware-wallets.nix +++ b/modules/hardware-wallets.nix @@ -1,12 +1,7 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.services.hardware-wallets; - dataDir = "/var/lib/hardware-wallets/"; - enabled = cfg.ledger || cfg.trezor; -in { options.services.hardware-wallets = { ledger = mkOption { type = types.bool; @@ -31,6 +26,12 @@ in { }; }; + cfg = config.services.hardware-wallets; + dataDir = "/var/lib/hardware-wallets/"; + enabled = cfg.ledger || cfg.trezor; +in { + inherit options; + config = mkMerge [ (mkIf (cfg.ledger || cfg.trezor) { assertions = [ diff --git a/modules/joinmarket-ob-watcher.nix b/modules/joinmarket-ob-watcher.nix index 4b9714b..b5378b5 100644 --- a/modules/joinmarket-ob-watcher.nix +++ b/modules/joinmarket-ob-watcher.nix @@ -2,6 +2,40 @@ with lib; let + options.services.joinmarket-ob-watcher = { + enable = mkEnableOption "JoinMarket orderbook watcher"; + address = mkOption { + type = types.str; + default = "127.0.0.1"; + description = "HTTP server address."; + }; + port = mkOption { + type = types.port; + default = 62601; + description = "HTTP server port."; + }; + dataDir = mkOption { + readOnly = true; + default = "/var/lib/joinmarket-ob-watcher"; + description = "The data directory for JoinMarket orderbook watcher."; + }; + user = mkOption { + type = types.str; + default = "joinmarket-ob-watcher"; + description = "The user as which to run JoinMarket."; + }; + group = mkOption { + type = types.str; + default = cfg.user; + description = "The group as which to run JoinMarket."; + }; + # This option is only used by netns-isolation + enforceTor = mkOption { + readOnly = true; + default = true; + }; + }; + cfg = config.services.joinmarket-ob-watcher; nbLib = config.nix-bitcoin.lib; nbPkgs = config.nix-bitcoin.pkgs; @@ -39,39 +73,7 @@ let ${socks5Settings} ''; in { - options.services.joinmarket-ob-watcher = { - enable = mkEnableOption "JoinMarket orderbook watcher"; - address = mkOption { - type = types.str; - default = "127.0.0.1"; - description = "HTTP server address."; - }; - port = mkOption { - type = types.port; - default = 62601; - description = "HTTP server port."; - }; - dataDir = mkOption { - readOnly = true; - default = "/var/lib/joinmarket-ob-watcher"; - description = "The data directory for JoinMarket orderbook watcher."; - }; - user = mkOption { - type = types.str; - default = "joinmarket-ob-watcher"; - description = "The user as which to run JoinMarket."; - }; - group = mkOption { - type = types.str; - default = cfg.user; - description = "The group as which to run JoinMarket."; - }; - # This option is only used by netns-isolation - enforceTor = mkOption { - readOnly = true; - default = true; - }; - }; + inherit options; config = mkIf cfg.enable { services.bitcoind.rpc.users.joinmarket-ob-watcher = { diff --git a/modules/joinmarket.nix b/modules/joinmarket.nix index a5aacc6..632a4b0 100644 --- a/modules/joinmarket.nix +++ b/modules/joinmarket.nix @@ -1,8 +1,102 @@ { config, lib, pkgs, ... }: with lib; - let + options.services.joinmarket = { + enable = mkEnableOption "JoinMarket"; + dataDir = mkOption { + type = types.path; + default = "/var/lib/joinmarket"; + description = "The data directory for JoinMarket."; + }; + user = mkOption { + type = types.str; + default = "joinmarket"; + description = "The user as which to run JoinMarket."; + }; + group = mkOption { + type = types.str; + default = cfg.user; + description = "The group as which to run JoinMarket."; + }; + rpcWalletFile = mkOption { + type = types.nullOr types.str; + default = "jm_wallet"; + description = '' + Name of the watch-only bitcoind wallet the JoinMarket addresses are imported to. + ''; + }; + cli = mkOption { + default = cli; + }; + # This option is only used by netns-isolation + enforceTor = mkOption { + readOnly = true; + default = true; + }; + inherit (nbLib) cliExec; + + yieldgenerator = { + enable = mkEnableOption "yield generator bot"; + ordertype = mkOption { + type = types.enum [ "reloffer" "absoffer" ]; + default = "reloffer"; + description = '' + Which fee type to actually use + ''; + }; + cjfee_a = mkOption { + type = types.ints.unsigned; + default = 500; + description = '' + Absolute offer fee you wish to receive for coinjoins (cj) in Satoshis + ''; + }; + cjfee_r = mkOption { + type = types.float; + default = 0.00002; + description = '' + Relative offer fee you wish to receive based on a cj's amount + ''; + }; + cjfee_factor = mkOption { + type = types.float; + default = 0.1; + description = '' + Variance around the average cj fee + ''; + }; + txfee = mkOption { + type = types.ints.unsigned; + default = 100; + description = '' + The average transaction fee you're adding to coinjoin transactions + ''; + }; + txfee_factor = mkOption { + type = types.float; + default = 0.3; + description = '' + Variance around the average tx fee + ''; + }; + minsize = mkOption { + type = types.ints.unsigned; + default = 100000; + description = '' + Minimum size of your cj offer in Satoshis. Lower cj amounts will be disregarded. + ''; + }; + size_factor = mkOption { + type = types.float; + default = 0.1; + description = '' + Variance around all offer sizes + ''; + }; + }; + }; + cfg = config.services.joinmarket; nbLib = config.nix-bitcoin.lib; nbPkgs = config.nix-bitcoin.pkgs; @@ -114,100 +208,7 @@ let chmod -R +x $out/bin ''; in { - options.services.joinmarket = { - enable = mkEnableOption "JoinMarket"; - dataDir = mkOption { - type = types.path; - default = "/var/lib/joinmarket"; - description = "The data directory for JoinMarket."; - }; - user = mkOption { - type = types.str; - default = "joinmarket"; - description = "The user as which to run JoinMarket."; - }; - group = mkOption { - type = types.str; - default = cfg.user; - description = "The group as which to run JoinMarket."; - }; - rpcWalletFile = mkOption { - type = types.nullOr types.str; - default = "jm_wallet"; - description = '' - Name of the watch-only bitcoind wallet the JoinMarket addresses are imported to. - ''; - }; - cli = mkOption { - default = cli; - }; - # This option is only used by netns-isolation - enforceTor = mkOption { - readOnly = true; - default = true; - }; - inherit (nbLib) cliExec; - - yieldgenerator = { - enable = mkEnableOption "yield generator bot"; - ordertype = mkOption { - type = types.enum [ "reloffer" "absoffer" ]; - default = "reloffer"; - description = '' - Which fee type to actually use - ''; - }; - cjfee_a = mkOption { - type = types.ints.unsigned; - default = 500; - description = '' - Absolute offer fee you wish to receive for coinjoins (cj) in Satoshis - ''; - }; - cjfee_r = mkOption { - type = types.float; - default = 0.00002; - description = '' - Relative offer fee you wish to receive based on a cj's amount - ''; - }; - cjfee_factor = mkOption { - type = types.float; - default = 0.1; - description = '' - Variance around the average cj fee - ''; - }; - txfee = mkOption { - type = types.ints.unsigned; - default = 100; - description = '' - The average transaction fee you're adding to coinjoin transactions - ''; - }; - txfee_factor = mkOption { - type = types.float; - default = 0.3; - description = '' - Variance around the average tx fee - ''; - }; - minsize = mkOption { - type = types.ints.unsigned; - default = 100000; - description = '' - Minimum size of your cj offer in Satoshis. Lower cj amounts will be disregarded. - ''; - }; - size_factor = mkOption { - type = types.float; - default = 0.1; - description = '' - Variance around all offer sizes - ''; - }; - }; - }; + inherit options; config = mkIf cfg.enable (mkMerge [{ services.bitcoind = { diff --git a/modules/lightning-loop.nix b/modules/lightning-loop.nix index 530b138..b7b388e 100644 --- a/modules/lightning-loop.nix +++ b/modules/lightning-loop.nix @@ -1,34 +1,7 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.services.lightning-loop; - nbLib = config.nix-bitcoin.lib; - secretsDir = config.nix-bitcoin.secretsDir; - - lnd = config.services.lnd; - - network = config.services.bitcoind.network; - rpclisten = "${cfg.rpcAddress}:${toString cfg.rpcPort}"; - configFile = builtins.toFile "loop.conf" '' - datadir=${cfg.dataDir} - network=${network} - rpclisten=${rpclisten} - restlisten=${cfg.restAddress}:${toString cfg.restPort} - logdir=${cfg.dataDir}/logs - tlscertpath=${secretsDir}/loop-cert - tlskeypath=${secretsDir}/loop-key - - lnd.host=${lnd.rpcAddress}:${toString lnd.rpcPort} - lnd.macaroonpath=${lnd.networkDir}/admin.macaroon - lnd.tlspath=${lnd.certPath} - - ${optionalString (cfg.proxy != null) "server.proxy=${cfg.proxy}"} - - ${cfg.extraConfig} - ''; -in { options.services.lightning-loop = { enable = mkEnableOption "lightning-loop"; rpcAddress = mkOption { @@ -86,6 +59,34 @@ in { enforceTor = nbLib.enforceTor; }; + cfg = config.services.lightning-loop; + nbLib = config.nix-bitcoin.lib; + secretsDir = config.nix-bitcoin.secretsDir; + + lnd = config.services.lnd; + + network = config.services.bitcoind.network; + rpclisten = "${cfg.rpcAddress}:${toString cfg.rpcPort}"; + configFile = builtins.toFile "loop.conf" '' + datadir=${cfg.dataDir} + network=${network} + rpclisten=${rpclisten} + restlisten=${cfg.restAddress}:${toString cfg.restPort} + logdir=${cfg.dataDir}/logs + tlscertpath=${secretsDir}/loop-cert + tlskeypath=${secretsDir}/loop-key + + lnd.host=${lnd.rpcAddress}:${toString lnd.rpcPort} + lnd.macaroonpath=${lnd.networkDir}/admin.macaroon + lnd.tlspath=${lnd.certPath} + + ${optionalString (cfg.proxy != null) "server.proxy=${cfg.proxy}"} + + ${cfg.extraConfig} + ''; +in { + inherit options; + config = mkIf cfg.enable { services.lnd.enable = true; diff --git a/modules/lightning-pool.nix b/modules/lightning-pool.nix index 7f49f3d..4a9c9ca 100644 --- a/modules/lightning-pool.nix +++ b/modules/lightning-pool.nix @@ -1,27 +1,7 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.services.lightning-pool; - nbLib = config.nix-bitcoin.lib; - - lnd = config.services.lnd; - - network = config.services.bitcoind.network; - rpclisten = "${cfg.rpcAddress}:${toString cfg.rpcPort}"; - configFile = builtins.toFile "pool.conf" '' - rpclisten=${rpclisten} - restlisten=${cfg.restAddress}:${toString cfg.restPort} - ${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"} - - lnd.host=${lnd.rpcAddress}:${toString lnd.rpcPort} - lnd.macaroondir=${lnd.networkDir} - lnd.tlspath=${lnd.certPath} - - ${cfg.extraConfig} - ''; -in { options.services.lightning-pool = { enable = mkEnableOption "lightning-pool"; rpcAddress = mkOption { @@ -79,6 +59,27 @@ in { enforceTor = nbLib.enforceTor; }; + cfg = config.services.lightning-pool; + nbLib = config.nix-bitcoin.lib; + + lnd = config.services.lnd; + + network = config.services.bitcoind.network; + rpclisten = "${cfg.rpcAddress}:${toString cfg.rpcPort}"; + configFile = builtins.toFile "pool.conf" '' + rpclisten=${rpclisten} + restlisten=${cfg.restAddress}:${toString cfg.restPort} + ${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"} + + lnd.host=${lnd.rpcAddress}:${toString lnd.rpcPort} + lnd.macaroondir=${lnd.networkDir} + lnd.tlspath=${lnd.certPath} + + ${cfg.extraConfig} + ''; +in { + inherit options; + config = mkIf cfg.enable { services.lnd.enable = true; diff --git a/modules/liquid.nix b/modules/liquid.nix index 6fe7d14..b729a11 100644 --- a/modules/liquid.nix +++ b/modules/liquid.nix @@ -1,73 +1,7 @@ { config, pkgs, lib, ... }: with lib; - let - cfg = config.services.liquidd; - nbLib = config.nix-bitcoin.lib; - nbPkgs = config.nix-bitcoin.pkgs; - secretsDir = config.nix-bitcoin.secretsDir; - pidFile = "${cfg.dataDir}/liquidd.pid"; - configFile = pkgs.writeText "elements.conf" '' - chain=${config.services.bitcoind.makeNetworkName "liquidv1" '' - regtest - [regtest]'' # Add [regtest] config section - } - ${optionalString (cfg.dbCache != null) "dbcache=${toString cfg.dbCache}"} - ${optionalString (cfg.prune != null) "prune=${toString cfg.prune}"} - ${optionalString (cfg.validatepegin != null) "validatepegin=${if cfg.validatepegin then "1" else "0"}"} - - # Connection options - ${optionalString cfg.listen "bind=${cfg.address}"} - port=${toString cfg.port} - ${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"} - listen=${if cfg.listen then "1" else "0"} - - # RPC server options - rpcport=${toString cfg.rpc.port} - ${concatMapStringsSep "\n" - (rpcUser: "rpcauth=${rpcUser.name}:${rpcUser.passwordHMAC}") - (attrValues cfg.rpc.users) - } - rpcbind=${cfg.rpc.address} - rpcconnect=${cfg.rpc.address} - ${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpcallowip} - rpcuser=${cfg.rpcuser} - mainchainrpchost=${config.services.bitcoind.rpc.address} - mainchainrpcport=${toString config.services.bitcoind.rpc.port} - mainchainrpcuser=${config.services.bitcoind.rpc.users.public.name} - - # Extra config options (from liquidd nixos service) - ${cfg.extraConfig} - ''; - cmdlineOptions = concatMapStringsSep " " (arg: "'${arg}'") [ - "-datadir=${cfg.dataDir}" - "-pid=${pidFile}" - ]; - hexStr = types.strMatching "[0-9a-f]+"; - rpcUserOpts = { name, ... }: { - options = { - name = mkOption { - type = types.str; - example = "alice"; - description = '' - Username for JSON-RPC connections. - ''; - }; - passwordHMAC = mkOption { - type = with types; uniq (strMatching "[0-9a-f]+\\$[0-9a-f]{64}"); - example = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae"; - description = '' - Password HMAC-SHA-256 for JSON-RPC connections. Must be a string of the - format $. - ''; - }; - }; - config = { - name = mkDefault name; - }; - }; -in { options = { services.liquidd = { @@ -203,6 +137,73 @@ in { }; }; + cfg = config.services.liquidd; + nbLib = config.nix-bitcoin.lib; + nbPkgs = config.nix-bitcoin.pkgs; + secretsDir = config.nix-bitcoin.secretsDir; + pidFile = "${cfg.dataDir}/liquidd.pid"; + configFile = pkgs.writeText "elements.conf" '' + chain=${config.services.bitcoind.makeNetworkName "liquidv1" '' + regtest + [regtest]'' # Add [regtest] config section + } + ${optionalString (cfg.dbCache != null) "dbcache=${toString cfg.dbCache}"} + ${optionalString (cfg.prune != null) "prune=${toString cfg.prune}"} + ${optionalString (cfg.validatepegin != null) "validatepegin=${if cfg.validatepegin then "1" else "0"}"} + + # Connection options + ${optionalString cfg.listen "bind=${cfg.address}"} + port=${toString cfg.port} + ${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"} + listen=${if cfg.listen then "1" else "0"} + + # RPC server options + rpcport=${toString cfg.rpc.port} + ${concatMapStringsSep "\n" + (rpcUser: "rpcauth=${rpcUser.name}:${rpcUser.passwordHMAC}") + (attrValues cfg.rpc.users) + } + rpcbind=${cfg.rpc.address} + rpcconnect=${cfg.rpc.address} + ${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpcallowip} + rpcuser=${cfg.rpcuser} + mainchainrpchost=${config.services.bitcoind.rpc.address} + mainchainrpcport=${toString config.services.bitcoind.rpc.port} + mainchainrpcuser=${config.services.bitcoind.rpc.users.public.name} + + # Extra config options (from liquidd nixos service) + ${cfg.extraConfig} + ''; + cmdlineOptions = concatMapStringsSep " " (arg: "'${arg}'") [ + "-datadir=${cfg.dataDir}" + "-pid=${pidFile}" + ]; + hexStr = types.strMatching "[0-9a-f]+"; + rpcUserOpts = { name, ... }: { + options = { + name = mkOption { + type = types.str; + example = "alice"; + description = '' + Username for JSON-RPC connections. + ''; + }; + passwordHMAC = mkOption { + type = with types; uniq (strMatching "[0-9a-f]+\\$[0-9a-f]{64}"); + example = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae"; + description = '' + Password HMAC-SHA-256 for JSON-RPC connections. Must be a string of the + format $. + ''; + }; + }; + config = { + name = mkDefault name; + }; + }; +in { + inherit options; + config = mkIf cfg.enable { services.bitcoind.enable = true; diff --git a/modules/lnd-rest-onion-service.nix b/modules/lnd-rest-onion-service.nix index 344885e..8b2ea25 100644 --- a/modules/lnd-rest-onion-service.nix +++ b/modules/lnd-rest-onion-service.nix @@ -1,24 +1,7 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.services.lnd.restOnionService; - nbLib = config.nix-bitcoin.lib; - runAsUser = config.nix-bitcoin.runAsUserCmd; - - lnd = config.services.lnd; - - bin = pkgs.writeScriptBin "lndconnect-rest-onion" '' - #!/usr/bin/env -S ${runAsUser} ${lnd.user} ${pkgs.bash}/bin/bash - - exec ${cfg.package}/bin/lndconnect \ - --host=$(cat ${config.nix-bitcoin.onionAddresses.dataDir}/lnd/lnd-rest) \ - --port=${toString lnd.restPort} \ - --lnddir=${lnd.dataDir} \ - --tlscertpath=${lnd.certPath} "$@" - ''; -in { options.services.lnd.restOnionService = { enable = mkOption { default = false; @@ -36,6 +19,24 @@ in { }; }; + cfg = config.services.lnd.restOnionService; + nbLib = config.nix-bitcoin.lib; + runAsUser = config.nix-bitcoin.runAsUserCmd; + + lnd = config.services.lnd; + + bin = pkgs.writeScriptBin "lndconnect-rest-onion" '' + #!/usr/bin/env -S ${runAsUser} ${lnd.user} ${pkgs.bash}/bin/bash + + exec ${cfg.package}/bin/lndconnect \ + --host=$(cat ${config.nix-bitcoin.onionAddresses.dataDir}/lnd/lnd-rest) \ + --port=${toString lnd.restPort} \ + --lnddir=${lnd.dataDir} \ + --tlscertpath=${lnd.certPath} "$@" + ''; +in { + inherit options; + config = mkIf cfg.enable { services.tor = { enable = true; diff --git a/modules/lnd.nix b/modules/lnd.nix index 5c7b5ec..7c1a84f 100644 --- a/modules/lnd.nix +++ b/modules/lnd.nix @@ -1,42 +1,7 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.services.lnd; - nbLib = config.nix-bitcoin.lib; - secretsDir = config.nix-bitcoin.secretsDir; - runAsUser = config.nix-bitcoin.runAsUserCmd; - - bitcoind = config.services.bitcoind; - bitcoindRpcAddress = bitcoind.rpc.address; - networkDir = "${cfg.dataDir}/chain/bitcoin/${bitcoind.network}"; - configFile = pkgs.writeText "lnd.conf" '' - datadir=${cfg.dataDir} - logdir=${cfg.dataDir}/logs - tlscertpath=${cfg.certPath} - tlskeypath=${secretsDir}/lnd-key - - listen=${toString cfg.address}:${toString cfg.port} - rpclisten=${cfg.rpcAddress}:${toString cfg.rpcPort} - restlisten=${cfg.restAddress}:${toString cfg.restPort} - - bitcoin.${bitcoind.network}=1 - bitcoin.active=1 - bitcoin.node=bitcoind - - ${optionalString (cfg.enforceTor) "tor.active=true"} - ${optionalString (cfg.tor-socks != null) "tor.socks=${cfg.tor-socks}"} - - bitcoind.rpchost=${bitcoindRpcAddress}:${toString bitcoind.rpc.port} - bitcoind.rpcuser=${bitcoind.rpc.users.public.name} - bitcoind.zmqpubrawblock=${bitcoind.zmqpubrawblock} - bitcoind.zmqpubrawtx=${bitcoind.zmqpubrawtx} - - ${cfg.extraConfig} - ''; -in { - options.services.lnd = { enable = mkEnableOption "Lightning Network Daemon"; dataDir = mkOption { @@ -157,6 +122,42 @@ in { inherit (nbLib) enforceTor; }; + cfg = config.services.lnd; + nbLib = config.nix-bitcoin.lib; + secretsDir = config.nix-bitcoin.secretsDir; + runAsUser = config.nix-bitcoin.runAsUserCmd; + + bitcoind = config.services.bitcoind; + bitcoindRpcAddress = bitcoind.rpc.address; + networkDir = "${cfg.dataDir}/chain/bitcoin/${bitcoind.network}"; + configFile = pkgs.writeText "lnd.conf" '' + datadir=${cfg.dataDir} + logdir=${cfg.dataDir}/logs + tlscertpath=${cfg.certPath} + tlskeypath=${secretsDir}/lnd-key + + listen=${toString cfg.address}:${toString cfg.port} + rpclisten=${cfg.rpcAddress}:${toString cfg.rpcPort} + restlisten=${cfg.restAddress}:${toString cfg.restPort} + + bitcoin.${bitcoind.network}=1 + bitcoin.active=1 + bitcoin.node=bitcoind + + ${optionalString (cfg.enforceTor) "tor.active=true"} + ${optionalString (cfg.tor-socks != null) "tor.socks=${cfg.tor-socks}"} + + bitcoind.rpchost=${bitcoindRpcAddress}:${toString bitcoind.rpc.port} + bitcoind.rpcuser=${bitcoind.rpc.users.public.name} + bitcoind.zmqpubrawblock=${bitcoind.zmqpubrawblock} + bitcoind.zmqpubrawtx=${bitcoind.zmqpubrawtx} + + ${cfg.extraConfig} + ''; +in { + + inherit options; + config = mkIf cfg.enable { assertions = [ { assertion = bitcoind.prune == 0; diff --git a/modules/netns-isolation.nix b/modules/netns-isolation.nix index e7ea4c5..88e486d 100644 --- a/modules/netns-isolation.nix +++ b/modules/netns-isolation.nix @@ -1,50 +1,7 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.nix-bitcoin.netns-isolation; - - netns = builtins.mapAttrs (n: v: { - inherit (v) id; - address = "169.254.${toString cfg.addressblock}.${toString v.id}"; - availableNetns = availableNetns.${n}; - netnsName = "nb-${n}"; - }) enabledServices; - - # Symmetric netns connection matrix - # if clightning.connections = [ "bitcoind" ]; then - # availableNetns.bitcoind = [ "clighting" ]; - # and - # availableNetns.clighting = [ "bitcoind" ]; - # - # FIXME: Although negligible for our purposes, this calculation's runtime - # is in the order of (number of connections * number of services), - # because attrsets and lists are fully copied on each update with '//' or '++'. - # This can only be improved with an update in the nix language. - # - availableNetns = let - # base = { clightning = [ "bitcoind" ]; ... } - base = builtins.mapAttrs (n: v: - builtins.filter isEnabled v.connections - ) enabledServices; - in - foldl (xs: s1: - foldl (xs: s2: - xs // { "${s2}" = xs.${s2} ++ [ s1 ]; } - ) xs cfg.services.${s1}.connections - ) base (builtins.attrNames base); - - enabledServices = filterAttrs (n: v: isEnabled n) cfg.services; - isEnabled = x: config.services.${x}.enable; - - ip = "${pkgs.iproute}/bin/ip"; - iptables = "${config.networking.firewall.package}/bin/iptables"; - - bridgeIp = "169.254.${toString cfg.addressblock}.10"; - - mkCliExec = service: "exec netns-exec ${netns.${service}.netnsName}"; -in { options.nix-bitcoin.netns-isolation = { enable = mkEnableOption "netns isolation"; @@ -92,6 +49,50 @@ in { }; }; + cfg = config.nix-bitcoin.netns-isolation; + + netns = builtins.mapAttrs (n: v: { + inherit (v) id; + address = "169.254.${toString cfg.addressblock}.${toString v.id}"; + availableNetns = availableNetns.${n}; + netnsName = "nb-${n}"; + }) enabledServices; + + # Symmetric netns connection matrix + # if clightning.connections = [ "bitcoind" ]; then + # availableNetns.bitcoind = [ "clighting" ]; + # and + # availableNetns.clighting = [ "bitcoind" ]; + # + # FIXME: Although negligible for our purposes, this calculation's runtime + # is in the order of (number of connections * number of services), + # because attrsets and lists are fully copied on each update with '//' or '++'. + # This can only be improved with an update in the nix language. + # + availableNetns = let + # base = { clightning = [ "bitcoind" ]; ... } + base = builtins.mapAttrs (n: v: + builtins.filter isEnabled v.connections + ) enabledServices; + in + foldl (xs: s1: + foldl (xs: s2: + xs // { "${s2}" = xs.${s2} ++ [ s1 ]; } + ) xs cfg.services.${s1}.connections + ) base (builtins.attrNames base); + + enabledServices = filterAttrs (n: v: isEnabled n) cfg.services; + isEnabled = x: config.services.${x}.enable; + + ip = "${pkgs.iproute}/bin/ip"; + iptables = "${config.networking.firewall.package}/bin/iptables"; + + bridgeIp = "169.254.${toString cfg.addressblock}.10"; + + mkCliExec = service: "exec netns-exec ${netns.${service}.netnsName}"; +in { + inherit options; + config = mkIf cfg.enable (mkMerge [ # Base infrastructure diff --git a/modules/nodeinfo.nix b/modules/nodeinfo.nix index c395bfb..5a9599c 100644 --- a/modules/nodeinfo.nix +++ b/modules/nodeinfo.nix @@ -2,6 +2,16 @@ with lib; let + options = { + nix-bitcoin.nodeinfo = { + enable = mkEnableOption "nodeinfo"; + program = mkOption { + readOnly = true; + default = script; + }; + }; + }; + cfg = config.nix-bitcoin.nodeinfo; # Services included in the output @@ -102,15 +112,7 @@ let inherit (config.services.tor.relay) onionServices; in { - options = { - nix-bitcoin.nodeinfo = { - enable = mkEnableOption "nodeinfo"; - program = mkOption { - readOnly = true; - default = script; - }; - }; - }; + inherit options; config = { environment.systemPackages = optional cfg.enable script; diff --git a/modules/onion-addresses.nix b/modules/onion-addresses.nix index e3872a9..9a5cd47 100644 --- a/modules/onion-addresses.nix +++ b/modules/onion-addresses.nix @@ -7,11 +7,7 @@ { config, lib, ... }: with lib; - let - cfg = config.nix-bitcoin.onionAddresses; - nbLib = config.nix-bitcoin.lib; -in { options.nix-bitcoin.onionAddresses = { access = mkOption { type = with types; attrsOf (listOf str); @@ -42,6 +38,11 @@ in { }; }; + cfg = config.nix-bitcoin.onionAddresses; + nbLib = config.nix-bitcoin.lib; +in { + inherit options; + config = mkIf (cfg.access != {} || cfg.services != []) { systemd.services.onion-addresses = { wantedBy = [ "tor.service" ]; diff --git a/modules/onion-services.nix b/modules/onion-services.nix index a6d39a0..25c9f45 100644 --- a/modules/onion-services.nix +++ b/modules/onion-services.nix @@ -7,19 +7,7 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.nix-bitcoin.onionServices; - nbLib = config.nix-bitcoin.lib; - - services = builtins.attrNames cfg; - - activeServices = builtins.filter (service: - config.services.${service}.enable && cfg.${service}.enable - ) services; - - publicServices = builtins.filter (service: cfg.${service}.public) activeServices; -in { options.nix-bitcoin.onionServices = mkOption { default = {}; type = with types; attrsOf (submodule ( @@ -52,6 +40,19 @@ in { )); }; + cfg = config.nix-bitcoin.onionServices; + nbLib = config.nix-bitcoin.lib; + + services = builtins.attrNames cfg; + + activeServices = builtins.filter (service: + config.services.${service}.enable && cfg.${service}.enable + ) services; + + publicServices = builtins.filter (service: cfg.${service}.public) activeServices; +in { + inherit options; + config = mkMerge [ (mkIf (cfg != {}) { # Define hidden services diff --git a/modules/operator.nix b/modules/operator.nix index f336f82..627f8d1 100644 --- a/modules/operator.nix +++ b/modules/operator.nix @@ -8,8 +8,6 @@ with lib; let - cfg = config.nix-bitcoin.operator; -in { options.nix-bitcoin.operator = { enable = mkEnableOption "operator user"; name = mkOption { @@ -29,6 +27,10 @@ in { }; }; + cfg = config.nix-bitcoin.operator; +in { + inherit options; + config = mkIf cfg.enable { users.users.${cfg.name} = { isNormalUser = true; diff --git a/modules/recurring-donations.nix b/modules/recurring-donations.nix index 7d0680b..84922a0 100644 --- a/modules/recurring-donations.nix +++ b/modules/recurring-donations.nix @@ -1,8 +1,39 @@ { config, lib, pkgs, ... }: with lib; - let + options.services.recurring-donations = { + enable = mkEnableOption "recurring-donations"; + tallycoin = mkOption { + type = types.attrs; + default = {}; + description = '' + This option is used to specify tallycoin donation receivers using an + attribute set. For example the following setting instructs the module + to repeatedly send 1000 satoshis to djbooth007. + { + "djbooth007" = 1000; + } + ''; + }; + interval = mkOption { + type = types.str; + default = "Mon *-*-* 00:00:00"; + description = '' + Schedules the donations. Default is weekly on Mon 00:00:00. See `man + systemd.time` for further options. + ''; + }; + randomizedDelaySec = mkOption { + type = types.int; + default = 86400; + description = '' + Random delay to add to scheduled time for donation. Default is one day. + ''; + }; + enforceTor = nbLib.enforceTor; + }; + cfg = config.services.recurring-donations; nbLib = config.nix-bitcoin.lib; recurring-donations-script = pkgs.writeScript "recurring-donations.sh" '' @@ -40,37 +71,7 @@ let } ''; in { - options.services.recurring-donations = { - enable = mkEnableOption "recurring-donations"; - tallycoin = mkOption { - type = types.attrs; - default = {}; - description = '' - This option is used to specify tallycoin donation receivers using an - attribute set. For example the following setting instructs the module - to repeatedly send 1000 satoshis to djbooth007. - { - "djbooth007" = 1000; - } - ''; - }; - interval = mkOption { - type = types.str; - default = "Mon *-*-* 00:00:00"; - description = '' - Schedules the donations. Default is weekly on Mon 00:00:00. See `man - systemd.time` for further options. - ''; - }; - randomizedDelaySec = mkOption { - type = types.int; - default = 86400; - description = '' - Random delay to add to scheduled time for donation. Default is one day. - ''; - }; - enforceTor = nbLib.enforceTor; - }; + inherit options; config = mkIf cfg.enable { services.clightning.enable = true; diff --git a/modules/spark-wallet.nix b/modules/spark-wallet.nix index bdefea8..73b2b9a 100644 --- a/modules/spark-wallet.nix +++ b/modules/spark-wallet.nix @@ -1,27 +1,7 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.services.spark-wallet; - nbLib = config.nix-bitcoin.lib; - - # Use wasabi rate provider because the default (bitstamp) doesn't accept - # connections through Tor - torRateProvider = "--rate-provider wasabi --proxy socks5h://${config.nix-bitcoin.torClientAddressWithPort}"; - startScript = '' - ${optionalString (cfg.getPublicAddressCmd != "") '' - publicURL="--public-url http://$(${cfg.getPublicAddressCmd})" - ''} - exec ${config.nix-bitcoin.pkgs.spark-wallet}/bin/spark-wallet \ - --ln-path '${config.services.clightning.networkDir}' \ - --host ${cfg.address} --port ${toString cfg.port} \ - --config '${config.nix-bitcoin.secretsDir}/spark-wallet-login' \ - ${optionalString cfg.enforceTor torRateProvider} \ - $publicURL \ - --pairing-qr --print-key ${cfg.extraArgs} - ''; -in { options.services.spark-wallet = { enable = mkEnableOption "spark-wallet"; address = mkOption { @@ -61,6 +41,27 @@ in { inherit (nbLib) enforceTor; }; + cfg = config.services.spark-wallet; + nbLib = config.nix-bitcoin.lib; + + # Use wasabi rate provider because the default (bitstamp) doesn't accept + # connections through Tor + torRateProvider = "--rate-provider wasabi --proxy socks5h://${config.nix-bitcoin.torClientAddressWithPort}"; + startScript = '' + ${optionalString (cfg.getPublicAddressCmd != "") '' + publicURL="--public-url http://$(${cfg.getPublicAddressCmd})" + ''} + exec ${config.nix-bitcoin.pkgs.spark-wallet}/bin/spark-wallet \ + --ln-path '${config.services.clightning.networkDir}' \ + --host ${cfg.address} --port ${toString cfg.port} \ + --config '${config.nix-bitcoin.secretsDir}/spark-wallet-login' \ + ${optionalString cfg.enforceTor torRateProvider} \ + $publicURL \ + --pairing-qr --print-key ${cfg.extraArgs} + ''; +in { + inherit options; + config = mkIf cfg.enable { services.clightning.enable = true; diff --git a/modules/versioning.nix b/modules/versioning.nix index 76c8af8..c57add6 100644 --- a/modules/versioning.nix +++ b/modules/versioning.nix @@ -7,6 +7,21 @@ with lib; let + options = { + nix-bitcoin.configVersion = mkOption { + type = with types; nullOr str; + default = null; + description = '' + Set this option to the nix-bitcoin release version that your config is + compatible with. + + When upgrading to a backwards-incompatible release, nix-bitcoin will throw an + error during evaluation and provide hints for migrating your config to the + new release. + ''; + }; + }; + version = config.nix-bitcoin.configVersion; # Sorted by increasing version numbers @@ -161,20 +176,7 @@ in ./obsolete-options.nix ]; - options = { - nix-bitcoin.configVersion = mkOption { - type = with types; nullOr str; - default = null; - description = '' - Set this option to the nix-bitcoin release version that your config is - compatible with. - - When upgrading to a backwards-incompatible release, nix-bitcoin will throw an - error during evaluation and provide hints for migrating your config to the - new release. - ''; - }; - }; + inherit options; config = { # Force evaluation. An actual option value is never assigned From ad97c268c639a30cff19bb380ce4feec63f77af4 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Mon, 13 Sep 2021 13:40:48 +0200 Subject: [PATCH 3/5] modules: move user/group options to bottom These are insignificant, generic options; place them above readonly options. We already do this in other services. Also move user/group config to bottom in spark-wallet. --- modules/bitcoind.nix | 20 ++++++++++---------- modules/btcpayserver.nix | 20 ++++++++++---------- modules/electrs.nix | 20 ++++++++++---------- modules/joinmarket.nix | 14 +++++++------- modules/liquid.nix | 21 ++++++++++----------- modules/spark-wallet.nix | 14 +++++++------- 6 files changed, 54 insertions(+), 55 deletions(-) diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix index 50f1a88..e52b525 100644 --- a/modules/bitcoind.nix +++ b/modules/bitcoind.nix @@ -43,16 +43,6 @@ let default = "/var/lib/bitcoind"; description = "The data directory for bitcoind."; }; - user = mkOption { - type = types.str; - default = "bitcoin"; - description = "The user as which to run bitcoind."; - }; - group = mkOption { - type = types.str; - default = cfg.user; - description = "The group as which to run bitcoind."; - }; rpc = { address = mkOption { type = types.str; @@ -221,6 +211,16 @@ let example = "bech32"; description = "The type of addresses to use"; }; + user = mkOption { + type = types.str; + default = "bitcoin"; + description = "The user as which to run bitcoind."; + }; + group = mkOption { + type = types.str; + default = cfg.user; + description = "The group as which to run bitcoind."; + }; cli = mkOption { readOnly = true; type = types.package; diff --git a/modules/btcpayserver.nix b/modules/btcpayserver.nix index f35b7f6..682b5c7 100644 --- a/modules/btcpayserver.nix +++ b/modules/btcpayserver.nix @@ -67,16 +67,6 @@ let default = "/var/lib/btcpayserver"; description = "The data directory for btcpayserver."; }; - user = mkOption { - type = types.str; - default = "btcpayserver"; - description = "The user as which to run btcpayserver."; - }; - group = mkOption { - type = types.str; - default = cfg.btcpayserver.user; - description = "The group as which to run btcpayserver."; - }; lightningBackend = mkOption { type = types.nullOr (types.enum [ "clightning" "lnd" ]); default = null; @@ -93,6 +83,16 @@ let example = "btcpayserver"; description = "The prefix for root-relative btcpayserver URLs."; }; + user = mkOption { + type = types.str; + default = "btcpayserver"; + description = "The user as which to run btcpayserver."; + }; + group = mkOption { + type = types.str; + default = cfg.btcpayserver.user; + description = "The group as which to run btcpayserver."; + }; enforceTor = nbLib.enforceTor; }; }; diff --git a/modules/electrs.nix b/modules/electrs.nix index f650954..095f6a0 100644 --- a/modules/electrs.nix +++ b/modules/electrs.nix @@ -19,16 +19,6 @@ let default = "/var/lib/electrs"; description = "The data directory for electrs."; }; - user = mkOption { - type = types.str; - default = "electrs"; - description = "The user as which to run electrs."; - }; - group = mkOption { - type = types.str; - default = cfg.user; - description = "The group as which to run electrs."; - }; high-memory = mkOption { type = types.bool; default = false; @@ -46,6 +36,16 @@ let default = ""; description = "Extra command line arguments passed to electrs."; }; + user = mkOption { + type = types.str; + default = "electrs"; + description = "The user as which to run electrs."; + }; + group = mkOption { + type = types.str; + default = cfg.user; + description = "The group as which to run electrs."; + }; enforceTor = nbLib.enforceTor; }; diff --git a/modules/joinmarket.nix b/modules/joinmarket.nix index 632a4b0..f2e92d9 100644 --- a/modules/joinmarket.nix +++ b/modules/joinmarket.nix @@ -9,6 +9,13 @@ let default = "/var/lib/joinmarket"; description = "The data directory for JoinMarket."; }; + rpcWalletFile = mkOption { + type = types.nullOr types.str; + default = "jm_wallet"; + description = '' + Name of the watch-only bitcoind wallet the JoinMarket addresses are imported to. + ''; + }; user = mkOption { type = types.str; default = "joinmarket"; @@ -19,13 +26,6 @@ let default = cfg.user; description = "The group as which to run JoinMarket."; }; - rpcWalletFile = mkOption { - type = types.nullOr types.str; - default = "jm_wallet"; - description = '' - Name of the watch-only bitcoind wallet the JoinMarket addresses are imported to. - ''; - }; cli = mkOption { default = cli; }; diff --git a/modules/liquid.nix b/modules/liquid.nix index b729a11..e2a57e8 100644 --- a/modules/liquid.nix +++ b/modules/liquid.nix @@ -3,7 +3,6 @@ with lib; let options = { - services.liquidd = { enable = mkEnableOption "Liquid sidechain"; address = mkOption { @@ -31,16 +30,6 @@ let default = "/var/lib/liquidd"; description = "The data directory for liquidd."; }; - user = mkOption { - type = types.str; - default = "liquid"; - description = "The user as which to run liquidd."; - }; - group = mkOption { - type = types.str; - default = cfg.user; - description = "The group as which to run liquidd."; - }; rpc = { address = mkOption { type = types.str; @@ -120,6 +109,16 @@ let Validate pegin claims. All functionaries must run this. ''; }; + user = mkOption { + type = types.str; + default = "liquid"; + description = "The user as which to run liquidd."; + }; + group = mkOption { + type = types.str; + default = cfg.user; + description = "The group as which to run liquidd."; + }; cli = mkOption { readOnly = true; default = pkgs.writeScriptBin "elements-cli" '' diff --git a/modules/spark-wallet.nix b/modules/spark-wallet.nix index 73b2b9a..0ca153c 100644 --- a/modules/spark-wallet.nix +++ b/modules/spark-wallet.nix @@ -65,13 +65,6 @@ in { config = mkIf cfg.enable { services.clightning.enable = true; - users.users.${cfg.user} = { - isSystemUser = true; - group = cfg.group; - extraGroups = [ config.services.clightning.group ]; - }; - users.groups.${cfg.group} = {}; - systemd.services.spark-wallet = { wantedBy = [ "multi-user.target" ]; requires = [ "clightning.service" ]; @@ -85,6 +78,13 @@ in { // nbLib.nodejs; }; + users.users.${cfg.user} = { + isSystemUser = true; + group = cfg.group; + extraGroups = [ config.services.clightning.group ]; + }; + users.groups.${cfg.group} = {}; + nix-bitcoin.secrets.spark-wallet-login.user = cfg.user; nix-bitcoin.generateSecretsCmds.spark-wallet = '' makePasswordSecret spark-wallet-password From c8774375d32186ca190e6f5b2e50ec881c53268c Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Mon, 13 Sep 2021 13:40:49 +0200 Subject: [PATCH 4/5] modules: use consistent service variables Benefits of adding top-level variables for used services: - Makes it obvious which other services are referenced by a service - Less code We already do this in many other places. --- modules/btcpayserver.nix | 12 +++++++----- modules/charge-lnd.nix | 2 +- modules/clightning.nix | 1 + modules/liquid.nix | 11 +++++++---- modules/lnd.nix | 1 + modules/spark-wallet.nix | 6 ++++-- 6 files changed, 21 insertions(+), 12 deletions(-) diff --git a/modules/btcpayserver.nix b/modules/btcpayserver.nix index 682b5c7..aa2422f 100644 --- a/modules/btcpayserver.nix +++ b/modules/btcpayserver.nix @@ -100,6 +100,8 @@ let cfg = config.services; nbLib = config.nix-bitcoin.lib; nbPkgs = config.nix-bitcoin.pkgs; + + bitcoind = config.services.bitcoind; in { inherit options; @@ -139,10 +141,10 @@ in { systemd.services.nbxplorer = let configFile = builtins.toFile "config" '' - network=${config.services.bitcoind.network} + network=${bitcoind.network} btcrpcuser=${cfg.bitcoind.rpc.users.btcpayserver.name} - btcrpcurl=http://${config.services.bitcoind.rpc.address}:${toString cfg.bitcoind.rpc.port} - btcnodeendpoint=${config.services.bitcoind.address}:${toString config.services.bitcoind.port} + btcrpcurl=http://${bitcoind.rpc.address}:${toString cfg.bitcoind.rpc.port} + btcnodeendpoint=${bitcoind.address}:${toString bitcoind.port} bind=${cfg.nbxplorer.address} port=${toString cfg.nbxplorer.port} ${optionalString cfg.btcpayserver.lbtc '' @@ -180,9 +182,9 @@ in { systemd.services.btcpayserver = let nbExplorerUrl = "http://${cfg.nbxplorer.address}:${toString cfg.nbxplorer.port}/"; - nbExplorerCookie = "${cfg.nbxplorer.dataDir}/${config.services.bitcoind.makeNetworkName "Main" "RegTest"}/.cookie"; + nbExplorerCookie = "${cfg.nbxplorer.dataDir}/${bitcoind.makeNetworkName "Main" "RegTest"}/.cookie"; configFile = builtins.toFile "config" ('' - network=${config.services.bitcoind.network} + network=${bitcoind.network} bind=${cfg.btcpayserver.address} port=${toString cfg.btcpayserver.port} socksendpoint=${config.nix-bitcoin.torClientAddressWithPort} diff --git a/modules/charge-lnd.nix b/modules/charge-lnd.nix index 8e72478..f6579c1 100644 --- a/modules/charge-lnd.nix +++ b/modules/charge-lnd.nix @@ -69,6 +69,7 @@ let cfg = config.services.charge-lnd; nbLib = config.nix-bitcoin.lib; + lnd = config.services.lnd; electrs = if (config.services ? electrs) && config.services.electrs.enable then config.services.electrs @@ -77,7 +78,6 @@ let user = "charge-lnd"; group = user; dataDir = "/var/lib/charge-lnd"; - configFile = builtins.toFile "charge-lnd.config" cfg.policies; checkedConfig = pkgs.runCommandNoCC "charge-lnd-checked.config" { } '' ${config.nix-bitcoin.pkgs.charge-lnd}/bin/charge-lnd --check --config ${configFile} diff --git a/modules/clightning.nix b/modules/clightning.nix index 6aea551..58a59bd 100644 --- a/modules/clightning.nix +++ b/modules/clightning.nix @@ -76,6 +76,7 @@ let cfg = config.services.clightning; nbLib = config.nix-bitcoin.lib; nbPkgs = config.nix-bitcoin.pkgs; + network = config.services.bitcoind.makeNetworkName "bitcoin" "regtest"; configFile = pkgs.writeText "config" '' network=${network} diff --git a/modules/liquid.nix b/modules/liquid.nix index e2a57e8..9a311fc 100644 --- a/modules/liquid.nix +++ b/modules/liquid.nix @@ -140,9 +140,12 @@ let nbLib = config.nix-bitcoin.lib; nbPkgs = config.nix-bitcoin.pkgs; secretsDir = config.nix-bitcoin.secretsDir; + + bitcoind = config.services.bitcoind; + pidFile = "${cfg.dataDir}/liquidd.pid"; configFile = pkgs.writeText "elements.conf" '' - chain=${config.services.bitcoind.makeNetworkName "liquidv1" '' + chain=${bitcoind.makeNetworkName "liquidv1" '' regtest [regtest]'' # Add [regtest] config section } @@ -166,9 +169,9 @@ let rpcconnect=${cfg.rpc.address} ${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpcallowip} rpcuser=${cfg.rpcuser} - mainchainrpchost=${config.services.bitcoind.rpc.address} - mainchainrpcport=${toString config.services.bitcoind.rpc.port} - mainchainrpcuser=${config.services.bitcoind.rpc.users.public.name} + mainchainrpchost=${bitcoind.rpc.address} + mainchainrpcport=${toString bitcoind.rpc.port} + mainchainrpcuser=${bitcoind.rpc.users.public.name} # Extra config options (from liquidd nixos service) ${cfg.extraConfig} diff --git a/modules/lnd.nix b/modules/lnd.nix index 7c1a84f..7e93113 100644 --- a/modules/lnd.nix +++ b/modules/lnd.nix @@ -128,6 +128,7 @@ let runAsUser = config.nix-bitcoin.runAsUserCmd; bitcoind = config.services.bitcoind; + bitcoindRpcAddress = bitcoind.rpc.address; networkDir = "${cfg.dataDir}/chain/bitcoin/${bitcoind.network}"; configFile = pkgs.writeText "lnd.conf" '' diff --git a/modules/spark-wallet.nix b/modules/spark-wallet.nix index 0ca153c..a55be9a 100644 --- a/modules/spark-wallet.nix +++ b/modules/spark-wallet.nix @@ -44,6 +44,8 @@ let cfg = config.services.spark-wallet; nbLib = config.nix-bitcoin.lib; + clightning = config.services.clightning; + # Use wasabi rate provider because the default (bitstamp) doesn't accept # connections through Tor torRateProvider = "--rate-provider wasabi --proxy socks5h://${config.nix-bitcoin.torClientAddressWithPort}"; @@ -52,7 +54,7 @@ let publicURL="--public-url http://$(${cfg.getPublicAddressCmd})" ''} exec ${config.nix-bitcoin.pkgs.spark-wallet}/bin/spark-wallet \ - --ln-path '${config.services.clightning.networkDir}' \ + --ln-path '${clightning.networkDir}' \ --host ${cfg.address} --port ${toString cfg.port} \ --config '${config.nix-bitcoin.secretsDir}/spark-wallet-login' \ ${optionalString cfg.enforceTor torRateProvider} \ @@ -81,7 +83,7 @@ in { users.users.${cfg.user} = { isSystemUser = true; group = cfg.group; - extraGroups = [ config.services.clightning.group ]; + extraGroups = [ clightning.group ]; }; users.groups.${cfg.group} = {}; From 9114ec669a8c015ce956ff66007a7803d2a0c8f6 Mon Sep 17 00:00:00 2001 From: Erik Arvstedt Date: Thu, 16 Sep 2021 12:48:21 +0200 Subject: [PATCH 5/5] lnd: improve options formatting --- modules/lnd.nix | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/modules/lnd.nix b/modules/lnd.nix index 7e93113..648a2c1 100644 --- a/modules/lnd.nix +++ b/modules/lnd.nix @@ -4,16 +4,6 @@ with lib; let options.services.lnd = { enable = mkEnableOption "Lightning Network Daemon"; - dataDir = mkOption { - type = types.path; - default = "/var/lib/lnd"; - description = "The data directory for LND."; - }; - networkDir = mkOption { - readOnly = true; - default = networkDir; - description = "The network data directory."; - }; address = mkOption { type = types.str; default = "localhost"; @@ -37,15 +27,23 @@ let restAddress = mkOption { type = types.str; default = "localhost"; - description = '' - Address to listen for REST connections. - ''; + description = "Address to listen for REST connections."; }; restPort = mkOption { type = types.port; default = 8080; description = "Port to listen for REST connections."; }; + dataDir = mkOption { + type = types.path; + default = "/var/lib/lnd"; + description = "The data directory for LND."; + }; + networkDir = mkOption { + readOnly = true; + default = "${cfg.dataDir}/chain/bitcoin/${bitcoind.network}"; + description = "The network data directory."; + }; tor-socks = mkOption { type = types.nullOr types.str; default = if cfg.enforceTor then config.nix-bitcoin.torClientAddressWithPort else null; @@ -87,13 +85,13 @@ let }; cli = mkOption { default = pkgs.writeScriptBin "lncli" - # Switch user because lnd makes datadir contents readable by user only - '' - ${runAsUser} ${cfg.user} ${cfg.package}/bin/lncli \ - --rpcserver ${cfg.rpcAddress}:${toString cfg.rpcPort} \ - --tlscertpath '${cfg.certPath}' \ - --macaroonpath '${networkDir}/admin.macaroon' "$@" - ''; + # Switch user because lnd makes datadir contents readable by user only + '' + ${runAsUser} ${cfg.user} ${cfg.package}/bin/lncli \ + --rpcserver ${cfg.rpcAddress}:${toString cfg.rpcPort} \ + --tlscertpath '${cfg.certPath}' \ + --macaroonpath '${networkDir}/admin.macaroon' "$@" + ''; description = "Binary to connect with the lnd instance."; }; getPublicAddressCmd = mkOption { @@ -130,7 +128,7 @@ let bitcoind = config.services.bitcoind; bitcoindRpcAddress = bitcoind.rpc.address; - networkDir = "${cfg.dataDir}/chain/bitcoin/${bitcoind.network}"; + networkDir = cfg.networkDir; configFile = pkgs.writeText "lnd.conf" '' datadir=${cfg.dataDir} logdir=${cfg.dataDir}/logs