Merge fort-nix/nix-bitcoin#402: Misc. improvements

6d694a6269 backups: allow extraFiles to override default settings (Erik Arvstedt)
0c45415c86 backups: exclude bitcoind, liquidd txindex data (Erik Arvstedt)
0853dedc43 tests/regtest: don't fail when restarting bitcoind (Erik Arvstedt)
b73c093d3d joinmarket-ob-watcher: require nix-bitcoin.service (Erik Arvstedt)
27905e2c3a tests: disable restarting joinmarket-ob-watcher (Erik Arvstedt)
c8251cdad7 onion-services: don't always enable Tor (Erik Arvstedt)
3c6a664b7b examples/configuration: show how to enable sudo/doas for `operator` (Erik Arvstedt)
4d5bc810eb secrets: fix setup-secrets in case of no secrets (Erik Arvstedt)
e61c743644 test: add option `extraTestScript` (Erik Arvstedt)
2cf12d8765 README: minor fixes (Erik Arvstedt)
e57ab83a51 docs/hardware: update (Erik Arvstedt)
1b597f92a6 docs/hardware: add line breaks (Erik Arvstedt)
a92d6a8e80 netns: expose bridgeIp as an option (Erik Arvstedt)
f36df8f563 secure-node: remove redundant bitcoind settings (Erik Arvstedt)
09169365d8 liquid: remove unused features (Erik Arvstedt)
82d910e937 nbxplorer: fix bitcoind, liquidd settings (Erik Arvstedt)
f61e928139 services: support 0.0.0.0/:: in `address` options (Erik Arvstedt)
1848c3dd98 btcpayserver: minor improvements (Erik Arvstedt)
e561637600 minor fixes (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  nixbitcoin:
    ACK 6d694a6269
  jonasnick:
    ACK 6d694a6269

Tree-SHA512: 9a409e05e75284a27b94ef489ab0bce8bf49b50fa01e31c7c3430e388e273e7186f74794b979b625db9cd7ec2861e9933cc93e4c54139314f7f9d54d9b5f39f2
This commit is contained in:
Jonas Nick 2021-10-06 13:21:53 +00:00
commit 693c646c49
No known key found for this signature in database
GPG Key ID: 4861DBF262123605
27 changed files with 143 additions and 85 deletions

View File

@ -52,7 +52,7 @@ Features
A [configuration preset](modules/presets/secure-node.nix) for setting up a secure node A [configuration preset](modules/presets/secure-node.nix) for setting up a secure node
* All applications use Tor for outbound connections and support accepting inbound connections via onion services. * All applications use Tor for outbound connections and support accepting inbound connections via onion services.
NixOS modules NixOS modules ([src](modules/modules.nix))
* Application services * Application services
* [bitcoind](https://github.com/bitcoin/bitcoin), with a default banlist against spy nodes * [bitcoind](https://github.com/bitcoin/bitcoin), with a default banlist against spy nodes
* [clightning](https://github.com/ElementsProject/lightning) with support for announcing an onion service\ * [clightning](https://github.com/ElementsProject/lightning) with support for announcing an onion service\
@ -85,19 +85,19 @@ NixOS modules
Security Security
--- ---
* **Simplicity:** Only services you select in `configuration.nix` and their dependencies are installed, packages and dependencies are [pinned](pkgs/nixpkgs-pinned.nix), support for [doas](https://github.com/Duncaen/OpenDoas) ([sudo alternative](https://lobste.rs/s/efsvqu/heap_based_buffer_overflow_sudo_cve_2021#c_c6fcfa)), most packages are built from the [NixOS stable channel](https://github.com/NixOS/nixpkgs/tree/nixos-20.09), with a few exceptions that are built from the nixpkgs unstable channel, builds happen in a [sandboxed environment](https://nixos.org/manual/nix/stable/#conf-sandbox), code is continuously reviewed and refined. * **Simplicity:** Only services enabled in `configuration.nix` and their dependencies are installed, support for [doas](https://github.com/Duncaen/OpenDoas) ([sudo alternative](https://lobste.rs/s/efsvqu/heap_based_buffer_overflow_sudo_cve_2021#c_c6fcfa)), code is continuously reviewed and refined.
* **Integrity:** Nix package manager, NixOS and packages can be built from source to reduce reliance on binary caches, nix-bitcoin merge commits are signed, all commits are approved by multiple nix-bitcoin developers, upstream packages are cryptographically verified where possible, we use this software ourselves. * **Integrity:** The Nix package manager guarantees that all dependencies are exactly specified, packages can be built from source to reduce reliance on binary caches, nix-bitcoin merge commits are signed, all commits are approved by multiple nix-bitcoin developers, upstream packages are cryptographically verified where possible, we use this software ourselves.
* **Principle of Least Privilege:** Services operate with least privileges; they each have their own user and are restricted further with [systemd options](pkgs/lib.nix), [RPC whitelisting](modules/bitcoind-rpc-public-whitelist.nix), and [netns-isolation](modules/netns-isolation.nix). There's a non-root user *operator* to interact with the various services. * **Principle of Least Privilege:** Services operate with least privileges; they each have their own user and are restricted further with [systemd features](pkgs/lib.nix), [RPC whitelisting](modules/bitcoind-rpc-public-whitelist.nix) and [netns-isolation](modules/netns-isolation.nix). There's a non-root user *operator* to interact with the various services.
* **Defense-in-depth:** nix-bitcoin is built with a [hardened kernel](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/hardened.nix) by default, services are confined through discretionary access control, Linux namespaces, [dbus firewall](modules/security.nix) and seccomp-bpf with continuous improvements. * **Defense-in-depth:** nix-bitcoin supports a [hardened kernel](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/hardened.nix), services are confined through discretionary access control, Linux namespaces, [dbus firewall](modules/security.nix) and seccomp-bpf with continuous improvements.
Note that if the machine you're deploying *from* is insecure, there is nothing nix-bitcoin can do to protect itself. Note that if the machine you're deploying *from* is insecure, there is nothing nix-bitcoin can do to protect itself.
Docs Docs
--- ---
* [FAQ](docs/faq.md)
* [Hardware Requirements](docs/hardware.md) * [Hardware Requirements](docs/hardware.md)
* [Install instructions](docs/install.md) * [Install instructions](docs/install.md)
* [Usage instructions](docs/usage.md) * [Usage instructions](docs/usage.md)
* [FAQ](docs/faq.md)
Troubleshooting Troubleshooting
--- ---

View File

@ -1,8 +1,18 @@
Hardware requirements Hardware requirements
--- ---
* Disk space: 500 GB (400GB for Bitcoin blockchain + some room) * RAM: 2GB. ECC memory is better. Additionally, it's recommended to use DDR4 memory with
* Bitcoin Core pruning is not supported at the moment because it's not supported by c-lightning. It's possible to use pruning but you need to know what you're doing. targeted row refresh (TRR) enabled (https://rambleed.com/).
* RAM: 2GB of memory. ECC memory is better. Additionally, it's recommended to use DDR4 memory with targeted row refresh (TRR) enabled (https://rambleed.com/). * Disk space: 500 GB (400GB for Bitcoin blockchain + some room) for an unpruned
instance of Bitcoin Core.
* This can be significantly lowered by enabling pruning.
Note: Pruning is not supported by `electrs`.
Tested hardware includes [pcengine's apu2c4](https://pcengines.ch/apu2c4.htm), [GB-BACE-3150](https://www.gigabyte.com/Mini-PcBarebone/GB-BACE-3150-rev-10), [GB-BACE-3160](https://www.gigabyte.com/de/Mini-PcBarebone/GB-BACE-3160-rev-10#ov). Tested low-end hardware includes:
Some hardware (including Intel NUCs) may not be compatible with the hardened kernel turned on by default (see https://github.com/fort-nix/nix-bitcoin/issues/39#issuecomment-517366093 for a workaround). - [Raspberry Pi 4](https://www.raspberrypi.org/products/raspberry-pi-4-model-b/)
- [PC Engines apu2c4](https://pcengines.ch/apu2c4.htm)
- [Gigabyte GB-BACE-3150](https://www.gigabyte.com/Mini-PcBarebone/GB-BACE-3150-rev-10)
- [Gigabyte GB-BACE-3160](https://www.gigabyte.com/de/Mini-PcBarebone/GB-BACE-3160-rev-10#ov)
Some hardware (including Intel NUCs) may not be compatible with the [hardened kernel preset](../modules/presets/hardened.nix)
(See https://github.com/fort-nix/nix-bitcoin/issues/39#issuecomment-517366093
for a workaround).

View File

@ -243,6 +243,10 @@
openssh.authorizedKeys.keys = [ "" ]; openssh.authorizedKeys.keys = [ "" ];
}; };
# FIXME: Uncomment this to allow the operator user to run
# commands as root with `sudo` or `doas`
# users.users.operator.extraGroups = [ "wheel" ];
# FIXME: add packages you need in your system # FIXME: add packages you need in your system
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
vim vim
@ -261,5 +265,4 @@
# When upgrading to a backwards-incompatible release, nix-bitcoin will display an # When upgrading to a backwards-incompatible release, nix-bitcoin will display an
# an error and provide hints for migrating your config to the new release. # an error and provide hints for migrating your config to the new release.
nix-bitcoin.configVersion = "0.0.51"; nix-bitcoin.configVersion = "0.0.51";
} }

View File

@ -40,14 +40,25 @@ let
cfg = config.services.backups; cfg = config.services.backups;
filelist = pkgs.writeText "filelist.txt" '' # Potential backup file paths are are matched against filelist
${optionalString (!cfg.with-bulk-data) "- ${config.services.bitcoind.dataDir}/blocks"} # entries from top to bottom.
${optionalString (!cfg.with-bulk-data) "- ${config.services.bitcoind.dataDir}/chainstate"} # The first match determines inclusion or exclusion.
filelist = builtins.toFile "filelist.txt" ''
${builtins.concatStringsSep "\n" cfg.extraFiles}
${optionalString (!cfg.with-bulk-data) ''
- ${config.services.bitcoind.dataDir}/blocks
- ${config.services.bitcoind.dataDir}/chainstate
- ${config.services.bitcoind.dataDir}/indexes
''}
${config.services.bitcoind.dataDir} ${config.services.bitcoind.dataDir}
${config.services.clightning.dataDir} ${config.services.clightning.dataDir}
${config.services.lnd.dataDir} ${config.services.lnd.dataDir}
${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/blocks"} ${optionalString (!cfg.with-bulk-data) ''
${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/chainstate"} - ${config.services.liquidd.dataDir}/*/blocks
- ${config.services.liquidd.dataDir}/*/chainstate
- ${config.services.liquidd.dataDir}/*/indexes
''}
${config.services.liquidd.dataDir} ${config.services.liquidd.dataDir}
${optionalString cfg.with-bulk-data "${config.services.electrs.dataDir}"} ${optionalString cfg.with-bulk-data "${config.services.electrs.dataDir}"}
${config.services.nbxplorer.dataDir} ${config.services.nbxplorer.dataDir}
@ -59,9 +70,6 @@ let
${builtins.concatStringsSep "\n" postgresqlBackupPaths} ${builtins.concatStringsSep "\n" postgresqlBackupPaths}
# Extra files
${builtins.concatStringsSep "\n" cfg.extraFiles}
# Exclude all unspecified files and directories # Exclude all unspecified files and directories
- / - /
''; '';

View File

@ -26,7 +26,6 @@ let
package = mkOption { package = mkOption {
type = types.package; type = types.package;
default = config.nix-bitcoin.pkgs.bitcoind; default = config.nix-bitcoin.pkgs.bitcoind;
defaultText = "pkgs.blockchains.bitcoind";
description = "The package providing bitcoin binaries."; description = "The package providing bitcoin binaries.";
}; };
extraConfig = mkOption { extraConfig = mkOption {

View File

@ -101,23 +101,36 @@ let
nbLib = config.nix-bitcoin.lib; nbLib = config.nix-bitcoin.lib;
nbPkgs = config.nix-bitcoin.pkgs; nbPkgs = config.nix-bitcoin.pkgs;
bitcoind = config.services.bitcoind; inherit (config.services) bitcoind liquidd;
in { in {
inherit options; inherit options;
config = mkIf cfg.btcpayserver.enable { config = mkIf cfg.btcpayserver.enable {
services.bitcoind.enable = true; services.bitcoind = {
enable = true;
rpc.users.btcpayserver = {
passwordHMACFromFile = true;
rpcwhitelist = cfg.bitcoind.rpc.users.public.rpcwhitelist ++ [
"setban"
"generatetoaddress"
"getpeerinfo"
];
};
# Enable p2p connections
listen = true;
extraConfig = ''
whitelist=${nbLib.address cfg.nbxplorer.address}
'';
};
services.clightning.enable = mkIf (cfg.btcpayserver.lightningBackend == "clightning") true; services.clightning.enable = mkIf (cfg.btcpayserver.lightningBackend == "clightning") true;
services.lnd.enable = mkIf (cfg.btcpayserver.lightningBackend == "lnd") true; services.lnd.enable = mkIf (cfg.btcpayserver.lightningBackend == "lnd") true;
services.liquidd.enable = mkIf cfg.btcpayserver.lbtc true; services.liquidd = mkIf cfg.btcpayserver.lbtc {
enable = true;
services.bitcoind.rpc.users.btcpayserver = { # Enable p2p connections
passwordHMACFromFile = true; listen = true;
rpcwhitelist = cfg.bitcoind.rpc.users.public.rpcwhitelist ++ [ extraConfig = ''
"setban" whitelist=${nbLib.address cfg.nbxplorer.address}
"generatetoaddress" '';
"getpeerinfo"
];
}; };
services.lnd.macaroons.btcpayserver = mkIf (cfg.btcpayserver.lightningBackend == "lnd") { services.lnd.macaroons.btcpayserver = mkIf (cfg.btcpayserver.lightningBackend == "lnd") {
@ -143,15 +156,15 @@ in {
configFile = builtins.toFile "config" '' configFile = builtins.toFile "config" ''
network=${bitcoind.network} network=${bitcoind.network}
btcrpcuser=${cfg.bitcoind.rpc.users.btcpayserver.name} btcrpcuser=${cfg.bitcoind.rpc.users.btcpayserver.name}
btcrpcurl=http://${bitcoind.rpc.address}:${toString cfg.bitcoind.rpc.port} btcrpcurl=http://${nbLib.addressWithPort bitcoind.rpc.address cfg.bitcoind.rpc.port}
btcnodeendpoint=${bitcoind.address}:${toString bitcoind.port} btcnodeendpoint=${nbLib.addressWithPort bitcoind.address bitcoind.port}
bind=${cfg.nbxplorer.address} bind=${cfg.nbxplorer.address}
port=${toString cfg.nbxplorer.port} port=${toString cfg.nbxplorer.port}
${optionalString cfg.btcpayserver.lbtc '' ${optionalString cfg.btcpayserver.lbtc ''
chains=btc,lbtc chains=btc,lbtc
lbtcrpcuser=${cfg.liquidd.rpcuser} lbtcrpcuser=${liquidd.rpcuser}
lbtcrpcurl=http://${cfg.liquidd.rpc.address}:${toString cfg.liquidd.rpc.port} lbtcrpcurl=http://${nbLib.addressWithPort liquidd.rpc.address liquidd.rpc.port}
lbtcnodeendpoint=${cfg.liquidd.address}:${toString cfg.liquidd.port} lbtcnodeendpoint=${nbLib.addressWithPort liquidd.address liquidd.port}
''} ''}
''; '';
in { in {
@ -221,8 +234,8 @@ in {
''; '';
serviceConfig = nbLib.defaultHardening // { serviceConfig = nbLib.defaultHardening // {
ExecStart = '' ExecStart = ''
${cfg.btcpayserver.package}/bin/btcpayserver --conf=${cfg.btcpayserver.dataDir}/settings.config \ ${cfg.btcpayserver.package}/bin/btcpayserver --conf='${cfg.btcpayserver.dataDir}/settings.config' \
--datadir=${cfg.btcpayserver.dataDir} --datadir='${cfg.btcpayserver.dataDir}'
''; '';
User = cfg.btcpayserver.user; User = cfg.btcpayserver.user;
Restart = "on-failure"; Restart = "on-failure";
@ -236,7 +249,7 @@ in {
isSystemUser = true; isSystemUser = true;
group = cfg.nbxplorer.group; group = cfg.nbxplorer.group;
extraGroups = [ "bitcoinrpc-public" ] extraGroups = [ "bitcoinrpc-public" ]
++ optional cfg.btcpayserver.lbtc cfg.liquidd.group; ++ optional cfg.btcpayserver.lbtc liquidd.group;
home = cfg.nbxplorer.dataDir; home = cfg.nbxplorer.dataDir;
}; };
users.groups.${cfg.nbxplorer.group} = {}; users.groups.${cfg.nbxplorer.group} = {};

View File

@ -112,9 +112,10 @@ in
ExecStart = '' ExecStart = ''
${config.nix-bitcoin.pkgs.charge-lnd}/bin/charge-lnd \ ${config.nix-bitcoin.pkgs.charge-lnd}/bin/charge-lnd \
--lnddir ${dataDir}/lnddir-proxy \ --lnddir ${dataDir}/lnddir-proxy \
--grpc ${lnd.rpcAddress}:${toString lnd.rpcPort} \ --grpc ${nbLib.addressWithPort lnd.rpcAddress lnd.rpcPort} \
--config ${checkedConfig} \ --config ${checkedConfig} \
${optionalString (electrs != null) "--electrum-server ${electrs.address}:${toString electrs.port}"} \ ${optionalString (electrs != null)
"--electrum-server ${nbLib.addressWithPort electrs.address electrs.port}"} \
${escapeShellArgs cfg.extraFlags} ${escapeShellArgs cfg.extraFlags}
''; '';
Type = "oneshot"; Type = "oneshot";

View File

@ -7,7 +7,7 @@ let
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = "IP address or UNIX domain socket to listen for peer connections."; description = "Address to listen for peer connections.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
@ -84,7 +84,7 @@ let
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"} ${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
always-use-proxy=${boolToString cfg.always-use-proxy} always-use-proxy=${boolToString cfg.always-use-proxy}
bind-addr=${cfg.address}:${toString cfg.port} bind-addr=${cfg.address}:${toString cfg.port}
bitcoin-rpcconnect=${config.services.bitcoind.rpc.address} bitcoin-rpcconnect=${nbLib.address config.services.bitcoind.rpc.address}
bitcoin-rpcport=${toString config.services.bitcoind.rpc.port} bitcoin-rpcport=${toString config.services.bitcoind.rpc.port}
bitcoin-rpcuser=${config.services.bitcoind.rpc.users.public.name} bitcoin-rpcuser=${config.services.bitcoind.rpc.users.public.name}
rpc-file-mode=0660 rpc-file-mode=0660

View File

@ -96,7 +96,7 @@ in {
--daemon-dir='${bitcoind.dataDir}' \ --daemon-dir='${bitcoind.dataDir}' \
--electrum-rpc-addr=${cfg.address}:${toString cfg.port} \ --electrum-rpc-addr=${cfg.address}:${toString cfg.port} \
--monitoring-addr=${cfg.address}:${toString cfg.monitoringPort} \ --monitoring-addr=${cfg.address}:${toString cfg.monitoringPort} \
--daemon-rpc-addr=${bitcoind.rpc.address}:${toString bitcoind.rpc.port} \ --daemon-rpc-addr=${nbLib.addressWithPort bitcoind.rpc.address bitcoind.rpc.port} \
${cfg.extraArgs} ${cfg.extraArgs}
''; '';
User = cfg.user; User = cfg.user;

View File

@ -93,10 +93,10 @@ in {
"d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -" "d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -"
]; ];
systemd.services.joinmarket-ob-watcher = { systemd.services.joinmarket-ob-watcher = rec {
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
requires = [ "tor.service" ]; requires = [ "tor.service" "bitcoind.service" ];
after = [ "tor.service" ]; after = requires;
# The service writes to HOME/.config/matplotlib # The service writes to HOME/.config/matplotlib
environment.HOME = cfg.dataDir; environment.HOME = cfg.dataDir;
preStart = '' preStart = ''

View File

@ -124,7 +124,7 @@ let
[BLOCKCHAIN] [BLOCKCHAIN]
blockchain_source = bitcoin-rpc blockchain_source = bitcoin-rpc
network = ${bitcoind.network} network = ${bitcoind.network}
rpc_host = ${bitcoind.rpc.address} rpc_host = ${nbLib.address bitcoind.rpc.address}
rpc_port = ${toString bitcoind.rpc.port} rpc_port = ${toString bitcoind.rpc.port}
rpc_user = ${bitcoind.rpc.users.privileged.name} rpc_user = ${bitcoind.rpc.users.privileged.name}
${optionalString (cfg.rpcWalletFile != null) "rpc_wallet_file = ${cfg.rpcWalletFile}"} ${optionalString (cfg.rpcWalletFile != null) "rpc_wallet_file = ${cfg.rpcWalletFile}"}

View File

@ -50,7 +50,7 @@ let
cli = mkOption { cli = mkOption {
default = pkgs.writeScriptBin "loop" '' default = pkgs.writeScriptBin "loop" ''
${cfg.package}/bin/loop \ ${cfg.package}/bin/loop \
--rpcserver ${rpclisten} \ --rpcserver ${nbLib.addressWithPort cfg.rpcAddress cfg.rpcPort} \
--macaroonpath '${cfg.dataDir}/${network}/loop.macaroon' \ --macaroonpath '${cfg.dataDir}/${network}/loop.macaroon' \
--tlscertpath '${secretsDir}/loop-cert' "$@" --tlscertpath '${secretsDir}/loop-cert' "$@"
''; '';
@ -66,17 +66,16 @@ let
lnd = config.services.lnd; lnd = config.services.lnd;
network = config.services.bitcoind.network; network = config.services.bitcoind.network;
rpclisten = "${cfg.rpcAddress}:${toString cfg.rpcPort}";
configFile = builtins.toFile "loop.conf" '' configFile = builtins.toFile "loop.conf" ''
datadir=${cfg.dataDir} datadir=${cfg.dataDir}
network=${network} network=${network}
rpclisten=${rpclisten} rpclisten=${cfg.rpcAddress}:${toString cfg.rpcPort}
restlisten=${cfg.restAddress}:${toString cfg.restPort} restlisten=${cfg.restAddress}:${toString cfg.restPort}
logdir=${cfg.dataDir}/logs logdir=${cfg.dataDir}/logs
tlscertpath=${secretsDir}/loop-cert tlscertpath=${secretsDir}/loop-cert
tlskeypath=${secretsDir}/loop-key tlskeypath=${secretsDir}/loop-key
lnd.host=${lnd.rpcAddress}:${toString lnd.rpcPort} lnd.host=${nbLib.addressWithPort lnd.rpcAddress lnd.rpcPort}
lnd.macaroonpath=${lnd.networkDir}/admin.macaroon lnd.macaroonpath=${lnd.networkDir}/admin.macaroon
lnd.tlspath=${lnd.certPath} lnd.tlspath=${lnd.certPath}

View File

@ -50,7 +50,7 @@ let
cli = mkOption { cli = mkOption {
default = pkgs.writeScriptBin "pool" '' default = pkgs.writeScriptBin "pool" ''
exec ${cfg.package}/bin/pool \ exec ${cfg.package}/bin/pool \
--rpcserver ${rpclisten} \ --rpcserver ${nbLib.addressWithPort cfg.rpcAddress cfg.rpcPort} \
--network ${network} \ --network ${network} \
--basedir '${cfg.dataDir}' "$@" --basedir '${cfg.dataDir}' "$@"
''; '';
@ -65,9 +65,8 @@ let
lnd = config.services.lnd; lnd = config.services.lnd;
network = config.services.bitcoind.network; network = config.services.bitcoind.network;
rpclisten = "${cfg.rpcAddress}:${toString cfg.rpcPort}";
configFile = builtins.toFile "pool.conf" '' configFile = builtins.toFile "pool.conf" ''
rpclisten=${rpclisten} rpclisten=${cfg.rpcAddress}:${toString cfg.rpcPort}
restlisten=${cfg.restAddress}:${toString cfg.restPort} restlisten=${cfg.restAddress}:${toString cfg.restPort}
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"} ${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}

View File

@ -143,7 +143,6 @@ let
bitcoind = config.services.bitcoind; bitcoind = config.services.bitcoind;
pidFile = "${cfg.dataDir}/liquidd.pid";
configFile = pkgs.writeText "elements.conf" '' configFile = pkgs.writeText "elements.conf" ''
chain=${bitcoind.makeNetworkName "liquidv1" '' chain=${bitcoind.makeNetworkName "liquidv1" ''
regtest regtest
@ -169,18 +168,13 @@ let
rpcconnect=${cfg.rpc.address} rpcconnect=${cfg.rpc.address}
${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpcallowip} ${lib.concatMapStrings (rpcallowip: "rpcallowip=${rpcallowip}\n") cfg.rpcallowip}
rpcuser=${cfg.rpcuser} rpcuser=${cfg.rpcuser}
mainchainrpchost=${bitcoind.rpc.address} mainchainrpchost=${nbLib.address bitcoind.rpc.address}
mainchainrpcport=${toString bitcoind.rpc.port} mainchainrpcport=${toString bitcoind.rpc.port}
mainchainrpcuser=${bitcoind.rpc.users.public.name} mainchainrpcuser=${bitcoind.rpc.users.public.name}
# Extra config options (from liquidd nixos service) # Extra config options (from liquidd nixos service)
${cfg.extraConfig} ${cfg.extraConfig}
''; '';
cmdlineOptions = concatMapStringsSep " " (arg: "'${arg}'") [
"-datadir=${cfg.dataDir}"
"-pid=${pidFile}"
];
hexStr = types.strMatching "[0-9a-f]+";
rpcUserOpts = { name, ... }: { rpcUserOpts = { name, ... }: {
options = { options = {
name = mkOption { name = mkOption {
@ -234,8 +228,7 @@ in {
Type = "simple"; Type = "simple";
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
ExecStart = "${nbPkgs.elementsd}/bin/elementsd ${cmdlineOptions}"; ExecStart = "${nbPkgs.elementsd}/bin/elementsd -datadir='${cfg.dataDir}'";
PIDFile = pidFile;
Restart = "on-failure"; Restart = "on-failure";
ReadWritePaths = cfg.dataDir; ReadWritePaths = cfg.dataDir;
} // nbLib.allowedIPAddresses cfg.enforceTor; } // nbLib.allowedIPAddresses cfg.enforceTor;

View File

@ -41,7 +41,7 @@ in {
services.tor = { services.tor = {
enable = true; enable = true;
relay.onionServices.lnd-rest = nbLib.mkOnionService { relay.onionServices.lnd-rest = nbLib.mkOnionService {
target.addr = lnd.restAddress; target.addr = nbLib.address lnd.restAddress;
target.port = lnd.restPort; target.port = lnd.restPort;
port = lnd.restPort; port = lnd.restPort;
}; };

View File

@ -127,7 +127,7 @@ let
bitcoind = config.services.bitcoind; bitcoind = config.services.bitcoind;
bitcoindRpcAddress = bitcoind.rpc.address; bitcoindRpcAddress = nbLib.address bitcoind.rpc.address;
networkDir = cfg.networkDir; networkDir = cfg.networkDir;
configFile = pkgs.writeText "lnd.conf" '' configFile = pkgs.writeText "lnd.conf" ''
datadir=${cfg.dataDir} datadir=${cfg.dataDir}
@ -217,11 +217,13 @@ in {
# existing, but the RPC service isn't yet, which results in error # existing, but the RPC service isn't yet, which results in error
# "waiting to start, RPC services not available". # "waiting to start, RPC services not available".
curl = "${pkgs.curl}/bin/curl -s --show-error --retry 10 --cacert ${cfg.certPath}"; curl = "${pkgs.curl}/bin/curl -s --show-error --retry 10 --cacert ${cfg.certPath}";
restUrl = "https://${cfg.restAddress}:${toString cfg.restPort}/v1"; restUrl = "https://${nbLib.addressWithPort cfg.restAddress cfg.restPort}/v1";
in [ in [
(nbLib.script "lnd-create-wallet" '' (nbLib.script "lnd-create-wallet" ''
attempts=250 attempts=250
while ! { exec 3>/dev/tcp/${cfg.restAddress}/${toString cfg.restPort} && exec 3>&-; } &>/dev/null; do while ! {
exec 3>/dev/tcp/${nbLib.address cfg.restAddress}/${toString cfg.restPort} && exec 3>&-
} &>/dev/null; do
((attempts-- == 0)) && { echo "lnd REST service unreachable"; exit 1; } ((attempts-- == 0)) && { echo "lnd REST service unreachable"; exit 1; }
sleep 0.1 sleep 0.1
done done

View File

@ -18,9 +18,9 @@
./lightning-loop.nix ./lightning-loop.nix
./lightning-pool.nix ./lightning-pool.nix
./charge-lnd.nix ./charge-lnd.nix
./btcpayserver.nix
./electrs.nix ./electrs.nix
./liquid.nix ./liquid.nix
./btcpayserver.nix
./joinmarket.nix ./joinmarket.nix
./joinmarket-ob-watcher.nix ./joinmarket-ob-watcher.nix
./hardware-wallets.nix ./hardware-wallets.nix

View File

@ -47,6 +47,12 @@ let
readOnly = true; readOnly = true;
description = "Exposes netns parameters."; description = "Exposes netns parameters.";
}; };
bridgeIp = mkOption {
default = bridgeIp;
readOnly = true;
description = "IP of the netns bridge interface.";
};
}; };
cfg = config.nix-bitcoin.netns-isolation; cfg = config.nix-bitcoin.netns-isolation;

View File

@ -16,7 +16,7 @@ with lib;
torClientAddressWithPort = mkOption { torClientAddressWithPort = mkOption {
readOnly = true; readOnly = true;
default = with config.services.tor.client.socksListenAddress; default = with config.services.tor.client.socksListenAddress;
"${addr}:${toString port}"; "${addr}:${toString port}";
}; };

View File

@ -13,6 +13,7 @@ let
}; };
cfg = config.nix-bitcoin.nodeinfo; cfg = config.nix-bitcoin.nodeinfo;
nbLib = config.nix-bitcoin.lib;
# Services included in the output # Services included in the output
services = { services = {
@ -96,7 +97,7 @@ let
mkInfo = extraCode: name: cfg: mkInfo = extraCode: name: cfg:
'' ''
add_service("${name}", """ add_service("${name}", """
info["local_address"] = "${cfg.address}:${toString cfg.port}" info["local_address"] = "${nbLib.addressWithPort cfg.address cfg.port}"
'' + mkIfOnionPort name (onionPort: '' '' + mkIfOnionPort name (onionPort: ''
set_onion_address(info, "${name}", ${onionPort}) set_onion_address(info, "${name}", ${onionPort})
'') + extraCode + '' '') + extraCode + ''

View File

@ -43,18 +43,18 @@ let
cfg = config.nix-bitcoin.onionServices; cfg = config.nix-bitcoin.onionServices;
nbLib = config.nix-bitcoin.lib; nbLib = config.nix-bitcoin.lib;
services = builtins.attrNames cfg; onionServices = builtins.attrNames cfg;
activeServices = builtins.filter (service: activeServices = builtins.filter (service:
config.services.${service}.enable && cfg.${service}.enable config.services.${service}.enable && cfg.${service}.enable
) services; ) onionServices;
publicServices = builtins.filter (service: cfg.${service}.public) activeServices; publicServices = builtins.filter (service: cfg.${service}.public) activeServices;
in { in {
inherit options; inherit options;
config = mkMerge [ config = mkMerge [
(mkIf (cfg != {}) { (mkIf (activeServices != []) {
# Define hidden services # Define hidden services
services.tor = { services.tor = {
enable = true; enable = true;
@ -65,7 +65,7 @@ in {
in nbLib.mkOnionService { in nbLib.mkOnionService {
port = if externalPort != null then externalPort else service.port; port = if externalPort != null then externalPort else service.port;
target.port = service.port; target.port = service.port;
target.addr = if service.address == "0.0.0.0" then "127.0.0.1" else service.address; target.addr = nbLib.address service.address;
} }
); );
}; };
@ -93,7 +93,7 @@ in {
publicServices' = builtins.filter (service: publicServices' = builtins.filter (service:
let srv = cfg.${service}; let srv = cfg.${service};
in srv.public && srv.enable in srv.public && srv.enable
) services; ) onionServices;
in genAttrs publicServices' (service: { in genAttrs publicServices' (service: {
getPublicAddressCmd = "cat ${config.nix-bitcoin.onionAddresses.dataDir}/services/${service}"; getPublicAddressCmd = "cat ${config.nix-bitcoin.onionAddresses.dataDir}/services/${service}";
}); });

View File

@ -36,8 +36,6 @@ in {
enable = true; enable = true;
listen = true; listen = true;
dataDirReadableByGroup = mkIf cfg.electrs.high-memory true; dataDirReadableByGroup = mkIf cfg.electrs.high-memory true;
discover = false;
addresstype = "bech32";
dbCache = 1000; dbCache = 1000;
}; };

View File

@ -13,7 +13,8 @@ let
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = ''
Set permissions for existing secrets in `nix-bitcoin.secretsDir`. Set permissions for existing secrets in `nix-bitcoin.secretsDir`
before services are started.
''; '';
}; };
@ -21,7 +22,7 @@ let
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = ''
Automatically generate all required secrets at system startup. Automatically generate all required secrets before services are started.
Note: Make sure to create a backup of the generated secrets. Note: Make sure to create a backup of the generated secrets.
''; '';
}; };
@ -57,7 +58,7 @@ let
}; };
permissions = mkOption { permissions = mkOption {
type = str; type = str;
default = "0440"; default = "440";
}; };
}; };
} }
@ -204,7 +205,9 @@ in {
} }
# Make all other files accessible to root only # Make all other files accessible to root only
unprocessedFiles=$(comm -23 <(printf '%s\n' *) <(printf '%s\n' "''${processedFiles[@]}" | sort)) unprocessedFiles=$(
comm -23 <(shopt -s nullglob; printf '%s\n' *) <(printf '%s\n' "''${processedFiles[@]}")
)
if [[ $unprocessedFiles ]]; then if [[ $unprocessedFiles ]]; then
IFS=$'\n' IFS=$'\n'
chown root: $unprocessedFiles chown root: $unprocessedFiles

View File

@ -83,4 +83,17 @@ let self = {
map = [ map ]; map = [ map ];
version = 3; version = 3;
}; };
# Convert a bind address, which may be a special INADDR_ANY address,
# to an actual IP address
address = addr:
if addr == "0.0.0.0" then
"127.0.0.1"
else if addr == "::" then
"::1"
else
addr;
addressWithPort = addr: port: "${self.address addr}:${toString port}";
}; in self }; in self

View File

@ -42,6 +42,7 @@ name: testConfig:
builtins.concatStringsSep "\n\n" [ builtins.concatStringsSep "\n\n" [
initData initData
(builtins.readFile ./../tests.py) (builtins.readFile ./../tests.py)
cfg.test.extraTestScript
# Don't run tests in interactive mode. # Don't run tests in interactive mode.
# is_interactive is set in ../run-tests.sh # is_interactive is set in ../run-tests.sh
'' ''

View File

@ -19,7 +19,11 @@ with lib;
dictionary variable 'test_data'. The data is exported via JSON. dictionary variable 'test_data'. The data is exported via JSON.
''; '';
}; };
extraTestScript = mkOption {
type = types.lines;
default = "";
description = "Extra lines added to the Python test script.";
};
container = { container = {
# Forwarded to extra-container. For descriptions, see # Forwarded to extra-container. For descriptions, see
# https://github.com/erikarvstedt/extra-container/blob/master/eval-config.nix # https://github.com/erikarvstedt/extra-container/blob/master/eval-config.nix

View File

@ -98,6 +98,10 @@ let
txfee = 200; txfee = 200;
}; };
# Disable restarting joinmarket-ob-watcher because it always fails
# on non-synced mainnet nodes
systemd.services.joinmarket-ob-watcher.serviceConfig.Restart = mkForce "no";
tests.nodeinfo = config.nix-bitcoin.nodeinfo.enable; tests.nodeinfo = config.nix-bitcoin.nodeinfo.enable;
tests.backups = cfg.backups.enable; tests.backups = cfg.backups.enable;
@ -225,7 +229,8 @@ let
services.bitcoind.regtest = true; services.bitcoind.regtest = true;
systemd.services.bitcoind.postStart = mkAfter '' systemd.services.bitcoind.postStart = mkAfter ''
cli=${config.services.bitcoind.cli}/bin/bitcoin-cli cli=${config.services.bitcoind.cli}/bin/bitcoin-cli
$cli createwallet "test" # Don't fail when wallet already exists
$cli createwallet "test" || true
address=$($cli getnewaddress) address=$($cli getnewaddress)
$cli generatetoaddress 10 $address $cli generatetoaddress 10 $address
''; '';