Merge #339: Misc improvements

4cddf284e9 treewide: remove use of deprecated `stdenv.lib` (Erik Arvstedt)
6ba5880b2c test.py: improve composability of test 'banlist-and-restart' (Erik Arvstedt)
44439e2a81 tests: optimize building multiple tests at once (Erik Arvstedt)
9ca52af523 tests: improve make-test-vm.nix (Erik Arvstedt)
08fe9ba84a services: add finer-grained address family restrictions (Erik Arvstedt)
020433cec6 services: add helper fn setAllowedIPAddresses (Erik Arvstedt)
cdf27d9d0c bitcoind: improve service timeouts (Erik Arvstedt)
09cd3ce5e4 lnd: show curl error messages (Erik Arvstedt)
d214605b32 spark-wallet: add flakes compatibility (Erik Arvstedt)
81db927f66 spark-wallet/generate: remove supplement.json (Erik Arvstedt)
84b3217c3d fetch-release: minor improvements (Erik Arvstedt)
45d0964e27 examples/shell.nix: minor improvements (Erik Arvstedt)
cc7149eb78 examples: improve robustness of deploy scripts (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  nixbitcoin:
    ACK 4cddf284e9

Tree-SHA512: 5f863a406a56b4b916ea662c411dce6884a7633a49e862015ddf68c20e772a14108095782753c2e33061d8d19cbf9053239f98644cb12fd883ef79e68d8a977b
This commit is contained in:
Jonas Nick 2021-03-22 15:51:54 +00:00
commit 9ae2c8a6d2
No known key found for this signature in database
GPG Key ID: 4861DBF262123605
34 changed files with 234 additions and 181 deletions

View File

@ -8,10 +8,12 @@ set -euo pipefail
# Run with option `--interactive` or `-i` to start a shell for interacting with # Run with option `--interactive` or `-i` to start a shell for interacting with
# the node. # the node.
if [[ ! -v IN_NIX_SHELL ]]; then if [[ ! -v NIX_BITCOIN_EXAMPLES_DIR ]]; then
echo "Running script in nix shell env..." echo "Running script in nix shell env..."
cd "${BASH_SOURCE[0]%/*}" cd "${BASH_SOURCE[0]%/*}"
exec nix-shell --run "./${BASH_SOURCE[0]##*/} $*" exec nix-shell --run "./${BASH_SOURCE[0]##*/} $*"
else
cd "$NIX_BITCOIN_EXAMPLES_DIR"
fi fi
if [[ $(sysctl -n net.ipv4.ip_forward || sudo sysctl -n net.ipv4.ip_forward) != 1 ]]; then if [[ $(sysctl -n net.ipv4.ip_forward || sudo sysctl -n net.ipv4.ip_forward) != 1 ]]; then
@ -22,7 +24,7 @@ fi
if [[ $EUID != 0 ]]; then if [[ $EUID != 0 ]]; then
# NixOS containers require root permissions # NixOS containers require root permissions
exec sudo "PATH=$PATH" "NIX_PATH=$NIX_PATH" "IN_NIX_SHELL=$IN_NIX_SHELL" "${BASH_SOURCE[0]}" "$@" exec sudo "PATH=$PATH" "NIX_PATH=$NIX_PATH" "NIX_BITCOIN_EXAMPLES_DIR=$NIX_BITCOIN_EXAMPLES_DIR" "${BASH_SOURCE[0]}" "$@"
fi fi
interactive= interactive=

View File

@ -12,10 +12,12 @@ set -euo pipefail
# MAKE SURE TO REPLACE the SSH identity file if you use this script for # MAKE SURE TO REPLACE the SSH identity file if you use this script for
# anything serious. # anything serious.
if [[ ! -v IN_NIX_SHELL ]]; then if [[ ! -v NIX_BITCOIN_EXAMPLES_DIR ]]; then
echo "Running script in nix shell env..." echo "Running script in nix shell env..."
cd "${BASH_SOURCE[0]%/*}" cd "${BASH_SOURCE[0]%/*}"
exec nix-shell --run "./${BASH_SOURCE[0]##*/} $*" exec nix-shell --run "./${BASH_SOURCE[0]##*/} $*"
else
cd "$NIX_BITCOIN_EXAMPLES_DIR"
fi fi
source qemu-vm/run-vm.sh source qemu-vm/run-vm.sh

View File

@ -11,10 +11,12 @@ set -euo pipefail
# MAKE SURE TO REPLACE the SSH identity file if you use this script for # MAKE SURE TO REPLACE the SSH identity file if you use this script for
# anything serious. # anything serious.
if [[ ! -v IN_NIX_SHELL ]]; then if [[ ! -v NIX_BITCOIN_EXAMPLES_DIR ]]; then
echo "Running script in nix shell env..." echo "Running script in nix shell env..."
cd "${BASH_SOURCE[0]%/*}" cd "${BASH_SOURCE[0]%/*}"
exec nix-shell --run "./${BASH_SOURCE[0]##*/} $*" exec nix-shell --run "./${BASH_SOURCE[0]##*/} $*"
else
cd "$NIX_BITCOIN_EXAMPLES_DIR"
fi fi
source qemu-vm/run-vm.sh source qemu-vm/run-vm.sh

View File

@ -8,25 +8,28 @@ let
else nix-bitcoin-release; else nix-bitcoin-release;
nixpkgs-path = (import "${toString nix-bitcoin-path}/pkgs/nixpkgs-pinned.nix").nixpkgs; nixpkgs-path = (import "${toString nix-bitcoin-path}/pkgs/nixpkgs-pinned.nix").nixpkgs;
nixpkgs = import nixpkgs-path {}; pkgs = import nixpkgs-path {};
nix-bitcoin = nixpkgs.callPackage nix-bitcoin-path {}; nix-bitcoin = pkgs.callPackage nix-bitcoin-path {};
nix-bitcoin-unpacked = (import <nixpkgs> {}).runCommand "nix-bitcoin-src" {} '' nix-bitcoin-unpacked = (import <nixpkgs> {}).runCommand "nix-bitcoin-src" {} ''
mkdir $out; tar xf ${builtins.fetchurl nix-bitcoin-release} -C $out mkdir $out; tar xf ${builtins.fetchurl nix-bitcoin-release} -C $out
''; '';
in in
with nixpkgs; with pkgs;
stdenv.mkDerivation rec { stdenv.mkDerivation rec {
name = "nix-bitcoin-environment"; name = "nix-bitcoin-environment";
path = lib.makeBinPath [ nix-bitcoin.extra-container figlet ]; path = lib.makeBinPath [ nix-bitcoin.extra-container ];
shellHook = '' shellHook = ''
export NIX_PATH="nixpkgs=${nixpkgs-path}:nix-bitcoin=${toString nix-bitcoin-path}:." export NIX_PATH="nixpkgs=${nixpkgs-path}:nix-bitcoin=${toString nix-bitcoin-path}:."
export PATH="${path}''${PATH:+:}$PATH" export PATH="${path}''${PATH:+:}$PATH"
alias fetch-release="${toString nix-bitcoin-path}/helper/fetch-release" export NIX_BITCOIN_EXAMPLES_DIR="${toString ./.}"
fetch-release() {
${toString nix-bitcoin-path}/helper/fetch-release
}
krops-deploy() { krops-deploy() {
# Ensure strict permissions on secrets/ directory before rsyncing it to # Ensure strict permissions on secrets/ directory before rsyncing it to
@ -35,7 +38,13 @@ stdenv.mkDerivation rec {
$(nix-build --no-out-link ${toString ./krops/deploy.nix}) $(nix-build --no-out-link ${toString ./krops/deploy.nix})
} }
figlet "nix-bitcoin" # Print logo if
# 1. stdout is a TTY, i.e. we're not piping the output
# 2. the shell is interactive
if [[ -t 1 && $- == *i* ]]; then
${figlet}/bin/figlet "nix-bitcoin"
fi
(mkdir -p secrets; cd secrets; env -i ${nix-bitcoin.generate-secrets}) (mkdir -p secrets; cd secrets; env -i ${nix-bitcoin.generate-secrets})
# Don't run this hook when another nix-shell is run inside this shell # Don't run this hook when another nix-shell is run inside this shell

View File

@ -1,36 +1,40 @@
#! /usr/bin/env nix-shell #!/usr/bin/env nix-shell
#! nix-shell -i bash -p bash coreutils curl jq gnugrep gnupg #!nix-shell -i bash -p bash coreutils curl jq gnupg
set -euo pipefail set -euo pipefail
scriptDir=$(cd "${BASH_SOURCE[0]%/*}" && pwd) scriptDir=$(cd "${BASH_SOURCE[0]%/*}" && pwd)
REPO=fort-nix/nix-bitcoin repo=fort-nix/nix-bitcoin
if [[ ! -v VERSION ]]; then if [[ ! -v version ]]; then
VERSION=$(curl --silent "https://api.github.com/repos/$REPO/releases/latest" | jq -r '.tag_name' | tail -c +2) version=$(curl --silent "https://api.github.com/repos/$repo/releases/latest" | jq -r '.tag_name' | tail -c +2)
fi fi
TMPDIR=$(mktemp -d) TMPDIR=$(mktemp -d)
GPG_HOME=$(mktemp -d) trap "rm -rf $TMPDIR" EXIT
trap "rm -rf $TMPDIR $GPG_HOME" EXIT
GPG_HOME=$TMPDIR/gpg-home
mkdir -p -m 700 "$GPG_HOME"
cd $TMPDIR cd $TMPDIR
BASEURL=https://github.com/$REPO/releases/download/v$VERSION baseUrl=https://github.com/$repo/releases/download/v$version
curl --silent -L -O $BASEURL/SHA256SUMS.txt curl --silent -L -O $baseUrl/SHA256SUMS.txt
curl --silent -L -O $BASEURL/SHA256SUMS.txt.asc curl --silent -L -O $baseUrl/SHA256SUMS.txt.asc
# Import key and verify fingerprint # Import key
gpg --homedir $GPG_HOME --import "$scriptDir/key-jonasnick.bin" &> /dev/null gpg --homedir $GPG_HOME --import "$scriptDir/key-jonasnick.bin" &> /dev/null
# Verify key fingerprint
gpg --homedir $GPG_HOME --list-keys 36C71A37C9D988BDE82508D9B1A70E4F8DCD0366 > /dev/null gpg --homedir $GPG_HOME --list-keys 36C71A37C9D988BDE82508D9B1A70E4F8DCD0366 > /dev/null
# Verify signature for SHA256SUMS.txt
gpg --homedir $GPG_HOME --verify SHA256SUMS.txt.asc &> /dev/null || { gpg --homedir $GPG_HOME --verify SHA256SUMS.txt.asc &> /dev/null || {
echo "ERROR: Signature verification failed. Please open an issue in the project repository." echo "Error: Signature verification failed. Please open an issue in the project repository."
exit 1 exit 1
} }
SHA256=$(cat SHA256SUMS.txt | grep -Eo '^[^ ]+') sha256=$(cat SHA256SUMS.txt | cut -d\ -f1)
cat <<EOF cat <<EOF
{ {
url = "$BASEURL/nix-bitcoin-$VERSION.tar.gz"; url = "$baseUrl/nix-bitcoin-$version.tar.gz";
sha256 = "$SHA256"; sha256 = "$sha256";
} }
EOF EOF

View File

@ -55,6 +55,8 @@ let
# Extra options # Extra options
${cfg.extraConfig} ${cfg.extraConfig}
''; '';
zmqServerEnabled = (cfg.zmqpubrawblock != null) || (cfg.zmqpubrawtx != null);
in { in {
options = { options = {
services.bitcoind = { services.bitcoind = {
@ -351,15 +353,14 @@ in {
NotifyAccess = "all"; NotifyAccess = "all";
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
TimeoutStartSec = 300; TimeoutStartSec = "5min";
TimeoutStopSec = "10min";
ExecStart = "${cfg.package}/bin/bitcoind -datadir='${cfg.dataDir}'"; ExecStart = "${cfg.package}/bin/bitcoind -datadir='${cfg.dataDir}'";
Restart = "on-failure"; Restart = "on-failure";
UMask = mkIf cfg.dataDirReadableByGroup "0027"; UMask = mkIf cfg.dataDirReadableByGroup "0027";
ReadWritePaths = cfg.dataDir; ReadWritePaths = cfg.dataDir;
} // (if cfg.enforceTor } // nbLib.allowedIPAddresses cfg.enforceTor
then nbLib.allowTor // optionalAttrs zmqServerEnabled nbLib.allowNetlink;
else nbLib.allowAnyIP)
// optionalAttrs (cfg.zmqpubrawblock != null || cfg.zmqpubrawtx != null) nbLib.allowAnyProtocol;
}; };
# Use this to update the banlist: # Use this to update the banlist:
@ -384,7 +385,7 @@ in {
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
ReadWritePaths = cfg.dataDir; ReadWritePaths = cfg.dataDir;
} // nbLib.allowTor; } // nbLib.allowLocalIPAddresses;
}; };
users.users.${cfg.user}.group = cfg.group; users.users.${cfg.user}.group = cfg.group;

View File

@ -155,10 +155,7 @@ in {
RestartSec = "10s"; RestartSec = "10s";
ReadWritePaths = cfg.nbxplorer.dataDir; ReadWritePaths = cfg.nbxplorer.dataDir;
MemoryDenyWriteExecute = "false"; MemoryDenyWriteExecute = "false";
} // (if cfg.nbxplorer.enforceTor } // nbLib.allowedIPAddresses cfg.nbxplorer.enforceTor;
then nbLib.allowTor
else nbLib.allowAnyIP
);
}; };
systemd.services.btcpayserver = let systemd.services.btcpayserver = let
@ -204,10 +201,7 @@ in {
RestartSec = "10s"; RestartSec = "10s";
ReadWritePaths = cfg.btcpayserver.dataDir; ReadWritePaths = cfg.btcpayserver.dataDir;
MemoryDenyWriteExecute = "false"; MemoryDenyWriteExecute = "false";
} // (if cfg.btcpayserver.enforceTor } // nbLib.allowedIPAddresses cfg.btcpayserver.enforceTor;
then nbLib.allowTor
else nbLib.allowAnyIP
);
}; in self; }; in self;
users.users.${cfg.nbxplorer.user} = { users.users.${cfg.nbxplorer.user} = {

View File

@ -4,6 +4,8 @@ with lib;
let let
cfg = config.services.clightning.plugins.zmq; cfg = config.services.clightning.plugins.zmq;
nbLib = config.nix-bitcoin.lib;
endpoints = [ endpoints = [
"channel-opened" "channel-opened"
"connect" "connect"
@ -38,5 +40,9 @@ in
plugin=${config.nix-bitcoin.pkgs.clightning-plugins.zmq.path} plugin=${config.nix-bitcoin.pkgs.clightning-plugins.zmq.path}
${concatStrings (map setEndpoint endpoints)} ${concatStrings (map setEndpoint endpoints)}
''; '';
# The zmq server requires AF_NETLINK
systemd.services.clightning.serviceConfig.RestrictAddressFamilies =
mkForce nbLib.allowNetlink.RestrictAddressFamilies;
}; };
} }

View File

@ -128,10 +128,7 @@ in {
Restart = "on-failure"; Restart = "on-failure";
RestartSec = "10s"; RestartSec = "10s";
ReadWritePaths = cfg.dataDir; ReadWritePaths = cfg.dataDir;
} // (if cfg.enforceTor } // nbLib.allowedIPAddresses cfg.enforceTor;
then nbLib.allowTor
else nbLib.allowAnyIP
);
# Wait until the rpc socket appears # Wait until the rpc socket appears
postStart = '' postStart = ''
while [[ ! -e ${cfg.networkDir}/lightning-rpc ]]; do while [[ ! -e ${cfg.networkDir}/lightning-rpc ]]; do

View File

@ -102,10 +102,7 @@ in {
Restart = "on-failure"; Restart = "on-failure";
RestartSec = "10s"; RestartSec = "10s";
ReadWritePaths = "${cfg.dataDir} ${if cfg.high-memory then "${bitcoind.dataDir}" else ""}"; ReadWritePaths = "${cfg.dataDir} ${if cfg.high-memory then "${bitcoind.dataDir}" else ""}";
} // (if cfg.enforceTor } // nbLib.allowedIPAddresses cfg.enforceTor;
then nbLib.allowTor
else nbLib.allowAnyIP
);
}; };
users.users.${cfg.user} = { users.users.${cfg.user} = {

View File

@ -102,9 +102,7 @@ in {
Restart = "on-failure"; Restart = "on-failure";
RestartSec = "10s"; RestartSec = "10s";
ReadWritePaths = cfg.dataDir; ReadWritePaths = cfg.dataDir;
} // (if cfg.enforceTor } // nbLib.allowedIPAddresses cfg.enforceTor;
then nbLib.allowTor
else nbLib.allowAnyIP);
}; };
nix-bitcoin.secrets = { nix-bitcoin.secrets = {

View File

@ -100,9 +100,8 @@ in {
Restart = "on-failure"; Restart = "on-failure";
RestartSec = "10s"; RestartSec = "10s";
ReadWritePaths = cfg.dataDir; ReadWritePaths = cfg.dataDir;
} // (if cfg.enforceTor } // (nbLib.allowedIPAddresses cfg.enforceTor)
then nbLib.allowTor // nbLib.allowNetlink; # required by gRPC-Go
else nbLib.allowAnyIP);
}; };
}; };
} }

View File

@ -239,10 +239,7 @@ in {
PIDFile = pidFile; PIDFile = pidFile;
Restart = "on-failure"; Restart = "on-failure";
ReadWritePaths = cfg.dataDir; ReadWritePaths = cfg.dataDir;
} // (if cfg.enforceTor } // nbLib.allowedIPAddresses cfg.enforceTor;
then nbLib.allowTor
else nbLib.allowAnyIP
);
}; };
users.users.${cfg.user} = { users.users.${cfg.user} = {

View File

@ -198,6 +198,7 @@ in {
RestartSec = "10s"; RestartSec = "10s";
ReadWritePaths = cfg.dataDir; ReadWritePaths = cfg.dataDir;
ExecStartPost = let ExecStartPost = let
curl = "${pkgs.curl}/bin/curl -s --show-error";
restUrl = "https://${cfg.restAddress}:${toString cfg.restPort}/v1"; restUrl = "https://${cfg.restAddress}:${toString cfg.restPort}/v1";
in [ in [
(nbLib.script "lnd-create-wallet" '' (nbLib.script "lnd-create-wallet" ''
@ -212,13 +213,13 @@ in {
if [[ ! -f "$mnemonic" ]]; then if [[ ! -f "$mnemonic" ]]; then
echo Create lnd seed echo Create lnd seed
umask u=r,go= umask u=r,go=
${pkgs.curl}/bin/curl -s \ ${curl} \
--cacert ${secretsDir}/lnd-cert \ --cacert ${secretsDir}/lnd-cert \
-X GET ${restUrl}/genseed | ${pkgs.jq}/bin/jq -c '.cipher_seed_mnemonic' > "$mnemonic" -X GET ${restUrl}/genseed | ${pkgs.jq}/bin/jq -c '.cipher_seed_mnemonic' > "$mnemonic"
fi fi
echo Create lnd wallet echo Create lnd wallet
${pkgs.curl}/bin/curl -s --output /dev/null --show-error \ ${curl} --output /dev/null \
--cacert ${secretsDir}/lnd-cert \ --cacert ${secretsDir}/lnd-cert \
-X POST -d "{\"wallet_password\": \"$(cat ${secretsDir}/lnd-wallet-password | tr -d '\n' | base64 -w0)\", \ -X POST -d "{\"wallet_password\": \"$(cat ${secretsDir}/lnd-wallet-password | tr -d '\n' | base64 -w0)\", \
\"cipher_seed_mnemonic\": $(cat "$mnemonic" | tr -d '\n')}" \ \"cipher_seed_mnemonic\": $(cat "$mnemonic" | tr -d '\n')}" \
@ -231,8 +232,7 @@ in {
done done
else else
echo Unlock lnd wallet echo Unlock lnd wallet
${curl} \
${pkgs.curl}/bin/curl -s \
-H "Grpc-Metadata-macaroon: $(${pkgs.xxd}/bin/xxd -ps -u -c 99999 '${networkDir}/admin.macaroon')" \ -H "Grpc-Metadata-macaroon: $(${pkgs.xxd}/bin/xxd -ps -u -c 99999 '${networkDir}/admin.macaroon')" \
--cacert ${secretsDir}/lnd-cert \ --cacert ${secretsDir}/lnd-cert \
-X POST \ -X POST \
@ -251,7 +251,7 @@ in {
${lib.concatMapStrings (macaroon: '' ${lib.concatMapStrings (macaroon: ''
echo "Create custom macaroon ${macaroon}" echo "Create custom macaroon ${macaroon}"
macaroonPath="$RUNTIME_DIRECTORY/${macaroon}.macaroon" macaroonPath="$RUNTIME_DIRECTORY/${macaroon}.macaroon"
${pkgs.curl}/bin/curl -s \ ${curl} \
-H "Grpc-Metadata-macaroon: $(${pkgs.xxd}/bin/xxd -ps -u -c 99999 '${networkDir}/admin.macaroon')" \ -H "Grpc-Metadata-macaroon: $(${pkgs.xxd}/bin/xxd -ps -u -c 99999 '${networkDir}/admin.macaroon')" \
--cacert ${secretsDir}/lnd-cert \ --cacert ${secretsDir}/lnd-cert \
-X POST \ -X POST \
@ -262,10 +262,7 @@ in {
'') (attrNames cfg.macaroons)} '') (attrNames cfg.macaroons)}
'') '')
]; ];
} // (if cfg.enforceTor } // nbLib.allowedIPAddresses cfg.enforceTor;
then nbLib.allowTor
else nbLib.allowAnyIP
) // nbLib.allowAnyProtocol; # For ZMQ
}; };
users.users.${cfg.user} = { users.users.${cfg.user} = {

View File

@ -83,9 +83,7 @@ in {
ExecStart = "${pkgs.bash}/bin/bash ${recurring-donations-script}"; ExecStart = "${pkgs.bash}/bin/bash ${recurring-donations-script}";
User = "recurring-donations"; User = "recurring-donations";
Type = "oneshot"; Type = "oneshot";
} // (if cfg.enforceTor } // nbLib.allowedIPAddresses cfg.enforceTor;
then nbLib.allowTor
else nbLib.allowAnyIP);
}; };
systemd.timers.recurring-donations = { systemd.timers.recurring-donations = {
requires = [ "clightning.service" ]; requires = [ "clightning.service" ];

View File

@ -79,9 +79,7 @@ in {
User = cfg.user; User = cfg.user;
Restart = "on-failure"; Restart = "on-failure";
RestartSec = "10s"; RestartSec = "10s";
} // (if cfg.enforceTor } // nbLib.allowedIPAddresses cfg.enforceTor
then nbLib.allowTor
else nbLib.allowAnyIP)
// nbLib.nodejs; // nbLib.nodejs;
}; };
nix-bitcoin.secrets.spark-wallet-login.user = cfg.user; nix-bitcoin.secrets.spark-wallet-login.user = cfg.user;

View File

@ -1,4 +1,4 @@
{ stdenv, fetchurl, pkgconfig, curl, libev, sqlite }: { lib, stdenv, fetchurl, pkgconfig, curl, libev, sqlite }:
let let
curlWithGnuTLS = curl.override { gnutlsSupport = true; sslSupport = false; }; curlWithGnuTLS = curl.override { gnutlsSupport = true; sslSupport = false; };
@ -16,7 +16,7 @@ stdenv.mkDerivation rec {
enableParallelBuilding = true; enableParallelBuilding = true;
meta = with stdenv.lib; { meta = with lib; {
description = "Automated C-Lightning Node Manager"; description = "Automated C-Lightning Node Manager";
homepage = "https://github.com/ZmnSCPxj/clboss"; homepage = "https://github.com/ZmnSCPxj/clboss";
maintainers = with maintainers; [ nixbitcoin ]; maintainers = with maintainers; [ nixbitcoin ];

View File

@ -1,8 +1,8 @@
{ stdenv, fetchurl, pkgconfig, autoreconfHook, openssl, db48, boost, zeromq, rapidcheck { lib, stdenv, fetchurl, pkgconfig, autoreconfHook, openssl, db48, boost, zeromq, rapidcheck
, zlib, miniupnpc, qtbase ? null, qttools ? null, wrapQtAppsHook ? null, utillinux, protobuf, python3, qrencode, libevent , zlib, miniupnpc, qtbase ? null, qttools ? null, wrapQtAppsHook ? null, utillinux, protobuf, python3, qrencode, libevent
, withGui }: , withGui }:
with stdenv.lib; with lib;
stdenv.mkDerivation rec { stdenv.mkDerivation rec {
pname = "elements${optionalString (!withGui) "d"}"; pname = "elements${optionalString (!withGui) "d"}";
version = "0.18.1.9"; version = "0.18.1.9";

View File

@ -1,6 +1,4 @@
{ pkgs, stdenv, fetchurl, fetchFromGitHub, python3 }: { lib, pkgs, stdenv, fetchurl, fetchFromGitHub, python3 }:
with stdenv.lib;
let let
python = python3.override { python = python3.override {

View File

@ -1,4 +1,5 @@
{ stdenv { lib
, stdenv
, buildPythonPackage , buildPythonPackage
, fetchPypi , fetchPypi
, pkgs , pkgs
@ -18,7 +19,7 @@ buildPythonPackage rec {
# Only needed for tests # Only needed for tests
checkInputs = [ pkgs.openssl ]; checkInputs = [ pkgs.openssl ];
meta = with stdenv.lib; { meta = with lib; {
description = "ECDSA cryptographic signature library"; description = "ECDSA cryptographic signature library";
homepage = "https://github.com/warner/python-ecdsa"; homepage = "https://github.com/warner/python-ecdsa";
license = licenses.mit; license = licenses.mit;

View File

@ -1,4 +1,4 @@
{ stdenv, libusb1, udev, darwin, fetchPypi, buildPythonPackage, cython }: { lib, stdenv, libusb1, udev, darwin, fetchPypi, buildPythonPackage, cython }:
buildPythonPackage rec { buildPythonPackage rec {
pname = "hidapi"; pname = "hidapi";
@ -10,18 +10,18 @@ buildPythonPackage rec {
}; };
propagatedBuildInputs = propagatedBuildInputs =
stdenv.lib.optionals stdenv.isLinux [ libusb1 udev ] ++ lib.optionals stdenv.isLinux [ libusb1 udev ] ++
stdenv.lib.optionals stdenv.isDarwin [ darwin.IOKit darwin.apple_sdk.frameworks.CoreFoundation ] ++ lib.optionals stdenv.isDarwin [ darwin.IOKit darwin.apple_sdk.frameworks.CoreFoundation ] ++
[ cython ]; [ cython ];
# Fix the USB backend library lookup # Fix the USB backend library lookup
postPatch = stdenv.lib.optionalString stdenv.isLinux '' postPatch = lib.optionalString stdenv.isLinux ''
libusb=${libusb1.dev}/include/libusb-1.0 libusb=${libusb1.dev}/include/libusb-1.0
test -d $libusb || { echo "ERROR: $libusb doesn't exist, please update/fix this build expression."; exit 1; } test -d $libusb || { echo "ERROR: $libusb doesn't exist, please update/fix this build expression."; exit 1; }
sed -i -e "s|/usr/include/libusb-1.0|$libusb|" setup.py sed -i -e "s|/usr/include/libusb-1.0|$libusb|" setup.py
''; '';
meta = with stdenv.lib; { meta = with lib; {
description = "A Cython interface to the hidapi from https://github.com/signal11/hidapi"; description = "A Cython interface to the hidapi from https://github.com/signal11/hidapi";
homepage = "https://github.com/trezor/cython-hidapi"; homepage = "https://github.com/trezor/cython-hidapi";
# license can actually be either bsd3 or gpl3 # license can actually be either bsd3 or gpl3

View File

@ -33,15 +33,23 @@ let self = {
SystemCallArchitectures = "native"; SystemCallArchitectures = "native";
}; };
allowNetlink = {
RestrictAddressFamilies = self.defaultHardening.RestrictAddressFamilies + " AF_NETLINK";
};
# nodejs applications apparently rely on memory write execute # nodejs applications apparently rely on memory write execute
nodejs = { MemoryDenyWriteExecute = "false"; }; nodejs = { MemoryDenyWriteExecute = "false"; };
# Allow tor traffic. Allow takes precedence over Deny.
allowTor = { # Allow takes precedence over Deny.
allowLocalIPAddresses = {
IPAddressAllow = "127.0.0.1/32 ::1/128 169.254.0.0/16"; IPAddressAllow = "127.0.0.1/32 ::1/128 169.254.0.0/16";
}; };
# Allow any traffic allowAllIPAddresses = { IPAddressAllow = "any"; };
allowAnyIP = { IPAddressAllow = "any"; }; allowTor = self.allowLocalIPAddresses;
allowAnyProtocol = { RestrictAddressFamilies = "~"; }; allowedIPAddresses = onlyLocal:
if onlyLocal
then self.allowLocalIPAddresses
else self.allowAllIPAddresses;
enforceTor = mkOption { enforceTor = mkOption {
type = types.bool; type = types.bool;

View File

@ -1,6 +1,4 @@
{ stdenv, fetchFromGitHub, autoreconfHook }: { lib, stdenv, fetchFromGitHub, autoreconfHook }:
let inherit (stdenv.lib) optionals; in
stdenv.mkDerivation { stdenv.mkDerivation {
pname = "secp256k1"; pname = "secp256k1";
@ -18,7 +16,7 @@ stdenv.mkDerivation {
configureFlags = ["--enable-module-recovery" "--disable-jni" "--enable-experimental" "--enable-module-ecdh" "--enable-benchmark=no" ]; configureFlags = ["--enable-module-recovery" "--disable-jni" "--enable-experimental" "--enable-module-ecdh" "--enable-benchmark=no" ];
meta = with stdenv.lib; { meta = with lib; {
description = "Optimized C library for EC operations on curve secp256k1"; description = "Optimized C library for EC operations on curve secp256k1";
homepage = "https://github.com/bitcoin-core/secp256k1"; homepage = "https://github.com/bitcoin-core/secp256k1";
license = with licenses; [ mit ]; license = with licenses; [ mit ];

View File

@ -5,11 +5,7 @@
}, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-10_x"}: }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-10_x"}:
let let
globalBuildInputs = pkgs.lib.attrValues (import ./supplement.nix { nodeEnv = import "${toString pkgs.path}/pkgs/development/node-packages/node-env.nix" {
inherit nodeEnv;
inherit (pkgs) fetchurl fetchgit;
});
nodeEnv = import ./node-env.nix {
inherit (pkgs) stdenv python2 utillinux runCommand writeTextFile; inherit (pkgs) stdenv python2 utillinux runCommand writeTextFile;
inherit nodejs; inherit nodejs;
libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null; libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null;
@ -17,5 +13,5 @@ let
in in
import ./node-packages.nix { import ./node-packages.nix {
inherit (pkgs) fetchurl fetchgit; inherit (pkgs) fetchurl fetchgit;
inherit nodeEnv globalBuildInputs; inherit nodeEnv;
} }

View File

@ -1,5 +1,5 @@
{ stdenv, pkgs, lib }: { stdenv, pkgs, lib }:
lib.head (lib.attrValues (import ./composition.nix { lib.head (builtins.attrValues (import ./composition.nix {
inherit pkgs; inherit pkgs;
inherit (stdenv.hostPlatform) system; inherit (stdenv.hostPlatform) system;
})) }))

View File

@ -20,7 +20,14 @@ jq '.dependencies["qrcode-terminal"] = .optionalDependencies["qrcode-terminal"]'
# Run node2nix # Run node2nix
cp pkg.json $TMPDIR/pkg.json cp pkg.json $TMPDIR/pkg.json
node2nix --nodejs-10 -i $TMPDIR/pkg.json -c composition.nix --no-copy-node-env --supplement-input supplement.json node2nix --nodejs-10 -i $TMPDIR/pkg.json -c composition.nix --no-copy-node-env
# Set node env import.
# The reason for not providing a custom node-env.nix file is the following:
# To be flakes-compatible, we have to locate the nixpgs source via `pkgs.path` instead of `<nixpkgs>`.
# This requires the `pkgs` variable which is available only in composition.nix, not in node-env.nix.
nodeEnvImport='import "${toString pkgs.path}/pkgs/development/node-packages/node-env.nix"'
sed -i "s|import ./node-env.nix|$nodeEnvImport|" composition.nix
# Use verified source in node-packages.nix # Use verified source in node-packages.nix
url="https://github.com/shesek/spark-wallet/releases/download/v$version/spark-wallet-$version-npm.tgz" url="https://github.com/shesek/spark-wallet/releases/download/v$version/spark-wallet-$version-npm.tgz"

View File

@ -1 +0,0 @@
import <nixpkgs/pkgs/development/node-packages/node-env.nix>

View File

@ -1,2 +0,0 @@
[
]

View File

@ -84,6 +84,6 @@ if [[ ! ($containerBin && $(realpath $containerBin) == *extra-container-0.6*) ]]
fi fi
read -d '' src <<EOF || true read -d '' src <<EOF || true
(import "$scriptDir/tests.nix" { scenario = "$scenario"; }).container ((import "$scriptDir/tests.nix" {}).getTest "$scenario").container
EOF EOF
exec extra-container $containerCommand -E "$src" "$@" exec extra-container $containerCommand -E "$src" "$@"

View File

@ -1,37 +1,45 @@
testArgs: pkgs:
let let
pkgs = import <nixpkgs> { config = {}; overlays = []; }; pythonTesting = import "${toString pkgs.path}/nixos/lib/testing-python.nix" {
system = pkgs.stdenv.hostPlatform.system;
inherit pkgs;
};
in
test = (import "${pkgs.path}/nixos/tests/make-test-python.nix") (testArgs pkgs); args:
let
test = pythonTesting.makeTest args;
fixedTest = { ... }@args: fixedDriver = test.driver.overrideAttrs (old: let
let # Allow the test script to have longer lines by fixing the call to the 'black'
pkgsFixed = pkgs // { # code formatter.
# Fix the black Python code formatter that's used in the test to allow the test # The default width of 88 chars is too restrictive for our script.
# script to have longer lines. The default width of 88 chars is too restrictive for parts = builtins.split ''/nix/store/[^ ]+/black '' old.buildCommand;
# our script. preMatch = builtins.elemAt parts 0;
python3Packages = pkgs.python3Packages // { postMatch = builtins.elemAt parts 2;
black = pkgs.writeScriptBin "black" '' in {
fileToCheck=''${@:$#} # See `mkDriver` in nixpkgs/nixos/lib/testing-python.nix for the original definition of `buildCommand`
[[ $fileToCheck = *test-script ]] && extraArgs='--line-length 100' buildCommand = ''
exec ${pkgs.python3Packages.black}/bin/black $extraArgs "$@" ${preMatch}${pkgs.python3Packages.black}/bin/black --line-length 100 ${postMatch}
''; '';
}; # Keep reference to the `testDriver` derivation, required by `buildCommand`
}; testDriverReference = old.buildCommand;
test' = test (args // { pkgs = pkgsFixed; }); });
in
# See nixpkgs/nixos/lib/testing-python.nix for the original definition # 1. Use fixed driver
test'.overrideAttrs (_: { # 2. Save test logging output
# 1. Save test output # 3. Add link to driver so that a gcroot to a test prevents the driver from
# 2. Add link to driver so that a gcroot to a test prevents the driver from
# being garbage-collected # being garbage-collected
fixedTest = test.overrideAttrs (_: {
# See `runTests` in nixpkgs/nixos/lib/testing-python.nix for the original definition of `buildCommand`
buildCommand = '' buildCommand = ''
mkdir $out mkdir $out
LOGFILE=$out/output.xml tests='exec(os.environ["testScript"])' ${test'.driver}/bin/nixos-test-driver LOGFILE=$out/output.xml tests='exec(os.environ["testScript"])' ${fixedDriver}/bin/nixos-test-driver
ln -s ${test'.driver} $out/driver ln -s ${fixedDriver} $out/driver
''; '';
}) // { inherit (test') nodes driver; } ; }) // {
driver = fixedDriver;
inherit (test) nodes;
};
in in
fixedTest fixedTest

View File

@ -1,13 +1,25 @@
scenario: testConfig: pkgs:
let
makeVM = import ./make-test-vm.nix pkgs;
inherit (pkgs) lib;
in
name: testConfig:
{ {
vm = import ./make-test-vm.nix (pkgs: { vm = makeVM {
name = "nix-bitcoin-${scenario}"; name = "nix-bitcoin-${name}";
machine = { machine = {
imports = [ testConfig ]; imports = [ testConfig ];
virtualisation = {
# Needed because duplicity requires 270 MB of free temp space, regardless of backup size # Needed because duplicity requires 270 MB of free temp space, regardless of backup size
virtualisation.diskSize = 1024; diskSize = 1024;
# Min. 800 MiB needed to avoid 'out of memory' errors
memorySize = lib.mkDefault 2048;
cores = lib.mkDefault 2;
};
}; };
testScript = nodes: let testScript = nodes: let
@ -37,7 +49,7 @@ scenario: testConfig:
run_tests() run_tests()
'' ''
]; ];
}); };
container = { container = {
# The container name has a 11 char length limit # The container name has a 11 char length limit

View File

@ -110,7 +110,7 @@ trap 'eval "$runAtExit"' EXIT
if [[ $scenario = *' '* ]]; then if [[ $scenario = *' '* ]]; then
export scenarioOverridesFile=$(mktemp ${XDG_RUNTIME_DIR:-/tmp}/nb-scenario.XXX) export scenarioOverridesFile=$(mktemp ${XDG_RUNTIME_DIR:-/tmp}/nb-scenario.XXX)
runAtExit+='rm -f "$scenarioOverridesFile";' runAtExit+='rm -f "$scenarioOverridesFile";'
echo "{ testEnv, config, pkgs, lib }: with testEnv; with lib; { tmp = $scenario; }" > "$scenarioOverridesFile" echo "{ scenarios, pkgs, lib }: with lib; { tmp = $scenario; }" > "$scenarioOverridesFile"
scenario=tmp scenario=tmp
fi fi
@ -120,7 +120,7 @@ run() {
export TMPDIR=$(mktemp -d /tmp/nix-bitcoin-test.XXX) export TMPDIR=$(mktemp -d /tmp/nix-bitcoin-test.XXX)
runAtExit+="rm -rf $TMPDIR;" runAtExit+="rm -rf $TMPDIR;"
nix-build --out-link $TMPDIR/driver -E "(import \"$scriptDir/tests.nix\" { scenario = \"$scenario\"; }).vm" -A driver nix-build --out-link $TMPDIR/driver -E "((import \"$scriptDir/tests.nix\" {}).getTest \"$scenario\").vm" -A driver
# Variable 'tests' contains the Python code that is executed by the driver on startup # Variable 'tests' contains the Python code that is executed by the driver on startup
if [[ $1 == --interactive ]]; then if [[ $1 == --interactive ]]; then
@ -212,7 +212,7 @@ vmTestNixExpr() {
fi fi
cat <<EOF cat <<EOF
((import "$scriptDir/tests.nix" { scenario = "$scenario"; }).vm {}).overrideAttrs (old: rec { ((import "$scriptDir/tests.nix" {}).getTest "$scenario").vm.overrideAttrs (old: rec {
buildCommand = '' buildCommand = ''
export QEMU_OPTS="-smp $numCPUs -m $memoryMiB $extraQEMUOpts" export QEMU_OPTS="-smp $numCPUs -m $memoryMiB $extraQEMUOpts"
echo "VM stats: CPUs: $numCPUs, memory: $memoryMiB MiB" echo "VM stats: CPUs: $numCPUs, memory: $memoryMiB MiB"

View File

@ -1,14 +1,20 @@
# Integration tests, can be run without internet access. # Integration tests, can be run without internet access.
{ scenario ? "default" }: let
nixpkgs = (import ../pkgs/nixpkgs-pinned.nix).nixpkgs;
in
import ./lib/make-test.nix scenario ( { extraScenarios ? { ... }: {}
{ config, pkgs, lib, ... }: with lib; , pkgs ? import nixpkgs { config = {}; overlays = []; }
let testEnv = rec { }:
with pkgs.lib;
let
globalPkgs = pkgs;
baseConfig = { pkgs, config, ... }: let
cfg = config.services; cfg = config.services;
mkIfTest = test: mkIf (config.tests.${test} or false); mkIfTest = test: mkIf (config.tests.${test} or false);
in {
baseConfig = {
imports = [ imports = [
./lib/test-lib.nix ./lib/test-lib.nix
../modules/modules.nix ../modules/modules.nix
@ -26,6 +32,9 @@ let testEnv = rec {
}; };
config = mkMerge [{ config = mkMerge [{
# Share the same pkgs instance among tests
nixpkgs.pkgs = mkDefault globalPkgs;
tests.bitcoind = cfg.bitcoind.enable; tests.bitcoind = cfg.bitcoind.enable;
services.bitcoind = { services.bitcoind = {
enable = true; enable = true;
@ -183,14 +192,14 @@ let testEnv = rec {
]; ];
}; };
netnsBase = { netnsBase = { config, pkgs, ... }: {
nix-bitcoin.netns-isolation.enable = true; nix-bitcoin.netns-isolation.enable = true;
test.data.netns = config.nix-bitcoin.netns-isolation.netns; test.data.netns = config.nix-bitcoin.netns-isolation.netns;
tests.netns-isolation = true; tests.netns-isolation = true;
environment.systemPackages = [ pkgs.fping ]; environment.systemPackages = [ pkgs.fping ];
}; };
regtestBase = { regtestBase = { config, ... }: {
tests.regtest = true; tests.regtest = true;
services.bitcoind.regtest = true; services.bitcoind.regtest = true;
@ -241,20 +250,29 @@ let testEnv = rec {
# You can also set the env var `scenarioOverridesFile` (used below) to define custom scenarios. # You can also set the env var `scenarioOverridesFile` (used below) to define custom scenarios.
}; };
}; };
};
in
let
overrides = builtins.getEnv "scenarioOverridesFile"; overrides = builtins.getEnv "scenarioOverridesFile";
scenarios = testEnv.scenarios // (optionalAttrs (overrides != "") (import overrides { extraScenarios' = (if (overrides != "") then import overrides else extraScenarios) {
inherit testEnv config pkgs lib; inherit scenarios pkgs;
})); inherit (pkgs) lib;
autoScenario = {
services.${scenario}.enable = true;
}; };
in { allScenarios = scenarios // extraScenarios';
makeTest = name: config:
makeTest' name {
imports = [ imports = [
scenarios.base allScenarios.base
(scenarios.${scenario} or autoScenario) config
]; ];
};
makeTest' = import ./lib/make-test.nix pkgs;
tests = builtins.mapAttrs makeTest allScenarios;
getTest = name: tests.${name} or (makeTest name {
services.${name}.enable = true;
});
in
tests // {
inherit getTest;
} }
)

View File

@ -352,10 +352,9 @@ def _():
# Current time in µs # Current time in µs
pre_restart = succeed("date +%s.%6N").rstrip() pre_restart = succeed("date +%s.%6N").rstrip()
# Sanity-check system by restarting all services # Sanity-check system by restarting bitcoind.
succeed( # This also restarts all services depending on bitcoind.
"systemctl restart bitcoind clightning lnd lightning-loop lightning-pool spark-wallet liquidd" succeed("systemctl restart bitcoind")
)
# Now that the bitcoind restart triggered a banlist import restart, check that # Now that the bitcoind restart triggered a banlist import restart, check that
# re-importing already banned addresses works # re-importing already banned addresses works
@ -367,27 +366,37 @@ def _():
@test("regtest") @test("regtest")
def _(): def _():
if "electrs" in enabled_tests: def enabled(unit):
if unit in enabled_tests:
# Wait because the unit might have been restarted in the preceding
# 'banlist-and-restart' test
machine.wait_for_unit(unit)
return True
else:
return False
if enabled("electrs"):
machine.wait_for_unit("onion-addresses")
machine.wait_until_succeeds(log_has_string("electrs", "BlockchainInfo")) machine.wait_until_succeeds(log_has_string("electrs", "BlockchainInfo"))
get_block_height_cmd = ( get_block_height_cmd = (
"""echo '{"method": "blockchain.headers.subscribe", "id": 0, "params": []}'""" """echo '{"method": "blockchain.headers.subscribe", "id": 0, "params": []}'"""
f" | nc -N {ip('electrs')} 50001 | jq -M .result.height" f" | nc -N {ip('electrs')} 50001 | jq -M .result.height"
) )
assert_full_match(get_block_height_cmd, "10\n") assert_full_match(get_block_height_cmd, "10\n")
if "clightning" in enabled_tests: if enabled("clightning"):
machine.wait_until_succeeds( machine.wait_until_succeeds(
"[[ $(runuser -u operator -- lightning-cli getinfo | jq -M .blockheight) == 10 ]]" "[[ $(runuser -u operator -- lightning-cli getinfo | jq -M .blockheight) == 10 ]]"
) )
if "lnd" in enabled_tests: if enabled("lnd"):
machine.wait_until_succeeds( machine.wait_until_succeeds(
"[[ $(runuser -u operator -- lncli getinfo | jq -M .block_height) == 10 ]]" "[[ $(runuser -u operator -- lncli getinfo | jq -M .block_height) == 10 ]]"
) )
if "lightning-loop" in enabled_tests: if enabled("lightning-loop"):
machine.wait_until_succeeds( machine.wait_until_succeeds(
log_has_string("lightning-loop", "Starting event loop at height 10") log_has_string("lightning-loop", "Starting event loop at height 10")
) )
succeed("runuser -u operator -- loop getparams") succeed("runuser -u operator -- loop getparams")
if "lightning-pool" in enabled_tests: if enabled("lightning-pool"):
machine.wait_until_succeeds( machine.wait_until_succeeds(
log_has_string("lightning-pool", "lnd is now fully synced to its chain backend") log_has_string("lightning-pool", "lnd is now fully synced to its chain backend")
) )