diff --git a/README.md b/README.md
index ea801e4..c6e658b 100644
--- a/README.md
+++ b/README.md
@@ -43,7 +43,7 @@ running nix-bitcoin does not require any previous experience with the Nix ecosys
Examples
---
-See the [examples directory](examples/README.md).
+See [here for examples](examples/README.md).
Features
---
@@ -76,7 +76,7 @@ NixOS modules
* Helper
* [netns-isolation](modules/netns-isolation.nix): isolates applications on the network-level via network namespaces
* [nodeinfo](modules/nodeinfo.nix): script which prints info about the node's services
- * [backups](modules/backups.nix): daily duplicity backups of all your node's important files
+ * [backups](modules/backups.nix): duplicity backups of all your node's important files
* [operator](modules/operator.nix): adds non-root user `operator` who has access to client tools (e.g. `bitcoin-cli`, `lightning-cli`)
Security
diff --git a/ci/build-to-cachix.sh b/ci/build-to-cachix.sh
index 73a8260..0fbbd5a 100755
--- a/ci/build-to-cachix.sh
+++ b/ci/build-to-cachix.sh
@@ -11,18 +11,8 @@ cachixCache=nix-bitcoin
trap 'echo Error at line $LINENO' ERR
-atExit() {
- rm -rf $tmpDir
- if [[ -v cachixPid ]]; then stopCachix; fi
-}
tmpDir=$(mktemp -d -p /tmp)
-trap atExit EXIT
-
-stopCachix() {
- kill $cachixPid 2>/dev/null || true
- # Wait for cachix to finish
- tail --pid=$cachixPid -f /dev/null
-}
+trap "rm -rf $tmpDir" EXIT
## Instantiate
@@ -43,14 +33,14 @@ fi
if [[ $CACHIX_SIGNING_KEY ]]; then
# Speed up task by uploading store paths as soon as they are created
- cachix push $cachixCache --watch-store &
- cachixPid=$!
+ buildCmd="cachix watch-exec $cachixCache nix-build --"
+else
+ buildCmd=nix-build
fi
-nix-build --out-link $tmpDir/result $tmpDir/drv >/dev/null
+$buildCmd --out-link $tmpDir/result $tmpDir/drv >/dev/null
if [[ $CACHIX_SIGNING_KEY ]]; then
- stopCachix
cachix push $cachixCache $outPath
fi
diff --git a/examples/deploy-container.sh b/examples/deploy-container.sh
index 965c2ec..53b3843 100755
--- a/examples/deploy-container.sh
+++ b/examples/deploy-container.sh
@@ -5,8 +5,8 @@ set -euo pipefail
# Running this script leaves no traces on your host system.
# This demo is a template for your own experiments.
-# Feel free to modify or to run nix-shell and execute individual statements of this
-# script in the interactive shell.
+# Run with option `--interactive` or `-i` to start a shell for interacting with
+# the node.
if [[ ! -v IN_NIX_SHELL ]]; then
echo "Running script in nix shell env..."
diff --git a/examples/deploy-nixops.sh b/examples/deploy-nixops.sh
index 568bbcd..8e8307b 100755
--- a/examples/deploy-nixops.sh
+++ b/examples/deploy-nixops.sh
@@ -5,8 +5,8 @@ set -euo pipefail
# Running this script leaves no traces on your host system.
# This demo is a template for your own experiments.
-# Feel free to modify or to run nix-shell and execute individual statements of this
-# script in the interactive shell.
+# Run with option `--interactive` or `-i` to start a shell for interacting with
+# the node.
if [[ ! -v IN_NIX_SHELL ]]; then
echo "Running script in nix shell env..."
diff --git a/examples/deploy-qemu-vm.sh b/examples/deploy-qemu-vm.sh
index 331451f..c83a96e 100755
--- a/examples/deploy-qemu-vm.sh
+++ b/examples/deploy-qemu-vm.sh
@@ -5,8 +5,8 @@ set -euo pipefail
# Running this script leaves no traces on your host system.
# This demo is a template for your own experiments.
-# Feel free to modify or to run nix-shell and execute individual statements of this
-# script in the interactive shell.
+# Run with option `--interactive` or `-i` to start a shell for interacting with
+# the node.
# MAKE SURE TO REPLACE the SSH identity file if you use this script for
# anything serious.
diff --git a/modules/backups.nix b/modules/backups.nix
index 322a84c..2669620 100644
--- a/modules/backups.nix
+++ b/modules/backups.nix
@@ -4,13 +4,15 @@ with lib;
let
cfg = config.services.backups;
+ secretsDir = config.nix-bitcoin.secretsDir;
+
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}
- /secrets/lnd-seed-mnemonic
+ ${secretsDir}/lnd-seed-mnemonic
${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/blocks"}
${optionalString (!cfg.with-bulk-data) "- ${config.services.liquidd.dataDir}/*/chainstate"}
${config.services.liquidd.dataDir}
@@ -18,7 +20,7 @@ let
${config.services.nbxplorer.dataDir}
${config.services.btcpayserver.dataDir}
${config.services.joinmarket.dataDir}
- /secrets/jm-wallet-seed
+ ${secretsDir}/jm-wallet-seed
${config.services.postgresqlBackup.location}/btcpaydb.sql.gz
/var/lib/tor
# Extra files
@@ -27,7 +29,6 @@ let
# Exclude all unspecified files and directories
- /
'';
-
in {
options.services.backups = {
enable = mkEnableOption "Backups service";
@@ -72,7 +73,7 @@ in {
"--include-filelist" "${filelist}"
"--full-if-older-than" "1M"
];
- targetUrl = "${cfg.destination}";
+ targetUrl = cfg.destination;
frequency = cfg.frequency;
secretFile = "${config.nix-bitcoin.secretsDir}/backup-encryption-env";
};
diff --git a/modules/bitcoind-rpc-public-whitelist.nix b/modules/bitcoind-rpc-public-whitelist.nix
index 966111e..70ce406 100644
--- a/modules/bitcoind-rpc-public-whitelist.nix
+++ b/modules/bitcoind-rpc-public-whitelist.nix
@@ -58,5 +58,5 @@
"validateaddress"
"verifymessage"
# Zmq
- "getzmqnotifications"
+ "getzmqnotifications"
]
diff --git a/modules/bitcoind.nix b/modules/bitcoind.nix
index af84cc8..fe8e9d3 100644
--- a/modules/bitcoind.nix
+++ b/modules/bitcoind.nix
@@ -7,7 +7,7 @@ let
nbLib = config.nix-bitcoin.lib;
secretsDir = config.nix-bitcoin.secretsDir;
- configFile = pkgs.writeText "bitcoin.conf" ''
+ configFile = builtins.toFile "bitcoin.conf" ''
# We're already logging via journald
nodebuglogfile=1
@@ -90,7 +90,7 @@ in {
par=16
logips=1
'';
- description = "Additional configurations to be appended to bitcoin.conf.";
+ description = "Extra lines appended to bitcoin.conf.";
};
dataDir = mkOption {
type = types.path;
@@ -138,7 +138,7 @@ in {
alice.passwordHMAC = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae";
bob.passwordHMAC = "b2dd077cb54591a2f3139e69a897ac$4e71f08d48b4347cf8eff3815c0e25ae2e9a4340474079f55705f40574f4ec99";
};
- type = with types; loaOf (submodule ({ name, ... }: {
+ type = with types; attrsOf (submodule ({ name, ... }: {
options = {
name = mkOption {
type = types.str;
@@ -197,9 +197,7 @@ in {
listen = mkOption {
type = types.bool;
default = false;
- description = ''
- If enabled, the bitcoin service will listen.
- '';
+ description = "Accept incoming connections.";
};
dataDirReadableByGroup = mkOption {
type = types.bool;
@@ -228,21 +226,15 @@ in {
type = types.nullOr (types.ints.between 4 16384);
default = null;
example = 4000;
- description = "Override the default database cache size in megabytes.";
+ description = "Override the default database cache size in MiB.";
};
prune = mkOption {
type = types.ints.unsigned;
default = 0;
example = 10000;
description = ''
- Reduce storage requirements by enabling pruning (deleting) of old
- blocks. This allows the pruneblockchain RPC to be called to delete
- specific blocks, and enables automatic pruning of old blocks if a
- target size in MiB is provided. This mode is incompatible with -txindex
- and -rescan. Warning: Reverting this setting requires re-downloading
- the entire blockchain. ("disable" = disable pruning blocks, "manual"
- = allow manual pruning via RPC, >=550 = automatically prune block files
- to stay under the specified target size in MiB)
+ Automatically prune block files to stay under the specified target size in MiB.
+ Value 0 disables pruning.
'';
};
zmqpubrawblock = mkOption {
@@ -281,7 +273,7 @@ in {
type = types.nullOr types.str;
default = null;
example = "bech32";
- description = "What type of addresses to use";
+ description = "The type of addresses to use";
};
cli = mkOption {
readOnly = true;
@@ -320,7 +312,6 @@ in {
];
systemd.services.bitcoind = {
- description = "Bitcoin daemon";
requires = [ "nix-bitcoin-secrets.target" ];
after = [ "network.target" "nix-bitcoin-secrets.target" ];
wantedBy = [ "multi-user.target" ];
@@ -334,10 +325,10 @@ in {
in ''
${optionalString cfg.dataDirReadableByGroup "chmod -R g+rX '${cfg.dataDir}/blocks'"}
cfg=$(
- cat ${configFile};
+ cat ${configFile}
${extraRpcauth}
${/* Enable bitcoin-cli for group 'bitcoin' */ ""}
- printf "rpcuser=${cfg.rpc.users.privileged.name}\nrpcpassword="; cat "${secretsDir}/bitcoin-rpcpassword-privileged";
+ printf "rpcuser=${cfg.rpc.users.privileged.name}\nrpcpassword="; cat "${secretsDir}/bitcoin-rpcpassword-privileged"
echo
${optionalString (cfg.getPublicAddressCmd != "") ''
echo "externalip=$(${cfg.getPublicAddressCmd})"
@@ -351,13 +342,13 @@ in {
serviceConfig = nbLib.defaultHardening // {
Type = "notify";
NotifyAccess = "all";
- User = "${cfg.user}";
- Group = "${cfg.group}";
+ User = cfg.user;
+ Group = cfg.group;
TimeoutStartSec = 300;
ExecStart = "${cfg.package}/bin/bitcoind -datadir='${cfg.dataDir}'";
Restart = "on-failure";
UMask = mkIf cfg.dataDirReadableByGroup "0027";
- ReadWritePaths = "${cfg.dataDir}";
+ ReadWritePaths = cfg.dataDir;
} // (if cfg.enforceTor
then nbLib.allowTor
else nbLib.allowAnyIP)
@@ -383,16 +374,13 @@ in {
done
'';
serviceConfig = nbLib.defaultHardening // {
- User = "${cfg.user}";
- Group = "${cfg.group}";
- ReadWritePaths = "${cfg.dataDir}";
+ User = cfg.user;
+ Group = cfg.group;
+ ReadWritePaths = cfg.dataDir;
} // nbLib.allowTor;
};
- users.users.${cfg.user} = {
- group = cfg.group;
- description = "Bitcoin daemon user";
- };
+ users.users.${cfg.user}.group = cfg.group;
users.groups.${cfg.group} = {};
users.groups.bitcoinrpc = {};
nix-bitcoin.operator.groups = [ cfg.group ];
diff --git a/modules/btcpayserver.nix b/modules/btcpayserver.nix
index b663132..a65b8fa 100644
--- a/modules/btcpayserver.nix
+++ b/modules/btcpayserver.nix
@@ -99,20 +99,34 @@ in {
services.clightning.enable = mkIf (cfg.btcpayserver.lightningBackend == "clightning") true;
services.lnd.enable = mkIf (cfg.btcpayserver.lightningBackend == "lnd") true;
- systemd.tmpfiles.rules = [
- "d '${cfg.nbxplorer.dataDir}' 0770 ${cfg.nbxplorer.user} ${cfg.nbxplorer.group} - -"
- "d '${cfg.btcpayserver.dataDir}' 0770 ${cfg.btcpayserver.user} ${cfg.btcpayserver.group} - -"
- ];
+ services.bitcoind.rpc.users.btcpayserver = {
+ passwordHMACFromFile = true;
+ rpcwhitelist = cfg.bitcoind.rpc.users.public.rpcwhitelist ++ [
+ "setban"
+ "generatetoaddress"
+ "getpeerinfo"
+ ];
+ };
+
+ services.lnd.macaroons.btcpayserver = mkIf (cfg.btcpayserver.lightningBackend == "lnd") {
+ inherit (cfg.btcpayserver) user;
+ permissions = ''{"entity":"info","action":"read"},{"entity":"onchain","action":"read"},{"entity":"offchain","action":"read"},{"entity":"address","action":"read"},{"entity":"message","action":"read"},{"entity":"peers","action":"read"},{"entity":"signer","action":"read"},{"entity":"invoices","action":"read"},{"entity":"invoices","action":"write"},{"entity":"address","action":"write"}'';
+ };
services.postgresql = {
enable = true;
ensureDatabases = [ "btcpaydb" ];
ensureUsers = [{
- name = "${cfg.btcpayserver.user}";
+ name = cfg.btcpayserver.user;
ensurePermissions."DATABASE btcpaydb" = "ALL PRIVILEGES";
}];
};
+ systemd.tmpfiles.rules = [
+ "d '${cfg.nbxplorer.dataDir}' 0770 ${cfg.nbxplorer.user} ${cfg.nbxplorer.group} - -"
+ "d '${cfg.btcpayserver.dataDir}' 0770 ${cfg.btcpayserver.user} ${cfg.btcpayserver.group} - -"
+ ];
+
systemd.services.nbxplorer = let
configFile = builtins.toFile "config" ''
network=${config.services.bitcoind.network}
@@ -123,12 +137,11 @@ in {
port=${toString cfg.nbxplorer.port}
'';
in {
- description = "Run nbxplorer";
wantedBy = [ "multi-user.target" ];
requires = [ "bitcoind.service" ];
after = [ "bitcoind.service" ];
preStart = ''
- install -m 600 ${configFile} ${cfg.nbxplorer.dataDir}/settings.config
+ install -m 600 ${configFile} '${cfg.nbxplorer.dataDir}/settings.config'
echo "btcrpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword-btcpayserver)" \
>> '${cfg.nbxplorer.dataDir}/settings.config'
'';
@@ -151,13 +164,13 @@ in {
systemd.services.btcpayserver = let
configFile = builtins.toFile "config" (''
network=${config.services.bitcoind.network}
- postgres=User ID=${cfg.btcpayserver.user};Host=/run/postgresql;Database=btcpaydb
+ bind=${cfg.btcpayserver.address}
+ port=${toString cfg.btcpayserver.port}
socksendpoint=${cfg.tor.client.socksListenAddress}
btcexplorerurl=http://${cfg.nbxplorer.address}:${toString cfg.nbxplorer.port}/
btcexplorercookiefile=${cfg.nbxplorer.dataDir}/${config.services.bitcoind.makeNetworkName "Main" "RegTest"}/.cookie
- bind=${cfg.btcpayserver.address}
+ postgres=User ID=${cfg.btcpayserver.user};Host=/run/postgresql;Database=btcpaydb
${optionalString (cfg.btcpayserver.rootpath != null) "rootpath=${cfg.btcpayserver.rootpath}"}
- port=${toString cfg.btcpayserver.port}
'' + optionalString (cfg.btcpayserver.lightningBackend == "clightning") ''
btclightning=type=clightning;server=unix:///${cfg.clightning.dataDir}/bitcoin/lightning-rpc
'');
@@ -168,17 +181,17 @@ in {
"certthumbprint=";
in let self = {
wantedBy = [ "multi-user.target" ];
- requires = [ "nbxplorer.service" ]
+ requires = [ "nbxplorer.service" "postgresql.service" ]
++ optional (cfg.btcpayserver.lightningBackend != null) "${cfg.btcpayserver.lightningBackend}.service";
after = self.requires;
preStart = ''
- install -m 600 ${configFile} ${cfg.btcpayserver.dataDir}/settings.config
+ install -m 600 ${configFile} '${cfg.btcpayserver.dataDir}/settings.config'
${optionalString (cfg.btcpayserver.lightningBackend == "lnd") ''
{
echo -n "${lndConfig}";
${pkgs.openssl}/bin/openssl x509 -noout -fingerprint -sha256 -in ${config.nix-bitcoin.secretsDir}/lnd-cert \
| sed -e 's/.*=//;s/://g';
- } >> ${cfg.btcpayserver.dataDir}/settings.config
+ } >> '${cfg.btcpayserver.dataDir}/settings.config'
''}
'';
serviceConfig = nbLib.defaultHardening // {
@@ -197,20 +210,13 @@ in {
);
}; in self;
- services.lnd.macaroons.btcpayserver = mkIf (cfg.btcpayserver.lightningBackend == "lnd") {
- inherit (cfg.btcpayserver) user;
- permissions = ''{"entity":"info","action":"read"},{"entity":"onchain","action":"read"},{"entity":"offchain","action":"read"},{"entity":"address","action":"read"},{"entity":"message","action":"read"},{"entity":"peers","action":"read"},{"entity":"signer","action":"read"},{"entity":"invoices","action":"read"},{"entity":"invoices","action":"write"},{"entity":"address","action":"write"}'';
- };
-
users.users.${cfg.nbxplorer.user} = {
- description = "nbxplorer user";
group = cfg.nbxplorer.group;
extraGroups = [ "bitcoinrpc" ];
home = cfg.nbxplorer.dataDir;
};
users.groups.${cfg.nbxplorer.group} = {};
users.users.${cfg.btcpayserver.user} = {
- description = "btcpayserver user";
group = cfg.btcpayserver.group;
extraGroups = [ "nbxplorer" ]
++ optional (cfg.btcpayserver.lightningBackend == "clightning") cfg.clightning.user;
@@ -218,18 +224,12 @@ in {
};
users.groups.${cfg.btcpayserver.group} = {};
- services.bitcoind.rpc.users.btcpayserver = {
- passwordHMACFromFile = true;
- rpcwhitelist = cfg.bitcoind.rpc.users.public.rpcwhitelist ++ [
- "setban"
- "generatetoaddress"
- "getpeerinfo"
- ];
+ nix-bitcoin.secrets = {
+ bitcoin-rpcpassword-btcpayserver = {
+ user = "bitcoin";
+ group = "nbxplorer";
+ };
+ bitcoin-HMAC-btcpayserver.user = "bitcoin";
};
- nix-bitcoin.secrets.bitcoin-rpcpassword-btcpayserver = {
- user = "bitcoin";
- group = "nbxplorer";
- };
- nix-bitcoin.secrets.bitcoin-HMAC-btcpayserver.user = "bitcoin";
};
}
diff --git a/modules/clightning.nix b/modules/clightning.nix
index d8838ec..69c53aa 100644
--- a/modules/clightning.nix
+++ b/modules/clightning.nix
@@ -11,7 +11,7 @@ let
network=${network}
bitcoin-datadir=${config.services.bitcoind.dataDir}
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
- always-use-proxy=${if cfg.always-use-proxy then "true" else "false"}
+ 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}
@@ -21,13 +21,7 @@ let
'';
in {
options.services.clightning = {
- enable = mkOption {
- type = types.bool;
- default = false;
- description = ''
- If enabled, the clightning service will be installed.
- '';
- };
+ enable = mkEnableOption "clightning";
address = mkOption {
type = types.str;
default = "127.0.0.1";
@@ -41,13 +35,17 @@ in {
proxy = mkOption {
type = types.nullOr types.str;
default = if cfg.enforceTor then config.services.tor.client.socksListenAddress else null;
- description = "Set a socks proxy to use to connect to Tor nodes (or for all connections if *always-use-proxy* is set)";
+ description = ''
+ Socks proxy for connecting to Tor nodes (or for all connections if option always-use-proxy is set).
+ '';
};
always-use-proxy = mkOption {
type = types.bool;
default = cfg.enforceTor;
description = ''
- Always use the *proxy*, even to connect to normal IP addresses (you can still connect to Unix domain sockets manually). This also disables all DNS lookups, to avoid leaking information.
+ Always use the proxy, even to connect to normal IP addresses.
+ You can still connect to Unix domain sockets manually.
+ This also disables all DNS lookups, to avoid leaking address information.
'';
};
dataDir = mkOption {
@@ -63,7 +61,7 @@ in {
extraConfig = mkOption {
type = types.lines;
default = "";
- description = "Additional lines appended to the config file.";
+ description = "Extra lines appended to the configuration file.";
};
user = mkOption {
type = types.str;
@@ -77,8 +75,7 @@ in {
};
cli = mkOption {
readOnly = true;
- default = pkgs.writeScriptBin "lightning-cli"
- ''
+ default = pkgs.writeScriptBin "lightning-cli" ''
${nbPkgs.clightning}/bin/lightning-cli --lightning-dir='${cfg.dataDir}' "$@"
'';
description = "Binary to connect with the clightning instance.";
@@ -103,44 +100,34 @@ in {
};
environment.systemPackages = [ nbPkgs.clightning (hiPrio cfg.cli) ];
- users.users.${cfg.user} = {
- description = "clightning User";
- group = cfg.group;
- extraGroups = [ "bitcoinrpc" ];
- };
- users.groups.${cfg.group} = {};
- nix-bitcoin.operator.groups = [ cfg.group ];
systemd.tmpfiles.rules = [
"d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -"
];
systemd.services.clightning = {
- description = "Run clightningd";
path = [ nbPkgs.bitcoind ];
wantedBy = [ "multi-user.target" ];
requires = [ "bitcoind.service" ];
after = [ "bitcoind.service" ];
preStart = ''
- cp ${configFile} ${cfg.dataDir}/config
chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}'
# The RPC socket has to be removed otherwise we might have stale sockets
rm -f ${cfg.networkDir}/lightning-rpc
- chmod 640 ${cfg.dataDir}/config
+ install -m 640 ${configFile} '${cfg.dataDir}/config'
{
echo "bitcoin-rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword-public)"
${optionalString (cfg.getPublicAddressCmd != "") ''
echo "announce-addr=$(${cfg.getPublicAddressCmd})"
''}
} >> '${cfg.dataDir}/config'
-
- '';
+ '';
serviceConfig = nbLib.defaultHardening // {
ExecStart = "${nbPkgs.clightning}/bin/lightningd --lightning-dir=${cfg.dataDir}";
- User = "${cfg.user}";
+ User = cfg.user;
Restart = "on-failure";
RestartSec = "10s";
- ReadWritePaths = "${cfg.dataDir}";
+ ReadWritePaths = cfg.dataDir;
} // (if cfg.enforceTor
then nbLib.allowTor
else nbLib.allowAnyIP
@@ -154,5 +141,12 @@ in {
chmod g+x ${cfg.networkDir}
'';
};
+
+ users.users.${cfg.user} = {
+ group = cfg.group;
+ extraGroups = [ "bitcoinrpc" ];
+ };
+ users.groups.${cfg.group} = {};
+ nix-bitcoin.operator.groups = [ cfg.group ];
};
}
diff --git a/modules/electrs.nix b/modules/electrs.nix
index a2c8102..f11dc76 100644
--- a/modules/electrs.nix
+++ b/modules/electrs.nix
@@ -68,7 +68,6 @@ in {
];
systemd.services.electrs = {
- description = "Electrs Electrum Server";
wantedBy = [ "multi-user.target" ];
requires = [ "bitcoind.service" ];
after = [ "bitcoind.service" ];
@@ -110,7 +109,6 @@ in {
};
users.users.${cfg.user} = {
- description = "electrs User";
group = cfg.group;
extraGroups = [ "bitcoinrpc" ] ++ optionals cfg.high-memory [ "bitcoin" ];
};
diff --git a/modules/hardware-wallets.nix b/modules/hardware-wallets.nix
index 1d1c2b1..b2e9352 100644
--- a/modules/hardware-wallets.nix
+++ b/modules/hardware-wallets.nix
@@ -47,11 +47,12 @@ in {
# Provides lsusb for debugging
pkgs.usbutils
];
- users.groups."${cfg.group}" = {};
+
+ users.groups.${cfg.group} = {};
nix-bitcoin.operator.groups = [ cfg.group ];
})
- (mkIf cfg.ledger {
+ (mkIf cfg.ledger {
# Ledger Nano S according to https://github.com/LedgerHQ/udev-rules/blob/master/add_udev_rules.sh
# Don't use rules from nixpkgs because we want to use our own group.
services.udev.packages = lib.singleton (pkgs.writeTextFile {
diff --git a/modules/joinmarket-ob-watcher.nix b/modules/joinmarket-ob-watcher.nix
index e8b2a30..62f670b 100644
--- a/modules/joinmarket-ob-watcher.nix
+++ b/modules/joinmarket-ob-watcher.nix
@@ -46,16 +46,6 @@ in {
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 orderbook watcher.";
- };
- group = mkOption {
- type = types.str;
- default = cfg.user;
- description = "The group as which to run JoinMarket orderbook watcher.";
- };
# This option is only used by netns-isolation
enforceTor = mkOption {
readOnly = true;
@@ -64,6 +54,7 @@ in {
};
config = mkIf cfg.enable {
+ # Joinmarket is Tor-only
services.tor = {
enable = true;
client.enable = true;
@@ -73,27 +64,23 @@ in {
wantedBy = [ "multi-user.target" ];
requires = [ "tor.service" ];
after = [ "tor.service" ];
+ # The service writes to HOME/.config/matplotlib
+ environment.HOME = cfg.dataDir;
preStart = ''
ln -snf ${configFile} ${cfg.dataDir}/joinmarket.cfg
'';
serviceConfig = nbLib.defaultHardening // rec {
+ DynamicUser = true;
StateDirectory = "joinmarket-ob-watcher";
StateDirectoryMode = "0770";
- WorkingDirectory = "${cfg.dataDir}"; # The service creates dir 'logs' in the working dir
+ WorkingDirectory = cfg.dataDir; # The service creates dir 'logs' in the working dir
ExecStart = ''
${nbPkgs.joinmarket}/bin/ob-watcher --datadir=${cfg.dataDir} \
--host=${cfg.address} --port=${toString cfg.port}
'';
- User = cfg.user;
Restart = "on-failure";
RestartSec = "10s";
} // nbLib.allowTor;
};
-
- users.users.${cfg.user} = {
- group = cfg.group;
- home = cfg.dataDir; # The service writes to HOME/.config/matplotlib
- };
- users.groups.${cfg.group} = {};
};
}
diff --git a/modules/joinmarket.nix b/modules/joinmarket.nix
index ccdc8cb..f3cbf5d 100644
--- a/modules/joinmarket.nix
+++ b/modules/joinmarket.nix
@@ -141,75 +141,79 @@ in {
};
config = mkIf cfg.enable (mkMerge [{
- services.bitcoind.enable = true;
+ services.bitcoind = {
+ enable = true;
+ disablewallet = false;
+ };
+
+ # Joinmarket is Tor-only
+ services.tor = {
+ enable = true;
+ client.enable = true;
+ # Needed for payjoin onion service creation
+ controlSocket.enable = true;
+ };
environment.systemPackages = [
(hiPrio cfg.cli)
];
- users.users.${cfg.user} = {
- description = "joinmarket User";
- group = "${cfg.group}";
- home = cfg.dataDir;
- extraGroups = [ "tor" ];
- };
- users.groups.${cfg.group} = {};
- nix-bitcoin.operator = {
- groups = [ cfg.group ];
- sudoUsers = [ cfg.group ];
- };
systemd.tmpfiles.rules = [
"d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -"
];
- services.bitcoind.disablewallet = false;
-
- # Joinmarket is TOR-only
- services.tor = {
- enable = true;
- client.enable = true;
- controlSocket.enable = true;
- };
-
systemd.services.joinmarket = {
- description = "JoinMarket Daemon";
wantedBy = [ "multi-user.target" ];
requires = [ "bitcoind.service" ];
after = [ "bitcoind.service" ];
path = [ pkgs.sudo ];
serviceConfig = nbLib.defaultHardening // {
- ExecStartPre = nbLib.privileged ''
+ ExecStartPre = nbLib.privileged "joinmarket-create-config" ''
install -o '${cfg.user}' -g '${cfg.group}' -m 640 ${configFile} ${cfg.dataDir}/joinmarket.cfg
sed -i \
"s|@@RPC_PASSWORD@@|rpc_password = $(cat ${secretsDir}/bitcoin-rpcpassword-privileged)|" \
'${cfg.dataDir}/joinmarket.cfg'
'';
# Generating wallets (jmclient/wallet.py) is only supported for mainnet or testnet
- ExecStartPost = mkIf (bitcoind.network == "mainnet") (nbLib.privileged ''
- walletname=wallet.jmdat
- pw=$(cat "${secretsDir}"/jm-wallet-password)
- mnemonic=${secretsDir}/jm-wallet-seed
- if [[ ! -f ${cfg.dataDir}/wallets/$walletname ]]; then
- echo Create joinmarket wallet
- # Use bash variables so commands don't proceed on previous failures
- # (like with pipes)
- cd ${cfg.dataDir} && \
- out=$(sudo -u ${cfg.user} \
- ${nbPkgs.joinmarket}/bin/jm-genwallet \
- --datadir=${cfg.dataDir} $walletname $pw)
- recoveryseed=$(echo "$out" | grep 'recovery_seed')
- echo "$recoveryseed" | cut -d ':' -f2 > $mnemonic
- fi
- '');
+ ExecStartPost = mkIf (bitcoind.network == "mainnet")
+ (nbLib.privileged "joinmarket-create-wallet" ''
+ walletname=wallet.jmdat
+ wallet=${cfg.dataDir}/wallets/$walletname
+ if [[ ! -f $wallet ]]; then
+ echo "Create wallet"
+ pw=$(cat "${secretsDir}"/jm-wallet-password)
+ cd ${cfg.dataDir}
+ if ! sudo -u ${cfg.user} ${nbPkgs.joinmarket}/bin/jm-genwallet --datadir=${cfg.dataDir} $walletname $pw \
+ | grep 'recovery_seed' \
+ | cut -d ':' -f2 \
+ | (umask u=r,go=; cat > "${secretsDir}/jm-wallet-seed"); then
+ echo "wallet creation failed"
+ rm -f "$wallet" "${secretsDir}/jm-wallet-seed"
+ exit 1
+ fi
+ fi
+ '');
ExecStart = "${nbPkgs.joinmarket}/bin/joinmarketd";
- WorkingDirectory = "${cfg.dataDir}"; # The service creates 'commitmentlist' in the working dir
- User = "${cfg.user}";
+ WorkingDirectory = cfg.dataDir; # The service creates 'commitmentlist' in the working dir
+ User = cfg.user;
Restart = "on-failure";
RestartSec = "10s";
- ReadWritePaths = "${cfg.dataDir}";
+ ReadWritePaths = cfg.dataDir;
} // nbLib.allowTor;
};
+ users.users.${cfg.user} = {
+ group = cfg.group;
+ home = cfg.dataDir;
+ # Allow access to the tor control socket, needed for payjoin onion service creation
+ extraGroups = [ "tor" ];
+ };
+ users.groups.${cfg.group} = {};
+ nix-bitcoin.operator = {
+ groups = [ cfg.group ];
+ sudoUsers = [ cfg.group ];
+ };
+
nix-bitcoin.secrets.jm-wallet-password.user = cfg.user;
}
@@ -227,7 +231,6 @@ in {
chmod +x $out
'';
in {
- description = "CoinJoin maker bot to gain privacy and passively generate income";
wantedBy = [ "joinmarket.service" ];
requires = [ "joinmarket.service" ];
after = [ "joinmarket.service" ];
@@ -242,10 +245,14 @@ in {
serviceConfig = nbLib.defaultHardening // rec {
RuntimeDirectory = "joinmarket-yieldgenerator"; # Only used to create start script
RuntimeDirectoryMode = "700";
- WorkingDirectory = "${cfg.dataDir}"; # The service creates dir 'logs' in the working dir
+ WorkingDirectory = cfg.dataDir; # The service creates dir 'logs' in the working dir
ExecStart = "${pkgs.bash}/bin/bash /run/${RuntimeDirectory}/start";
- User = "${cfg.user}";
- ReadWritePaths = "${cfg.dataDir}";
+ # Show "joinmarket-yieldgenerator" instead of "bash" in the journal.
+ # The parent bash start process has to run alongside the main process
+ # because it provides the wallet password via stdin to the main process
+ SyslogIdentifier = "joinmarket-yieldgenerator";
+ User = cfg.user;
+ ReadWritePaths = cfg.dataDir;
} // nbLib.allowTor;
};
})
diff --git a/modules/lightning-loop.nix b/modules/lightning-loop.nix
index fd87b19..3c84713 100644
--- a/modules/lightning-loop.nix
+++ b/modules/lightning-loop.nix
@@ -101,7 +101,7 @@ in {
User = "lnd";
Restart = "on-failure";
RestartSec = "10s";
- ReadWritePaths = "${cfg.dataDir}";
+ ReadWritePaths = cfg.dataDir;
} // (if cfg.enforceTor
then nbLib.allowTor
else nbLib.allowAnyIP);
diff --git a/modules/liquid.nix b/modules/liquid.nix
index 26b9e5a..a5ee67e 100644
--- a/modules/liquid.nix
+++ b/modules/liquid.nix
@@ -87,9 +87,8 @@ in {
par=16
rpcthreads=16
logips=1
-
'';
- description = "Additional configurations to be appended to elements.conf.";
+ description = "Extra lines appended to elements.conf.";
};
dataDir = mkOption {
type = types.path;
@@ -123,7 +122,7 @@ in {
alice.passwordHMAC = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae";
bob.passwordHMAC = "b2dd077cb54591a2f3139e69a897ac$4e71f08d48b4347cf8eff3815c0e25ae2e9a4340474079f55705f40574f4ec99";
};
- type = with types; loaOf (submodule rpcUserOpts);
+ type = with types; attrsOf (submodule rpcUserOpts);
description = ''
RPC user information for JSON-RPC connections.
'';
@@ -221,25 +220,25 @@ in {
];
systemd.services.liquidd = {
- description = "Elements daemon providing access to the Liquid sidechain";
requires = [ "bitcoind.service" ];
after = [ "bitcoind.service" ];
wantedBy = [ "multi-user.target" ];
preStart = ''
- cp '${configFile}' '${cfg.dataDir}/elements.conf'
- chmod 640 '${cfg.dataDir}/elements.conf'
chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}'
- echo "rpcpassword=$(cat ${secretsDir}/liquid-rpcpassword)" >> '${cfg.dataDir}/elements.conf'
- echo "mainchainrpcpassword=$(cat ${secretsDir}/bitcoin-rpcpassword-public)" >> '${cfg.dataDir}/elements.conf'
+ install -m 640 ${configFile} '${cfg.dataDir}/elements.conf'
+ {
+ echo "rpcpassword=$(cat ${secretsDir}/liquid-rpcpassword)"
+ echo "mainchainrpcpassword=$(cat ${secretsDir}/bitcoin-rpcpassword-public)"
+ } >> '${cfg.dataDir}/elements.conf'
'';
serviceConfig = nbLib.defaultHardening // {
Type = "simple";
- User = "${cfg.user}";
- Group = "${cfg.group}";
+ User = cfg.user;
+ Group = cfg.group;
ExecStart = "${nbPkgs.elementsd}/bin/elementsd ${cmdlineOptions}";
- PIDFile = "${pidFile}";
+ PIDFile = pidFile;
Restart = "on-failure";
- ReadWritePaths = "${cfg.dataDir}";
+ ReadWritePaths = cfg.dataDir;
} // (if cfg.enforceTor
then nbLib.allowTor
else nbLib.allowAnyIP
@@ -249,7 +248,6 @@ in {
users.users.${cfg.user} = {
group = cfg.group;
extraGroups = [ "bitcoinrpc" ];
- description = "Liquid sidechain user";
};
users.groups.${cfg.group} = {};
nix-bitcoin.operator.groups = [ cfg.group ];
diff --git a/modules/lnd.nix b/modules/lnd.nix
index 4899dac..930d7d4 100644
--- a/modules/lnd.nix
+++ b/modules/lnd.nix
@@ -37,13 +37,7 @@ let
in {
options.services.lnd = {
- enable = mkOption {
- type = types.bool;
- default = false;
- description = ''
- If enabled, the LND service will be installed.
- '';
- };
+ enable = mkEnableOption "Lightning Network Daemon";
dataDir = mkOption {
type = types.path;
default = "/var/lib/lnd";
@@ -89,7 +83,7 @@ in {
tor-socks = mkOption {
type = types.nullOr types.str;
default = if cfg.enforceTor then config.services.tor.client.socksListenAddress else null;
- description = "Set a socks proxy to use to connect to Tor nodes";
+ description = "Socks proxy for connecting to Tor nodes";
};
macaroons = mkOption {
default = {};
@@ -118,7 +112,7 @@ in {
example = ''
autopilot.active=1
'';
- description = "Additional configurations to be appended to lnd.conf.";
+ description = "Extra lines appended to lnd.conf.";
};
package = mkOption {
type = types.package;
@@ -156,9 +150,13 @@ in {
services.bitcoind = {
enable = true;
+
# Increase rpc thread count due to reports that lightning implementations fail
# under high bitcoind rpc load
rpc.threads = 16;
+
+ zmqpubrawblock = "tcp://${bitcoindRpcAddress}:28332";
+ zmqpubrawtx = "tcp://${bitcoindRpcAddress}:28333";
};
environment.systemPackages = [ cfg.package (hiPrio cfg.cli) ];
@@ -167,13 +165,7 @@ in {
"d '${cfg.dataDir}' 0770 lnd lnd - -"
];
- services.bitcoind = {
- zmqpubrawblock = "tcp://${bitcoindRpcAddress}:28332";
- zmqpubrawtx = "tcp://${bitcoindRpcAddress}:28333";
- };
-
systemd.services.lnd = {
- description = "Run LND";
wantedBy = [ "multi-user.target" ];
requires = [ "bitcoind.service" ];
after = [ "bitcoind.service" ];
@@ -193,12 +185,12 @@ in {
User = "lnd";
Restart = "on-failure";
RestartSec = "10s";
- ReadWritePaths = "${cfg.dataDir}";
+ ReadWritePaths = cfg.dataDir;
ExecStartPost = let
restUrl = "https://${cfg.restAddress}:${toString cfg.restPort}/v1";
in [
# Run fully privileged for secrets dir write access
- "+${nbLib.script ''
+ (nbLib.privileged "lnd-create-mnemonic" ''
attempts=250
while ! { exec 3>/dev/tcp/${cfg.restAddress}/${toString cfg.restPort} && exec 3>&-; } &>/dev/null; do
((attempts-- == 0)) && { echo "lnd REST service unreachable"; exit 1; }
@@ -214,8 +206,8 @@ in {
-X GET ${restUrl}/genseed | ${pkgs.jq}/bin/jq -c '.cipher_seed_mnemonic' > "$mnemonic"
fi
chown lnd: "$mnemonic"
- ''}"
- "${nbLib.script ''
+ '')
+ (nbLib.script "lnd-create-wallet" ''
if [[ ! -f ${networkDir}/wallet.db ]]; then
echo Create lnd wallet
@@ -246,9 +238,9 @@ in {
sleep 0.1
done
- ''}"
+ '')
# Run fully privileged for chown
- "+${nbLib.script ''
+ (nbLib.privileged "lnd-create-macaroons" ''
umask ug=r,o=
${lib.concatMapStrings (macaroon: ''
echo "Create custom macaroon ${macaroon}"
@@ -262,7 +254,7 @@ in {
${pkgs.jq}/bin/jq -c '.macaroon' | ${pkgs.xxd}/bin/xxd -p -r > "$macaroonPath"
chown ${cfg.macaroons.${macaroon}.user}: "$macaroonPath"
'') (attrNames cfg.macaroons)}
- ''}"
+ '')
];
} // (if cfg.enforceTor
then nbLib.allowTor
@@ -271,7 +263,6 @@ in {
};
users.users.lnd = {
- description = "LND User";
group = "lnd";
extraGroups = [ "bitcoinrpc" ];
home = cfg.dataDir; # lnd creates .lnd dir in HOME
diff --git a/modules/netns-isolation.nix b/modules/netns-isolation.nix
index e4f02f1..30fb57c 100644
--- a/modules/netns-isolation.nix
+++ b/modules/netns-isolation.nix
@@ -105,7 +105,7 @@ in {
source = config.nix-bitcoin.pkgs.netns-exec;
capabilities = "cap_sys_admin=ep";
owner = cfg.allowedUser;
- permissions = "u+rx,g+rx,o-rwx";
+ permissions = "550";
};
systemd.services = {
@@ -119,7 +119,7 @@ in {
after = [ "network-pre.target" ];
serviceConfig = {
Type = "oneshot";
- RemainAfterExit = "yes";
+ RemainAfterExit = true;
};
script = ''
${ip} link add name nb-br type bridge
@@ -182,7 +182,7 @@ in {
'';
serviceConfig = {
Type = "oneshot";
- RemainAfterExit = "yes";
+ RemainAfterExit = true;
};
};
};
diff --git a/modules/recurring-donations.nix b/modules/recurring-donations.nix
index 84ebea9..f1fa533 100644
--- a/modules/recurring-donations.nix
+++ b/modules/recurring-donations.nix
@@ -41,13 +41,7 @@ let
'';
in {
options.services.recurring-donations = {
- enable = mkOption {
- type = types.bool;
- default = false;
- description = ''
- If enabled, the recurring-donations service will be installed.
- '';
- };
+ enable = mkEnableOption "recurring-donations";
tallycoin = mkOption {
type = types.attrs;
default = {};
@@ -81,15 +75,7 @@ in {
config = mkIf cfg.enable {
services.clightning.enable = true;
- users.users.recurring-donations = {
- description = "recurring-donations User";
- group = "recurring-donations";
- extraGroups = [ "clightning" ];
- };
- users.groups.recurring-donations = {};
-
systemd.services.recurring-donations = {
- description = "Run recurring-donations";
requires = [ "clightning.service" ];
after = [ "clightning.service" ];
path = with pkgs; [ nix-bitcoin.clightning curl sudo jq ];
@@ -111,5 +97,11 @@ in {
};
wantedBy = [ "multi-user.target" ];
};
+
+ users.users.recurring-donations = {
+ group = "recurring-donations";
+ extraGroups = [ "clightning" ];
+ };
+ users.groups.recurring-donations = {};
};
}
diff --git a/modules/spark-wallet.nix b/modules/spark-wallet.nix
index 3a46f89..419cb3c 100644
--- a/modules/spark-wallet.nix
+++ b/modules/spark-wallet.nix
@@ -23,13 +23,7 @@ let
'';
in {
options.services.spark-wallet = {
- enable = mkOption {
- type = types.bool;
- default = false;
- description = ''
- If enabled, the spark-wallet service will be installed.
- '';
- };
+ enable = mkEnableOption "spark-wallet";
address = mkOption {
type = types.str;
default = "localhost";
@@ -61,14 +55,12 @@ in {
services.clightning.enable = true;
users.users.spark-wallet = {
- description = "spark-wallet User";
group = "spark-wallet";
extraGroups = [ "clightning" ];
};
users.groups.spark-wallet = {};
systemd.services.spark-wallet = {
- description = "Run spark-wallet";
wantedBy = [ "multi-user.target" ];
requires = [ "clightning.service" ];
after = [ "clightning.service" ];
diff --git a/pkgs/elementsd/default.nix b/pkgs/elementsd/default.nix
index 1b9ae92..a46a1a3 100644
--- a/pkgs/elementsd/default.nix
+++ b/pkgs/elementsd/default.nix
@@ -3,20 +3,20 @@
, withGui }:
with stdenv.lib;
-stdenv.mkDerivation rec{
- name = "elements" + (toString (optional (!withGui) "d")) + "-" + version;
+stdenv.mkDerivation rec {
+ pname = "elements${optionalString (!withGui) "d"}";
version = "0.18.1.9";
src = fetchurl {
- urls = [
- "https://github.com/ElementsProject/elements/archive/elements-${version}.tar.gz"
- ];
+ url = "https://github.com/ElementsProject/elements/archive/elements-${version}.tar.gz";
+ # Use ./get-sha256.sh to fetch latest (verified) sha256
sha256 = "c6f1b040a896a1aaa7340f5cd48e119c84fef88df5d4c17d5ad5c13783f5b6c7";
- };
+ };
nativeBuildInputs =
[ pkgconfig autoreconfHook ]
++ optional withGui wrapQtAppsHook;
+
buildInputs = [ openssl db48 boost zlib zeromq
miniupnpc protobuf libevent]
++ optionals stdenv.isLinux [ utillinux ]
@@ -27,10 +27,10 @@ stdenv.mkDerivation rec{
] ++ optionals (!doCheck) [
"--disable-tests"
"--disable-gui-tests"
- ]
- ++ optionals withGui [ "--with-gui=qt5"
- "--with-qt-bindir=${qtbase.dev}/bin:${qttools.dev}/bin"
- ];
+ ] ++ optionals withGui [
+ "--with-gui=qt5"
+ "--with-qt-bindir=${qtbase.dev}/bin:${qttools.dev}/bin"
+ ];
checkInputs = [ rapidcheck python3 ];
diff --git a/pkgs/lib.nix b/pkgs/lib.nix
index ab8bfb0..b6919cf 100644
--- a/pkgs/lib.nix
+++ b/pkgs/lib.nix
@@ -28,8 +28,9 @@ let self = {
CapabilityBoundingSet = "";
# @system-service whitelist and docker seccomp blacklist (except for "clone"
# which is a core requirement for systemd services)
+ # @system-service is defined in src/shared/seccomp-util.c (systemd source)
SystemCallFilter = [ "@system-service" "~add_key clone3 get_mempolicy kcmp keyctl mbind move_pages name_to_handle_at personality process_vm_readv process_vm_writev request_key set_mempolicy setns unshare userfaultfd" ];
- SystemCallArchitectures= "native";
+ SystemCallArchitectures = "native";
};
# nodejs applications apparently rely on memory write execute
@@ -51,13 +52,13 @@ let self = {
'';
};
- script = src: pkgs.writers.writeBash "script" ''
+ script = name: src: pkgs.writers.writeBash name ''
set -eo pipefail
${src}
'';
# Used for ExecStart*
- privileged = src: "+${self.script src}";
+ privileged = name: src: "+${self.script name src}";
cliExec = mkOption {
# Used by netns-isolation to execute the cli in the service's private netns
diff --git a/pkgs/python-packages/chromalog/default.nix b/pkgs/python-packages/chromalog/default.nix
index 44589a8..0d2e0c8 100644
--- a/pkgs/python-packages/chromalog/default.nix
+++ b/pkgs/python-packages/chromalog/default.nix
@@ -6,7 +6,7 @@ buildPythonPackage rec {
src = fetchFromGitHub {
owner = "freelan-developers";
repo = "chromalog";
- rev = "${version}";
+ rev = version;
sha256 = "0pj4s52rgwlvwkzrj85y92c5r9c84pz8gga45jl5spysrv41y9p0";
};
diff --git a/test/lib/copy-src.sh b/test/lib/copy-src.sh
new file mode 100644
index 0000000..71bc3a2
--- /dev/null
+++ b/test/lib/copy-src.sh
@@ -0,0 +1,18 @@
+# Re-run run-tests.sh in a snapshot copy of the source.
+# Maintain /tmp/nix-bitcoin-src as a source cache to minimize copies.
+
+tmp=$(mktemp -d '/tmp/nix-bitcoin-src.XXXXX')
+
+# Ignore errors from now on
+set +e
+
+# Move source cache if it exists (atomic)
+mv /tmp/nix-bitcoin-src $tmp/src 2>/dev/null
+
+rsync -a --delete --exclude='.git*' "$scriptDir/../" $tmp/src && \
+ echo "Copied src" && \
+ _nixBitcoinInCopySrc=1 $tmp/src/test/run-tests.sh "${args[@]}"
+
+# Set the current src as the source cache (atomic)
+mv -T $tmp/src /tmp/nix-bitcoin-src 2>/dev/null
+rm -rf $tmp
diff --git a/test/run-tests.sh b/test/run-tests.sh
index 2593a3f..3f30408 100755
--- a/test/run-tests.sh
+++ b/test/run-tests.sh
@@ -42,12 +42,20 @@
# For now, creating NixOS containers requires root permissions.
# See ./lib/make-container.sh for a complete documentation.
#
+# Run tests from a snapshot copy of the source files
+# ./run-tests.sh --copy-src|-c ...
+#
+# This allows you to continue editing the nix-bitcoin sources while tests are running
+# and reading source files.
+# Files are copied to /tmp, a caching scheme helps minimizing copies.
+#
# To add custom scenarios, set the environment variable `scenarioOverridesFile`.
set -eo pipefail
scriptDir=$(cd "${BASH_SOURCE[0]%/*}" && pwd)
+args=("$@")
scenario=
outLinkPrefix=
ciBuild=
@@ -77,6 +85,13 @@ while :; do
shift
ciBuild=1
;;
+ --copy-src|-c)
+ shift
+ if [[ ! $_nixBitcoinInCopySrc ]]; then
+ . "$scriptDir/lib/copy-src.sh"
+ exit
+ fi
+ ;;
*)
break
esac
@@ -172,7 +187,7 @@ doBuild() {
# Run the test by building the test derivation
buildTest() {
- vmTestNixExpr | doBuild $scenario $outLinkArg "$@" -
+ vmTestNixExpr | doBuild $scenario "$@" -
}
vmTestNixExpr() {