Compare commits

..

4 Commits

Author SHA1 Message Date
Greg Shuflin
6a7631f228 Patch to prevent chmod 2022-09-25 01:15:53 -07:00
Jonas Nick
34f6eb90d7
Merge fort-nix/nix-bitcoin#550: Update nixpkgs
261f7a043f update nixpkgs (Jonas Nick)
09c765368f clightning-plugins: update packages (Jonas Nick)

Pull request description:

ACKs for top commit:
  erikarvstedt:
    ACK 261f7a043f

Tree-SHA512: 30cec6e06dc56b84daf058441a25dc7593b2754c7cbdbb48562528a81727f8a7abbaf5d31497a136903485534e41b171d55a60d9bc91548feb7ff7997985e364
2022-09-22 18:58:27 +00:00
Jonas Nick
261f7a043f
update nixpkgs
electrs: 0.9.7 -> 0.9.9
elementsd: 0.21.0.2 -> 22.0
fulcrum: 1.7.0 -> 1.8.1
2022-09-22 16:57:19 +00:00
Jonas Nick
09c765368f
clightning-plugins: update packages 2022-09-22 16:57:00 +00:00
115 changed files with 1344 additions and 3346 deletions

View File

@ -9,7 +9,7 @@ task:
container: container:
# Defined in https://github.com/nix-community/docker-nixpkgs # Defined in https://github.com/nix-community/docker-nixpkgs
image: nixpkgs/nix-flakes:nixos-22.11 image: nixpkgs/nix-flakes:nixos-22.05
matrix: matrix:
- name: modules_test - name: modules_test
@ -27,16 +27,14 @@ task:
- scenario: default - scenario: default
- scenario: netns - scenario: netns
- scenario: netnsRegtest - scenario: netnsRegtest
- scenario: trustedcoin
# This script is run as root # This script is run as root
build_script: build_script:
- echo "sandbox = true" >> /etc/nix/nix.conf - echo "sandbox = true" >> /etc/nix/nix.conf
- nix shell --inputs-from . nixpkgs#{bash,coreutils,cachix} -c ./test/ci/build.sh $scenario - nix shell --inputs-from . nixpkgs#{bash,coreutils,gawk,cachix} -c ./test/ci/build.sh
- name: flake - name: flake
build_script: build_script:
- nix flake check - nix flake check
- ./test/nixos-search/ci-test.sh
- name: shellcheck - name: shellcheck
build_script: build_script:

View File

@ -53,8 +53,6 @@ Hint: To show a table of contents, click the button (![Github TOC button](docs/i
top left corner of the documents. top left corner of the documents.
<!-- TODO-EXTERNAL: --> <!-- TODO-EXTERNAL: -->
<!-- Change query to `nix-bitcoin` when upstream search has been fixed -->
* [NixOS options search](https://search.nixos.org/flakes?channel=unstable&sort=relevance&type=options&query=bitcoin)
* [Hardware requirements](docs/hardware.md) * [Hardware requirements](docs/hardware.md)
* [Installation](docs/install.md) * [Installation](docs/install.md)
* [Configuration and maintenance](docs/configuration.md) * [Configuration and maintenance](docs/configuration.md)
@ -79,22 +77,19 @@ NixOS modules ([src](modules/modules.nix))
* [prometheus](https://github.com/lightningd/plugins/tree/master/prometheus): lightning node exporter for the prometheus timeseries server * [prometheus](https://github.com/lightningd/plugins/tree/master/prometheus): lightning node exporter for the prometheus timeseries server
* [rebalance](https://github.com/lightningd/plugins/tree/master/rebalance): keeps your channels balanced * [rebalance](https://github.com/lightningd/plugins/tree/master/rebalance): keeps your channels balanced
* [summary](https://github.com/lightningd/plugins/tree/master/summary): print a nice summary of the node status * [summary](https://github.com/lightningd/plugins/tree/master/summary): print a nice summary of the node status
* [trustedcoin](https://github.com/nbd-wtf/trustedcoin) [[experimental](docs/services.md#trustedcoin-hints)]: replaces bitcoind with trusted public explorers
* [zmq](https://github.com/lightningd/plugins/tree/master/zmq): publishes notifications via ZeroMQ to configured endpoints * [zmq](https://github.com/lightningd/plugins/tree/master/zmq): publishes notifications via ZeroMQ to configured endpoints
* [clightning-rest](https://github.com/Ride-The-Lightning/c-lightning-REST): REST server for clightning * [clightning-rest](https://github.com/Ride-The-Lightning/c-lightning-REST): REST server for clightning
* [lnd](https://github.com/lightningnetwork/lnd) with support for announcing an onion service and [static channel backups](https://github.com/lightningnetwork/lnd/blob/master/docs/recovery.md) * [lnd](https://github.com/lightningnetwork/lnd) with support for announcing an onion service and [static channel backups](https://github.com/lightningnetwork/lnd/blob/master/docs/recovery.md)
* [Lightning Loop](https://github.com/lightninglabs/loop) * [Lightning Loop](https://github.com/lightninglabs/loop)
* [Lightning Pool](https://github.com/lightninglabs/pool) * [Lightning Pool](https://github.com/lightninglabs/pool)
* [charge-lnd](https://github.com/accumulator/charge-lnd): policy-based channel fee manager * [charge-lnd](https://github.com/accumulator/charge-lnd): policy-based channel fee manager
* [lndconnect](https://github.com/LN-Zap/lndconnect): connect your wallet to lnd or * [lndconnect](https://github.com/LN-Zap/lndconnect): connect your wallet to lnd or clightning via a REST onion service
clightning [via WireGuard](./docs/services.md#use-zeus-mobile-lightning-wallet-via-wireguard) or
[Tor](./docs/services.md#use-zeus-mobile-lightning-wallet-via-tor)
* [Ride The Lightning](https://github.com/Ride-The-Lightning/RTL): web interface for `lnd` and `clightning` * [Ride The Lightning](https://github.com/Ride-The-Lightning/RTL): web interface for `lnd` and `clightning`
* [spark-wallet](https://github.com/shesek/spark-wallet) * [spark-wallet](https://github.com/shesek/spark-wallet)
* [electrs](https://github.com/romanz/electrs): Electrum server * [electrs](https://github.com/romanz/electrs)
* [fulcrum](https://github.com/cculianu/Fulcrum): Electrum server (see [the module](modules/fulcrum.nix) for a comparison with electrs) * [fulcrum](https://github.com/cculianu/Fulcrum) (see [the module](modules/fulcrum.nix) for a comparison to electrs)
* [btcpayserver](https://github.com/btcpayserver/btcpayserver) * [btcpayserver](https://github.com/btcpayserver/btcpayserver)
* [liquid](https://github.com/elementsproject/elements): federated sidechain * [liquid](https://github.com/elementsproject/elements)
* [JoinMarket](https://github.com/joinmarket-org/joinmarket-clientserver) * [JoinMarket](https://github.com/joinmarket-org/joinmarket-clientserver)
* [JoinMarket Orderbook Watcher](https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master/docs/orderbook.md) * [JoinMarket Orderbook Watcher](https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master/docs/orderbook.md)
* [bitcoin-core-hwi](https://github.com/bitcoin-core/HWI) * [bitcoin-core-hwi](https://github.com/bitcoin-core/HWI)
@ -102,13 +97,7 @@ NixOS modules ([src](modules/modules.nix))
* [netns-isolation](modules/netns-isolation.nix): isolates applications on the network-level via network namespaces * [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 * [nodeinfo](modules/nodeinfo.nix): script which prints info about the node's services
* [backups](modules/backups.nix): 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): configures a non-root user who has access to client tools (e.g. `bitcoin-cli`, `lightning-cli`) * [operator](modules/operator.nix): adds non-root user `operator` who has access to client tools (e.g. `bitcoin-cli`, `lightning-cli`)
### Extension modules
Extension modules are maintained in separate repositories and have their own review
and release process.
* [Mempool](https://github.com/fort-nix/nix-bitcoin-mempool): Bitcoin visualizer, explorer and API service
Security Security
--- ---
@ -129,10 +118,6 @@ The nix-bitcoin security fund is a 2 of 3 bitcoin multisig address open for dona
security researchers who discover vulnerabilities in nix-bitcoin or its upstream dependencies.\ security researchers who discover vulnerabilities in nix-bitcoin or its upstream dependencies.\
See [Security Fund](./SECURITY.md#nix-bitcoin-security-fund) for details. See [Security Fund](./SECURITY.md#nix-bitcoin-security-fund) for details.
Developing
---
See [dev/README](./dev/README.md).
Troubleshooting Troubleshooting
--- ---
If you are having problems with nix-bitcoin check the [FAQ](docs/faq.md) or submit an issue.\ If you are having problems with nix-bitcoin check the [FAQ](docs/faq.md) or submit an issue.\

View File

@ -1,104 +0,0 @@
This directory contains docs and helper scripts for developing and debugging:
- [`dev.sh`](./dev.sh): misc dev helpers
- [`dev-features.sh`](./dev-features.sh): helpers for developing specific
nix-bitcoin features, like services
- [`topics`](./topics) features specific topics
- [`dev-scenarios.nix`](./dev-scenarios.nix): extra test scenarios used in the above scripts
See also: [test/README.md](../test/README.md)
## Run a dev shell
There are two ways to run a dev shell:
### 1. Run command `nix develop`
This starts a shell with [`test/run-tests.sh`](../test/run-tests.sh) and
the scripts in dir [`helper`](../helper) added to `PATH`.
### 2. Setup and start the `direnv` dev env
This is an opinionated, [direnv](https://direnv.net/)-based dev env, optimized for developer experience.
[`dev-env/create.sh`](./dev-env/create.sh) creates a git repo with the following contents:
- Dir `src` which contains the nix-bitcoin repo
- Dir `bin` for helper scripts
- File `scenarios.nix` for custom test scenarios
- File `.envrc` that defines a [direnv](https://direnv.net/) environment,
mainly for adding nix-bitcoin and helper scripts to `PATH`
#### Installation
1. [Install direnv](https://direnv.net/docs/installation.html).\
If you use NixOS (and Bash as the default shell), just add the following to your system config:
```nix
environment.systemPackages = [ pkgs.direnv ];
programs.bash.interactiveShellInit = ''
eval "$(direnv hook bash)"
'';
```
2. Create the dev env:
```bash
# Set up a dev environment in dir ~/dev/nix-bitcoin.
# The dir is created automatically.
./dev-env/create.sh ~/dev/nix-bitcoin
cd ~/dev/nix-bitcoin
# Enable direnv
direnv allow
```
3. Optional: Editor integration
- Add envrc support to your editor
- Setup your editor so you can easily execute lines or paragraphs from a shell script
file in a shell.\
This simplifies using dev helper scripts like [`./dev.sh`](./dev.sh).
#### Explore the dev env
```bash
# The direnv is automatically activated when visiting any subdir of ~/dev/nix-bitcoin
cd ~/dev/nix-bitcoin
ls -al . bin lib
# The direnv config file
cat .envrc
# You can use this file to define extra scenarios
cat scenarios.nix
# Binary `dev-run-tests` runs nix-bitcoin's `run-tests.sh` with extra scenarios from ./scenarios.nix
# Example:
# Run command `nodeinfo` in `myscenario` (defined in ./scenarios.nix) via a container
dev-run-tests -s myscenario container --run c nodeinfo
# Equivalent (shorthand)
te -s myscenario container --run c nodeinfo
# Run the tests for `myscenario` in a VM
te -s myscenario
# Start an interactive shell inside a VM
te -s myscenario vm
```
See also: [test/README.md](../test/README.md)
## Adding a new service
It's easiest to use an existing service as a template:
- [electrs.nix](../modules/electrs.nix): a basic service
- [clightning.nix](../modules/clightning.nix): simple, but covers a few more features.\
(A `cli` binary and a runtime-composed config to include secrets.)
- [rtl.nix](../modules/rtl.nix): includes a custom package, defined in [pkgs/rtl](../pkgs/rtl).\
Most other services use packages that are already included in nixpkgs.
## Switching to a new NixOS release
- [flake.nix](../flake.nix): update `nixpkgs.url`
- [cirrus.yml](../.cirrus.yml): update toplevel container -> image attribute
- [examples/configuration.nix](../examples/configuration.nix): update `system.stateVersion`
- Treewide: check if any `TODO-EXTERNAL` comments can be resolved

View File

@ -1,65 +0,0 @@
#!/usr/bin/env bash
# shellcheck disable=SC2016
set -euo pipefail
destDir=${1:-nix-bitcoin}
scriptDir=$(cd "${BASH_SOURCE[0]%/*}" && pwd)
mkdir -p "$destDir/"{bin,lib}
cd "$destDir"
if [[ ! -e src ]]; then
echo "Cloning fort-nix/nix-bitcoin"
git clone https://github.com/fort-nix/nix-bitcoin src
fi
echo 'export root=$PWD
export src=$root/src
PATH_add bin
PATH_add src/helper' > .envrc
if [[ ! -e scenarios.nix ]]; then
cp "$scriptDir/template-scenarios.nix" scenarios.nix
fi
install -m 755 <(
echo '#!/usr/bin/env bash'
echo 'exec run-tests.sh --extra-scenarios "$root/scenarios.nix" "$@"'
) bin/dev-run-tests
install -m 755 <(
echo '#!/usr/bin/env bash'
echo 'exec $root/src/test/run-tests.sh --out-link-prefix /tmp/nix-bitcoin/test "$@"'
) bin/run-tests.sh
ln -sfn dev-run-tests bin/te
## nix-bitcoin-firejail
echo '# Add your shell config files here that should be accessible in the sandbox
whitelist ${HOME}/.bashrc
read-only ${HOME}/.bashrc' > lib/nix-bitcoin-firejail.conf
install -m 755 <(
echo '#!/usr/bin/env bash'
echo '# A sandbox for running shells/binaries in an isolated environment:'
echo '# - The sandbox user is the calling user, with all capabilities dropped'
echo '# and with no way to gain new privileges (e.g. via `sudo`).'
echo '# - $HOME is bind-mounted to a dir that only contains shell config files and files required by direnv.'
echo '#'
echo '# You can modify the firejail env by editing `lib/nix-bitcoin-firejail.conf` in your dev env dir.'
echo 'exec firejail --profile="$root/lib/nix-bitcoin-firejail.conf" --profile="$root/src/dev/dev-env/nix-bitcoin-firejail.conf" "$@"'
) bin/nix-bitcoin-firejail
echo "1" > lib/dev-env-version
## git
echo '/src' > .gitignore
if [[ ! -e .git ]]; then
git init
git add .
git commit -a -m init
fi

View File

@ -1,16 +0,0 @@
pkgs:
pkgs.mkShell {
shellHook = ''
# A known rev from the master branch to test whether `nix develop`
# is called inside the nix-bitcoin repo
rev=5cafafd02777919c10e559b5686237fdefe920c2
if git cat-file -e $rev &>/dev/null; then
root=$(git rev-parse --show-toplevel)
export PATH=$root/test:$root/helper:$PATH
else
echo 'Error: `nix develop` must be called inside the nix-bitcoin repo.'
exit 1
fi
'';
}

View File

@ -1,25 +0,0 @@
include default.local
include globals.local
include disable-common.inc
include disable-programs.inc
caps.drop all
netfilter
noinput
nonewprivs
noroot
notv
novideo
protocol unix,inet,inet6
seccomp
## Enable features
allow-debuggers
# Enable direnv configs
whitelist ${HOME}/.config/direnv
read-only ${HOME}/.config/direnv
whitelist ${HOME}/.local/share/direnv
read-only ${HOME}/.local/share/direnv

View File

@ -1,20 +0,0 @@
{ pkgs, lib, scenarios, nix-bitcoin }:
with lib;
rec {
# For more examples, see `scenarios` and `exampleScenarios` in ./src/test/tests.nix
template = { config, pkgs, lib, ... }: {
imports = [
(nix-bitcoin + "/modules/presets/secure-node.nix")
scenarios.netnsBase
scenarios.regtestBase
];
test.container.enableWAN = true;
test.container.exposeLocalhost = true;
};
myscenario = { config, pkgs, lib, ... }: {
services.clightning.enable = true;
nix-bitcoin.nodeinfo.enable = true;
};
}

View File

@ -1,300 +0,0 @@
# shellcheck disable=SC2086,SC2154
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Run tests
# See ../test/README.md for a tutorial
# and ../test/run-tests.sh for a complete documentation
# Start a shell in a container
run-tests.sh -s electrs container
# Run a command in a container.
# The container is deleted afterwards.
run-tests.sh -s electrs container --run c journalctl -u electrs
# Run a bash command
run-tests.sh -s bitcoind container --run c bash -c "sleep 1; journalctl -u bitcoind"
run-tests.sh -s '{
imports = [ scenarios.regtestBase ];
services.electrs.enable = true;
}' container --run c journalctl -u electrs
run-tests.sh -s "{
services.electrs.enable = true;
nix-bitcoin.nodeinfo.enable = true;
}" container --run c nodeinfo
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Get generic node infos
# Start container shell
run-tests.sh -s bitcoind container
# Run commands inside the shell:
# The node's services
c systemctl status
# Failed units
c systemctl list-units --failed
# Analyze container boot performance
c systemd-analyze critical-chain
# Listening TCP sockets
c netstat -nltp
# Listening sockets
c netstat -nlp
# The container root filesystem
ls -al /var/lib/nixos-containers/nb-test
# The container root filesystem on NixOS systems with stateVersion < 22.05
ls -al /var/lib/containers/nb-test
# Start a shell in the context of a service process.
# Must be run inside the container (enter with cmd `c`).
enter_service() {
name=$1
pid=$(systemctl show -p MainPID --value "$name")
IFS=- read -r uid gid < <(stat -c "%u-%g" "/proc/$pid")
nsenter --all -t "$pid" --setuid "$uid" --setgid "$gid" bash
}
enter_service clightning
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# bitcoind
run-tests.sh -s bitcoind container
c systemctl status bitcoind
c systemctl cat bitcoind
c journalctl --output=short-precise -u bitcoind
ls -al /var/lib/nixos-containers/nb-test/var/lib/bitcoind
c bitcoin-cli getpeerinfo
c bitcoin-cli getnetworkinfo
c bitcoin-cli getblockchaininfo
run-tests.sh -s '{
imports = [ scenarios.regtestBase ];
services.bitcoind.enable = true;
}' container
address=$(c bitcoin-cli getnewaddress)
echo $address
c bitcoin-cli generatetoaddress 10 $address
# Run bitcoind with network access
run-tests.sh -s "{
test.container.enableWAN = true;
services.bitcoind.enable = true;
}" container --run c journalctl -u bitcoind -f
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# clightning
run-tests.sh -s clightning container
c systemctl status clightning
c journalctl --output=short-precise -u clightning
c lightning-cli getinfo
# Plugins
run-tests.sh -s "{
services.clightning.enable = true;
test.features.clightningPlugins = true;
}" container
c lightning-cli plugin list
# Show plugin config
nix eval --raw .#makeTest --apply '
makeTest: let
config = (makeTest {
config = {
services.clightning.enable = true;
test.features.clightningPlugins = true;
};
}).nodes.machine;
in
config.services.clightning.extraConfig
'
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# clightning-rest
run-tests.sh -s clightning-rest container
c systemctl status clightning-rest
c journalctl -u clightning-rest
c systemctl status clightning-rest-migrate-datadir
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# spark-wallet
run-tests.sh -s "{
services.spark-wallet.enable = true;
test.container.exposeLocalhost = true;
}" container
c systemctl status spark-wallet
c journalctl -u spark-wallet
sparkAuth=$(c cat /secrets/spark-wallet-login | grep -ohP '(?<=login=).*')
curl -v http://$sparkAuth@$ip:9737
# Open in browser
runuser -u "$(logname)" -- xdg-open http://$sparkAuth@$ip:9737
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# electrs
run-tests.sh -s "{
imports = [ scenarios.regtestBase ];
services.electrs.enable = true;
}" container
c systemctl status electrs
c systemctl cat electrs
c journalctl --output=short-precise -u electrs
electrs_rpc() {
echo "$1" | c nc 127.0.0.1 50001 | head -1 | jq
}
electrs_rpc '{"method": "server.version", "id": 0, "params": ["electrum/3.3.8", "1.4"]}'
electrs_rpc '{"method": "blockchain.headers.subscribe", "id": 0}'
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# fulcrum
run-tests.sh -s "{
imports = [ scenarios.regtestBase ];
services.fulcrum.enable = true;
}" container
c systemctl status fulcrum
c systemctl cat fulcrum
c journalctl --output=short-precise -u fulcrum
fulcrum_rpc() {
echo "$1" | c nc 127.0.0.1 50002 | head -1 | jq
}
fulcrum_rpc '{"method": "server.version", "id": 0, "params": ["electrum/3.3.8", "1.4"]}'
fulcrum_rpc '{"method": "blockchain.headers.subscribe", "id": 0}'
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# lnd
run-tests.sh -s lnd container
c systemctl status lnd
c journalctl -u lnd
c lncli getinfo
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# lightning-loop
run-tests.sh -s lightning-loop container
c systemctl status lightning-loop
c journalctl -u lightning-loop
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# btcpayserver
# https://docs.btcpayserver.org/Development/GreenFieldExample/
run-tests.sh -s btcpayserver-regtest container
c systemctl status btcpayserver
c journalctl -u btcpayserver
c systemctl cat btcpayserver
c systemctl status nbxplorer
c journalctl -u nbxplorer
## Access the API
request() {
local type=$1
local method=$2
local body=$3
shift; shift; shift
curl -sSL -H "Content-Type: application/json" -X $type --user "a@a.a:aaaaaa" \
-d "$body" "$@" "$ip:23000/api/v1/$method" | jq
}
post() {
local method=$1
local body=$2
shift; shift
request post "$method" "$body" "$@"
}
get() {
local method=$1
request get "$method"
}
# Create new user
post users '{"email": "a@a.a", "password": "aaaaaa", "isAdministrator": true}'
# Login with:
# user: a@a.a
# password: aaaaaa
runuser -u "$(logname)" -- xdg-open http://$ip:23000
# create store
post stores '{"name": "a", "defaultPaymentMethod": "BTC_LightningNetwork"}'
post stores '{"name": "a", "defaultPaymentMethod": "BTC"}'
store=$(get stores | jq -r .[].id)
echo $store
get stores/$store
get stores/$store/payment-methods
get stores/$store/payment-methods/LightningNetwork
# Connect to internal lightning node (internal API, doesn't work)
# Lightning must be manually setup via the webinterface.
post stores/$store/lightning/BTC/setup "" --data-raw 'LightningNodeType=Internal&ConnectionString=&command=save'
nix run --inputs-from . nixpkgs#lynx -- --dump http://$ip:23000/embed/$store/BTC/ln
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# liquid
run-tests.sh -s liquid container
c systemctl status liquidd
c elements-cli getpeerinfo
c elements-cli getnetworkinfo
c liquidswap-cli --help
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# tor
run-tests.sh container
c cat /var/lib/tor/state
c ls -al /var/lib/tor/onion/
c ls -al /var/lib/tor/onion/bitcoind
c ls -al /var/lib/tor/onion/clightning-rest
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# joinmarket
run-tests.sh -s joinmarket container
c systemctl status joinmarket
c journalctl -u joinmarket
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# joinmarket-ob-watcher
# This starts a container with WAN access, so that jm-ob-watcher
# can connect to the joinmarket IRC servers over Tor
run-tests.sh -s jm-ob-watcher container
c systemctl status joinmarket-ob-watcher
c journalctl -u joinmarket-ob-watcher
# Manually wait for string 'started http server, visit http://127.0.0.1:62601/'
# This can take >10 minutes when the Tor network is under heavy load.
# While connecting, errors like `We failed to connect and handshake with ANY directories...`
# may be shown.
c journalctl -f -u joinmarket-ob-watcher
# Check webinterface
c curl localhost:62601
nix run --inputs-from . nixpkgs#lynx -- --dump $ip:62601
c curl -s localhost:62601 | grep -i "orders found"
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# rtl
# see ./topics/rtl.sh

View File

@ -1,78 +0,0 @@
# Extra scenarios for developing and debugging
{ lib, scenarios }:
with lib;
{
btcpayserver-regtest = {
imports = [ scenarios.regtestBase ];
services.btcpayserver.enable = true;
test.container.exposeLocalhost = true;
# services.btcpayserver.lbtc = false;
# Required for testing interactive plugin installation
test.container.enableWAN = true;
};
# A node with internet access to test joinmarket-ob-watcher
jm-ob-watcher = {
services.joinmarket-ob-watcher.enable = true;
# Don't download blocks
services.bitcoind.extraConfig = ''
connect = 0;
'';
test.container.exposeLocalhost = true;
test.container.enableWAN = true;
};
rtl-dev = { config, pkgs, lib, ... }: {
imports = [
# scenarios.netnsBase
# scenarios.regtestBase
];
services.rtl = {
enable = true;
nodes.clightning = {
enable = true;
extraConfig.Settings.themeColor = "INDIGO";
};
# nodes.lnd.enable = false;
# services.rtl.nodes.reverseOrder = true;
nightTheme = true;
extraCurrency = "CHF";
};
test.container.exposeLocalhost = true;
nix-bitcoin.nodeinfo.enable = true;
# test.container.enableWAN = true;
};
wireguard-lndconnect-online = { config, pkgs, lib, ... }: {
imports = [
../modules/presets/wireguard.nix
scenarios.regtestBase
];
# 51820 (default wg port) + 1
networking.wireguard.interfaces.wg-nb.listenPort = 51821;
test.container.enableWAN = true;
# test.container.exposeLocalhost = true;
services.clightning.extraConfig = "disable-dns";
services.lnd = {
enable = true;
lndconnect = {
enable = true;
onion = true;
};
};
services.clightning-rest = {
enable = true;
lndconnect = {
enable = true;
onion = true;
};
};
nix-bitcoin.nodeinfo.enable = true;
};
}

View File

@ -1,128 +0,0 @@
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Access nix-bitcoin flake packages
function nb() {
nix build --no-link --print-out-paths --print-build-logs "$@"
}
# A package defined by nix-bitcoin
nb .#joinmarket
# Equivalent
nb .#modulesPkgs.joinmarket
# A nix-bitcoin python package
nb .#nbPython3Packages.pyln-client
# A pinned package from nixpkgs(-unstable)
nb .#pinned.electrs
# Equivalent
nb .#modulesPkgs.electrs
## Eval packages
# Check version
nix eval .#joinmarket.version
# Eval derivation. --raw is needed due to a Nix bug (https://github.com/NixOS/nix/issues/5731)
nix eval --raw .#joinmarket; echo
# Check the version of a package in the nixpkgs(-unstable) inputs of the nix-bitcoin flake
nix eval --inputs-from . nixpkgs#electrs.version
nix eval --inputs-from . nixpkgs-unstable#electrs.version
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Inspect test systems
# Build a test system
nix build -o /tmp/system --print-build-logs "$(nix eval --raw .#tests.default --apply '
test: test.nodes.machine.system.build.toplevel.drvPath
')"
readlink /tmp/system
# Inspect system files
cat /tmp/system/activate
cat /tmp/system/etc/system/bitcoind.service
# Evaluate a config value
nix eval .#tests.default --apply '
test: test.nodes.machine.services.bitcoind.rpc.port
'
# Evaluate a config value in a custom test
nix eval .#makeTest --apply '
makeTest: let
config = (makeTest {
config = {
services.electrs.port = 10000;
};
}).nodes.machine;
in
config.services.electrs.port
'
# Evaluate a config value in a scenario defined in a file
nix eval --impure .#getTest --apply '
getTest: let
config = (getTest {
name = "default";
extraScenariosFile = builtins.getEnv("root") + "/scenarios.nix";
}).nodes.machine;
in
config.services.bitcoind.port
'
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Manually run a nix-bitcoin container, without the test framework.
# This allows sharing directories with the container host via option `bindMounts.`
read -rd '' src <<'EOF' || :
let
nix-bitcoin = builtins.getFlake "git+file://${toString ../.}";
in
nix-bitcoin.inputs.extra-container.lib.buildContainers {
system = "x86_64-linux";
inherit (nix-bitcoin.inputs) nixpkgs;
# legacyInstallDirs = true;
config = {
containers.nb-adhoc = {
# bindMounts."/shared" = { hostPath = "/my/hostpath"; isReadOnly = false; };
extra.addressPrefix = "10.200.255";
config = {
imports = [ nix-bitcoin.nixosModules.default ];
services.bitcoind.enable = true;
nix-bitcoin.generateSecrets = true;
nix-bitcoin.nodeinfo.enable = true;
};
};
};
}
EOF
nix run --impure --expr "$src"
# Run command in container
nix shell --impure --expr "$src" -c container --run c nodeinfo
# TODO-EXTERNAL: Use this instead when https://github.com/NixOS/nix/issues/7444 is fixed
# nix run --impure --expr "$src" -- --run c nodeinfo
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Show build logs from a CI test run
#
# If a specific test derivation was already built successfully, the test is not rerun
# and the CI logs don't show the test output.
# To view the test output:
# 1. Get the test store path at the end of the CI logs
# 2.
fetch_build_log() {
local log=$1
nix cat-store --store https://nix-bitcoin.cachix.org "$log/output.xml" |
nix shell --inputs-from . nixpkgs#html-tidy -c tidy -xml -i - > /tmp/build-output.xml
echo
echo "Fetched log to /tmp/build-output.xml"
}
# Set this to your store path
fetch_build_log /nix/store/0cdjhvg84jsp47f3357812zjmj2wmz94-vm-test-run-nix-bitcoin-default
# Show runtime
grep "script finished in" /tmp/build-output.xml
# View XML with node folding
firefox /tmp/build-output.xml

View File

@ -1,64 +0,0 @@
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Test Tor and WireGuard connections on a mobile device
# 1. Run container
run-tests.sh -s wireguard-lndconnect-online container
# 2. Test connecting via Tor
# Print QR codes for lnd, clightning-rest connections via Tor
c lndconnect
c lndconnect-clightning
# Add these to Zeus >= 0.7.1.
# To explicitly check if the connection is successful, press the node logo in the top
# left corner, and then "Node Info".
# Debug
c lndconnect --url
c lndconnect-clightning --url
# 3. Test connecting via WireGuard
# 3.1 Forward WireGuard port from the container host to the container
iptables -t nat -A PREROUTING -p udp --dport 51821 -j DNAT --to-destination 10.225.255.2
# 3.2. Optional: When your container host has an external firewall,
# forward the WireGuard port to the container host:
# - Port: 51821
# - Protocol: UDP
# - Destination: IPv4 of the container host
# 3.2 Print QR code and setup wireguard on the mobile device
c nix-bitcoin-wg-connect
c nix-bitcoin-wg-connect --text
# Print QR codes for lnd, clightning-rest connections via WireGuard
c lndconnect-wg
c lndconnect-clightning-wg
# Add these to Zeus >= 0.7.1.
# To explicitly check if the connection is successful, press the node logo in the top
# left corner, and then "Node Info".
# Debug
c lndconnect-wg --url
c lndconnect-clightning-wg --url
# 3.3.remove external firewall port forward, remove local port forward:
iptables -t nat -D PREROUTING -p udp --dport 51821 -j DNAT --to-destination 10.225.255.2
# Now exit the container shell
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Debug lndconnect
run-tests.sh -s wireguard-lndconnect-online container
c nodeinfo
c lndconnect --url
c lndconnect-wg --url
c lndconnect-clightning --url
c lndconnect-clightning-wg --url
c lndconnect
c lndconnect-wg
c lndconnect-clightning
c lndconnect-clightning-wg

View File

@ -1,47 +0,0 @@
# shellcheck disable=SC2154
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Docs
# https://github.com/Ride-The-Lightning/RTL
# config options: https://github.com/Ride-The-Lightning/RTL/blob/master/.github/docs/Application_configurations.md
# https://github.com/Ride-The-Lightning/c-lightning-REST
# local src: ~/s/RTL/
# Browse API docs (in container shell)
runuser -u "$(logname)" -- xdg-open "http://$ip:4001/api-docs/"
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Debug the service
run-tests.sh -s rtl-dev container
c systemctl status rtl
c journalctl -u rtl
c cat /var/lib/rtl/RTL-Config.json
c systemctl status clightning-rest
# Open webinterface. Password: a
runuser -u "$(logname)" -- xdg-open "http://$ip:3000"
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# Build RTL manually
# [[~/s/RTL/dockerfiles/Dockerfile][dockerfile]]
# [[~/s/RTL/package.json][package.json]]
rtl_src=~/s/RTL
git clone https://github.com/Ride-The-Lightning/RTL "$rtl_src"
nix build -o /tmp/nix-bitcoin-dev/nodejs --inputs-from . nixpkgs#nodejs-16_x
# Start a shell in a sandbox
env --chdir "$rtl_src" nix-bitcoin-firejail --whitelist="$rtl_src" --whitelist=/tmp/nix-bitcoin-dev/nodejs
PATH=/tmp/nix-bitcoin-dev/nodejs/bin:"$PATH"
# Install
npm ci --omit=dev --omit=optional --no-update-notifier --ignore-scripts
# If the above fails, try: (details: https://github.com/Ride-The-Lightning/RTL/issues/1182)
npm ci --omit=dev --omit=optional --no-update-notifier --ignore-scripts --legacy-peer-deps
# Run
node rtl --help
git clean -xdf # Cleanup repo

View File

@ -135,7 +135,7 @@ You can use the same approach to allow connections to other services.
## Example: bitcoind ## Example: bitcoind
```shell ```shell
# 1. Stop bitcoind on your node # 1. Stop bitcoind on your nodes
ssh root@nix-bitcoin-node 'systemctl stop bitcoind' ssh root@nix-bitcoin-node 'systemctl stop bitcoind'
# Also stop bitcoind on the node that you'll be copying data from # Also stop bitcoind on the node that you'll be copying data from

View File

@ -46,7 +46,7 @@ This is borrowed from the [NixOS manual](https://nixos.org/nixos/manual/index.ht
ls /sys/firmware/efi ls /sys/firmware/efi
``` ```
If the file exists you should continue the installation for UEFI otherwise for Legacy Boot. If the file exists exists, you should continue the installation for UEFI otherwise for Legacy Boot.
4. Option 1: Partition and format for UEFI 4. Option 1: Partition and format for UEFI

View File

@ -142,154 +142,60 @@ You can find the `<onion-address>` with command `nodeinfo`.
The default password location is `$secretsDir/rtl-password`. The default password location is `$secretsDir/rtl-password`.
See: [Secrets dir](./configuration.md#secrets-dir) See: [Secrets dir](./configuration.md#secrets-dir)
# Use Zeus (mobile lightning wallet) via Tor # Use LND or clightning with Zeus (mobile wallet) via Tor
1. Install [Zeus](https://zeusln.app) (version ≥ 0.7.1) 1. Install [Zeus](https://zeusln.app)
2. Edit your `configuration.nix` 2. Edit your `configuration.nix`
##### For lnd ##### For lnd
Add the following config: Add the following config:
```nix ```
services.lnd.lndconnect = { services.lnd.lndconnectOnion.enable = true;
enable = true;
onion = true;
};
``` ```
##### For clightning ##### For clightning
Add the following config: Add the following config:
```nix ```
services.clightning-rest = { services.clightning-rest = {
enable = true; enable = true;
lndconnect = { lndconnectOnion.enable = true;
enable = true;
onion = true;
};
}; };
``` ```
3. Deploy your configuration 3. Deploy your configuration
4. Run the following command on your node (as user `operator`) to create a QR code 3. Run the following command on your node (as user `operator`) to create a QR code
with address and authentication information: with address and authentication information:
##### For lnd ##### For lnd
``` ```
lndconnect lndconnect-onion
``` ```
##### For clightning ##### For clightning
``` ```
lndconnect-clightning lndconnect-onion-clightning
``` ```
5. Configure Zeus 4. Configure Zeus
- Add a new node and scan the QR code - Add a new node
- Select `Scan lndconnect config` (at the bottom) and scan the QR code
- For clightning: Set `Node interface` to `c-lightning-REST`
- Click `Save node config` - Click `Save node config`
- Start sending and stacking sats privately - Start sending and stacking sats privately
### Additional lndconnect features ### Additional lndconnect features
- Create a plain text URL: Create plain text URLs or QR code images:
```bash ```
lndconnect --url lndconnect-onion --url
``` lndconnect-onion --image
- Set a custom host. By default, `lndconnect` detects the system's external IP and uses it as the host.
```bash
lndconnect --host myhost
```
# Use Zeus (mobile lightning wallet) via WireGuard
Connecting Zeus directly to your node is much faster than using Tor, but a bit more complex to setup.
There are two ways to establish a secure, direct connection:
- Connecting via TLS. This requires installing your lightning app's
TLS Certificate on your mobile device.
- Connecting via WireGuard. This approach is simpler and more versatile, and is
described in this guide.
1. Install [Zeus](https://zeusln.app) (version ≥ 0.7.1) and
[WireGuard](https://www.wireguard.com/install/) on your mobile device.
2. Add the following to your `configuration.nix`:
```nix
imports = [
# Use this line when using the default deployment method
<nix-bitcoin/modules/presets/wireguard.nix>
# Use this line when using Flakes
(nix-bitcoin + /modules/presets/wireguard.nix)
]
# For lnd
services.lnd.lndconnect.enable = true;
# For clightning
services.clightning-rest = {
enable = true;
lndconnect.enable = true;
};
```
3. Deploy your configuration.
4. If your node is behind an external firewall or NAT, add the following port forwarding
rule to the external device:
- Port: 51820 (the default value of option `networking.wireguard.interfaces.wg-nb.listenPort`)
- Protocol: UDP
- Destination: IP of your node
5. Setup WireGuard on your mobile device.
Run the following command on your node (as user `operator`) to create a QR code
for WireGuard:
```bash
nix-bitcoin-wg-connect
# For debugging: Show the WireGuard config as text
nix-bitcoin-wg-connect --text
```
The above commands automatically detect your node's external IP.\
To set a custom IP or hostname, run the following:
```
nix-bitcoin-wg-connect 93.184.216.34
nix-bitcoin-wg-connect mynode.org
```
Configure WireGuard:
- Press the `+` button in the bottom right corner
- Scan the QR code
- Add the tunnel
6. Setup Zeus
Run the following command on your node (as user `operator`) to create a QR code for Zeus:
##### For lnd
```
lndconnect-wg
```
##### For clightning
```
lndconnect-clightning-wg
```
Configure Zeus:
- Add a new node and scan the QR code
- Click `Save node config`
- On the certificate warning screen, click `I understand, save node config`.\
Certificates are not needed when connecting via WireGuard.
- Start sending and stacking sats privately
### Additional lndconnect features
Create a plain text URL:
```bash
lndconnect-wg --url
`````` ``````
Create a QR code for a custom hostname:
```
lndconnect-onion --host=mynode.org
```
# Connect to spark-wallet # Connect to spark-wallet
### Requirements ### Requirements
@ -621,27 +527,3 @@ services.clightning = {
``` ```
Please have a look at the module for a plugin (e.g. [prometheus.nix](../modules/clightning-plugins/prometheus.nix)) to learn its configuration options. Please have a look at the module for a plugin (e.g. [prometheus.nix](../modules/clightning-plugins/prometheus.nix)) to learn its configuration options.
### Trustedcoin hints
The [trustedcoin](https://github.com/nbd-wtf/trustedcoin) plugin use a Tor
proxy for all of its external connections by default. That's why you can
sometimes face issues with your connections to esploras getting blocked.
An example of clightning log error output in a case your connections are getting blocked:
```
lightningd[5138]: plugin-trustedcoin estimatefees error: https://blockstream.info/api error: 403 Forbidden
```
```
lightningd[4933]: plugin-trustedcoin getblock error: got something that isn't a block hash: <html><head>
lightningd[4933]: <meta http-equiv="content-type" content="text/html;
```
If you face these issues and you still need to use trustedcoin, use can disable
clightning's tor hardening by setting this option in your `configuration.nix`
file:
```
services.clightning.tor.enforce = false;
```

View File

@ -51,11 +51,41 @@ the node:
``` ```
### Tests ### Tests
The [nix-bitcoin test suite](../test/README.md) is also useful for exploring features. The internal test suite is also useful for exploring features.\
The following `run-tests.sh` commands leave no traces (outside of `/nix/store`) on
the host system.
```bash
git clone https://github.com/fort-nix/nix-bitcoin
cd nix-bitcoin/test
# Run a node in a VM. No tests are executed.
./run-tests.sh vm
systemctl status bitcoind
# Run a Python test shell inside a VM node
./run-tests.sh debug
print(succeed("systemctl status bitcoind"))
run_test("bitcoind")
# Run a node in a container. Requires systemd and root privileges.
./run-tests.sh container
c systemctl status bitcoind
# Explore a single feature
./run-tests.sh --scenario electrs container
# Run a command in a container
./run-tests.sh --scenario '{
services.clightning.enable = true;
nix-bitcoin.nodeinfo.enable = true;
}' container --run c nodeinfo
```
See [`run-tests.sh`](../test/run-tests.sh) for a complete documentation.
### Real-world example ### Real-world example
Check the [server repo](https://github.com/fort-nix/nixbitcoin.org) for https://nixbitcoin.org Check the [server repo](https://github.com/fort-nix/nixbitcoin.org) for https://nixbitcoin.org
to see the configuration of a Flakes-based nix-bitcoin node that's used in production. to see the configuration of a nix-bitcoin node that's used in production.
The commands in `shell.nix` allow you to locally run the node in a VM or container. The commands in `shell.nix` allow you to locally run the node in a VM or container.

View File

@ -56,18 +56,13 @@
# #
# == REST server # == REST server
# Set this to create a clightning REST onion service. # Set this to create a clightning REST onion service.
# This also adds binary `lndconnect-clightning` to the system environment. # This also adds binary `lndconnect-onion-clightning` to the system environment.
# This binary creates QR codes or URLs for connecting applications to clightning # This binary creates QR codes or URLs for connecting applications to clightning
# via the REST onion service. # via the REST onion service (see ../docs/services.md).
# You can also connect via WireGuard instead of Tor.
# See ../docs/services.md for details.
# #
# services.clightning-rest = { # services.clightning-rest = {
# enable = true; # enable = true;
# lndconnect = { # lndconnectOnion.enable = true;
# enable = true;
# onion = true;
# };
# }; # };
### LND ### LND
@ -83,17 +78,11 @@
# The onion service is automatically announced to peers. # The onion service is automatically announced to peers.
# nix-bitcoin.onionServices.lnd.public = true; # nix-bitcoin.onionServices.lnd.public = true;
# #
# Set this to create a lnd REST onion service. # Set this to create an lnd REST onion service.
# This also adds binary `lndconnect` to the system environment. # This also adds binary `lndconnect-onion` to the system environment.
# This binary generates QR codes or URLs for connecting applications to lnd via the # This binary generates QR codes or URLs for connecting applications to lnd via the
# REST onion service. # REST onion service (see ../docs/services.md).
# You can also connect via WireGuard instead of Tor. # services.lnd.lndconnectOnion.enable = true;
# See ../docs/services.md for details.
#
# services.lnd.lndconnect = {
# enable = true;
# onion = true;
# };
# #
## WARNING ## WARNING
# If you use lnd, you should manually backup your wallet mnemonic # If you use lnd, you should manually backup your wallet mnemonic
@ -298,10 +287,10 @@
# this value at the release version of the first install of this system. # this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option # Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "22.11"; # Did you read the comment? system.stateVersion = "22.05"; # Did you read the comment?
# The nix-bitcoin release version that your config is compatible with. # The nix-bitcoin release version that your config is compatible with.
# 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 instructions for migrating your config to the new release. # an error and provide instructions for migrating your config to the new release.
nix-bitcoin.configVersion = "0.0.85"; nix-bitcoin.configVersion = "0.0.70";
} }

View File

@ -1,11 +1,17 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
if [[ ! -v NIX_BITCOIN_EXAMPLES_DIR ]]; then
echo "Running script in nix shell env..."
cd "${BASH_SOURCE[0]%/*}"
exec nix-shell --run "./${BASH_SOURCE[0]##*/} $*"
else
cd "$NIX_BITCOIN_EXAMPLES_DIR"
fi
tmpDir=$(mktemp -d /tmp/nix-bitcoin-minimal-container.XXX) tmpDir=$(mktemp -d /tmp/nix-bitcoin-minimal-container.XXX)
trap 'rm -rf $tmpDir' EXIT trap 'rm -rf $tmpDir' EXIT
cd "${BASH_SOURCE[0]%/*}"
# Modify importable-configuration.nix to use the local <nix-bitcoin> # Modify importable-configuration.nix to use the local <nix-bitcoin>
# source instead of fetchTarball # source instead of fetchTarball
<importable-configuration.nix sed ' <importable-configuration.nix sed '
@ -25,4 +31,4 @@ cat > "$tmpDir/configuration.nix" <<EOF
} }
EOF EOF
./deploy-container.sh "$tmpDir/configuration.nix" "$@" "${BASH_SOURCE[0]%/*}/deploy-container.sh" "$tmpDir/configuration.nix" "$@"

View File

@ -8,21 +8,23 @@ 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 [[ $EUID != 0 ]]; then if [[ ! -v NIX_BITCOIN_EXAMPLES_DIR ]]; then
# NixOS containers require root permissions echo "Running script in nix shell env..."
exec sudo "${BASH_SOURCE[0]}" "$@" cd "${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) != 1 ]]; then if [[ $(sysctl -n net.ipv4.ip_forward || sudo sysctl -n net.ipv4.ip_forward) != 1 ]]; then
echo "Error: IP forwarding (net.ipv4.ip_forward) is not enabled." echo "Error: IP forwarding (net.ipv4.ip_forward) is not enabled."
echo "Needed for container WAN access." echo "Needed for container WAN access."
exit 1 exit 1
fi fi
if [[ ! -v DEPLOY_CONTAINER_NIX_SHELL ]]; then if [[ $EUID != 0 ]]; then
echo "Running script in nix shell env..." # NixOS containers require root permissions
cd "${BASH_SOURCE[0]%/*}" exec sudo "PATH=$PATH" "NIX_PATH=$NIX_PATH" "NIX_BITCOIN_EXAMPLES_DIR=$NIX_BITCOIN_EXAMPLES_DIR" "${BASH_SOURCE[0]}" "$@"
DEPLOY_CONTAINER_NIX_SHELL=1 exec nix-shell --run "./${BASH_SOURCE[0]##*/} $*"
fi fi
interactive= interactive=

View File

@ -14,7 +14,7 @@
# Import the secure-node preset, an opinionated config to enhance security # Import the secure-node preset, an opinionated config to enhance security
# and privacy. # and privacy.
# #
# (nix-bitcoin + "/modules/presets/secure-node.nix") # "${nix-bitcoin}/modules/presets/secure-node.nix"
{ {
# Automatically generate all secrets required by services. # Automatically generate all secrets required by services.

View File

@ -13,13 +13,13 @@ rec {
QEMU_OPTS="-smp $(nproc) -m 1500" ${vm}/bin/run-*-vm QEMU_OPTS="-smp $(nproc) -m 1500" ${vm}/bin/run-*-vm
''; '';
vm = (import (nixpkgs + "/nixos") { vm = (import "${nixpkgs}/nixos" {
inherit system; inherit system;
configuration = { config, lib, modulesPath, ... }: { configuration = { config, lib, modulesPath, ... }: {
imports = [ imports = [
nix-bitcoin.nixosModules.default nix-bitcoin.nixosModules.default
(nix-bitcoin + "/modules/presets/secure-node.nix") "${nix-bitcoin}/modules/presets/secure-node.nix"
(modulesPath + "/virtualisation/qemu-vm.nix") "${modulesPath}/virtualisation/qemu-vm.nix"
]; ];
virtualisation.graphics = false; virtualisation.graphics = false;
@ -29,9 +29,6 @@ rec {
# For faster startup in offline VMs # For faster startup in offline VMs
services.clightning.extraConfig = "disable-dns"; services.clightning.extraConfig = "disable-dns";
# Avoid lengthy build of the nixos manual
documentation.nixos.enable = false;
nixpkgs.pkgs = pkgs; nixpkgs.pkgs = pkgs;
services.getty.autologinUser = "root"; services.getty.autologinUser = "root";
nix.nixPath = [ "nixpkgs=${nixpkgs}" ]; nix.nixPath = [ "nixpkgs=${nixpkgs}" ];
@ -43,7 +40,6 @@ rec {
- nodeinfo - nodeinfo
- systemctl status bitcoind - systemctl status bitcoind
- systemctl status clightning - systemctl status clightning
- lightning-cli getinfo
''; '';
# Power off VM when the user exits the shell # Power off VM when the user exits the shell

View File

@ -3,7 +3,7 @@
# Disable the hardened preset to improve VM performance # Disable the hardened preset to improve VM performance
disabledModules = [ <nix-bitcoin/modules/presets/hardened.nix> ]; disabledModules = [ <nix-bitcoin/modules/presets/hardened.nix> ];
imports = [ (modulesPath + "/virtualisation/qemu-vm.nix") ]; imports = [ "${modulesPath}/virtualisation/qemu-vm.nix" ];
config = { config = {
virtualisation.graphics = false; virtualisation.graphics = false;

View File

@ -1,38 +1,12 @@
{ {
"nodes": { "nodes": {
"extra-container": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1679648217,
"narHash": "sha256-aq2J5Hj5IE8X8X/7v3n0wcv8n+FLzzENbcCF9xqhxAc=",
"owner": "erikarvstedt",
"repo": "extra-container",
"rev": "40c73f5e3292e73d6ce91625d9751be84fde17cb",
"type": "github"
},
"original": {
"owner": "erikarvstedt",
"repo": "extra-container",
"type": "github"
}
},
"flake-utils": { "flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": { "locked": {
"lastModified": 1681202837, "lastModified": 1659877975,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401", "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -43,27 +17,27 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1683207485, "lastModified": 1663760840,
"narHash": "sha256-gs+PHt/y/XQB7S8+YyBLAM8LjgYpPZUVFQBwpFSmJro=", "narHash": "sha256-ym5Iycs5H4cOaLfE2/vC0tsLp8XuBJQIHGV8/uXSy8M=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "cc45a3f8c98e1c33ca996e3504adefbf660a72d1", "rev": "9bdbbaa634aa666eb6a27096bdcb991c59181244",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-22.11", "ref": "nixos-22.05",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"nixpkgs-unstable": { "nixpkgsUnstable": {
"locked": { "locked": {
"lastModified": 1683353485, "lastModified": 1663757063,
"narHash": "sha256-Skp5El3egmoXPiINWjnoW0ktVfB7PR/xc4F4bhD+BJY=", "narHash": "sha256-H+BPgoXuVcdi3g5BH4cact4osjfjntaTQTdA/HNiCYE=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "caf436a52b25164b71e0d48b671127ac2e2a5b75", "rev": "a0e390471362e27349abc1090197e09fe8c59d16",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -75,25 +49,9 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"extra-container": "extra-container",
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"nixpkgs-unstable": "nixpkgs-unstable" "nixpkgsUnstable": "nixpkgsUnstable"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
} }
} }
}, },

View File

@ -5,42 +5,27 @@
''; '';
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.11"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.05";
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; nixpkgsUnstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils"; flake-utils.url = "github:numtide/flake-utils";
extra-container = {
url = "github:erikarvstedt/extra-container";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
};
}; };
outputs = { self, nixpkgs, nixpkgs-unstable, flake-utils, ... }: outputs = { self, nixpkgs, nixpkgsUnstable, flake-utils }:
let let
supportedSystems = [ supportedSystems = [
"x86_64-linux" "x86_64-linux"
"i686-linux"
"aarch64-linux" "aarch64-linux"
# On these 32-bit platforms, Python pkg `pymemcache` 4.0.0 (required by "armv7l-linux"
# `joinmarket`) is broken:
# "i686-linux"
# "armv7l-linux"
]; ];
test = import ./test/tests.nix nixpkgs.lib;
in { in {
lib = { lib = {
mkNbPkgs = { mkNbPkgs = {
system system
, pkgs ? nixpkgs.legacyPackages.${system} , pkgs ? nixpkgs.legacyPackages.${system}
, pkgsUnstable ? nixpkgs-unstable.legacyPackages.${system} , pkgsUnstable ? nixpkgsUnstable.legacyPackages.${system}
}: }:
import ./pkgs { inherit pkgs pkgsUnstable; }; import ./pkgs { inherit pkgs pkgsUnstable; };
test = {
inherit (test) scenarios;
};
inherit supportedSystems;
}; };
overlays.default = final: prev: let overlays.default = final: prev: let
@ -106,12 +91,7 @@
# Allow accessing the whole nested `nbPkgs` attrset (including `modulesPkgs`) # Allow accessing the whole nested `nbPkgs` attrset (including `modulesPkgs`)
# via this flake. # via this flake.
# `packages` is not allowed to contain nested pkgs attrsets. # `packages` is not allowed to contain nested pkgs attrsets.
legacyPackages = legacyPackages = nbPkgs;
nbPkgs //
(test.pkgs self pkgs) //
{
extra-container = self.inputs.extra-container.packages.${system}.default;
};
apps = rec { apps = rec {
default = vm; default = vm;
@ -122,8 +102,6 @@
program = toString packages.runVM; program = toString packages.runVM;
}; };
}; };
devShells.default = import ./dev/dev-env/dev-shell.nix pkgs;
} }
)); ));
} }

Binary file not shown.

View File

@ -1,12 +0,0 @@
# Start an interactive bash session in the current bash environment.
# This is helpful for debugging bash scripts like pkg update scripts,
# by adding `source <path-to>/start-bash-session.sh` at the location to
# be inspected.
# BASH_ENVIRONMENT contains definitions of read-only variables like 'BASHOPTS' that
# cause warnings on evaluation. Suppress these warnings while sourcing.
#
# shellcheck disable=SC2016
BASH_ENVIRONMENT=<(declare -p; declare -pf) \
bash --rcfile <(echo 'source $BASH_ENVIRONMENT 2>/dev/null')

View File

@ -12,19 +12,6 @@ set -euo pipefail
# pinned to stable. # pinned to stable.
# All other pkgs are pinned to unstable. # All other pkgs are pinned to unstable.
forceRun=
nixosVersion=
for arg in "$@"; do
case $arg in
-f)
forceRun=1
;;
*)
nixosVersion=$arg
;;
esac
done
# cd to script dir # cd to script dir
cd "${BASH_SOURCE[0]%/*}" cd "${BASH_SOURCE[0]%/*}"
@ -34,7 +21,7 @@ if [[ $(nix flake 2>&1) != *"requires a sub-command"* ]]; then
exit 1 exit 1
fi fi
if [[ $forceRun ]] && ! git diff --quiet ../flake.{nix,lock}; then if [[ ${1:-} != -f ]] && ! git diff --quiet ../flake.{nix,lock}; then
echo "error: flake.nix/flake.lock have changes. Run with option -f to ignore." echo "error: flake.nix/flake.lock have changes. Run with option -f to ignore."
exit 1 exit 1
fi fi
@ -49,9 +36,6 @@ versions=$(nix eval --json -f update-flake.nix versions)
# versions=$(echo "$versions" | sed 's|1|0|g') # versions=$(echo "$versions" | sed 's|1|0|g')
echo "Updating main flake" echo "Updating main flake"
if [[ $nixosVersion ]]; then
sed -Ei "s|(nixpkgs.url = .*nixos-)[^\"]+|\1$nixosVersion|" ../flake.nix
fi
nix flake update .. nix flake update ..
echo echo

View File

@ -6,7 +6,7 @@ let
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Enable backups of node data. Enable backups of node data.
This uses the NixOS duplicity service. This uses the NixOS duplicity service.
To further configure the backup, you can set NixOS options `services.duplicity.*`. To further configure the backup, you can set NixOS options `services.duplicity.*`.
@ -16,34 +16,34 @@ let
with-bulk-data = mkOption { with-bulk-data = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Whether to also backup Bitcoin blockchain and other bulk data. Whether to also backup Bitcoin blockchain and other bulk data.
''; '';
}; };
destination = mkOption { destination = mkOption {
type = types.str; type = types.str;
default = "file:///var/lib/localBackups"; default = "file:///var/lib/localBackups";
description = mdDoc '' description = ''
Where to back up to. Where to back up to.
''; '';
}; };
frequency = mkOption { frequency = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
description = mdDoc '' description = ''
Run backup with the given frequency. If null, do not run automatically. Run backup with the given frequency. If null, do not run automatically.
''; '';
}; };
postgresqlDatabases = mkOption { postgresqlDatabases = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = []; default = [];
description = mdDoc "List of database names to backup."; description = "List of database names to backup.";
}; };
extraFiles = mkOption { extraFiles = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = []; default = [];
example = [ "/var/lib/nginx" ]; example = [ "/var/lib/nginx" ];
description = mdDoc "Additional files to be appended to filelist."; description = "Additional files to be appended to filelist.";
}; };
}; };

View File

@ -8,19 +8,19 @@ let
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = mdDoc "Address to listen for peer connections."; description = "Address to listen for peer connections.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 8333; default = 8333;
description = mdDoc "Port to listen for peer connections."; description = "Port to listen for peer connections.";
}; };
onionPort = mkOption { onionPort = mkOption {
type = types.nullOr types.port; type = types.nullOr types.port;
# When the bitcoind onion service is enabled, add an onion-tagged socket # When the bitcoind onion service is enabled, add an onion-tagged socket
# to distinguish local connections from Tor connections # to distinguish local connections from Tor connections
default = if (config.nix-bitcoin.onionServices.bitcoind.enable or false) then 8334 else null; default = if (config.nix-bitcoin.onionServices.bitcoind.enable or false) then 8334 else null;
description = mdDoc '' description = ''
Port to listen for Tor peer connections. Port to listen for Tor peer connections.
If set, inbound connections to this port are tagged as onion peers. If set, inbound connections to this port are tagged as onion peers.
''; '';
@ -28,15 +28,15 @@ let
listen = mkOption { listen = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Listen for peer connections at `address:port` Listen for peer connections at `address:port`
and `address:onionPort` (if {option}`onionPort` is set). and `address:onionPort` (if `onionPort` is set).
''; '';
}; };
listenWhitelisted = mkOption { listenWhitelisted = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Listen for peer connections at `address:whitelistedPort`. Listen for peer connections at `address:whitelistedPort`.
Peers connected through this socket are automatically whitelisted. Peers connected through this socket are automatically whitelisted.
''; '';
@ -44,12 +44,12 @@ let
whitelistedPort = mkOption { whitelistedPort = mkOption {
type = types.port; type = types.port;
default = 8335; default = 8335;
description = mdDoc "See `listenWhitelisted`."; description = "See `listenWhitelisted`.";
}; };
getPublicAddressCmd = mkOption { getPublicAddressCmd = mkOption {
type = types.str; type = types.str;
default = ""; default = "";
description = mdDoc '' description = ''
Bash expression which outputs the public service address to announce to peers. Bash expression which outputs the public service address to announce to peers.
If left empty, no address is announced. If left empty, no address is announced.
''; '';
@ -58,7 +58,7 @@ let
type = types.package; type = types.package;
default = config.nix-bitcoin.pkgs.bitcoind; default = config.nix-bitcoin.pkgs.bitcoind;
defaultText = "config.nix-bitcoin.pkgs.bitcoind"; defaultText = "config.nix-bitcoin.pkgs.bitcoind";
description = mdDoc "The package providing bitcoin binaries."; description = "The package providing bitcoin binaries.";
}; };
extraConfig = mkOption { extraConfig = mkOption {
type = types.lines; type = types.lines;
@ -67,41 +67,41 @@ let
par=16 par=16
logips=1 logips=1
''; '';
description = mdDoc "Extra lines appended to {file}`bitcoin.conf`."; description = "Extra lines appended to <filename>bitcoin.conf</filename>.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/bitcoind"; default = "/var/lib/bitcoind";
description = mdDoc "The data directory for bitcoind."; description = "The data directory for bitcoind.";
}; };
rpc = { rpc = {
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = mdDoc '' description = ''
Address to listen for JSON-RPC connections. Address to listen for JSON-RPC connections.
''; '';
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 8332; default = 8332;
description = mdDoc "Port to listen for JSON-RPC connections."; description = "Port to listen for JSON-RPC connections.";
}; };
threads = mkOption { threads = mkOption {
type = types.nullOr types.ints.u16; type = types.nullOr types.ints.u16;
default = null; default = null;
description = mdDoc "The number of threads to service RPC calls."; description = "The number of threads to service RPC calls.";
}; };
allowip = mkOption { allowip = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = [ "127.0.0.1" ]; default = [ "127.0.0.1" ];
description = mdDoc '' description = ''
Allow JSON-RPC connections from specified sources. Allow JSON-RPC connections from specified sources.
''; '';
}; };
users = mkOption { users = mkOption {
default = {}; default = {};
description = mdDoc '' description = ''
Allowed users for JSON-RPC connections. Allowed users for JSON-RPC connections.
''; '';
example = { example = {
@ -116,16 +116,16 @@ let
type = types.str; type = types.str;
default = name; default = name;
example = "alice"; example = "alice";
description = mdDoc '' description = ''
Username for JSON-RPC connections. Username for JSON-RPC connections.
''; '';
}; };
passwordHMAC = mkOption { passwordHMAC = mkOption {
type = types.str; type = types.str;
example = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae"; example = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae";
description = mdDoc '' description = ''
Password HMAC-SHA-256 for JSON-RPC connections. Must be a string of the Password HMAC-SHA-256 for JSON-RPC connections. Must be a string of the
format `<SALT-HEX>$<HMAC-HEX>`. format `salt-hex$hmac-hex`.
''; '';
}; };
passwordHMACFromFile = mkOption { passwordHMACFromFile = mkOption {
@ -136,7 +136,7 @@ let
rpcwhitelist = mkOption { rpcwhitelist = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = []; default = [];
description = mdDoc '' description = ''
List of allowed rpc calls for each user. List of allowed rpc calls for each user.
If empty list, rpcwhitelist is disabled for that user. If empty list, rpcwhitelist is disabled for that user.
''; '';
@ -148,7 +148,7 @@ let
regtest = mkOption { regtest = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc "Enable regtest mode."; description = "Enable regtest mode.";
}; };
network = mkOption { network = mkOption {
readOnly = true; readOnly = true;
@ -161,12 +161,12 @@ let
proxy = mkOption { proxy = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null; default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null;
description = mdDoc "Connect through SOCKS5 proxy"; description = "Connect through SOCKS5 proxy";
}; };
i2p = mkOption { i2p = mkOption {
type = types.enum [ false true "only-outgoing" ]; type = types.enum [ false true "only-outgoing" ];
default = false; default = false;
description = mdDoc '' description = ''
Enable peer connections via i2p. Enable peer connections via i2p.
With `only-outgoing`, incoming i2p connections are disabled. With `only-outgoing`, incoming i2p connections are disabled.
''; '';
@ -174,7 +174,7 @@ let
dataDirReadableByGroup = mkOption { dataDirReadableByGroup = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
If enabled, data dir content is readable by the bitcoind service group. If enabled, data dir content is readable by the bitcoind service group.
Warning: This disables bitcoind's wallet support. Warning: This disables bitcoind's wallet support.
''; '';
@ -182,7 +182,7 @@ let
sysperms = mkOption { sysperms = mkOption {
type = types.nullOr types.bool; type = types.nullOr types.bool;
default = null; default = null;
description = mdDoc '' description = ''
Create new files with system default permissions, instead of umask 077 Create new files with system default permissions, instead of umask 077
(only effective with disabled wallet functionality) (only effective with disabled wallet functionality)
''; '';
@ -190,7 +190,7 @@ let
disablewallet = mkOption { disablewallet = mkOption {
type = types.nullOr types.bool; type = types.nullOr types.bool;
default = null; default = null;
description = mdDoc '' description = ''
Do not load the wallet and disable wallet RPC calls Do not load the wallet and disable wallet RPC calls
''; '';
}; };
@ -198,13 +198,13 @@ let
type = types.nullOr (types.ints.between 4 16384); type = types.nullOr (types.ints.between 4 16384);
default = null; default = null;
example = 4000; example = 4000;
description = mdDoc "Override the default database cache size in MiB."; description = "Override the default database cache size in MiB.";
}; };
prune = mkOption { prune = mkOption {
type = types.ints.unsigned; type = types.ints.unsigned;
default = 0; default = 0;
example = 10000; example = 10000;
description = mdDoc '' description = ''
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. Value 0 disables pruning.
''; '';
@ -212,25 +212,25 @@ let
txindex = mkOption { txindex = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc "Enable the transaction index."; description = "Enable the transaction index.";
}; };
zmqpubrawblock = mkOption { zmqpubrawblock = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
example = "tcp://127.0.0.1:28332"; example = "tcp://127.0.0.1:28332";
description = mdDoc "ZMQ address for zmqpubrawblock notifications"; description = "ZMQ address for zmqpubrawblock notifications";
}; };
zmqpubrawtx = mkOption { zmqpubrawtx = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
example = "tcp://127.0.0.1:28333"; example = "tcp://127.0.0.1:28333";
description = mdDoc "ZMQ address for zmqpubrawtx notifications"; description = "ZMQ address for zmqpubrawtx notifications";
}; };
assumevalid = mkOption { assumevalid = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
example = "00000000000000000000e5abc3a74fe27dc0ead9c70ea1deb456f11c15fd7bc6"; example = "00000000000000000000e5abc3a74fe27dc0ead9c70ea1deb456f11c15fd7bc6";
description = mdDoc '' description = ''
If this block is in the chain assume that it and its ancestors are If this block is in the chain assume that it and its ancestors are
valid and potentially skip their script verification. valid and potentially skip their script verification.
''; '';
@ -239,37 +239,37 @@ let
type = types.listOf types.str; type = types.listOf types.str;
default = []; default = [];
example = [ "ecoc5q34tmbq54wl.onion" ]; example = [ "ecoc5q34tmbq54wl.onion" ];
description = mdDoc "Add nodes to connect to and attempt to keep the connections open"; description = "Add nodes to connect to and attempt to keep the connections open";
}; };
discover = mkOption { discover = mkOption {
type = types.nullOr types.bool; type = types.nullOr types.bool;
default = null; default = null;
description = mdDoc "Discover own IP addresses"; description = "Discover own IP addresses";
}; };
addresstype = mkOption { addresstype = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
example = "bech32"; example = "bech32";
description = mdDoc "The type of addresses to use"; description = "The type of addresses to use";
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "bitcoin"; default = "bitcoin";
description = mdDoc "The user as which to run bitcoind."; description = "The user as which to run bitcoind.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = mdDoc "The group as which to run bitcoind."; description = "The group as which to run bitcoind.";
}; };
cli = mkOption { cli = mkOption {
readOnly = true; readOnly = true;
type = types.package; type = types.package;
default = pkgs.writers.writeBashBin "bitcoin-cli" '' default = pkgs.writeScriptBin "bitcoin-cli" ''
exec ${cfg.package}/bin/bitcoin-cli -datadir='${cfg.dataDir}' "$@" exec ${cfg.package}/bin/bitcoin-cli -datadir='${cfg.dataDir}' "$@"
''; '';
defaultText = "(See source)"; defaultText = "(See source)";
description = mdDoc "Binary to connect with the bitcoind instance."; description = "Binary to connect with the bitcoind instance.";
}; };
tor = nbLib.tor; tor = nbLib.tor;
}; };
@ -381,7 +381,7 @@ in {
# TODO-EXTERNAL: Instead of `wants`, use a future systemd dependency type # TODO-EXTERNAL: Instead of `wants`, use a future systemd dependency type
# that propagates initial start failures but no restarts # that propagates initial start failures but no restarts
wants = [ "nix-bitcoin-secrets.target" ]; wants = [ "nix-bitcoin-secrets.target" ];
after = [ "network-online.target" "nix-bitcoin-secrets.target" ]; after = [ "network.target" "nix-bitcoin-secrets.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
preStart = let preStart = let
@ -422,13 +422,13 @@ in {
NotifyAccess = "all"; NotifyAccess = "all";
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
TimeoutStartSec = "30min"; TimeoutStartSec = "10min";
TimeoutStopSec = "30min"; 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 "/fake-dir"];
ReadWritePaths = [ "/dummy" ]; #ReadWritePaths = [ "/dummy" ];
} // nbLib.allowedIPAddresses cfg.tor.enforce } // nbLib.allowedIPAddresses cfg.tor.enforce
// optionalAttrs zmqServerEnabled nbLib.allowNetlink; // optionalAttrs zmqServerEnabled nbLib.allowNetlink;
}; };

View File

@ -8,12 +8,12 @@ let
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = mdDoc "Address to listen on."; description = "Address to listen on.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 23000; default = 23000;
description = mdDoc "Port to listen on."; description = "Port to listen on.";
}; };
package = mkOption { package = mkOption {
type = types.package; type = types.package;
@ -22,38 +22,38 @@ let
else else
config.nix-bitcoin.pkgs.btcpayserver; config.nix-bitcoin.pkgs.btcpayserver;
defaultText = "(See source)"; defaultText = "(See source)";
description = mdDoc "The package providing btcpayserver binaries."; description = "The package providing btcpayserver binaries.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/btcpayserver"; default = "/var/lib/btcpayserver";
description = mdDoc "The data directory for btcpayserver."; description = "The data directory for btcpayserver.";
}; };
lightningBackend = mkOption { lightningBackend = mkOption {
type = types.nullOr (types.enum [ "clightning" "lnd" ]); type = types.nullOr (types.enum [ "clightning" "lnd" ]);
default = null; default = null;
description = mdDoc "The lightning node implementation to use."; description = "The lightning node implementation to use.";
}; };
lbtc = mkOption { lbtc = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc "Enable liquid support in btcpayserver."; description = "Enable liquid support in btcpayserver.";
}; };
rootpath = mkOption { rootpath = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
example = "btcpayserver"; example = "btcpayserver";
description = mdDoc "The prefix for root-relative btcpayserver URLs."; description = "The prefix for root-relative btcpayserver URLs.";
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "btcpayserver"; default = "btcpayserver";
description = mdDoc "The user as which to run btcpayserver."; description = "The user as which to run btcpayserver.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.btcpayserver.user; default = cfg.btcpayserver.user;
description = mdDoc "The group as which to run btcpayserver."; description = "The group as which to run btcpayserver.";
}; };
tor.enforce = nbLib.tor.enforce; tor.enforce = nbLib.tor.enforce;
}; };
@ -63,7 +63,7 @@ let
# This option is only used by netns-isolation # This option is only used by netns-isolation
internal = true; internal = true;
default = cfg.btcpayserver.enable; default = cfg.btcpayserver.enable;
description = mdDoc '' description = ''
nbxplorer is always enabled when btcpayserver is enabled. nbxplorer is always enabled when btcpayserver is enabled.
''; '';
}; };
@ -71,32 +71,32 @@ let
type = types.package; type = types.package;
default = config.nix-bitcoin.pkgs.nbxplorer; default = config.nix-bitcoin.pkgs.nbxplorer;
defaultText = "config.nix-bitcoin.pkgs.nbxplorer"; defaultText = "config.nix-bitcoin.pkgs.nbxplorer";
description = mdDoc "The package providing nbxplorer binaries."; description = "The package providing nbxplorer binaries.";
}; };
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = mdDoc "Address to listen on."; description = "Address to listen on.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 24444; default = 24444;
description = mdDoc "Port to listen on."; description = "Port to listen on.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/nbxplorer"; default = "/var/lib/nbxplorer";
description = mdDoc "The data directory for nbxplorer."; description = "The data directory for nbxplorer.";
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "nbxplorer"; default = "nbxplorer";
description = mdDoc "The user as which to run nbxplorer."; description = "The user as which to run nbxplorer.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.nbxplorer.user; default = cfg.nbxplorer.user;
description = mdDoc "The group as which to run nbxplorer."; description = "The group as which to run nbxplorer.";
}; };
tor.enforce = nbLib.tor.enforce; tor.enforce = nbLib.tor.enforce;
}; };
@ -193,14 +193,14 @@ in {
Restart = "on-failure"; Restart = "on-failure";
RestartSec = "10s"; RestartSec = "10s";
ReadWritePaths = [ cfg.nbxplorer.dataDir ]; ReadWritePaths = [ cfg.nbxplorer.dataDir ];
MemoryDenyWriteExecute = false; MemoryDenyWriteExecute = "false";
} // nbLib.allowedIPAddresses cfg.nbxplorer.tor.enforce; } // nbLib.allowedIPAddresses cfg.nbxplorer.tor.enforce;
}; };
systemd.services.btcpayserver = let systemd.services.btcpayserver = let
nbExplorerUrl = "http://${nbLib.addressWithPort cfg.nbxplorer.address cfg.nbxplorer.port}/"; nbExplorerUrl = "http://${nbLib.addressWithPort cfg.nbxplorer.address cfg.nbxplorer.port}/";
nbExplorerCookie = "${cfg.nbxplorer.dataDir}/${bitcoind.makeNetworkName "Main" "RegTest"}/.cookie"; nbExplorerCookie = "${cfg.nbxplorer.dataDir}/${bitcoind.makeNetworkName "Main" "RegTest"}/.cookie";
configFile = builtins.toFile "btcpayserver-config" ('' configFile = builtins.toFile "config" (''
network=${bitcoind.network} network=${bitcoind.network}
bind=${cfg.btcpayserver.address} bind=${cfg.btcpayserver.address}
port=${toString cfg.btcpayserver.port} port=${toString cfg.btcpayserver.port}
@ -212,40 +212,42 @@ in {
rootpath=${cfg.btcpayserver.rootpath} rootpath=${cfg.btcpayserver.rootpath}
'' + optionalString (cfg.btcpayserver.lightningBackend == "clightning") '' '' + optionalString (cfg.btcpayserver.lightningBackend == "clightning") ''
btclightning=type=clightning;server=unix:///${cfg.clightning.dataDir}/${bitcoind.makeNetworkName "bitcoin" "regtest"}/lightning-rpc btclightning=type=clightning;server=unix:///${cfg.clightning.dataDir}/${bitcoind.makeNetworkName "bitcoin" "regtest"}/lightning-rpc
'' + optionalString (cfg.btcpayserver.lightningBackend == "lnd") '' + optionalString cfg.btcpayserver.lbtc ''
(
"btclightning=type=lnd-rest;" +
"server=https://${cfg.lnd.restAddress}:${toString cfg.lnd.restPort}/;" +
"macaroonfilepath=/run/lnd/btcpayserver.macaroon;" +
"certfilepath=${config.services.lnd.certPath}" +
"\n"
)
+ optionalString cfg.btcpayserver.lbtc ''
chains=btc,lbtc chains=btc,lbtc
lbtcexplorerurl=${nbExplorerUrl} lbtcexplorerurl=${nbExplorerUrl}
lbtcexplorercookiefile=${nbExplorerCookie} lbtcexplorercookiefile=${nbExplorerCookie}
''); '');
lndConfig =
"btclightning=type=lnd-rest;" +
"server=https://${cfg.lnd.restAddress}:${toString cfg.lnd.restPort}/;" +
"macaroonfilepath=/run/lnd/btcpayserver.macaroon;" +
"certthumbprint=";
in let self = { in let self = {
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
requires = [ "nbxplorer.service" "postgresql.service" ] requires = [ "nbxplorer.service" "postgresql.service" ]
++ optional (cfg.btcpayserver.lightningBackend != null) "${cfg.btcpayserver.lightningBackend}.service"; ++ optional (cfg.btcpayserver.lightningBackend != null) "${cfg.btcpayserver.lightningBackend}.service";
after = self.requires; after = self.requires;
preStart = ''
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.services.lnd.certPath} \
| sed -e 's/.*=//;s/://g'
} >> '${cfg.btcpayserver.dataDir}/settings.config'
''}
'';
serviceConfig = nbLib.defaultHardening // { serviceConfig = nbLib.defaultHardening // {
ExecStart = '' ExecStart = ''
${cfg.btcpayserver.package}/bin/btcpayserver --conf=${configFile} \ ${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;
# Also restart after the program has exited successfully. Restart = "on-failure";
# This is required to support restarting from the web interface after RestartSec = "10s";
# interactive plugin installation.
# Restart rate limiting is implemented via the `startLimit*` options below.
Restart = "always";
ReadWritePaths = [ cfg.btcpayserver.dataDir ]; ReadWritePaths = [ cfg.btcpayserver.dataDir ];
MemoryDenyWriteExecute = false; MemoryDenyWriteExecute = "false";
} // nbLib.allowedIPAddresses cfg.btcpayserver.tor.enforce; } // nbLib.allowedIPAddresses cfg.btcpayserver.tor.enforce;
startLimitIntervalSec = 30;
startLimitBurst = 10;
}; in self; }; in self;
users.users.${cfg.nbxplorer.user} = { users.users.${cfg.nbxplorer.user} = {

View File

@ -9,17 +9,18 @@ let
type = listOf str; type = listOf str;
default = []; default = [];
example = [ "--verbose" "--dry-run" ]; example = [ "--verbose" "--dry-run" ];
description = mdDoc "Extra flags to pass to the charge-lnd command."; description = "Extra flags to pass to the charge-lnd command.";
}; };
interval = mkOption { interval = mkOption {
type = str; type = str;
default = "*-*-* 04:00:00"; default = "*-*-* 04:00:00";
example = "hourly"; example = "hourly";
description = mdDoc '' description = ''
Systemd calendar expression when to adjust fees. Systemd calendar expression when to adjust fees.
See {man}`systemd.time(7)` for possible values. See <citerefentry><refentrytitle>systemd.time</refentrytitle>
<manvolnum>7</manvolnum></citerefentry> for possible values.
Default is once a day. Default is once a day.
''; '';
@ -28,7 +29,7 @@ let
randomDelay = mkOption { randomDelay = mkOption {
type = str; type = str;
default = "1h"; default = "1h";
description = mdDoc '' description = ''
Random delay to add to scheduled time. Random delay to add to scheduled time.
''; '';
}; };
@ -54,7 +55,7 @@ let
[default] [default]
strategy = ignore strategy = ignore
''; '';
description = mdDoc '' description = ''
Policy definitions in INI format. Policy definitions in INI format.
See https://github.com/accumulator/charge-lnd/blob/master/README.md#usage See https://github.com/accumulator/charge-lnd/blob/master/README.md#usage
@ -125,6 +126,7 @@ in
}; };
systemd.timers.charge-lnd = { systemd.timers.charge-lnd = {
description = "Adjust LND routing fees";
wantedBy = [ "timers.target" ]; wantedBy = [ "timers.target" ];
timerConfig = { timerConfig = {
OnCalendar = cfg.interval; OnCalendar = cfg.interval;

View File

@ -7,7 +7,7 @@ let cfg = config.services.clightning.plugins.clboss; in
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Whether to enable CLBOSS (clightning plugin). Whether to enable CLBOSS (clightning plugin).
See also: https://github.com/ZmnSCPxj/clboss#operating See also: https://github.com/ZmnSCPxj/clboss#operating
''; '';
@ -15,36 +15,36 @@ let cfg = config.services.clightning.plugins.clboss; in
min-onchain = mkOption { min-onchain = mkOption {
type = types.ints.positive; type = types.ints.positive;
default = 30000; default = 30000;
description = mdDoc '' description = ''
Target amount (in satoshi) that CLBOSS will leave on-chain. Target amount (in satoshi) that CLBOSS will leave on-chain.
clboss will only open new channels if the funds in your clightning wallet are clboss will only open new channels if this amount is smaller than
larger than this amount. the funds in your clightning wallet.
''; '';
}; };
min-channel = mkOption { min-channel = mkOption {
type = types.ints.positive; type = types.ints.positive;
default = 500000; default = 500000;
description = mdDoc "The minimum size (in satoshi) of channels created by CLBOSS."; description = "The minimum size (in satoshi) of channels created by CLBOSS.";
}; };
max-channel = mkOption { max-channel = mkOption {
type = types.ints.positive; type = types.ints.positive;
default = 16777215; default = 16777215;
description = mdDoc "The maximum size (in satoshi) of channels created by CLBOSS."; description = "The maximum size (in satoshi) of channels created by CLBOSS.";
}; };
zerobasefee = mkOption { zerobasefee = mkOption {
type = types.enum [ "require" "allow" "disallow" ]; type = types.enum [ "require" "allow" "disallow" ];
default = "allow"; default = "allow";
description = mdDoc '' description = ''
`require`: set `base_fee` to 0. require: set `base_fee` to 0.
`allow`: set `base_fee` according to the CLBOSS heuristics, which may include value 0. allow: set `base_fee` according to the CLBOSS heuristics, which may include value 0.
`disallow`: set `base_fee` to according to the CLBOSS heuristics, with a minimum value of 1. disallow: set `base_fee` to according to the CLBOSS heuristics, with a minimum value of 1.
''; '';
}; };
package = mkOption { package = mkOption {
type = types.package; type = types.package;
default = config.nix-bitcoin.pkgs.clboss; default = config.nix-bitcoin.pkgs.clboss;
defaultText = "config.nix-bitcoin.pkgs.clboss"; defaultText = "config.nix-bitcoin.pkgs.clboss";
description = mdDoc "The package providing clboss binaries."; description = "The package providing clboss binaries.";
}; };
}; };

View File

@ -17,7 +17,6 @@ in {
./feeadjuster.nix ./feeadjuster.nix
./prometheus.nix ./prometheus.nix
./summary.nix ./summary.nix
./trustedcoin.nix
./zmq.nix ./zmq.nix
]; ];

View File

@ -6,7 +6,7 @@ let
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Enable feeaduster (clightning plugin). Enable feeaduster (clightning plugin).
This plugin auto-updates channel fees to keep channels balanced. This plugin auto-updates channel fees to keep channels balanced.
@ -18,17 +18,17 @@ let
fuzz = mkOption { fuzz = mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
description = mdDoc "Enable update threshold randomization and hysteresis."; description = "Enable update threshold randomization and hysteresis.";
}; };
adjustOnForward = mkOption { adjustOnForward = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc "Automatically update fees on forward events."; description = "Automatically update fees on forward events.";
}; };
method = mkOption { method = mkOption {
type = types.enum [ "soft" "default" "hard" ]; type = types.enum [ "soft" "default" "hard" ];
default = "default"; default = "default";
description = mdDoc '' description = ''
Adjustment method to calculate channel fees. Adjustment method to calculate channel fees.
`soft`: less difference when adjusting fees. `soft`: less difference when adjusting fees.
`hard`: greater difference when adjusting fees. `hard`: greater difference when adjusting fees.
@ -37,7 +37,7 @@ let
adjustDaily = mkOption { adjustDaily = mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
description = mdDoc "Automatically update fees daily."; description = "Automatically update fees daily.";
}; };
}; };

View File

@ -8,22 +8,22 @@ let cfg = config.services.clightning.plugins.summary; in
currency = mkOption { currency = mkOption {
type = types.str; type = types.str;
default = "USD"; default = "USD";
description = mdDoc "The currency to look up on btcaverage."; description = "The currency to look up on btcaverage.";
}; };
currencyPrefix = mkOption { currencyPrefix = mkOption {
type = types.str; type = types.str;
default = "USD $"; default = "USD $";
description = mdDoc "The prefix to use for the currency."; description = "The prefix to use for the currency.";
}; };
availabilityInterval = mkOption { availabilityInterval = mkOption {
type = types.int; type = types.int;
default = 300; default = 300;
description = mdDoc "How often in seconds the availability should be calculated."; description = "How often in seconds the availability should be calculated.";
}; };
availabilityWindow = mkOption { availabilityWindow = mkOption {
type = types.int; type = types.int;
default = 72; default = 72;
description = mdDoc "How many hours the availability should be averaged over."; description = "How many hours the availability should be averaged over.";
}; };
}; };

View File

@ -1,28 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let cfg = config.services.clightning.plugins.trustedcoin; in
{
options.services.clightning.plugins.trustedcoin = {
enable = mkEnableOption "Trustedcoin (clightning plugin)";
package = mkOption {
type = types.package;
default = config.nix-bitcoin.pkgs.trustedcoin;
defaultText = "config.nix-bitcoin.pkgs.trustedcoin";
description = mdDoc "The package providing trustedcoin binaries.";
};
};
config = mkIf cfg.enable {
services.clightning.extraConfig = ''
plugin=${cfg.package}/bin/trustedcoin
disable-plugin=bcli
'';
# Trustedcoin does not honor the clightning's proxy configuration.
# Ref.: https://github.com/nbd-wtf/trustedcoin/pull/19
systemd.services.clightning.environment = mkIf (config.services.clightning.proxy != null) {
HTTPS_PROXY = "socks5://${config.services.clightning.proxy}";
};
};
}

View File

@ -25,7 +25,7 @@ let
mkOption { mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
description = mdDoc "Endpoint for ${name}"; description = "Endpoint for ${name}";
}; };
setEndpoint = ep: setEndpoint = ep:

View File

@ -6,7 +6,7 @@ let
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Enable live replication of the clightning database. Enable live replication of the clightning database.
This prevents losing off-chain funds when the primary wallet file becomes This prevents losing off-chain funds when the primary wallet file becomes
inaccessible. inaccessible.
@ -26,7 +26,7 @@ let
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
example = "user@10.0.0.1:directory"; example = "user@10.0.0.1:directory";
description = mdDoc '' description = ''
The SSH destination for which a SSHFS will be mounted. The SSH destination for which a SSHFS will be mounted.
`directory` is relative to the home of `user`. `directory` is relative to the home of `user`.
@ -40,12 +40,12 @@ let
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 22; default = 22;
description = mdDoc "SSH port of the remote server."; description = "SSH port of the remote server.";
}; };
sshOptions = mkOption { sshOptions = mkOption {
type = with types; listOf str; type = with types; listOf str;
default = [ "reconnect" "ServerAliveInterval=50" ]; default = [ "reconnect" "ServerAliveInterval=50" ];
description = mdDoc "SSH options used for mounting the SSHFS."; description = "SSH options used for mounting the SSHFS.";
}; };
}; };
local = { local = {
@ -53,7 +53,7 @@ let
type = types.nullOr types.path; type = types.nullOr types.path;
default = null; default = null;
example = "/var/backup/clightning"; example = "/var/backup/clightning";
description = mdDoc '' description = ''
This option can be specified instead of `sshfs.destination` to enable This option can be specified instead of `sshfs.destination` to enable
replication to a local directory. replication to a local directory.
@ -69,7 +69,7 @@ let
setupDirectory = mkOption { setupDirectory = mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
description = mdDoc '' description = ''
Create `local.directory` if it doesn't exist and set write permissions Create `local.directory` if it doesn't exist and set write permissions
for the `clightning` user. for the `clightning` user.
''; '';
@ -78,10 +78,10 @@ let
encrypt = mkOption { encrypt = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Whether to encrypt the replicated database with gocryptfs. Whether to encrypt the replicated database with gocryptfs.
The encryption password is automatically generated and stored The encryption password is automatically generated and stored
in file {file}`$secretsDir/clightning-replication-password`. in file `$secretsDir/clightning-replication-password`.
''; '';
}; };
}; };

View File

@ -7,17 +7,17 @@ let
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 3001; default = 3001;
description = mdDoc "REST server port."; description = "REST server port.";
}; };
docPort = mkOption { docPort = mkOption {
type = types.port; type = types.port;
default = 4001; default = 4001;
description = mdDoc "Swagger API documentation server port."; description = "Swagger API documentation server port.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/clightning-rest"; default = "/var/lib/clightning-rest";
description = mdDoc "The data directory for clightning-rest."; description = "The data directory for clightning-rest.";
}; };
extraConfig = mkOption { extraConfig = mkOption {
type = types.attrs; type = types.attrs;
@ -25,7 +25,7 @@ let
example = { example = {
DOMAIN = "mynode.org"; DOMAIN = "mynode.org";
}; };
description = mdDoc '' description = ''
Extra config options. Extra config options.
See: https://github.com/Ride-The-Lightning/c-lightning-REST#option-1-via-config-file-cl-rest-configjson See: https://github.com/Ride-The-Lightning/c-lightning-REST#option-1-via-config-file-cl-rest-configjson
''; '';
@ -34,7 +34,7 @@ let
group = mkOption { group = mkOption {
readOnly = true; readOnly = true;
default = clightning.group; default = clightning.group;
description = mdDoc "The group under which clightning-rest is run."; description = "The group under which clightning-rest is run.";
}; };
# Rest server address. # Rest server address.
# Not configurable. The server always listens on all interfaces: # Not configurable. The server always listens on all interfaces:

View File

@ -7,24 +7,24 @@ let
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = mdDoc "Address to listen for peer connections."; description = "Address to listen for peer connections.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 9735; default = 9735;
description = mdDoc "Port to listen for peer connections."; description = "Port to listen for peer connections.";
}; };
proxy = mkOption { proxy = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null; default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null;
description = mdDoc '' description = ''
Socks proxy for connecting to Tor nodes (or for all connections if option always-use-proxy is set). Socks proxy for connecting to Tor nodes (or for all connections if option always-use-proxy is set).
''; '';
}; };
always-use-proxy = mkOption { always-use-proxy = mkOption {
type = types.bool; type = types.bool;
default = cfg.tor.proxy; default = cfg.tor.proxy;
description = mdDoc '' description = ''
Always use the proxy, even to connect to normal IP addresses. Always use the proxy, even to connect to normal IP addresses.
You can still connect to Unix domain sockets manually. You can still connect to Unix domain sockets manually.
This also disables all DNS lookups, to avoid leaking address information. This also disables all DNS lookups, to avoid leaking address information.
@ -33,18 +33,18 @@ let
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/clightning"; default = "/var/lib/clightning";
description = mdDoc "The data directory for clightning."; description = "The data directory for clightning.";
}; };
networkDir = mkOption { networkDir = mkOption {
readOnly = true; readOnly = true;
default = "${cfg.dataDir}/${network}"; default = "${cfg.dataDir}/${network}";
description = mdDoc "The network data directory."; description = "The network data directory.";
}; };
wallet = mkOption { wallet = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
example = "sqlite3:///var/lib/clightning/bitcoin/lightningd.sqlite3"; example = "sqlite3:///var/lib/clightning/bitcoin/lightningd.sqlite3";
description = mdDoc '' description = ''
Wallet data scheme (sqlite3 or postgres) and location/connection Wallet data scheme (sqlite3 or postgres) and location/connection
parameters, as fully qualified data source name. parameters, as fully qualified data source name.
''; '';
@ -55,42 +55,42 @@ let
example = '' example = ''
alias=mynode alias=mynode
''; '';
description = mdDoc '' description = ''
Extra lines appended to the configuration file. Extra lines appended to the configuration file.
See all available options at See all available options at
https://github.com/ElementsProject/lightning/blob/master/doc/lightningd-config.5.md https://github.com/ElementsProject/lightning/blob/master/doc/lightningd-config.5.md
or by running {command}`lightningd --help`. or by running `lightningd --help`.
''; '';
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "clightning"; default = "clightning";
description = mdDoc "The user as which to run clightning."; description = "The user as which to run clightning.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = mdDoc "The group as which to run clightning."; description = "The group as which to run clightning.";
}; };
package = mkOption { package = mkOption {
type = types.package; type = types.package;
default = nbPkgs.clightning; default = nbPkgs.clightning;
defaultText = "config.nix-bitcoin.pkgs.clightning"; defaultText = "config.nix-bitcoin.pkgs.clightning";
description = mdDoc "The package providing clightning binaries."; description = "The package providing clightning binaries.";
}; };
cli = mkOption { cli = mkOption {
readOnly = true; readOnly = true;
default = pkgs.writers.writeBashBin "lightning-cli" '' default = pkgs.writeScriptBin "lightning-cli" ''
${cfg.package}/bin/lightning-cli --lightning-dir='${cfg.dataDir}' "$@" ${cfg.package}/bin/lightning-cli --lightning-dir='${cfg.dataDir}' "$@"
''; '';
defaultText = "(See source)"; defaultText = "(See source)";
description = mdDoc "Binary to connect with the clightning instance."; description = "Binary to connect with the clightning instance.";
}; };
getPublicAddressCmd = mkOption { getPublicAddressCmd = mkOption {
type = types.str; type = types.str;
default = ""; default = "";
description = mdDoc '' description = ''
Bash expression which outputs the public service address to announce to peers. Bash expression which outputs the public service address to announce to peers.
If left empty, no address is announced. If left empty, no address is announced.
''; '';
@ -102,28 +102,19 @@ let
nbLib = config.nix-bitcoin.lib; nbLib = config.nix-bitcoin.lib;
nbPkgs = config.nix-bitcoin.pkgs; nbPkgs = config.nix-bitcoin.pkgs;
inherit (config.services) bitcoind; network = config.services.bitcoind.makeNetworkName "bitcoin" "regtest";
network = bitcoind.makeNetworkName "bitcoin" "regtest";
configFile = pkgs.writeText "config" '' configFile = pkgs.writeText "config" ''
network=${network} network=${network}
${optionalString (!cfg.plugins.trustedcoin.enable) "bitcoin-datadir=${bitcoind.dataDir}"} bitcoin-datadir=${config.services.bitcoind.dataDir}
${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=${nbLib.address config.services.bitcoind.rpc.address}
bitcoin-rpcconnect=${nbLib.address bitcoind.rpc.address} bitcoin-rpcport=${toString config.services.bitcoind.rpc.port}
bitcoin-rpcport=${toString bitcoind.rpc.port} bitcoin-rpcuser=${config.services.bitcoind.rpc.users.public.name}
bitcoin-rpcuser=${bitcoind.rpc.users.public.name}
rpc-file-mode=0660 rpc-file-mode=0660
log-timestamps=false log-timestamps=false
${optionalString (cfg.wallet != null) "wallet=${cfg.wallet}"} ${optionalString (cfg.wallet != null) "wallet=${cfg.wallet}"}
${ # TODO-EXTERNAL: When updating from a version of clightning before 22.11
# to version 22.11.1, then the database upgrade needs to be allowed
# explicitly. Remove this when it's unlikely that this module is used
# with a clightning version 22.11.1 package.
optionalString (cfg.package.version == "22.11.1") "database-upgrade=true"}
${cfg.extraConfig} ${cfg.extraConfig}
''; '';
@ -163,7 +154,6 @@ in {
{ {
cat ${configFile} cat ${configFile}
echo "bitcoin-rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword-public)" echo "bitcoin-rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword-public)"
${optionalString (cfg.getPublicAddressCmd != "") '' ${optionalString (cfg.getPublicAddressCmd != "") ''
echo "announce-addr=$(${cfg.getPublicAddressCmd}):${toString publicPort}" echo "announce-addr=$(${cfg.getPublicAddressCmd}):${toString publicPort}"
''} ''}

View File

@ -7,37 +7,37 @@ let
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = mdDoc "Address to listen for RPC connections."; description = "Address to listen for RPC connections.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 50001; default = 50001;
description = mdDoc "Port to listen for RPC connections."; description = "Port to listen for RPC connections.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/electrs"; default = "/var/lib/electrs";
description = mdDoc "The data directory for electrs."; description = "The data directory for electrs.";
}; };
monitoringPort = mkOption { monitoringPort = mkOption {
type = types.port; type = types.port;
default = 4224; default = 4224;
description = mdDoc "Prometheus monitoring port."; description = "Prometheus monitoring port.";
}; };
extraArgs = mkOption { extraArgs = mkOption {
type = types.separatedString " "; type = types.separatedString " ";
default = ""; default = "";
description = mdDoc "Extra command line arguments passed to electrs."; description = "Extra command line arguments passed to electrs.";
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "electrs"; default = "electrs";
description = mdDoc "The user as which to run electrs."; description = "The user as which to run electrs.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = mdDoc "The group as which to run electrs."; description = "The group as which to run electrs.";
}; };
tor.enforce = nbLib.tor.enforce; tor.enforce = nbLib.tor.enforce;
}; };

View File

@ -6,7 +6,7 @@ let
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Enable fulcrum, an Electrum server implemented in C++. Enable fulcrum, an Electrum server implemented in C++.
Compared to electrs, fulcrum has a 3x larger database size but Compared to electrs, fulcrum has a 3x larger database size but
@ -17,23 +17,23 @@ let
This module disables peering (a distributed list of electrum servers that can This module disables peering (a distributed list of electrum servers that can
be queried by clients), but you can manually enable it via option be queried by clients), but you can manually enable it via option
{option}`extraConfig`. `extraConfig`.
''; '';
}; };
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = mdDoc "Address to listen for RPC connections."; description = "Address to listen for RPC connections.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 50001; default = 50001;
description = mdDoc "Port to listen for RPC connections."; description = "Port to listen for RPC connections.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/fulcrum"; default = "/var/lib/fulcrum";
description = mdDoc "The data directory for fulcrum."; description = "The data directory for fulcrum.";
}; };
extraConfig = mkOption { extraConfig = mkOption {
type = types.lines; type = types.lines;
@ -41,7 +41,7 @@ let
example = '' example = ''
peering = true peering = true
''; '';
description = mdDoc '' description = ''
Extra lines appended to the configuration file. Extra lines appended to the configuration file.
See all available options at See all available options at
@ -51,12 +51,12 @@ let
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "fulcrum"; default = "fulcrum";
description = mdDoc "The user as which to run fulcrum."; description = "The user as which to run fulcrum.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = mdDoc "The group as which to run fulcrum."; description = "The group as which to run fulcrum.";
}; };
tor.enforce = nbLib.tor.enforce; tor.enforce = nbLib.tor.enforce;
}; };
@ -126,7 +126,6 @@ in {
Restart = "on-failure"; Restart = "on-failure";
RestartSec = "10s"; RestartSec = "10s";
ReadWritePaths = cfg.dataDir; ReadWritePaths = cfg.dataDir;
ProcSubset = "all"; # Fulcrum requires read access to /proc/meminfo
} // nbLib.allowedIPAddresses cfg.tor.enforce; } // nbLib.allowedIPAddresses cfg.tor.enforce;
}; };

View File

@ -6,21 +6,21 @@ let
ledger = mkOption { ledger = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
If enabled, the ledger udev rules will be installed. If enabled, the ledger udev rules will be installed.
''; '';
}; };
trezor = mkOption { trezor = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
If enabled, the trezor udev rules will be installed. If enabled, the trezor udev rules will be installed.
''; '';
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = "hardware-wallets"; default = "hardware-wallets";
description = mdDoc '' description = ''
Group the hardware wallet udev rules apply to. Group the hardware wallet udev rules apply to.
''; '';
}; };

View File

@ -7,27 +7,27 @@ let
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = mdDoc "HTTP server address."; description = "HTTP server address.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 62601; default = 62601;
description = mdDoc "HTTP server port."; description = "HTTP server port.";
}; };
dataDir = mkOption { dataDir = mkOption {
readOnly = true; readOnly = true;
default = "/var/lib/joinmarket-ob-watcher"; default = "/var/lib/joinmarket-ob-watcher";
description = mdDoc "The data directory for JoinMarket orderbook watcher."; description = "The data directory for JoinMarket orderbook watcher.";
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "joinmarket-ob-watcher"; default = "joinmarket-ob-watcher";
description = mdDoc "The user as which to run JoinMarket."; description = "The user as which to run JoinMarket.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = mdDoc "The group as which to run JoinMarket."; description = "The group as which to run JoinMarket.";
}; };
# This option is only used by netns-isolation. # This option is only used by netns-isolation.
# Tor is always enabled. # Tor is always enabled.

View File

@ -7,7 +7,7 @@ let
payjoinAddress = mkOption { payjoinAddress = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = mdDoc '' description = ''
The address where payjoin onion connections are forwarded to. The address where payjoin onion connections are forwarded to.
This address is never used directly, it only serves as the internal endpoint This address is never used directly, it only serves as the internal endpoint
for the payjoin onion service. for the payjoin onion service.
@ -18,12 +18,12 @@ let
payjoinPort = mkOption { payjoinPort = mkOption {
type = types.port; type = types.port;
default = 64180; # A random private port default = 64180; # A random private port
description = mdDoc "The port corresponding to option {option}`payjoinAddress`."; description = "The port corresponding to option `payjoinAddress`.";
}; };
messagingAddress = mkOption { messagingAddress = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = mdDoc '' description = ''
The address where messaging onion connections are forwarded to. The address where messaging onion connections are forwarded to.
This address is never used directly, it only serves as the internal endpoint This address is never used directly, it only serves as the internal endpoint
for the messaging onion service. for the messaging onion service.
@ -33,29 +33,29 @@ let
messagingPort = mkOption { messagingPort = mkOption {
type = types.port; type = types.port;
default = 64181; # payjoinPort + 1 default = 64181; # payjoinPort + 1
description = mdDoc "The port corresponding to option {option}`messagingAddress`."; description = "The port corresponding to option `messagingAddress`.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/joinmarket"; default = "/var/lib/joinmarket";
description = mdDoc "The data directory for JoinMarket."; description = "The data directory for JoinMarket.";
}; };
rpcWalletFile = mkOption { rpcWalletFile = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = "jm_wallet"; default = "jm_wallet";
description = mdDoc '' description = ''
Name of the watch-only bitcoind wallet the JoinMarket addresses are imported to. Name of the watch-only bitcoind wallet the JoinMarket addresses are imported to.
''; '';
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "joinmarket"; default = "joinmarket";
description = mdDoc "The user as which to run JoinMarket."; description = "The user as which to run JoinMarket.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = mdDoc "The group as which to run JoinMarket."; description = "The group as which to run JoinMarket.";
}; };
cli = mkOption { cli = mkOption {
default = cli; default = cli;
@ -77,57 +77,57 @@ let
ordertype = mkOption { ordertype = mkOption {
type = types.enum [ "reloffer" "absoffer" ]; type = types.enum [ "reloffer" "absoffer" ];
default = "reloffer"; default = "reloffer";
description = mdDoc '' description = ''
Which fee type to actually use. Which fee type to actually use
''; '';
}; };
cjfee_a = mkOption { cjfee_a = mkOption {
type = types.ints.unsigned; type = types.ints.unsigned;
default = 500; default = 500;
description = mdDoc '' description = ''
Absolute offer fee you wish to receive for coinjoins (cj) in Satoshis. Absolute offer fee you wish to receive for coinjoins (cj) in Satoshis
''; '';
}; };
cjfee_r = mkOption { cjfee_r = mkOption {
type = types.float; type = types.float;
default = 0.00002; default = 0.00002;
description = mdDoc '' description = ''
Relative offer fee you wish to receive based on a cj's amount. Relative offer fee you wish to receive based on a cj's amount
''; '';
}; };
cjfee_factor = mkOption { cjfee_factor = mkOption {
type = types.float; type = types.float;
default = 0.1; default = 0.1;
description = mdDoc '' description = ''
Variance around the average cj fee. Variance around the average cj fee
''; '';
}; };
txfee = mkOption { txfee = mkOption {
type = types.ints.unsigned; type = types.ints.unsigned;
default = 100; default = 100;
description = mdDoc '' description = ''
The average transaction fee you're adding to coinjoin transactions. The average transaction fee you're adding to coinjoin transactions
''; '';
}; };
txfee_contribution_factor = mkOption { txfee_contribution_factor = mkOption {
type = types.float; type = types.float;
default = 0.3; default = 0.3;
description = mdDoc '' description = ''
Variance around the average tx fee. Variance around the average tx fee
''; '';
}; };
minsize = mkOption { minsize = mkOption {
type = types.ints.unsigned; type = types.ints.unsigned;
default = 100000; default = 100000;
description = mdDoc '' description = ''
Minimum size of your cj offer in Satoshis. Lower cj amounts will be disregarded. Minimum size of your cj offer in Satoshis. Lower cj amounts will be disregarded.
''; '';
}; };
size_factor = mkOption { size_factor = mkOption {
type = types.float; type = types.float;
default = 0.1; default = 0.1;
description = mdDoc '' description = ''
Variance around all offer sizes. Variance around all offer sizes
''; '';
}; };
}; };
@ -158,7 +158,7 @@ let
onion_serving_host = ${cfg.messagingAddress} onion_serving_host = ${cfg.messagingAddress}
onion_serving_port = ${toString cfg.messagingPort} onion_serving_port = ${toString cfg.messagingPort}
hidden_service_dir = hidden_service_dir =
directory_nodes = g3hv4uynnmynqqq2mchf3fcm3yd46kfzmcdogejuckgwknwyq5ya6iad.onion:5222,3kxw6lf5vf6y26emzwgibzhrzhmhqiw6ekrek3nqfjjmhwznb2moonad.onion:5222,bqlpq6ak24mwvuixixitift4yu42nxchlilrcqwk2ugn45tdclg42qid.onion:5222 directory_nodes = 3kxw6lf5vf6y26emzwgibzhrzhmhqiw6ekrek3nqfjjmhwznb2moonad.onion:5222,jmdirjmioywe2s5jad7ts6kgcqg66rj6wujj6q77n6wbdrgocqwexzid.onion:5222,bqlpq6ak24mwvuixixitift4yu42nxchlilrcqwk2ugn45tdclg42qid.onion:5222
# irc.darkscience.net # irc.darkscience.net
[MESSAGING:server1] [MESSAGING:server1]

View File

@ -7,56 +7,56 @@ let
rpcAddress = mkOption { rpcAddress = mkOption {
type = types.str; type = types.str;
default = "localhost"; default = "localhost";
description = mdDoc "Address to listen for gRPC connections."; description = "Address to listen for gRPC connections.";
}; };
rpcPort = mkOption { rpcPort = mkOption {
type = types.port; type = types.port;
default = 11010; default = 11010;
description = mdDoc "Port to listen for gRPC connections."; description = "Port to listen for gRPC connections.";
}; };
restAddress = mkOption { restAddress = mkOption {
type = types.str; type = types.str;
default = cfg.rpcAddress; default = cfg.rpcAddress;
description = mdDoc "Address to listen for REST connections."; description = "Address to listen for REST connections.";
}; };
restPort = mkOption { restPort = mkOption {
type = types.port; type = types.port;
default = 8081; default = 8081;
description = mdDoc "Port to listen for REST connections."; description = "Port to listen for REST connections.";
}; };
package = mkOption { package = mkOption {
type = types.package; type = types.package;
default = config.nix-bitcoin.pkgs.lightning-loop; default = config.nix-bitcoin.pkgs.lightning-loop;
defaultText = "config.nix-bitcoin.pkgs.lightning-loop"; defaultText = "config.nix-bitcoin.pkgs.lightning-loop";
description = mdDoc "The package providing lightning-loop binaries."; description = "The package providing lightning-loop binaries.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/lightning-loop"; default = "/var/lib/lightning-loop";
description = mdDoc "The data directory for lightning-loop."; description = "The data directory for lightning-loop.";
}; };
proxy = mkOption { proxy = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null; default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null;
description = mdDoc "`host:port` of SOCKS5 proxy for connnecting to the loop server."; description = "host:port of SOCKS5 proxy for connnecting to the loop server.";
}; };
certificate = { certificate = {
extraIPs = mkOption { extraIPs = mkOption {
type = with types; listOf str; type = with types; listOf str;
default = []; default = [];
example = [ "60.100.0.1" ]; example = [ "60.100.0.1" ];
description = mdDoc '' description = ''
Extra `subjectAltName` IPs added to the certificate. Extra `subjectAltName` IPs added to the certificate.
This works the same as loop option {option}`tlsextraip`. This works the same as loop option `tlsextraip`.
''; '';
}; };
extraDomains = mkOption { extraDomains = mkOption {
type = with types; listOf str; type = with types; listOf str;
default = []; default = [];
example = [ "example.com" ]; example = [ "example.com" ];
description = mdDoc '' description = ''
Extra `subjectAltName` domain names added to the certificate. Extra `subjectAltName` domain names added to the certificate.
This works the same as loop option {option}`tlsextradomain`. This works the same as loop option `tlsextradomain`.
''; '';
}; };
}; };
@ -66,21 +66,21 @@ let
example = '' example = ''
debuglevel=trace debuglevel=trace
''; '';
description = mdDoc '' description = ''
Extra lines appended to the configuration file. Extra lines appended to the configuration file.
See here for all available options: See here for all available options:
https://github.com/lightninglabs/loop/blob/11ab596080e9d36f1df43edbeba0702b25aa7457/loopd/config.go#L119 https://github.com/lightninglabs/loop/blob/11ab596080e9d36f1df43edbeba0702b25aa7457/loopd/config.go#L119
''; '';
}; };
cli = mkOption { cli = mkOption {
default = pkgs.writers.writeBashBin "loop" '' default = pkgs.writeScriptBin "loop" ''
${cfg.package}/bin/loop \ ${cfg.package}/bin/loop \
--rpcserver ${nbLib.addressWithPort cfg.rpcAddress cfg.rpcPort} \ --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' "$@"
''; '';
defaultText = "(See source)"; defaultText = "(See source)";
description = mdDoc "Binary to connect with the lightning-loop instance."; description = "Binary to connect with the lightning-loop instance.";
}; };
tor = nbLib.tor; tor = nbLib.tor;
}; };

View File

@ -7,38 +7,38 @@ let
rpcAddress = mkOption { rpcAddress = mkOption {
type = types.str; type = types.str;
default = "localhost"; default = "localhost";
description = mdDoc "Address to listen for gRPC connections."; description = "Address to listen for gRPC connections.";
}; };
rpcPort = mkOption { rpcPort = mkOption {
type = types.port; type = types.port;
default = 12010; default = 12010;
description = mdDoc "Port to listen for gRPC connections."; description = "Port to listen for gRPC connections.";
}; };
restAddress = mkOption { restAddress = mkOption {
type = types.str; type = types.str;
default = cfg.rpcAddress; default = cfg.rpcAddress;
description = mdDoc "Address to listen for REST connections."; description = "Address to listen for REST connections.";
}; };
restPort = mkOption { restPort = mkOption {
type = types.port; type = types.port;
default = 8281; default = 8281;
description = mdDoc "Port to listen for REST connections."; description = "Port to listen for REST connections.";
}; };
package = mkOption { package = mkOption {
type = types.package; type = types.package;
default = config.nix-bitcoin.pkgs.lightning-pool; default = config.nix-bitcoin.pkgs.lightning-pool;
defaultText = "config.nix-bitcoin.pkgs.lightning-pool"; defaultText = "config.nix-bitcoin.pkgs.lightning-pool";
description = mdDoc "The package providing lightning-pool binaries."; description = "The package providing lightning-pool binaries.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/lightning-pool"; default = "/var/lib/lightning-pool";
description = mdDoc "The data directory for lightning-pool."; description = "The data directory for lightning-pool.";
}; };
proxy = mkOption { proxy = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null; default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null;
description = mdDoc "host:port of SOCKS5 proxy for connnecting to the pool auction server."; description = "host:port of SOCKS5 proxy for connnecting to the pool auction server.";
}; };
extraConfig = mkOption { extraConfig = mkOption {
type = types.lines; type = types.lines;
@ -46,17 +46,17 @@ let
example = '' example = ''
debuglevel=trace debuglevel=trace
''; '';
description = mdDoc "Extra lines appended to the configuration file."; description = "Extra lines appended to the configuration file.";
}; };
cli = mkOption { cli = mkOption {
default = pkgs.writers.writeBashBin "pool" '' default = pkgs.writeScriptBin "pool" ''
exec ${cfg.package}/bin/pool \ exec ${cfg.package}/bin/pool \
--rpcserver ${nbLib.addressWithPort cfg.rpcAddress cfg.rpcPort} \ --rpcserver ${nbLib.addressWithPort cfg.rpcAddress cfg.rpcPort} \
--network ${network} \ --network ${network} \
--basedir '${cfg.dataDir}' "$@" --basedir '${cfg.dataDir}' "$@"
''; '';
defaultText = "(See source)"; defaultText = "(See source)";
description = mdDoc "Binary to connect with the lightning-pool instance."; description = "Binary to connect with the lightning-pool instance.";
}; };
tor = nbLib.tor; tor = nbLib.tor;
}; };

View File

@ -8,19 +8,19 @@ let
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = mdDoc "Address to listen for peer connections."; description = "Address to listen for peer connections.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 7042; default = 7042;
description = mdDoc "Override the default port on which to listen for connections."; description = "Override the default port on which to listen for connections.";
}; };
onionPort = mkOption { onionPort = mkOption {
type = types.nullOr types.port; type = types.nullOr types.port;
# When the liquidd onion service is enabled, add an onion-tagged socket # When the liquidd onion service is enabled, add an onion-tagged socket
# to distinguish local connections from Tor connections # to distinguish local connections from Tor connections
default = if (config.nix-bitcoin.onionServices.liquidd.enable or false) then 7043 else null; default = if (config.nix-bitcoin.onionServices.liquidd.enable or false) then 7043 else null;
description = mdDoc '' description = ''
Port to listen for Tor peer connections. Port to listen for Tor peer connections.
If set, inbound connections to this port are tagged as onion peers. If set, inbound connections to this port are tagged as onion peers.
''; '';
@ -28,15 +28,15 @@ let
listen = mkOption { listen = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Listen for peer connections at `address:port` Listen for peer connections at `address:port`
and `address:onionPort` (if {option}`onionPort` is set). and `address:onionPort` (if `onionPort` is set).
''; '';
}; };
listenWhitelisted = mkOption { listenWhitelisted = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Listen for peer connections at `address:whitelistedPort`. Listen for peer connections at `address:whitelistedPort`.
Peers connected through this socket are automatically whitelisted. Peers connected through this socket are automatically whitelisted.
''; '';
@ -44,7 +44,7 @@ let
whitelistedPort = mkOption { whitelistedPort = mkOption {
type = types.port; type = types.port;
default = 7044; default = 7044;
description = mdDoc "See {option}`listenWhitelisted`."; description = "See `listenWhitelisted`.";
}; };
extraConfig = mkOption { extraConfig = mkOption {
type = types.lines; type = types.lines;
@ -54,23 +54,23 @@ let
rpcthreads=16 rpcthreads=16
logips=1 logips=1
''; '';
description = mdDoc "Extra lines appended to {file}`elements.conf`."; description = "Extra lines appended to <filename>elements.conf</filename>.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/liquidd"; default = "/var/lib/liquidd";
description = mdDoc "The data directory for liquidd."; description = "The data directory for liquidd.";
}; };
rpc = { rpc = {
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = mdDoc "Address to listen for JSON-RPC connections."; description = "Address to listen for JSON-RPC connections.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 7041; default = 7041;
description = mdDoc "Port to listen for JSON-RPC connections."; description = "Port to listen for JSON-RPC connections.";
}; };
users = mkOption { users = mkOption {
default = {}; default = {};
@ -79,7 +79,7 @@ let
bob.passwordHMAC = "b2dd077cb54591a2f3139e69a897ac$4e71f08d48b4347cf8eff3815c0e25ae2e9a4340474079f55705f40574f4ec99"; bob.passwordHMAC = "b2dd077cb54591a2f3139e69a897ac$4e71f08d48b4347cf8eff3815c0e25ae2e9a4340474079f55705f40574f4ec99";
}; };
type = with types; attrsOf (submodule rpcUserOpts); type = with types; attrsOf (submodule rpcUserOpts);
description = mdDoc '' description = ''
RPC user information for JSON-RPC connections. RPC user information for JSON-RPC connections.
''; '';
}; };
@ -87,25 +87,25 @@ let
rpcallowip = mkOption { rpcallowip = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = [ "127.0.0.1" ]; default = [ "127.0.0.1" ];
description = mdDoc '' description = ''
Allow JSON-RPC connections from specified source. Allow JSON-RPC connections from specified source.
''; '';
}; };
rpcuser = mkOption { rpcuser = mkOption {
type = types.str; type = types.str;
default = "liquidrpc"; default = "liquidrpc";
description = mdDoc "Username for JSON-RPC connections"; description = "Username for JSON-RPC connections";
}; };
proxy = mkOption { proxy = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null; default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null;
description = mdDoc "Connect through SOCKS5 proxy"; description = "Connect through SOCKS5 proxy";
}; };
dbCache = mkOption { dbCache = mkOption {
type = types.nullOr (types.ints.between 4 16384); type = types.nullOr (types.ints.between 4 16384);
default = null; default = null;
example = 4000; example = 4000;
description = mdDoc "Override the default database cache size in megabytes."; description = "Override the default database cache size in megabytes.";
}; };
prune = mkOption { prune = mkOption {
type = types.nullOr (types.coercedTo type = types.nullOr (types.coercedTo
@ -115,13 +115,13 @@ let
); );
default = null; default = null;
example = 10000; example = 10000;
description = mdDoc '' description = ''
Reduce storage requirements by enabling pruning (deleting) of old Reduce storage requirements by enabling pruning (deleting) of old
blocks. This allows the pruneblockchain RPC to be called to delete blocks. This allows the pruneblockchain RPC to be called to delete
specific blocks, and enables automatic pruning of old blocks if a specific blocks, and enables automatic pruning of old blocks if a
target size in MiB is provided. This mode is incompatible with -txindex target size in MiB is provided. This mode is incompatible with -txindex
and -rescan. Warning: Reverting this setting requires re-downloading and -rescan. Warning: Reverting this setting requires re-downloading
the entire blockchain. (`disable` = disable pruning blocks, `manual` the entire blockchain. ("disable" = disable pruning blocks, "manual"
= allow manual pruning via RPC, >=550 = automatically prune block files = allow manual pruning via RPC, >=550 = automatically prune block files
to stay under the specified target size in MiB) to stay under the specified target size in MiB)
''; '';
@ -129,34 +129,34 @@ let
validatepegin = mkOption { validatepegin = mkOption {
type = types.nullOr types.bool; type = types.nullOr types.bool;
default = null; default = null;
description = mdDoc '' description = ''
Validate pegin claims. All functionaries must run this. Validate pegin claims. All functionaries must run this.
''; '';
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "liquid"; default = "liquid";
description = mdDoc "The user as which to run liquidd."; description = "The user as which to run liquidd.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = mdDoc "The group as which to run liquidd."; description = "The group as which to run liquidd.";
}; };
cli = mkOption { cli = mkOption {
readOnly = true; readOnly = true;
default = pkgs.writers.writeBashBin "elements-cli" '' default = pkgs.writeScriptBin "elements-cli" ''
${nbPkgs.elementsd}/bin/elements-cli -datadir='${cfg.dataDir}' "$@" ${nbPkgs.elementsd}/bin/elements-cli -datadir='${cfg.dataDir}' "$@"
''; '';
defaultText = "(See source)"; defaultText = "(See source)";
description = mdDoc "Binary to connect with the liquidd instance."; description = "Binary to connect with the liquidd instance.";
}; };
swapCli = mkOption { swapCli = mkOption {
default = pkgs.writers.writeBashBin "liquidswap-cli" '' default = pkgs.writeScriptBin "liquidswap-cli" ''
${nbPkgs.liquid-swap}/bin/liquidswap-cli -c '${cfg.dataDir}/elements.conf' "$@" ${nbPkgs.liquid-swap}/bin/liquidswap-cli -c '${cfg.dataDir}/elements.conf' "$@"
''; '';
defaultText = "(See source)"; defaultText = "(See source)";
description = mdDoc "Binary for managing liquid swaps."; description = "Binary for managing liquid swaps.";
}; };
tor = nbLib.tor; tor = nbLib.tor;
}; };
@ -215,16 +215,16 @@ let
name = mkOption { name = mkOption {
type = types.str; type = types.str;
example = "alice"; example = "alice";
description = mdDoc '' description = ''
Username for JSON-RPC connections. Username for JSON-RPC connections.
''; '';
}; };
passwordHMAC = mkOption { passwordHMAC = mkOption {
type = with types; uniq (strMatching "[0-9a-f]+\\$[0-9a-f]{64}"); type = with types; uniq (strMatching "[0-9a-f]+\\$[0-9a-f]{64}");
example = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae"; example = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae";
description = mdDoc '' description = ''
Password HMAC-SHA-256 for JSON-RPC connections. Must be a string of the Password HMAC-SHA-256 for JSON-RPC connections. Must be a string of the
format `<SALT-HEX>$<HMAC-HEX>`. format `salt-hex$hmac-hex`.
''; '';
}; };
}; };
@ -270,8 +270,8 @@ in {
NotifyAccess = "all"; NotifyAccess = "all";
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
TimeoutStartSec = "2h"; TimeoutStartSec = "10min";
TimeoutStopSec = "2h"; TimeoutStopSec = "10min";
ExecStart = "${nbPkgs.elementsd}/bin/elementsd -datadir='${cfg.dataDir}'"; ExecStart = "${nbPkgs.elementsd}/bin/elementsd -datadir='${cfg.dataDir}'";
Restart = "on-failure"; Restart = "on-failure";
ReadWritePaths = [ cfg.dataDir ]; ReadWritePaths = [ cfg.dataDir ];

View File

@ -7,47 +7,47 @@ let
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "localhost"; default = "localhost";
description = mdDoc "Address to listen for peer connections"; description = "Address to listen for peer connections";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 9735; default = 9735;
description = mdDoc "Port to listen for peer connections"; description = "Port to listen for peer connections";
}; };
rpcAddress = mkOption { rpcAddress = mkOption {
type = types.str; type = types.str;
default = "localhost"; default = "localhost";
description = mdDoc "Address to listen for RPC connections."; description = "Address to listen for RPC connections.";
}; };
rpcPort = mkOption { rpcPort = mkOption {
type = types.port; type = types.port;
default = 10009; default = 10009;
description = mdDoc "Port to listen for gRPC connections."; description = "Port to listen for gRPC connections.";
}; };
restAddress = mkOption { restAddress = mkOption {
type = types.str; type = types.str;
default = "localhost"; default = "localhost";
description = mdDoc "Address to listen for REST connections."; description = "Address to listen for REST connections.";
}; };
restPort = mkOption { restPort = mkOption {
type = types.port; type = types.port;
default = 8080; default = 8080;
description = mdDoc "Port to listen for REST connections."; description = "Port to listen for REST connections.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/lnd"; default = "/var/lib/lnd";
description = mdDoc "The data directory for LND."; description = "The data directory for LND.";
}; };
networkDir = mkOption { networkDir = mkOption {
readOnly = true; readOnly = true;
default = "${cfg.dataDir}/chain/bitcoin/${bitcoind.network}"; default = "${cfg.dataDir}/chain/bitcoin/${bitcoind.network}";
description = mdDoc "The network data directory."; description = "The network data directory.";
}; };
tor-socks = mkOption { tor-socks = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null; default = if cfg.tor.proxy then config.nix-bitcoin.torClientAddressWithPort else null;
description = mdDoc "Socks proxy for connecting to Tor nodes"; description = "Socks proxy for connecting to Tor nodes";
}; };
macaroons = mkOption { macaroons = mkOption {
default = {}; default = {};
@ -55,18 +55,18 @@ let
options = { options = {
user = mkOption { user = mkOption {
type = types.str; type = types.str;
description = mdDoc "User who owns the macaroon."; description = "User who owns the macaroon.";
}; };
permissions = mkOption { permissions = mkOption {
type = types.str; type = types.str;
example = '' example = ''
{"entity":"info","action":"read"},{"entity":"onchain","action":"read"} {"entity":"info","action":"read"},{"entity":"onchain","action":"read"}
''; '';
description = mdDoc "List of granted macaroon permissions."; description = "List of granted macaroon permissions.";
}; };
}; };
}); });
description = mdDoc '' description = ''
Extra macaroon definitions. Extra macaroon definitions.
''; '';
}; };
@ -75,18 +75,18 @@ let
type = with types; listOf str; type = with types; listOf str;
default = []; default = [];
example = [ "60.100.0.1" ]; example = [ "60.100.0.1" ];
description = mdDoc '' description = ''
Extra `subjectAltName` IPs added to the certificate. Extra `subjectAltName` IPs added to the certificate.
This works the same as lnd option {option}`tlsextraip`. This works the same as lnd option `tlsextraip`.
''; '';
}; };
extraDomains = mkOption { extraDomains = mkOption {
type = with types; listOf str; type = with types; listOf str;
default = []; default = [];
example = [ "example.com" ]; example = [ "example.com" ];
description = mdDoc '' description = ''
Extra `subjectAltName` domain names added to the certificate. Extra `subjectAltName` domain names added to the certificate.
This works the same as lnd option {option}`tlsextradomain`. This works the same as lnd option `tlsextradomain`.
''; '';
}; };
}; };
@ -96,8 +96,8 @@ let
example = '' example = ''
autopilot.active=1 autopilot.active=1
''; '';
description = mdDoc '' description = ''
Extra lines appended to {file}`lnd.conf`. Extra lines appended to `lnd.conf`.
See here for all available options: See here for all available options:
https://github.com/lightningnetwork/lnd/blob/master/sample-lnd.conf https://github.com/lightningnetwork/lnd/blob/master/sample-lnd.conf
''; '';
@ -106,10 +106,10 @@ let
type = types.package; type = types.package;
default = config.nix-bitcoin.pkgs.lnd; default = config.nix-bitcoin.pkgs.lnd;
defaultText = "config.nix-bitcoin.pkgs.lnd"; defaultText = "config.nix-bitcoin.pkgs.lnd";
description = mdDoc "The package providing lnd binaries."; description = "The package providing lnd binaries.";
}; };
cli = mkOption { cli = mkOption {
default = pkgs.writers.writeBashBin "lncli" default = pkgs.writeScriptBin "lncli"
# Switch user because lnd makes datadir contents readable by user only # Switch user because lnd makes datadir contents readable by user only
'' ''
${runAsUser} ${cfg.user} ${cfg.package}/bin/lncli \ ${runAsUser} ${cfg.user} ${cfg.package}/bin/lncli \
@ -118,12 +118,12 @@ let
--macaroonpath '${networkDir}/admin.macaroon' "$@" --macaroonpath '${networkDir}/admin.macaroon' "$@"
''; '';
defaultText = "(See source)"; defaultText = "(See source)";
description = mdDoc "Binary to connect with the lnd instance."; description = "Binary to connect with the lnd instance.";
}; };
getPublicAddressCmd = mkOption { getPublicAddressCmd = mkOption {
type = types.str; type = types.str;
default = ""; default = "";
description = mdDoc '' description = ''
Bash expression which outputs the public service address to announce to peers. Bash expression which outputs the public service address to announce to peers.
If left empty, no address is announced. If left empty, no address is announced.
''; '';
@ -131,17 +131,17 @@ let
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "lnd"; default = "lnd";
description = mdDoc "The user as which to run LND."; description = "The user as which to run LND.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = mdDoc "The group as which to run LND."; description = "The group as which to run LND.";
}; };
certPath = mkOption { certPath = mkOption {
readOnly = true; readOnly = true;
default = "${secretsDir}/lnd-cert"; default = "${secretsDir}/lnd-cert";
description = mdDoc "LND TLS certificate path."; description = "LND TLS certificate path.";
}; };
tor = nbLib.tor; tor = nbLib.tor;
}; };
@ -174,26 +174,19 @@ let
${optionalString (cfg.tor-socks != null) "tor.socks=${cfg.tor-socks}"} ${optionalString (cfg.tor-socks != null) "tor.socks=${cfg.tor-socks}"}
bitcoind.rpchost=${bitcoindRpcAddress}:${toString bitcoind.rpc.port} bitcoind.rpchost=${bitcoindRpcAddress}:${toString bitcoind.rpc.port}
bitcoind.rpcuser=${bitcoind.rpc.users.${rpcUser}.name} bitcoind.rpcuser=${bitcoind.rpc.users.public.name}
bitcoind.zmqpubrawblock=${zmqHandleSpecialAddress bitcoind.zmqpubrawblock} bitcoind.zmqpubrawblock=${bitcoind.zmqpubrawblock}
bitcoind.zmqpubrawtx=${zmqHandleSpecialAddress bitcoind.zmqpubrawtx} bitcoind.zmqpubrawtx=${bitcoind.zmqpubrawtx}
wallet-unlock-password-file=${secretsDir}/lnd-wallet-password wallet-unlock-password-file=${secretsDir}/lnd-wallet-password
${cfg.extraConfig} ${cfg.extraConfig}
''; '';
zmqHandleSpecialAddress = builtins.replaceStrings [ "0.0.0.0" "[::]" ] [ "127.0.0.1" "[::1]" ];
isPruned = bitcoind.prune > 0;
# When bitcoind pruning is enabled, lnd requires non-public RPC commands `getpeerinfo`, `getnodeaddresses`
# to fetch missing blocks from peers (implemented in btcsuite/btcwallet/chain/pruned_block_dispatcher.go)
rpcUser = if isPruned then "lnd" else "public";
in { in {
inherit options; inherit options;
config = mkIf cfg.enable (mkMerge [ { config = mkIf cfg.enable {
assertions = [ assertions = [
{ assertion = { assertion =
!(config.services ? clightning) !(config.services ? clightning)
@ -214,8 +207,8 @@ in {
# under high bitcoind rpc load # under high bitcoind rpc load
rpc.threads = 16; rpc.threads = 16;
zmqpubrawblock = mkDefault "tcp://${bitcoindRpcAddress}:28332"; zmqpubrawblock = "tcp://${bitcoindRpcAddress}:28332";
zmqpubrawtx = mkDefault "tcp://${bitcoindRpcAddress}:28333"; zmqpubrawtx = "tcp://${bitcoindRpcAddress}:28333";
}; };
environment.systemPackages = [ cfg.package (hiPrio cfg.cli) ]; environment.systemPackages = [ cfg.package (hiPrio cfg.cli) ];
@ -233,7 +226,7 @@ in {
preStart = '' preStart = ''
install -m600 ${configFile} '${cfg.dataDir}/lnd.conf' install -m600 ${configFile} '${cfg.dataDir}/lnd.conf'
{ {
echo "bitcoind.rpcpass=$(cat ${secretsDir}/bitcoin-rpcpassword-${rpcUser})" echo "bitcoind.rpcpass=$(cat ${secretsDir}/bitcoin-rpcpassword-public)"
${optionalString (cfg.getPublicAddressCmd != "") '' ${optionalString (cfg.getPublicAddressCmd != "") ''
echo "externalip=$(${cfg.getPublicAddressCmd})" echo "externalip=$(${cfg.getPublicAddressCmd})"
''} ''}
@ -311,22 +304,5 @@ in {
makePasswordSecret lnd-wallet-password makePasswordSecret lnd-wallet-password
makeCert lnd '${nbLib.mkCertExtraAltNames cfg.certificate}' makeCert lnd '${nbLib.mkCertExtraAltNames cfg.certificate}'
''; '';
} };
(mkIf isPruned {
services.bitcoind.rpc.users.lnd = {
passwordHMACFromFile = true;
rpcwhitelist = bitcoind.rpc.users.public.rpcwhitelist ++ [
"getpeerinfo"
"getnodeaddresses"
];
};
nix-bitcoin.secrets = {
bitcoin-rpcpassword-lnd.user = cfg.user;
bitcoin-HMAC-lnd.user = bitcoind.user;
};
nix-bitcoin.generateSecretsCmds.lndBitcoinRPC = ''
makeBitcoinRPCPassword lnd
'';
}) ]);
} }

View File

@ -0,0 +1,126 @@
{ config, lib, pkgs, ... }:
with lib;
let
options = {
services.lnd.lndconnectOnion.enable = mkOption {
type = types.bool;
default = false;
description = ''
Create an onion service for the lnd REST server.
Add a `lndconnect-onion` binary to the system environment.
See: https://github.com/LN-Zap/lndconnect
Usage:
```
# Print QR code
lndconnect-onion
# Print URL
lndconnect-onion --url
```
'';
};
services.clightning-rest.lndconnectOnion.enable = mkOption {
type = types.bool;
default = false;
description = ''
Create an onion service for clightning-rest.
Add a `lndconnect-onion-clightning` binary to the system environment.
See: https://github.com/LN-Zap/lndconnect
Usage:
```
# Print QR code
lndconnect-onion-clightning
# Print URL
lndconnect-onion-clightning --url
```
'';
};
};
nbLib = config.nix-bitcoin.lib;
runAsUser = config.nix-bitcoin.runAsUserCmd;
inherit (config.services)
lnd
clightning
clightning-rest;
mkLndconnect = {
name,
shebang ? "#!${pkgs.stdenv.shell} -e",
onionService,
port,
certPath,
macaroonPath
}:
# TODO-EXTERNAL:
# lndconnect requires a --configfile argument, although it's unused
# https://github.com/LN-Zap/lndconnect/issues/25
pkgs.writeScriptBin name ''
${shebang}
exec ${config.nix-bitcoin.pkgs.lndconnect}/bin/lndconnect \
--host=$(cat ${config.nix-bitcoin.onionAddresses.dataDir}/${onionService}) \
--port=${toString port} \
--tlscertpath='${certPath}' \
--adminmacaroonpath='${macaroonPath}' \
--configfile=/dev/null "$@"
'';
operatorName = config.nix-bitcoin.operator.name;
in {
inherit options;
config = mkMerge [
(mkIf (lnd.enable && lnd.lndconnectOnion.enable) {
services.tor = {
enable = true;
relay.onionServices.lnd-rest = nbLib.mkOnionService {
target.addr = nbLib.address lnd.restAddress;
target.port = lnd.restPort;
port = lnd.restPort;
};
};
nix-bitcoin.onionAddresses.access.${lnd.user} = [ "lnd-rest" ];
environment.systemPackages = [(
mkLndconnect {
name = "lndconnect-onion";
# Run as lnd user because the macaroon and cert are not group-readable
shebang = "#!/usr/bin/env -S ${runAsUser} ${lnd.user} ${pkgs.bash}/bin/bash";
onionService = "${lnd.user}/lnd-rest";
port = lnd.restPort;
certPath = lnd.certPath;
macaroonPath = "${lnd.networkDir}/admin.macaroon";
}
)];
})
(mkIf (clightning-rest.enable && clightning-rest.lndconnectOnion.enable) {
services.tor = {
enable = true;
relay.onionServices.clightning-rest = nbLib.mkOnionService {
target.addr = nbLib.address clightning-rest.address;
target.port = clightning-rest.port;
port = clightning-rest.port;
};
};
# This also allows nodeinfo to show the clightning-rest onion address
nix-bitcoin.onionAddresses.access.${operatorName} = [ "clightning-rest" ];
environment.systemPackages = [(
mkLndconnect {
name = "lndconnect-onion-clightning";
onionService = "${operatorName}/clightning-rest";
port = clightning-rest.port;
certPath = "${clightning-rest.dataDir}/certs/certificate.pem";
macaroonPath = "${clightning-rest.dataDir}/certs/access.macaroon";
}
)];
})
];
}

View File

@ -1,205 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
options = {
services.lnd.lndconnect = {
enable = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
Add a `lndconnect` binary to the system environment which prints
connection info for lnd clients.
See: https://github.com/LN-Zap/lndconnect
Usage:
```bash
# Print QR code
lndconnect
# Print URL
lndconnect --url
```
'';
};
onion = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
Create an onion service for the lnd REST server,
which is used by lndconnect.
'';
};
};
services.clightning-rest.lndconnect = {
enable = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
Add a `lndconnect-clightning` binary to the system environment which prints
connection info for clightning clients.
See: https://github.com/LN-Zap/lndconnect
Usage:
```bash
# Print QR code
lndconnect-clightning
# Print URL
lndconnect-clightning --url
```
'';
};
onion = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
Create an onion service for the clightning REST server,
which is used by lndconnect.
'';
};
};
nix-bitcoin.mkLndconnect = mkOption {
readOnly = true;
default = mkLndconnect;
description = mdDoc ''
A function to create a lndconnect binary.
See the source for further details.
'';
};
};
nbLib = config.nix-bitcoin.lib;
runAsUser = config.nix-bitcoin.runAsUserCmd;
inherit (config.services)
lnd
clightning-rest;
mkLndconnect = {
name,
shebang ? "#!${pkgs.stdenv.shell} -e",
isClightning ? false,
port,
macaroonPath,
enableOnion,
onionService ? null,
certPath ? null
}:
# TODO-EXTERNAL:
# lndconnect requires a --configfile argument, although it's unused
# https://github.com/LN-Zap/lndconnect/issues/25
pkgs.hiPrio (pkgs.writeScriptBin name ''
${shebang}
url=$(
${getExe config.nix-bitcoin.pkgs.lndconnect} --url \
${optionalString enableOnion "--host=$(cat ${config.nix-bitcoin.onionAddresses.dataDir}/${onionService})"} \
--port=${toString port} \
${if enableOnion || certPath == null then "--nocert" else "--tlscertpath='${certPath}'"} \
--adminmacaroonpath='${macaroonPath}' \
--configfile=/dev/null "$@"
)
${optionalString isClightning
# - Change URL procotcol to c-lightning-rest
# - Encode macaroon as hex (in uppercase) instead of base 64.
# Because `macaroon` is always the last URL fragment, the
# sed replacement below works correctly.
''
macaroonHex=$(${getExe pkgs.xxd} -p -u -c 99999 '${macaroonPath}')
url=$(
echo "$url" | ${getExe pkgs.gnused} "
s|^lndconnect|c-lightning-rest|
s|macaroon=.*|macaroon=$macaroonHex|
";
)
''
}
# If --url is in args
if [[ " $* " =~ " --url " ]]; then
echo "$url"
else
# This UTF-8 encoding yields a smaller, more convenient output format
# compared to the native lndconnect output
echo -n "$url" | ${getExe pkgs.qrencode} -t UTF8 -o -
fi
'');
operatorName = config.nix-bitcoin.operator.name;
in {
inherit options;
config = mkMerge [
(mkIf (lnd.enable && lnd.lndconnect.enable)
(mkMerge [
{
environment.systemPackages = [(
mkLndconnect {
name = "lndconnect";
# Run as lnd user because the macaroon and cert are not group-readable
shebang = "#!/usr/bin/env -S ${runAsUser} ${lnd.user} ${pkgs.bash}/bin/bash";
enableOnion = lnd.lndconnect.onion;
onionService = "${lnd.user}/lnd-rest";
port = lnd.restPort;
certPath = lnd.certPath;
macaroonPath = "${lnd.networkDir}/admin.macaroon";
}
)];
services.lnd.restAddress = mkIf (!lnd.lndconnect.onion) "0.0.0.0";
}
(mkIf lnd.lndconnect.onion {
services.tor = {
enable = true;
relay.onionServices.lnd-rest = nbLib.mkOnionService {
target.addr = nbLib.address lnd.restAddress;
target.port = lnd.restPort;
port = lnd.restPort;
};
};
nix-bitcoin.onionAddresses.access = {
${lnd.user} = [ "lnd-rest" ];
${operatorName} = [ "lnd-rest" ];
};
})
]))
(mkIf (clightning-rest.enable && clightning-rest.lndconnect.enable)
(mkMerge [
{
environment.systemPackages = [(
mkLndconnect {
name = "lndconnect-clightning";
isClightning = true;
enableOnion = clightning-rest.lndconnect.onion;
onionService = "${operatorName}/clightning-rest";
port = clightning-rest.port;
certPath = "${clightning-rest.dataDir}/certs/certificate.pem";
macaroonPath = "${clightning-rest.dataDir}/certs/access.macaroon";
}
)];
# clightning-rest always binds to all interfaces
}
(mkIf clightning-rest.lndconnect.onion {
services.tor = {
enable = true;
relay.onionServices.clightning-rest = nbLib.mkOnionService {
target.addr = nbLib.address clightning-rest.address;
target.port = clightning-rest.port;
port = clightning-rest.port;
};
};
# This also allows nodeinfo to show the clightning-rest onion address
nix-bitcoin.onionAddresses.access.${operatorName} = [ "clightning-rest" ];
})
])
)
];
}

View File

@ -19,7 +19,7 @@
./lightning-loop.nix ./lightning-loop.nix
./lightning-pool.nix ./lightning-pool.nix
./charge-lnd.nix ./charge-lnd.nix
./lndconnect.nix # Requires onion-addresses.nix ./lndconnect-onion.nix # Requires onion-addresses.nix
./rtl.nix ./rtl.nix
./electrs.nix ./electrs.nix
./fulcrum.nix ./fulcrum.nix

View File

@ -8,7 +8,7 @@ let
addressblock = mkOption { addressblock = mkOption {
type = types.ints.u8; type = types.ints.u8;
default = 1; default = 1;
description = mdDoc '' description = ''
The address block N in 169.254.N.0/24, used as the prefix for netns addresses. The address block N in 169.254.N.0/24, used as the prefix for netns addresses.
''; '';
}; };
@ -20,7 +20,7 @@ let
id = mkOption { id = mkOption {
# TODO: Assert uniqueness # TODO: Assert uniqueness
type = types.ints.between 11 255; type = types.ints.between 11 255;
description = mdDoc '' description = ''
id for the netns, used for the IP address host part and id for the netns, used for the IP address host part and
for naming the interfaces. Must be unique. Must be greater than 10. for naming the interfaces. Must be unique. Must be greater than 10.
''; '';
@ -35,7 +35,7 @@ let
allowedUser = mkOption { allowedUser = mkOption {
type = types.str; type = types.str;
description = mdDoc '' description = ''
User that is allowed to execute commands in the service network namespaces. User that is allowed to execute commands in the service network namespaces.
The user's group is also authorized. The user's group is also authorized.
''; '';
@ -45,13 +45,13 @@ let
netns = mkOption { netns = mkOption {
readOnly = true; readOnly = true;
default = netns; default = netns;
description = mdDoc "Exposes netns parameters."; description = "Exposes netns parameters.";
}; };
bridgeIp = mkOption { bridgeIp = mkOption {
readOnly = true; readOnly = true;
default = bridgeIp; default = bridgeIp;
description = mdDoc "IP of the netns bridge interface."; description = "IP of the netns bridge interface.";
}; };
}; };
@ -215,11 +215,9 @@ in {
}; };
}; };
in in foldl (services: n:
foldl (services: n: services // (makeNetnsServices n netns.${n})
services // (makeNetnsServices n netns.${n}) ) {} (builtins.attrNames netns));
) {} (builtins.attrNames netns)
);
} }
# Service-specific config # Service-specific config
@ -299,7 +297,6 @@ in {
id = 31; id = 31;
connections = [ "bitcoind" ]; connections = [ "bitcoind" ];
}; };
# id = 32 reserved for the upcoming mempool module
}; };
services.bitcoind = { services.bitcoind = {

View File

@ -1,4 +1,4 @@
{ config, options, pkgs, lib, ... }: { config, pkgs, lib, ... }:
with lib; with lib;
{ {
@ -8,23 +8,11 @@ with lib;
type = types.attrs; type = types.attrs;
default = (import ../pkgs { inherit pkgs; }).modulesPkgs; default = (import ../pkgs { inherit pkgs; }).modulesPkgs;
defaultText = "nix-bitcoin/pkgs.modulesPkgs"; defaultText = "nix-bitcoin/pkgs.modulesPkgs";
apply = base:
let
final = foldl (prev: overlay:
prev // (overlay prev final)
) base options.nix-bitcoin.pkgOverlays.definitions;
in
final;
};
pkgOverlays = mkOption {
internal = true;
type = with types; functionTo attrs;
}; };
lib = mkOption { lib = mkOption {
readOnly = true; readOnly = true;
default = import ../pkgs/lib.nix lib pkgs config; default = import ../pkgs/lib.nix lib pkgs;
defaultText = "nix-bitcoin/pkgs/lib.nix"; defaultText = "nix-bitcoin/pkgs/lib.nix";
}; };
@ -39,7 +27,7 @@ with lib;
# Related issue: https://github.com/NixOS/nixpkgs/issues/94236 # Related issue: https://github.com/NixOS/nixpkgs/issues/94236
torify = mkOption { torify = mkOption {
readOnly = true; readOnly = true;
default = pkgs.writers.writeBashBin "torify" '' default = pkgs.writeScriptBin "torify" ''
${pkgs.tor}/bin/torify \ ${pkgs.tor}/bin/torify \
--address ${config.services.tor.client.socksListenAddress.addr} \ --address ${config.services.tor.client.socksListenAddress.addr} \
"$@" "$@"
@ -51,7 +39,8 @@ with lib;
runAsUserCmd = mkOption { runAsUserCmd = mkOption {
readOnly = true; readOnly = true;
default = if config.security.doas.enable default = if config.security.doas.enable
then "doas -u" # TODO-EXTERNAL: Use absolute path until https://github.com/NixOS/nixpkgs/pull/133622 is available.
then "/run/wrappers/bin/doas -u"
else "sudo -u"; else "sudo -u";
defaultText = "(See source)"; defaultText = "(See source)";
}; };

View File

@ -17,17 +17,17 @@ let
type = types.attrs; type = types.attrs;
default = {}; default = {};
defaultText = "(See source)"; defaultText = "(See source)";
description = mdDoc '' description = ''
Nodeinfo service definitions. Nodeinfo service definitions.
''; '';
}; };
lib = mkOption { nodeinfoLib = mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
default = nodeinfoLib; default = nodeinfoLib;
defaultText = "(See source)"; defaultText = "(See source)";
description = mdDoc '' description = ''
Helper functions for defining nodeinfo services. Helper functions for defining nodeinfo services.
''; '';
}; };
@ -63,7 +63,7 @@ let
infos = OrderedDict() infos = OrderedDict()
operator = "${config.nix-bitcoin.operator.name}" operator = "${config.nix-bitcoin.operator.name}"
def get_onion_address(name, port): def set_onion_address(info, name, port):
path = f"/var/lib/onion-addresses/{operator}/{name}" path = f"/var/lib/onion-addresses/{operator}/{name}"
try: try:
with open(path, "r") as f: with open(path, "r") as f:
@ -71,12 +71,11 @@ let
except OSError: except OSError:
print(f"error reading file {path}", file=sys.stderr) print(f"error reading file {path}", file=sys.stderr)
return return
return f"{onion_address}:{port}" info["onion_address"] = f"{onion_address}:{port}"
def add_service(service, make_info, systemd_service = None): def add_service(service, make_info):
systemd_service = systemd_service or service if not is_active(service):
if not is_active(systemd_service): infos[service] = "service is not running"
infos[service] = f"'{systemd_service}.service' is not running"
else: else:
info = OrderedDict() info = OrderedDict()
exec(make_info, globals(), locals()) exec(make_info, globals(), locals())
@ -97,19 +96,14 @@ let
) (builtins.attrNames cfg.services); ) (builtins.attrNames cfg.services);
nodeinfoLib = rec { nodeinfoLib = rec {
mkInfo = extraCode: name: cfg: mkInfo = extraCode: name: cfg: ''
mkInfoLong {
inherit extraCode name cfg;
};
mkInfoLong = { extraCode ? "", name, cfg, systemdServiceName ? name }: ''
add_service("${name}", """ add_service("${name}", """
info["local_address"] = "${nbLib.addressWithPort cfg.address cfg.port}" info["local_address"] = "${nbLib.addressWithPort cfg.address cfg.port}"
'' + mkIfOnionPort name (onionPort: '' '' + mkIfOnionPort name (onionPort: ''
info["onion_address"] = get_onion_address("${name}", ${onionPort}) set_onion_address(info, "${name}", ${onionPort})
'') + extraCode + '' '') + extraCode + ''
""", "${systemdServiceName}") """)
''; '';
mkIfOnionPort = name: fn: mkIfOnionPort = name: fn:
@ -123,10 +117,8 @@ let
in { in {
inherit options; inherit options;
config = mkIf cfg.enable { config = {
environment.systemPackages = [ script ]; environment.systemPackages = optional cfg.enable script;
nix-bitcoin.operator.enable = true;
nix-bitcoin.nodeinfo.services = with nodeinfoLib; { nix-bitcoin.nodeinfo.services = with nodeinfoLib; {
bitcoind = mkInfo ""; bitcoind = mkInfo "";
@ -135,13 +127,9 @@ in {
if 'onion_address' in info: if 'onion_address' in info:
info["id"] = f"{info['nodeid']}@{info['onion_address']}" info["id"] = f"{info['nodeid']}@{info['onion_address']}"
''; '';
lnd = name: cfg: mkInfo ('' lnd = mkInfo ''
info["rest_address"] = "${nbLib.addressWithPort cfg.restAddress cfg.restPort}"
'' + mkIfOnionPort "lnd-rest" (onionPort: ''
info["onion_rest_address"] = get_onion_address("lnd-rest", ${onionPort})
'') + ''
info["nodeid"] = shell("lncli getinfo | jq -r '.identity_pubkey'") info["nodeid"] = shell("lncli getinfo | jq -r '.identity_pubkey'")
'') name cfg; '';
clightning-rest = mkInfo ""; clightning-rest = mkInfo "";
electrs = mkInfo ""; electrs = mkInfo "";
fulcrum = mkInfo ""; fulcrum = mkInfo "";
@ -152,7 +140,7 @@ in {
rtl = mkInfo ""; rtl = mkInfo "";
# Only add sshd when it has an onion service # Only add sshd when it has an onion service
sshd = name: cfg: mkIfOnionPort "sshd" (onionPort: '' sshd = name: cfg: mkIfOnionPort "sshd" (onionPort: ''
add_service("sshd", """info["onion_address"] = get_onion_address("sshd", ${onionPort})""") add_service("sshd", """set_onion_address(info, "sshd", ${onionPort})""")
''); '');
}; };
}; };

View File

@ -33,6 +33,7 @@ in {
(mkRenamedOptionModule [ "services" "liquidd" "rpcbind" ] [ "services" "liquidd" "rpc" "address" ]) (mkRenamedOptionModule [ "services" "liquidd" "rpcbind" ] [ "services" "liquidd" "rpc" "address" ])
# 0.0.70 # 0.0.70
(mkRenamedOptionModule [ "services" "rtl" "cl-rest" ] [ "services" "clightning-rest" ]) (mkRenamedOptionModule [ "services" "rtl" "cl-rest" ] [ "services" "clightning-rest" ])
(mkRenamedOptionModule [ "services" "lnd" "restOnionService" "enable" ] [ "services" "lnd" "lndconnectOnion" "enable" ])
(mkRenamedOptionModule [ "nix-bitcoin" "setup-secrets" ] [ "nix-bitcoin" "setupSecrets" ]) (mkRenamedOptionModule [ "nix-bitcoin" "setup-secrets" ] [ "nix-bitcoin" "setupSecrets" ])
@ -45,28 +46,6 @@ in {
bitcoin peer connections for syncing blocks. This performs well on low and high bitcoin peer connections for syncing blocks. This performs well on low and high
memory systems. memory systems.
'') '')
# 0.0.86
(mkRemovedOptionModule [ "services" "lnd" "restOnionService" "enable" ] ''
Set the following options instead:
services.lnd.lndconnect = {
enable = true;
onion = true;
}
'')
(mkRemovedOptionModule [ "services" "lnd" "lndconnectOnion" ] ''
Set the following options instead:
services.lnd.lndconnect = {
enable = true;
onion = true;
}
'')
(mkRemovedOptionModule [ "services" "clightning-rest" "lndconnectOnion" ] ''
Set the following options instead:
services.clightning-rest.lndconnect = {
enable = true;
onion = true;
}
'')
] ++ ] ++
# 0.0.59 # 0.0.59
(map mkSplitEnforceTorOption [ (map mkSplitEnforceTorOption [

View File

@ -12,25 +12,23 @@ let
access = mkOption { access = mkOption {
type = with types; attrsOf (listOf str); type = with types; attrsOf (listOf str);
default = {}; default = {};
description = mdDoc '' description = ''
This option controls who is allowed to access onion addresses. This option controls who is allowed to access onion addresses.
For example, the following allows user 'myuser' to access bitcoind For example, the following allows user 'myuser' to access bitcoind
and clightning onion addresses: and clightning onion addresses:
```nix
{ {
"myuser" = [ "bitcoind" "clightning" ]; "myuser" = [ "bitcoind" "clightning" ];
}; };
```
The onion hostnames can then be read from The onion hostnames can then be read from
{file}`/var/lib/onion-addresses/myuser`. /var/lib/onion-addresses/myuser.
''; '';
}; };
services = mkOption { services = mkOption {
type = with types; listOf str; type = with types; listOf str;
default = []; default = [];
description = mdDoc '' description = ''
Services that can access their onion address via file Services that can access their onion address via file
{file}`/var/lib/onion-addresses/<service>` `/var/lib/onion-addresses/$service`
The file is readable only by the service user. The file is readable only by the service user.
''; '';
}; };
@ -55,8 +53,8 @@ in {
RemainAfterExit = true; RemainAfterExit = true;
StateDirectory = "onion-addresses"; StateDirectory = "onion-addresses";
StateDirectoryMode = "771"; StateDirectoryMode = "771";
PrivateNetwork = true; # This service needs no network access PrivateNetwork = "true"; # This service needs no network access
PrivateUsers = false; PrivateUsers = "false";
CapabilityBoundingSet = "CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_IPC_OWNER"; CapabilityBoundingSet = "CAP_CHOWN CAP_FSETID CAP_SETFCAP CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER CAP_IPC_OWNER";
}; };
script = '' script = ''

View File

@ -16,24 +16,24 @@ let
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = config.public; default = config.public;
description = mdDoc '' description = ''
Create an onion service for the given service. Create an onion service for the given service.
The service must define options {option}'address' and {option}'onionPort' (or `port`). The service must define options 'address' and 'onionPort' (or `port`).
''; '';
}; };
public = mkOption { public = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Make the onion address accessible to the service. Make the onion address accessible to the service.
If enabled, the onion service is automatically enabled. If enabled, the onion service is automatically enabled.
Only available for services that define option {option}`getPublicAddressCmd`. Only available for services that define option `getPublicAddressCmd`.
''; '';
}; };
externalPort = mkOption { externalPort = mkOption {
type = types.nullOr types.port; type = types.nullOr types.port;
default = null; default = null;
description = mdDoc "Override the external port of the onion service."; description = "Override the external port of the onion service.";
}; };
}; };
} }

View File

@ -6,7 +6,7 @@ let
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Whether to define a user named `operator` for convenient interactive access Whether to define a user named `operator` for convenient interactive access
to nix-bitcoin features (like `bitcoin-cli`). to nix-bitcoin features (like `bitcoin-cli`).
@ -18,17 +18,17 @@ let
name = mkOption { name = mkOption {
type = types.str; type = types.str;
default = "operator"; default = "operator";
description = mdDoc "Name of the operator user."; description = "Name of the operator user.";
}; };
groups = mkOption { groups = mkOption {
type = with types; listOf str; type = with types; listOf str;
default = []; default = [];
description = mdDoc "Extra groups of the operatur user."; description = "Extra groups of the operatur user.";
}; };
allowRunAsUsers = mkOption { allowRunAsUsers = mkOption {
type = with types; listOf str; type = with types; listOf str;
default = []; default = [];
description = mdDoc "Users as which the operator is allowed to run commands."; description = "Users as which the operator is allowed to run commands.";
}; };
}; };

View File

@ -5,9 +5,7 @@ let
secretsDir = config.nix-bitcoin.secretsDir; secretsDir = config.nix-bitcoin.secretsDir;
in { in {
services.bitcoind = { services.bitcoind = {
# Make the local bitcoin-cli work with the remote node. # Make the local bitcoin-cli work with the remote node
# Without this, bitcoin-cli would try to use the .cookie file in the local
# bitcoind data dir for authorization, which doesn't exist.
extraConfig = '' extraConfig = ''
rpcuser=${cfg.rpc.users.privileged.name} rpcuser=${cfg.rpc.users.privileged.name}
''; '';

View File

@ -1,8 +1,7 @@
{ modulesPath, ... }: { {
imports = [ imports = [
# Source: # Source: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/hardened.nix
# https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/hardened.nix <nixpkgs/nixos/modules/profiles/hardened.nix>
(modulesPath + "/profiles/hardened.nix")
]; ];
## Reset some options set by the hardened profile ## Reset some options set by the hardened profile

View File

@ -1,214 +0,0 @@
{ config, pkgs, lib, ... }:
# Create a WireGuard server with a single peer.
# Private/public keys are created via the secrets system.
# Add helper binaries `nix-bitcoin-wg-connect` and optionally `lndconnect-wg`, `lndconnect-clightning-wg`.
# See ../../docs/services.md ("Use Zeus (mobile lightning wallet) via WireGuard")
# for usage instructions.
# This is a rather opinionated implementation that lacks the flexibility offered by
# other nix-bitcoin modules, so ship this as a `preset`.
# Some users will prefer to use `lndconnect` with their existing WireGuard or Tailscale setup.
with lib;
let
options.nix-bitcoin.wireguard = {
subnet = mkOption {
type = types.str;
default = "10.10.0";
description = mdDoc "The /24 subnet of the wireguard network.";
};
restrictPeer = mkOption {
type = types.bool;
default = true;
description = mdDoc ''
Prevent the peer from connecting to any addresses except for the WireGuard server address.
'';
};
};
cfg = config.nix-bitcoin.wireguard;
wgSubnet = cfg.subnet;
inherit (config.networking.wireguard.interfaces) wg-nb;
inherit (config.services)
lnd
clightning-rest;
lndconnect = lnd.enable && lnd.lndconnect.enable;
lndconnect-clightning = clightning-rest.enable && clightning-rest.lndconnect.enable;
serverAddress = "${wgSubnet}.1";
peerAddress = "${wgSubnet}.2";
secretsDir = config.nix-bitcoin.secretsDir;
wgConnectUser = if config.nix-bitcoin.operator.enable
then config.nix-bitcoin.operator.name
else "root";
# A script that prints a QR code to connect a peer to the server.
# The QR code encodes a wg-quick config that can be imported by the wireguard
# mobile app.
wgConnect = pkgs.writers.writeBashBin "nix-bitcoin-wg-connect" ''
set -euo pipefail
text=
host=
for arg in "$@"; do
case $arg in
--text)
text=1
;;
*)
host=$arg
;;
esac
done
if [[ ! $host ]]; then
# Use lndconnect to fetch the external ip.
# This internally uses https://github.com/GlenDC/go-external-ip, which
# queries a set of external ip providers.
host=$(
${getExe config.nix-bitcoin.pkgs.lndconnect} --url --nocert \
--configfile=/dev/null --adminmacaroonpath=/dev/null \
| sed -nE 's|.*?/(.*?):.*|\1|p'
)
fi
config="[Interface]
PrivateKey = $(cat ${secretsDir}/wg-peer-private-key)
Address = ${peerAddress}/24
[Peer]
PublicKey = $(cat ${secretsDir}/wg-server-public-key)
AllowedIPs = ${wgSubnet}.0/24
Endpoint = $host:${toString wg-nb.listenPort}
PersistentKeepalive = 25
"
if [[ $text ]]; then
echo "$config"
else
echo "$config" | ${getExe pkgs.qrencode} -t UTF8 -o -
fi
'';
in {
inherit options;
config = {
assertions = [
{
# Don't support `netns-isolation` for now to keep things simple
assertion = !(config.nix-bitcoin.netns-isolation.enable or false);
message = "`nix-bitcoin.wireguard` is not compatible with `netns-isolation`.";
}
];
networking.wireguard.interfaces.wg-nb = {
ips = [ "${serverAddress}/24" ];
listenPort = mkDefault 51820;
privateKeyFile = "${secretsDir}/wg-server-private-key";
allowedIPsAsRoutes = false;
peers = [
{
# To use the actual public key from the secrets file, use dummy pubkey
# `peer0` and replace it via `getPubkeyFromFile` (see further below)
# at peer service runtime.
publicKey = "peer0";
allowedIPs = [ "${peerAddress}/32" ];
}
];
};
systemd.services = {
wireguard-wg-nb = rec {
wants = [ "nix-bitcoin-secrets.target" ];
after = wants;
};
# HACK: Modify start/stop scripts of the peer setup service to read
# the pubkey from a secrets file.
wireguard-wg-nb-peer-peer0 = let
getPubkeyFromFile = mkBefore ''
if [[ ! -v inPatchedSrc ]]; then
export inPatchedSrc=1
publicKey=$(cat "${secretsDir}/wg-peer-public-key")
<"''${BASH_SOURCE[0]}" sed "s|\bpeer0\b|$publicKey|g" | ${pkgs.bash}/bin/bash -s
exit
fi
'';
in {
script = getPubkeyFromFile;
postStop = getPubkeyFromFile;
};
};
environment.systemPackages = [
wgConnect
] ++ (optional lndconnect
(pkgs.writers.writeBashBin "lndconnect-wg" ''
exec lndconnect --host "${serverAddress}" --nocert "$@"
'')
) ++ (optional lndconnect-clightning
(pkgs.writers.writeBashBin "lndconnect-clightning-wg" ''
exec lndconnect-clightning --host "${serverAddress}" --nocert "$@"
'')
);
networking.firewall = let
restrictPeerRule = "-s ${peerAddress} ! -d ${serverAddress} -j REJECT";
in {
allowedUDPPorts = [ wg-nb.listenPort ];
extraCommands =
optionalString lndconnect ''
iptables -w -A nixos-fw -p tcp -s ${wgSubnet}.0/24 --dport ${toString lnd.restPort} -j nixos-fw-accept
''
+ optionalString lndconnect-clightning ''
iptables -w -A nixos-fw -p tcp -s ${wgSubnet}.0/24 --dport ${toString clightning-rest.port} -j nixos-fw-accept
''
+ optionalString cfg.restrictPeer ''
iptables -w -A nixos-fw ${restrictPeerRule}
iptables -w -A FORWARD ${restrictPeerRule}
'';
extraStopCommands =
# Rules added to chain `nixos-fw` are automatically removed when restarting
# the NixOS firewall service.
mkIf cfg.restrictPeer ''
iptables -w -D FORWARD ${restrictPeerRule} || :
'';
};
# Listen on all addresses, including `serverAddress`.
# This is safe because the listen ports are secured by the firewall.
services.lnd.restAddress = mkIf lndconnect "0.0.0.0";
# clightning-rest always listens on "0.0.0.0"
nix-bitcoin.secrets = {
wg-server-private-key = {};
wg-server-public-key = { user = wgConnectUser; group = "root"; };
wg-peer-private-key = { user = wgConnectUser; group = "root"; };
wg-peer-public-key = {};
};
nix-bitcoin.generateSecretsCmds.wireguard = let
wg = "${pkgs.wireguard-tools}/bin/wg";
in ''
makeWireguardKey() {
local name=$1
local priv=wg-$name-private-key
local pub=wg-$name-public-key
if [[ ! -e $priv ]]; then
${wg} genkey > $priv
fi
if [[ $priv -nt $pub ]]; then
${wg} pubkey < $priv > $pub
fi
}
makeWireguardKey server
makeWireguardKey peer
'';
};
}

View File

@ -7,33 +7,33 @@ let
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = mdDoc "HTTP server address."; description = "HTTP server address.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 3000; default = 3000;
description = mdDoc "HTTP server port."; description = "HTTP server port.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/rtl"; default = "/var/lib/rtl";
description = mdDoc "The data directory for RTL."; description = "The data directory for RTL.";
}; };
nodes = { nodes = {
clightning = { clightning = {
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc "Enable the clightning node interface."; description = "Enable the clightning node interface.";
}; };
extraConfig = mkOption { extraConfig = mkOption {
type = with types; attrsOf anything; type = types.attrs;
default = {}; default = {};
example = { example = {
Settings.userPersona = "MERCHANT"; Settings.userPersona = "MERCHANT";
Settings.logLevel = "DEBUG"; Settings.logLevel = "DEBUG";
}; };
description = mdDoc '' description = ''
Extra clightning node configuration. Extra clightning node configuration.
See here for all available options: See here for all available options:
https://github.com/Ride-The-Lightning/RTL/blob/master/.github/docs/Application_configurations.md https://github.com/Ride-The-Lightning/RTL/blob/master/.github/docs/Application_configurations.md
@ -44,21 +44,21 @@ let
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc "Enable the lnd node interface."; description = "Enable the lnd node interface.";
}; };
loop = mkOption { loop = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc "Enable swaps with lightning-loop."; description = "Enable swaps with lightning-loop.";
}; };
extraConfig = mkOption { extraConfig = mkOption {
type = with types; attrsOf anything; type = types.attrs;
default = {}; default = {};
example = { example = {
Settings.userPersona = "MERCHANT"; Settings.userPersona = "MERCHANT";
Settings.logLevel = "DEBUG"; Settings.logLevel = "DEBUG";
}; };
description = mdDoc '' description = ''
Extra lnd node configuration. Extra lnd node configuration.
See here for all available options: See here for all available options:
https://github.com/Ride-The-Lightning/RTL/blob/master/.github/docs/Application_configurations.md https://github.com/Ride-The-Lightning/RTL/blob/master/.github/docs/Application_configurations.md
@ -68,7 +68,7 @@ let
reverseOrder = mkOption { reverseOrder = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Reverse the order of nodes shown in the UI. Reverse the order of nodes shown in the UI.
By default, clightning is shown before lnd. By default, clightning is shown before lnd.
''; '';
@ -77,28 +77,28 @@ let
nightTheme = mkOption { nightTheme = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc "Enable the Night UI Theme."; description = "Enable the Night UI Theme.";
}; };
extraCurrency = mkOption { extraCurrency = mkOption {
type = with types; nullOr str; type = with types; nullOr str;
default = null; default = null;
example = "USD"; example = "USD";
description = mdDoc '' description = ''
Currency code (ISO 4217) of the extra currency used for displaying balances. Currency code (ISO 4217) of the extra currency used for displaying balances.
When set, this option enables online currency rate fetching. When set, this option enables online currency rate fetching.
Warning: Rate fetching requires outgoing clearnet connections, so option Warning: Rate fetching requires outgoing clearnet connections, so option
{option}`tor.enforce` is automatically disabled. `tor.enforce` is automatically disabled.
''; '';
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "rtl"; default = "rtl";
description = mdDoc "The user as which to run RTL."; description = "The user as which to run RTL.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = mdDoc "The group as which to run RTL."; description = "The group as which to run RTL.";
}; };
tor.enforce = nbLib.tor.enforce; tor.enforce = nbLib.tor.enforce;
}; };
@ -191,7 +191,6 @@ in {
optional cfg.nodes.lnd.enable "lnd.service"; optional cfg.nodes.lnd.enable "lnd.service";
after = requires; after = requires;
environment.RTL_CONFIG_PATH = cfg.dataDir; environment.RTL_CONFIG_PATH = cfg.dataDir;
environment.DB_DIRECTORY_PATH = cfg.dataDir;
serviceConfig = nbLib.defaultHardening // { serviceConfig = nbLib.defaultHardening // {
ExecStartPre = [ ExecStartPre = [
(nbLib.script "rtl-setup-config" '' (nbLib.script "rtl-setup-config" ''

View File

@ -6,14 +6,14 @@ let
secretsDir = mkOption { secretsDir = mkOption {
type = types.path; type = types.path;
default = "/etc/nix-bitcoin-secrets"; default = "/etc/nix-bitcoin-secrets";
description = mdDoc "Directory to store secrets"; description = "Directory to store secrets";
}; };
setupSecrets = mkOption { setupSecrets = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Set permissions for existing secrets in {option}`nix-bitcoin.secretsDir` Set permissions for existing secrets in `nix-bitcoin.secretsDir`
before services are started. before services are started.
''; '';
}; };
@ -21,16 +21,16 @@ let
generateSecrets = mkOption { generateSecrets = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Automatically generate all required secrets before services are started. 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.
''; '';
}; };
generateSecretsCmds = mkOption { generateSecretsCmds = mkOption {
type = types.attrsOf types.lines; type = types.attrsOf types.str;
default = {}; default = {};
description = mdDoc '' description = ''
Bash expressions for generating secrets. Bash expressions for generating secrets.
''; '';
}; };
@ -38,7 +38,7 @@ let
# Currently, this is used only by ../deployment/nixops.nix # Currently, this is used only by ../deployment/nixops.nix
deployment.secretsDir = mkOption { deployment.secretsDir = mkOption {
type = types.path; type = types.path;
description = mdDoc '' description = ''
Directory of local secrets that are transferred to the nix-bitcoin node on deployment Directory of local secrets that are transferred to the nix-bitcoin node on deployment
''; '';
}; };

View File

@ -6,16 +6,16 @@ with lib;
nix-bitcoin.security.dbusHideProcessInformation = mkOption { nix-bitcoin.security.dbusHideProcessInformation = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = mdDoc '' description = ''
Only allow users with group `proc` to retrieve systemd unit information like Only allow users with group 'proc' to retrieve systemd unit information like
cgroup paths (i.e. (sub)process command lines) via D-Bus. cgroup paths (i.e. (sub)process command lines) via D-Bus.
This mitigates a systemd security issue where (sub)process command lines can This mitigates a systemd security issue where (sub)process command lines can
be retrieved by services even when their access to /proc is restricted be retrieved by services even when their access to /proc is restricted
(via ProtectProc). (via ProtectProc).
This option works by restricting the D-Bus method `GetUnitProcesses`, which This option works by restricting the D-Bus method 'GetUnitProcesses', which
is also used internally by {command}`systemctl status`. is also used internally by `systemctl status`.
''; '';
}; };
}; };

View File

@ -7,22 +7,22 @@ let
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "localhost"; default = "localhost";
description = mdDoc "http(s) server address."; description = "http(s) server address.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 9737; default = 9737;
description = mdDoc "http(s) server port."; description = "http(s) server port.";
}; };
extraArgs = mkOption { extraArgs = mkOption {
type = types.separatedString " "; type = types.separatedString " ";
default = ""; default = "";
description = mdDoc "Extra command line arguments passed to spark-wallet."; description = "Extra command line arguments passed to spark-wallet.";
}; };
getPublicAddressCmd = mkOption { getPublicAddressCmd = mkOption {
type = types.str; type = types.str;
default = ""; default = "";
description = mdDoc '' description = ''
Bash expression which outputs the public service address. Bash expression which outputs the public service address.
If set, spark-wallet prints a QR code to the systemd journal which If set, spark-wallet prints a QR code to the systemd journal which
encodes an URL for accessing the web interface. encodes an URL for accessing the web interface.
@ -31,12 +31,12 @@ let
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "spark-wallet"; default = "spark-wallet";
description = mdDoc "The user as which to run spark-wallet."; description = "The user as which to run spark-wallet.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = mdDoc "The group as which to run spark-wallet."; description = "The group as which to run spark-wallet.";
}; };
tor = nbLib.tor; tor = nbLib.tor;
}; };

View File

@ -11,7 +11,7 @@ let
nix-bitcoin.configVersion = mkOption { nix-bitcoin.configVersion = mkOption {
type = with types; nullOr str; type = with types; nullOr str;
default = null; default = null;
description = mdDoc '' description = ''
Set this option to the nix-bitcoin release version that your config is Set this option to the nix-bitcoin release version that your config is
compatible with. compatible with.
@ -228,16 +228,7 @@ let
version = "0.0.70"; version = "0.0.70";
condition = config.services.lnd.lndconnectOnion.enable; condition = config.services.lnd.lndconnectOnion.enable;
message = '' message = ''
The `lndconnect-rest-onion` binary has been renamed to `lndconnect`. The `lndconnect-rest-onion` binary has been renamed to `lndconnect-onion`.
'';
}
{
version = "0.0.85";
condition = config.services.fulcrum.enable;
message = ''
Fulcrum 1.9.0 has changed its database format.
The database update happens automatically and instantly on deployment,
but you can't switch back to an older Fulcrum version afterwards.
''; '';
} }
]; ];

View File

@ -31,8 +31,8 @@ let
description = "Lightning node exporter for the prometheus timeseries server"; description = "Lightning node exporter for the prometheus timeseries server";
extraPkgs = [ prometheus_client ]; extraPkgs = [ prometheus_client ];
patchRequirements = patchRequirements =
"--replace prometheus-client==0.6.0 prometheus-client==0.15.0" "--replace prometheus-client==0.6.0 prometheus-client==0.13.1"
+ " --replace pyln-client~=0.9.3 pyln-client~=23.02"; + " --replace pyln-client~=0.9.3 pyln-client~=0.11.1";
}; };
rebalance = { rebalance = {
description = "Keeps your channels balanced"; description = "Keeps your channels balanced";
@ -80,7 +80,7 @@ let
inherit (plugin) description; inherit (plugin) description;
homepage = "https://github.com/lightningd/plugins"; homepage = "https://github.com/lightningd/plugins";
license = licenses.bsd3; license = licenses.bsd3;
maintainers = with maintainers; [ nixbitcoin erikarvstedt ]; maintainers = with maintainers; [ nixbitcoin earvstedt ];
platforms = platforms.unix; platforms = platforms.unix;
}; };
}; };

View File

@ -49,7 +49,7 @@ let self = stdenvNoCC.mkDerivation {
description = "REST API for C-Lightning"; description = "REST API for C-Lightning";
homepage = "https://github.com/Ride-The-Lightning/c-lightning-REST"; homepage = "https://github.com/Ride-The-Lightning/c-lightning-REST";
license = licenses.mit; license = licenses.mit;
maintainers = with maintainers; [ nixbitcoin erikarvstedt ]; maintainers = with maintainers; [ nixbitcoin earvstedt ];
platforms = platforms.unix; platforms = platforms.unix;
}; };
}; in self }; in self

View File

@ -13,24 +13,17 @@ let self = {
clightning-rest = pkgs.callPackage ./clightning-rest { inherit (self) fetchNodeModules; }; clightning-rest = pkgs.callPackage ./clightning-rest { inherit (self) fetchNodeModules; };
clboss = pkgs.callPackage ./clboss { }; clboss = pkgs.callPackage ./clboss { };
clightning-plugins = pkgs.recurseIntoAttrs (import ./clightning-plugins pkgs self.nbPython3Packages); clightning-plugins = pkgs.recurseIntoAttrs (import ./clightning-plugins pkgs self.nbPython3Packages);
joinmarket = pkgs.callPackage ./joinmarket { inherit (self) nbPython3PackagesJoinmarket; }; joinmarket = pkgs.callPackage ./joinmarket { nbPythonPackageOverrides = import ./python-packages self; };
lndinit = pkgs.callPackage ./lndinit { }; lndinit = pkgs.callPackage ./lndinit { };
liquid-swap = pkgs.python3Packages.callPackage ./liquid-swap { }; liquid-swap = pkgs.python3Packages.callPackage ./liquid-swap { };
rtl = pkgs.callPackage ./rtl { inherit (self) fetchNodeModules; }; rtl = pkgs.callPackage ./rtl { inherit (self) fetchNodeModules; };
# The secp256k1 version used by joinmarket # The secp256k1 version used by joinmarket
secp256k1 = pkgs.callPackage ./secp256k1 { }; secp256k1 = pkgs.callPackage ./secp256k1 { };
spark-wallet = pkgs.callPackage ./spark-wallet { }; spark-wallet = pkgs.callPackage ./spark-wallet { };
trustedcoin = pkgs.callPackage ./trustedcoin { };
# TODO-EXTERNAL: nbPython3Packages = (pkgs.python3.override {
# Remove this when https://github.com/lightningnetwork/lnd/pull/7672 packageOverrides = import ./python-packages self;
# has been resolved }).pkgs;
lnd = pkgsUnstable.callPackage ./lnd { };
pyPkgs = import ./python-packages self pkgs.python3;
inherit (self.pyPkgs)
nbPython3Packages
nbPython3PackagesJoinmarket;
fetchNodeModules = pkgs.callPackage ./build-support/fetch-node-modules.nix { }; fetchNodeModules = pkgs.callPackage ./build-support/fetch-node-modules.nix { };

View File

@ -1,15 +1,23 @@
{ stdenv, lib, fetchFromGitHub, python3, nbPython3PackagesJoinmarket }: { stdenv, lib, fetchurl, python3, nbPythonPackageOverrides, pkgs }:
let let
version = "0.9.9"; version = "0.9.7";
src = fetchFromGitHub { src = fetchurl {
owner = "joinmarket-org"; url = "https://github.com/JoinMarket-Org/joinmarket-clientserver/archive/v${version}.tar.gz";
repo = "joinmarket-clientserver"; sha256 = "13bfr8ha6bka8wiai8m79ki43dn2r311lrfffr39ni2wy1v12l93";
rev = "v${version}";
sha256 = "sha256-dkeSgAhjNl8o/ATKYAlQxxCrur5fLdXuMDXSnWaxYP8=";
}; };
runtimePackages = with nbPython3PackagesJoinmarket; [ pyPkgs = (python3.override {
packageOverrides = (self: super: let
overrides = nbPythonPackageOverrides self super;
in
overrides // {
cryptography = overrides.cryptography_3_3_2;
}
);
}).pkgs;
runtimePackages = with pyPkgs; [
joinmarketbase joinmarketbase
joinmarketclient joinmarketclient
joinmarketbitcoin joinmarketbitcoin

View File

@ -1,23 +1,25 @@
#!/usr/bin/env nix-shell #!/usr/bin/env bash
#!nix-shell -i bash -p git gnupg jq
set -euo pipefail set -euo pipefail
newVersion=$(curl -s "https://api.github.com/repos/joinmarket-org/joinmarket-clientserver/releases" | jq -r '.[0].tag_name') . "${BASH_SOURCE[0]%/*}/../../helper/run-in-nix-env" "git gnupg" "$@"
# Fetch release and GPG-verify the content hash TMPDIR="$(mktemp -d -p /tmp)"
tmpdir=$(mktemp -d /tmp/joinmarket-verify-gpg.XXX) trap 'rm -rf $TMPDIR' EXIT
repo=$tmpdir/repo cd "$TMPDIR"
git clone --depth 1 --branch "${newVersion}" -c advice.detachedHead=false https://github.com/joinmarket-org/joinmarket-clientserver "$repo"
export GNUPGHOME=$tmpdir echo "Fetching latest release"
git clone https://github.com/joinmarket-org/joinmarket-clientserver 2> /dev/null
cd joinmarket-clientserver
latest=$(git describe --tags "$(git rev-list --tags --max-count=1)")
echo "Latest release is $latest"
# GPG verification
export GNUPGHOME=$TMPDIR
echo "Fetching Adam Gibson's key" echo "Fetching Adam Gibson's key"
gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 2B6FC204D9BF332D062B461A141001A1AF77F20B 2> /dev/null gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 2B6FC204D9BF332D062B461A141001A1AF77F20B 2> /dev/null
echo echo "Verifying latest release"
echo "Verifying commit" git verify-tag "$latest"
git -C "$repo" verify-commit HEAD
rm -rf "$repo"/.git
newHash=$(nix hash path "$repo")
rm -rf "$tmpdir"
echo
echo "tag: $newVersion" echo "tag: $latest"
echo "hash: $newHash" # The prefix option is necessary because GitHub prefixes the archive contents in this format
echo "sha256: $(nix-hash --type sha256 --flat --base32 \
<(git archive --format tar.gz --prefix=joinmarket-clientserver-"${latest//v}"/ "$latest"))"

View File

@ -1,4 +1,4 @@
lib: pkgs: config: lib: pkgs:
with lib; with lib;
@ -7,33 +7,33 @@ with lib;
let self = { let self = {
# These settings roughly follow systemd's "strict" security profile # These settings roughly follow systemd's "strict" security profile
defaultHardening = { defaultHardening = {
PrivateTmp = true; PrivateTmp = "true";
ProtectSystem = "strict"; ProtectSystem = "strict";
ProtectHome = true; ProtectHome = "true";
NoNewPrivileges = true; NoNewPrivileges = "true";
PrivateDevices = true; PrivateDevices = "true";
MemoryDenyWriteExecute = true; MemoryDenyWriteExecute = "true";
ProtectKernelTunables = true; ProtectKernelTunables = "true";
ProtectKernelModules = true; ProtectKernelModules = "true";
ProtectKernelLogs = true; ProtectKernelLogs = "true";
ProtectClock = true; ProtectClock = "true";
ProtectProc = "invisible"; ProtectProc = "invisible";
ProcSubset = "pid"; ProcSubset = "pid";
ProtectControlGroups = true; ProtectControlGroups = "true";
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6"; RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
RestrictNamespaces = true; RestrictNamespaces = "true";
LockPersonality = true; LockPersonality = "true";
IPAddressDeny = "any"; IPAddressDeny = "any";
PrivateUsers = true; PrivateUsers = "true";
RestrictSUIDSGID = true; RestrictSUIDSGID = "true";
RemoveIPC = true; RemoveIPC = "true";
RestrictRealtime = true; RestrictRealtime = "true";
ProtectHostname = true; ProtectHostname = "true";
CapabilityBoundingSet = ""; CapabilityBoundingSet = "";
# @system-service whitelist and docker seccomp blacklist (except for "clone" # @system-service whitelist and docker seccomp blacklist (except for "clone"
# which is a core requirement for systemd services) # which is a core requirement for systemd services)
# @system-service is defined in src/shared/seccomp-util.c (systemd source) # @system-service is defined in src/shared/seccomp-util.c (systemd source)
SystemCallFilter = [ "@system-service" "~add_key kcmp keyctl mbind move_pages name_to_handle_at personality process_vm_readv process_vm_writev request_key setns unshare userfaultfd" ]; SystemCallFilter = [ "@system-service" "~add_key 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";
}; };
@ -42,7 +42,7 @@ let self = {
}; };
# nodejs applications require memory write execute for JIT compilation # nodejs applications require memory write execute for JIT compilation
nodejs = { MemoryDenyWriteExecute = false; }; nodejs = { MemoryDenyWriteExecute = "false"; };
# Allow takes precedence over Deny. # Allow takes precedence over Deny.
allowLocalIPAddresses = { allowLocalIPAddresses = {
@ -115,8 +115,4 @@ let self = {
(map (ip: "IP:${ip}") cert.extraIPs) (map (ip: "IP:${ip}") cert.extraIPs)
); );
test = {
mkIfTest = test: mkIf (config.tests.${test} or false);
};
}; in self }; in self

View File

@ -1,12 +0,0 @@
{ lnd, fetchpatch }:
lnd.overrideAttrs (_: {
patches = [
(fetchpatch {
# https://github.com/lightningnetwork/lnd/pull/7672
name = "fix-PKCS8-cert-key-support";
url = "https://github.com/lightningnetwork/lnd/commit/bfdd5db0d97a6d65489d980a917bbd2243dfe15c.patch";
hash = "sha256-j9EirxyNi48DGzLuHcZ36LrFlbJLXrE8L+1TYh5Yznk=";
})
];
})

View File

@ -19,6 +19,6 @@ buildGoModule rec {
description = "Wallet initializer utility for lnd"; description = "Wallet initializer utility for lnd";
homepage = "https://github.com/lightninglabs/lndinit"; homepage = "https://github.com/lightninglabs/lndinit";
license = licenses.mit; license = licenses.mit;
maintainers = with maintainers; [ erikarvstedt ]; maintainers = with maintainers; [ earvstedt ];
}; };
} }

View File

@ -16,5 +16,5 @@ let
in in
{ {
nixpkgs = fetch lockedInputs.nixpkgs; nixpkgs = fetch lockedInputs.nixpkgs;
nixpkgs-unstable = fetch lockedInputs.nixpkgs-unstable; nixpkgs-unstable = fetch lockedInputs.nixpkgsUnstable;
} }

View File

@ -6,7 +6,8 @@ pkgs: pkgsUnstable:
bitcoind bitcoind
extra-container extra-container
lightning-pool lightning-pool
lndconnect; lndconnect
nbxplorer;
inherit (pkgsUnstable) inherit (pkgsUnstable)
btcpayserver btcpayserver
@ -17,7 +18,7 @@ pkgs: pkgsUnstable:
fulcrum fulcrum
hwi hwi
lightning-loop lightning-loop
nbxplorer; lnd;
inherit pkgs pkgsUnstable; inherit pkgs pkgsUnstable;
} }

View File

@ -2,11 +2,11 @@
buildPythonPackage rec { buildPythonPackage rec {
pname = "bencoder.pyx"; pname = "bencoder.pyx";
version = "3.0.1"; version = "2.0.1";
src = fetchurl { src = fetchurl {
url = "https://github.com/whtsky/bencoder.pyx/archive/9a47768f3ceba9df9e6fbaa7c445f59960889009.tar.gz"; url = "https://github.com/whtsky/bencoder.pyx/archive/v${version}.tar.gz";
sha256 = "1yh565xjbbhn49xjfms80ac8psjbzn66n8dcx0x8mn7zzjv06clz"; sha256 = "f3ff92ac706a7e4692bed5e6cbe205963327f3076f55e408eb948659923eac72";
}; };
nativeBuildInputs = [ cython ]; nativeBuildInputs = [ cython ];

View File

@ -1,63 +1,51 @@
nbPkgs: python3: nbPkgs: self: super:
rec { let
pyPkgsOverrides = self: super: let inherit (self) callPackage;
inherit (self) callPackage;
clightningPkg = pkg: callPackage pkg { inherit (nbPkgs.pinned) clightning; };
in
{
coincurve = callPackage ./coincurve {};
txzmq = callPackage ./txzmq {};
pyln-client = clightningPkg ./pyln-client; joinmarketPkg = pkg: callPackage pkg { inherit (nbPkgs.joinmarket) version src; };
pyln-proto = clightningPkg ./pyln-proto; clightningPkg = pkg: callPackage pkg { inherit (nbPkgs.pinned) clightning; };
pyln-bolt7 = clightningPkg ./pyln-bolt7;
pylightning = clightningPkg ./pylightning;
# Packages only used by joinmarket unstable = (import ../nixpkgs-pinned.nix).nixpkgs-unstable;
bencoderpyx = callPackage ./bencoderpyx {}; in {
chromalog = callPackage ./chromalog {}; bencoderpyx = callPackage ./bencoderpyx {};
python-bitcointx = callPackage ./python-bitcointx { chromalog = callPackage ./chromalog {};
inherit (nbPkgs) secp256k1; coincurve = callPackage ./coincurve {};
openssl = super.pkgs.openssl_1_1; python-bitcointx = callPackage ./python-bitcointx { inherit (nbPkgs) secp256k1; };
}; runes = callPackage ./runes {};
runes = callPackage ./runes {}; sha256 = callPackage ./sha256 {};
sha256 = callPackage ./sha256 {}; txzmq = callPackage ./txzmq {};
}; urldecode = callPackage ./urldecode {};
# Joinmarket requires a custom package set because it uses older versions of Python pkgs joinmarketbase = joinmarketPkg ./jmbase;
pyPkgsOverridesJoinmarket = self: super: let joinmarketclient = joinmarketPkg ./jmclient;
inherit (self) callPackage; joinmarketbitcoin = joinmarketPkg ./jmbitcoin;
joinmarketPkg = pkg: callPackage pkg { inherit (nbPkgs.joinmarket) version src; }; joinmarketdaemon = joinmarketPkg ./jmdaemon;
in
(pyPkgsOverrides self super) // {
joinmarketbase = joinmarketPkg ./jmbase;
joinmarketclient = joinmarketPkg ./jmclient;
joinmarketbitcoin = joinmarketPkg ./jmbitcoin;
joinmarketdaemon = joinmarketPkg ./jmdaemon;
## Specific versions of packages that already exist in nixpkgs pyln-client = clightningPkg ./pyln-client;
pyln-proto = clightningPkg ./pyln-proto;
pyln-bolt7 = clightningPkg ./pyln-bolt7;
pylightning = clightningPkg ./pylightning;
# cryptography 3.3.2, required by joinmarketdaemon # Don't mark `klein` as broken.
cryptography = callPackage ./specific-versions/cryptography { # `klein` is fixed by using werkzeug 2.1.0 (see below)
openssl = super.pkgs.openssl_1_1; klein = super.klein.overrideAttrs (old: {
cryptography_vectors = callPackage ./specific-versions/cryptography/vectors.nix {}; meta = builtins.removeAttrs old.meta [ "broken" ];
}; });
# autobahn 20.12.3, required by joinmarketclient ## Specific versions of packages that already exist in nixpkgs
autobahn = callPackage ./specific-versions/autobahn.nix {};
# pyopenssl 21.0.0, required by joinmarketdaemon # cryptography 3.3.2, required by joinmarketdaemon
pyopenssl = callPackage ./specific-versions/pyopenssl.nix {}; # Used in the private python package set for joinmarket (../joinmarket/default.nix)
cryptography_3_3_2 = callPackage ./specific-versions/cryptography {
cryptography_vectors = callPackage ./specific-versions/cryptography/vectors.nix {};
};
# twisted 22.4.0, required by joinmarketbase # autobahn 20.12.3, required by joinmarketclient
twisted = callPackage ./specific-versions/twisted.nix {}; autobahn = callPackage ./specific-versions/autobahn.nix {};
};
nbPython3Packages = (python3.override { # werkzeug 2.1.0, required by jmclient (via pkg `klein`)
packageOverrides = pyPkgsOverrides; werkzeug = callPackage ./specific-versions/werkzeug.nix {};
}).pkgs;
nbPython3PackagesJoinmarket = (python3.override { # pyopenssl 20.0.1, required by joinmarketdaemon
packageOverrides = pyPkgsOverridesJoinmarket; pyopenssl = callPackage ./specific-versions/pyopenssl.nix {};
}).pkgs;
} }

View File

@ -1,4 +1,4 @@
{ version, src, lib, buildPythonPackage, fetchurl, pyaes, python-bitcointx, joinmarketbase }: { version, src, lib, buildPythonPackage, fetchurl, urldecode, pyaes, python-bitcointx, joinmarketbase }:
buildPythonPackage rec { buildPythonPackage rec {
pname = "joinmarketbitcoin"; pname = "joinmarketbitcoin";
@ -6,7 +6,7 @@ buildPythonPackage rec {
postUnpack = "sourceRoot=$sourceRoot/jmbitcoin"; postUnpack = "sourceRoot=$sourceRoot/jmbitcoin";
propagatedBuildInputs = [ pyaes python-bitcointx ]; propagatedBuildInputs = [ urldecode pyaes python-bitcointx ];
checkInputs = [ joinmarketbase ]; checkInputs = [ joinmarketbase ];

View File

@ -12,9 +12,9 @@ buildPythonPackage rec {
patchPhase = '' patchPhase = ''
substituteInPlace setup.py \ substituteInPlace setup.py \
--replace "'klein==20.6.0'" "'klein>=20.6.0'" --replace "'klein==20.6.0'" "'klein==21.8.0'"
substituteInPlace setup.py \ substituteInPlace setup.py \
--replace "'pyjwt==2.4.0'" "'pyjwt==2.5.0'" --replace "'pyjwt==2.1.0'" "'pyjwt==2.4.0'"
''; '';
meta = with lib; { meta = with lib; {

View File

@ -8,12 +8,6 @@ buildPythonPackage rec {
propagatedBuildInputs = [ txtorcon cryptography pyopenssl libnacl joinmarketbase ]; propagatedBuildInputs = [ txtorcon cryptography pyopenssl libnacl joinmarketbase ];
# libnacl 1.8.0 is not on github
patchPhase = ''
substituteInPlace setup.py \
--replace "'libnacl==1.8.0'" "'libnacl==1.7.2'"
'';
meta = with lib; { meta = with lib; {
description = "Client library for Bitcoin coinjoins"; description = "Client library for Bitcoin coinjoins";
homepage = "https://github.com/Joinmarket-Org/joinmarket-clientserver"; homepage = "https://github.com/Joinmarket-Org/joinmarket-clientserver";

View File

@ -16,5 +16,13 @@ buildPythonPackage rec {
checkInputs = [ pytestCheckHook ]; checkInputs = [ pytestCheckHook ];
# TODO-EXTERNAL:
# This patch is a variant (fixed relative path) of
# https://github.com/ElementsProject/lightning/pull/5574. This is already
# fixed upstream. Remove this after the next clightning release.
patches = [
./msat-null.patch
];
postUnpack = "sourceRoot=$sourceRoot/contrib/${pname}"; postUnpack = "sourceRoot=$sourceRoot/contrib/${pname}";
} }

View File

@ -0,0 +1,16 @@
diff --git a/pyln/client/lightning.py b/pyln/client/lightning.py
index 38fc7563f..0013b89a3 100644
--- a/pyln/client/lightning.py
+++ b/pyln/client/lightning.py
@@ -455,6 +455,11 @@ class LightningRpc(UnixDomainSocketRpc):
if k.endswith('msat'):
if isinstance(v, list):
obj[k] = [Millisatoshi(e) for e in v]
+ # FIXME: Deprecated "listconfigs" gives two 'null' fields:
+ # "lease-fee-base-msat": null,
+ # "channel-fee-max-base-msat": null,
+ elif v is None:
+ obj[k] = None
else:
obj[k] = Millisatoshi(v)
else:

View File

@ -27,8 +27,4 @@ buildPythonPackage rec {
checkInputs = [ pytestCheckHook ]; checkInputs = [ pytestCheckHook ];
postUnpack = "sourceRoot=$sourceRoot/contrib/pyln-proto"; postUnpack = "sourceRoot=$sourceRoot/contrib/pyln-proto";
postPatch = ''
sed -i 's|cryptography = "^36.0.1"|cryptography = "^38.0.0"|' pyproject.toml
'';
} }

View File

@ -6,50 +6,17 @@
, cryptography , cryptography
, pyasn1 , pyasn1
, idna , idna
, pytestCheckHook , pytest
, pretend , pretend
, flaky , flaky
, glibcLocales , glibcLocales
, six , six
}: }:
buildPythonPackage rec { let
pname = "pyopenssl"; # https://github.com/pyca/pyopenssl/issues/791
version = "21.0.0"; # These tests, we disable in the case that libressl is passed in as openssl.
failingLibresslTests = [
src = fetchPypi {
pname = "pyOpenSSL";
inherit version;
sha256 = "5e2d8c5e46d0d865ae933bef5230090bdaf5506281e9eec60fa250ee80600cb3";
};
outputs = [ "out" "dev" ];
# Seems to fail unpredictably on Darwin. See https://hydra.nixos.org/build/49877419/nixlog/1
# for one example, but I've also seen ContextTests.test_set_verify_callback_exception fail.
doCheck = !stdenv.isDarwin;
nativeBuildInputs = [ openssl ];
propagatedBuildInputs = [ cryptography pyasn1 idna six ];
checkInputs = [ pytestCheckHook pretend flaky glibcLocales ];
preCheck = ''
export LANG="en_US.UTF-8"
'';
disabledTests = [
# https://github.com/pyca/pyopenssl/issues/692
# These tests, we disable always.
"test_set_default_verify_paths"
"test_fallback_default_verify_paths"
# https://github.com/pyca/pyopenssl/issues/768
"test_wantWriteError"
# https://github.com/pyca/pyopenssl/issues/1043
"test_alpn_call_failure"
] ++ lib.optionals (lib.hasPrefix "libressl" openssl.meta.name) [
# https://github.com/pyca/pyopenssl/issues/791
# These tests, we disable in the case that libressl is passed in as openssl.
"test_op_no_compression" "test_op_no_compression"
"test_npn_advertise_error" "test_npn_advertise_error"
"test_npn_select_error" "test_npn_select_error"
@ -62,21 +29,64 @@ buildPythonPackage rec {
"test_verify_with_revoked" "test_verify_with_revoked"
"test_set_notAfter" "test_set_notAfter"
"test_set_notBefore" "test_set_notBefore"
] ++ lib.optionals (lib.versionAtLeast (lib.getVersion openssl.name) "1.1") [ ];
# these tests are extremely tightly wed to the exact output of the openssl cli tool, including exact punctuation.
# these tests are extremely tightly wed to the exact output of the openssl cli tool,
# including exact punctuation.
failingOpenSSL_1_1Tests = [
"test_dump_certificate" "test_dump_certificate"
"test_dump_privatekey_text" "test_dump_privatekey_text"
"test_dump_certificate_request" "test_dump_certificate_request"
"test_export_text" "test_export_text"
] ++ lib.optionals stdenv.is32bit [
# https://github.com/pyca/pyopenssl/issues/974
"test_verify_with_time"
]; ];
meta = with lib; { disabledTests = [
description = "Python wrapper around the OpenSSL library"; # https://github.com/pyca/pyopenssl/issues/692
homepage = "https://github.com/pyca/pyopenssl"; # These tests, we disable always.
license = licenses.asl20; "test_set_default_verify_paths"
maintainers = with maintainers; [ SuperSandro2000 ]; "test_fallback_default_verify_paths"
# https://github.com/pyca/pyopenssl/issues/768
"test_wantWriteError"
] ++ (
lib.optionals (lib.hasPrefix "libressl" openssl.meta.name) failingLibresslTests
) ++ (
lib.optionals (lib.versionAtLeast (lib.getVersion openssl.name) "1.1") failingOpenSSL_1_1Tests
) ++ (
# https://github.com/pyca/pyopenssl/issues/974
lib.optionals stdenv.is32bit [ "test_verify_with_time" ]
);
# Compose the final string expression, including the "-k" and the single quotes.
testExpression = lib.optionalString (disabledTests != [])
"-k 'not ${lib.concatStringsSep " and not " disabledTests}'";
in
buildPythonPackage rec {
pname = "pyopenssl";
version = "20.0.1";
src = fetchPypi {
pname = "pyOpenSSL";
inherit version;
sha256 = "4c231c759543ba02560fcd2480c48dcec4dae34c9da7d3747c508227e0624b51";
}; };
outputs = [ "out" "dev" ];
checkPhase = ''
runHook preCheck
export LANG="en_US.UTF-8"
py.test tests ${testExpression}
runHook postCheck
'';
# Seems to fail unpredictably on Darwin. See https://hydra.nixos.org/build/49877419/nixlog/1
# for one example, but I've also seen ContextTests.test_set_verify_callback_exception fail.
doCheck = !stdenv.isDarwin;
nativeBuildInputs = [ openssl ];
propagatedBuildInputs = [ cryptography pyasn1 idna six ];
checkInputs = [ pytest pretend flaky glibcLocales ];
} }

View File

@ -1,173 +0,0 @@
{ lib
, stdenv
, buildPythonPackage
, pythonOlder
, fetchPypi
, python
, appdirs
, attrs
, automat
, bcrypt
, constantly
, contextvars
, cryptography
, git
, glibcLocales
, h2
, hyperlink
, idna
, incremental
, priority
, pyasn1
, pyhamcrest
, pynacl
, pyopenssl
, pyserial
, service-identity
, setuptools
, typing-extensions
, zope_interface
# for passthru.tests
, cassandra-driver
, klein
, magic-wormhole
, scrapy
, treq
, txaio
, txamqp
, txrequests
, txtorcon
, thrift
, nixosTests
}:
buildPythonPackage rec {
pname = "twisted";
version = "22.4.0";
format = "setuptools";
disabled = pythonOlder "3.6";
src = fetchPypi {
pname = "Twisted";
inherit version;
extension = "tar.gz";
sha256 = "sha256-oEeZD1ffrh4L0rffJSbU8W3NyEN3TcEIt4xS8qXxNoA=";
};
__darwinAllowLocalNetworking = true;
propagatedBuildInputs = [
attrs
automat
constantly
hyperlink
incremental
setuptools
typing-extensions
zope_interface
];
postPatch = ''
echo 'ListingTests.test_localeIndependent.skip = "Timezone issue"'>> src/twisted/conch/test/test_cftp.py
echo 'ListingTests.test_newFile.skip = "Timezone issue"'>> src/twisted/conch/test/test_cftp.py
echo 'ListingTests.test_newSingleDigitDayOfMonth.skip = "Timezone issue"'>> src/twisted/conch/test/test_cftp.py
echo 'ListingTests.test_oldFile.skip = "Timezone issue"'>> src/twisted/conch/test/test_cftp.py
echo 'ListingTests.test_oldSingleDigitDayOfMonth.skip = "Timezone issue"'>> src/twisted/conch/test/test_cftp.py
echo 'PTYProcessTestsBuilder_AsyncioSelectorReactorTests.test_openFileDescriptors.skip = "invalid syntax"'>> src/twisted/internet/test/test_process.py
echo 'PTYProcessTestsBuilder_SelectReactorTests.test_openFileDescriptors.skip = "invalid syntax"'>> src/twisted/internet/test/test_process.py
echo 'UNIXTestsBuilder_AsyncioSelectorReactorTests.test_sendFileDescriptorTriggersPauseProducing.skip = "sendFileDescriptor producer was not paused"'>> src/twisted/internet/test/test_unix.py
echo 'UNIXTestsBuilder_SelectReactorTests.test_sendFileDescriptorTriggersPauseProducing.skip = "sendFileDescriptor producer was not paused"'>> src/twisted/internet/test/test_unix.py
echo 'FileObserverTests.test_getTimezoneOffsetEastOfUTC.skip = "mktime argument out of range"'>> src/twisted/test/test_log.py
echo 'FileObserverTests.test_getTimezoneOffsetWestOfUTC.skip = "mktime argument out of range"'>> src/twisted/test/test_log.py
echo 'FileObserverTests.test_getTimezoneOffsetWithoutDaylightSavingTime.skip = "tuple differs, values not"'>> src/twisted/test/test_log.py
echo 'MulticastTests.test_joinLeave.skip = "No such device"'>> src/twisted/test/test_udp.py
echo 'MulticastTests.test_loopback.skip = "No such device"'>> src/twisted/test/test_udp.py
echo 'MulticastTests.test_multicast.skip = "Reactor was unclean"'>> src/twisted/test/test_udp.py
echo 'MulticastTests.test_multiListen.skip = "No such device"'>> src/twisted/test/test_udp.py
echo 'DomishExpatStreamTests.test_namespaceWithWhitespace.skip = "syntax error: line 1, column 0"'>> src/twisted/words/test/test_domish.py
# not packaged
substituteInPlace src/twisted/test/test_failure.py \
--replace "from cython_test_exception_raiser import raiser # type: ignore[import]" "raiser = None"
'' + lib.optionalString stdenv.isLinux ''
echo 'PTYProcessTestsBuilder_EPollReactorTests.test_openFileDescriptors.skip = "invalid syntax"'>> src/twisted/internet/test/test_process.py
echo 'PTYProcessTestsBuilder_PollReactorTests.test_openFileDescriptors.skip = "invalid syntax"'>> src/twisted/internet/test/test_process.py
echo 'UNIXTestsBuilder_EPollReactorTests.test_sendFileDescriptorTriggersPauseProducing.skip = "sendFileDescriptor producer was not paused"'>> src/twisted/internet/test/test_unix.py
echo 'UNIXTestsBuilder_PollReactorTests.test_sendFileDescriptorTriggersPauseProducing.skip = "sendFileDescriptor producer was not paused"'>> src/twisted/internet/test/test_unix.py
# Patch t.p._inotify to point to libc. Without this,
# twisted.python.runtime.platform.supportsINotify() == False
substituteInPlace src/twisted/python/_inotify.py --replace \
"ctypes.util.find_library(\"c\")" "'${stdenv.cc.libc}/lib/libc.so.6'"
'' + lib.optionalString (stdenv.isAarch64 && stdenv.isDarwin) ''
echo 'AbortConnectionTests_AsyncioSelectorReactorTests.test_fullWriteBufferAfterByteExchange.skip = "Timeout after 120 seconds"' >> src/twisted/internet/test/test_tcp.py
echo 'AbortConnectionTests_AsyncioSelectorReactorTests.test_resumeProducingAbort.skip = "Timeout after 120 seconds"' >> src/twisted/internet/test/test_tcp.py
'';
# Generate Twisted's plug-in cache. Twisted users must do it as well. See
# http://twistedmatrix.com/documents/current/core/howto/plugin.html#auto3
# and http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=477103 for details.
postFixup = ''
$out/bin/twistd --help > /dev/null
'';
checkInputs = [
git
glibcLocales
pyhamcrest
]
++ passthru.optional-dependencies.conch
# not supported on aarch64-darwin: https://github.com/pyca/pyopenssl/issues/873
++ lib.optionals (!(stdenv.isDarwin && stdenv.isAarch64)) passthru.optional-dependencies.tls;
checkPhase = ''
export SOURCE_DATE_EPOCH=315532800
export PATH=$out/bin:$PATH
# race conditions when running in paralell
${python.interpreter} -m twisted.trial twisted
'';
passthru = {
optional-dependencies = rec {
conch = [ appdirs bcrypt cryptography pyasn1 ];
conch_nacl = conch ++ [ pynacl ];
contextvars = lib.optionals (pythonOlder "3.7") [ contextvars ];
http2 = [ h2 priority ];
serial = [ pyserial ];
tls = [ idna pyopenssl service-identity ];
};
tests = {
inherit
cassandra-driver
klein
magic-wormhole
scrapy
treq
txaio
txamqp
txrequests
txtorcon
thrift;
inherit (nixosTests) buildbot matrix-synapse;
};
};
meta = with lib; {
homepage = "https://github.com/twisted/twisted";
description = "Twisted, an event-driven networking engine written in Python";
longDescription = ''
Twisted is an event-driven networking engine written in Python
and licensed under the MIT license.
'';
license = licenses.mit;
maintainers = with maintainers; [ SuperSandro2000 ];
};
}

View File

@ -0,0 +1,68 @@
{ lib
, stdenv
, buildPythonPackage
, pythonOlder
, fetchPypi
, watchdog
, dataclasses
, ephemeral-port-reserve
, pytest-timeout
, pytest-xprocess
, pytestCheckHook
}:
buildPythonPackage rec {
pname = "werkzeug";
version = "2.1.0";
format = "setuptools";
disabled = pythonOlder "3.7";
src = fetchPypi {
pname = "Werkzeug";
inherit version;
sha256 = "sha256-m1VGaj6Z4TsfBoamYRfTm9qFqZIWbgp5rt/PNYYyj3o=";
};
propagatedBuildInputs = lib.optionals (!stdenv.isDarwin) [
# watchdog requires macos-sdk 10.13+
watchdog
] ++ lib.optionals (pythonOlder "3.7") [
dataclasses
];
checkInputs = [
ephemeral-port-reserve
pytest-timeout
pytest-xprocess
pytestCheckHook
];
disabledTests = lib.optionals stdenv.isDarwin [
"test_get_machine_id"
];
disabledTestPaths = [
# ConnectionRefusedError: [Errno 111] Connection refused
"tests/test_serving.py"
];
pytestFlagsArray = [
# don't run tests that are marked with filterwarnings, they fail with
# warnings._OptionError: unknown warning category: 'pytest.PytestUnraisableExceptionWarning'
"-m 'not filterwarnings'"
];
meta = with lib; {
homepage = "https://palletsprojects.com/p/werkzeug/";
description = "The comprehensive WSGI web application library";
longDescription = ''
Werkzeug is a comprehensive WSGI web application library. It
began as a simple collection of various utilities for WSGI
applications and has become one of the most advanced WSGI
utility libraries.
'';
license = licenses.bsd3;
maintainers = with maintainers; [ ];
};
}

View File

@ -0,0 +1,16 @@
{ lib, buildPythonPackage, fetchPypi }:
buildPythonPackage rec {
pname = "urldecode";
version = "0.1";
src = fetchPypi {
inherit pname version;
sha256 = "0w8my7kdwxppsfzzi1b2cxhypm6r1fsrnb2hnd752axq4gfsddjj";
};
meta = with lib; {
description = "A simple function to decode an encoded url";
homepage = "https://github.com/jennyq/urldecode";
maintainers = with maintainers; [ nixbitcoin ];
};
}

View File

@ -10,11 +10,22 @@
}: }:
let self = stdenvNoCC.mkDerivation { let self = stdenvNoCC.mkDerivation {
pname = "rtl"; pname = "rtl";
version = "0.13.6"; version = "0.13.1";
src = fetchurl { src = applyPatches {
url = "https://github.com/Ride-The-Lightning/RTL/archive/refs/tags/v${self.version}.tar.gz"; src = fetchurl {
hash = "sha256-eyRM28h2TV3IyW4hDPHj/wMJxLEZin7AqWQZGQt5mV4="; url = "https://github.com/Ride-The-Lightning/RTL/archive/refs/tags/v${self.version}.tar.gz";
hash = "sha256-k40xwDDJxny1nPN2xz60WfbinxMNM0QPdglibO2anZw=";
};
patches = [
# Move non-runtime deps to `devDependencies`
# https://github.com/Ride-The-Lightning/RTL/pull/1070
(fetchpatch {
url = "https://github.com/Ride-The-Lightning/RTL/pull/1070.patch";
sha256 = "sha256-esDkYI27SNzj2AhYHS9XqlW0r2mr+o0K4A6PUE2kbWU=";
})
];
}; };
passthru = { passthru = {
@ -23,10 +34,7 @@ let self = stdenvNoCC.mkDerivation {
nodeModules = fetchNodeModules { nodeModules = fetchNodeModules {
inherit (self) src nodejs; inherit (self) src nodejs;
# TODO-EXTERNAL: Remove `npmFlags` when no longer required hash = "sha256-bYZ6snfXhDZ3MMga45EHVrPZxC0/Q0e3AgCgMBire64=";
# See: https://github.com/Ride-The-Lightning/RTL/issues/1182
npmFlags = "--legacy-peer-deps";
hash = "sha256-C4yK6deYXPrTa383aXiHoO0w3JAMIfAaESCEy9KKY2k=";
}; };
}; };
@ -60,7 +68,7 @@ let self = stdenvNoCC.mkDerivation {
description = "A web interface for LND, c-lightning and Eclair"; description = "A web interface for LND, c-lightning and Eclair";
homepage = "https://github.com/Ride-The-Lightning/RTL"; homepage = "https://github.com/Ride-The-Lightning/RTL";
license = licenses.mit; license = licenses.mit;
maintainers = with maintainers; [ nixbitcoin erikarvstedt ]; maintainers = with maintainers; [ nixbitcoin earvstedt ];
platforms = platforms.unix; platforms = platforms.unix;
}; };
}; in self }; in self

View File

@ -2,7 +2,7 @@
set -euo pipefail set -euo pipefail
. "${BASH_SOURCE[0]%/*}/../../helper/run-in-nix-env" "gnupg wget gnused" "$@" . "${BASH_SOURCE[0]%/*}/../../helper/run-in-nix-env" "gnupg wget gnused" "$@"
version="0.13.6" version="0.13.1"
repo=https://github.com/Ride-The-Lightning/RTL repo=https://github.com/Ride-The-Lightning/RTL
scriptDir=$(cd "${BASH_SOURCE[0]%/*}" && pwd) scriptDir=$(cd "${BASH_SOURCE[0]%/*}" && pwd)

View File

@ -5,7 +5,7 @@
}, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-14_x"}: }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-14_x"}:
let let
nodeEnv = import (pkgs.path + "/pkgs/development/node-packages/node-env.nix") { nodeEnv = import "${toString pkgs.path}/pkgs/development/node-packages/node-env.nix" {
inherit (pkgs) stdenv lib python2 runCommand writeTextFile writeShellScript; inherit (pkgs) stdenv lib python2 runCommand writeTextFile writeShellScript;
inherit pkgs nodejs; inherit pkgs nodejs;
libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null; libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null;

View File

@ -10,7 +10,7 @@ nodePackages.package.override {
description = "A minimalistic wallet GUI for c-lightning"; description = "A minimalistic wallet GUI for c-lightning";
homepage = "https://github.com/shesek/spark-wallet"; homepage = "https://github.com/shesek/spark-wallet";
license = licenses.mit; license = licenses.mit;
maintainers = with maintainers; [ nixbitcoin erikarvstedt ]; maintainers = with maintainers; [ nixbitcoin earvstedt ];
platforms = platforms.unix; platforms = platforms.unix;
}; };
} }

View File

@ -1,23 +0,0 @@
{ lib, buildGoModule, fetchFromGitHub }:
buildGoModule rec {
pname = "trustedcoin";
version = "0.6.1";
src = fetchFromGitHub {
owner = "nbd-wtf";
repo = pname;
rev = "v${version}";
sha256 = "sha256-UNQjxhAT0mK1In7vUtIoMoMNBV+0wkrwbDmm7m+0R3o=";
};
vendorSha256 = "sha256-xvkK9rMQlXTnNyOMd79qxVSvhgPobcBk9cq4/YWbupY=";
subPackages = [ "." ];
meta = with lib; {
description = "Light bitcoin node implementation";
homepage = "https://github.com/nbd-wtf/trustedcoin";
maintainers = with maintainers; [ seberm fort-nix ];
platforms = platforms.linux;
};
}

View File

@ -1,20 +0,0 @@
#! /usr/bin/env nix-shell
#! nix-shell -i bash -p git gnupg curl jq
set -euo pipefail
TMPDIR="$(mktemp -d -p /tmp)"
trap 'rm -rf $TMPDIR' EXIT
cd "$TMPDIR"
echo "Fetching latest release"
repo='nbd-wtf/trustedcoin'
latest=$(curl --location --silent --show-error https://api.github.com/repos/${repo}/releases/latest | jq -r .tag_name)
echo "Latest release is $latest"
git clone --depth 1 --branch "$latest" "https://github.com/${repo}" 2>/dev/null
cd trustedcoin
echo "tag: $latest"
git checkout -q "tags/$latest"
rm -rf .git
nix --extra-experimental-features nix-command hash path .

View File

@ -1,84 +0,0 @@
The [`run-tests.sh`](./run-tests.sh) command is most convenient and versatile way to run tests.\
It leave no traces (outside of `/nix/store`) on the host system.
`run-tests.sh` requires Nix >= 2.10.
### Summary
```bash
./run-tests.sh [--scenario|-s <scenario>] [build|vm|debug|container]
```
See the top of [run-tests.sh](../test/run-tests.sh) for a complete documentation.\
Test scenarios are defined in [tests.nix](./tests.nix) and [tests.py](tests.py).
### Tutorial
#### Running tests
```bash
# Run the basic set of tests. These tests are also run on the GitHub CI server.
./run-tests.sh
# Run the test for scenario `regtest`.
# The test is run via the Nix build system. Successful runs are cached.
./run-tests.sh -s regtest build
./run-tests.sh -s regtest # Shorthand, equivalent
# To test a single service, use its name as a scenario.
./run-tests.sh -s clightning
# When no scenario is specified, scenario `default` is used.
./run-tests.sh build
```
#### Debugging
```bash
# Start a shell is inside a test VM. No tests are executed.
./run-tests.sh -s bitcoind vm
systemctl status bitcoind
# Run a Python NixOS test shell inside a VM.
# See https://nixos.org/manual/nixos/stable/#ssec-machine-objects for available commands.
./run-tests.sh debug
print(succeed("systemctl status bitcoind"))
run_test("bitcoind")
# Start a shell in a container node. Requires systemd and root privileges.
./run-tests.sh container
# In the container shell: Run command in container (with prefix `c`)
c systemctl status bitcoind
# Explore a single feature
./run-tests.sh -s electrs container
# Run a command in a container.
# The container is deleted afterwards.
./run-tests.sh -s clightning container --run c lightning-cli getinfo
# Define a custom scenario
./run-tests.sh --scenario '{
services.clightning.enable = true;
nix-bitcoin.nodeinfo.enable = true;
}' container --run c nodeinfo
```
# Running tests with Flakes
Tests can also be accessed via the nix-bitcoin flake:
```bash
# Build test
nix build --no-link ..#tests.default
# Run a node in a VM. No tests are executed.
nix run ..#tests.default.vm
# Run a Python test shell inside a VM node
nix run ..#tests.default.run -- --debug
# Run a node in a container. Requires extra-container, systemd and root privileges
nix run ..#tests.default.container
nix run ..#tests.default.containerLegacy # For NixOS with `system.stateVersion` <22.05
# Run a command in a container
nix run ..#tests.default.container -- --run c nodeinfo
nix run ..#tests.default.containerLegacy -- --run c nodeinfo # For NixOS with `system.stateVersion` <22.05
```

View File

@ -1,14 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# This script can also be run locally for testing: # This script can also be run locally for testing:
# ./build.sh <scenario> # scenario=default ./build.sh
# #
# When variable CIRRUS_CI is unset, this script leaves no persistent traces on the host system. # When variable CIRRUS_CI is unset, this script leaves no persistent traces on the host system.
set -euo pipefail set -euo pipefail
scenario=$1
if [[ -v CIRRUS_CI ]]; then if [[ -v CIRRUS_CI ]]; then
if [[ ! -e /dev/kvm ]]; then if [[ ! -e /dev/kvm ]]; then
>&2 echo "No KVM available on VM host." >&2 echo "No KVM available on VM host."
@ -18,5 +16,5 @@ if [[ -v CIRRUS_CI ]]; then
chmod o+rw /dev/kvm chmod o+rw /dev/kvm
fi fi
cd "${BASH_SOURCE[0]%/*}" # shellcheck disable=SC2154
exec ./build-to-cachix.sh --expr "(builtins.getFlake (toString ../..)).legacyPackages.\${builtins.currentSystem}.tests.$scenario" "${BASH_SOURCE[0]%/*}/../run-tests.sh" --ci --scenario "$scenario"

View File

@ -1,21 +1,22 @@
# You can run this test via `run-tests.sh -s clightning-replication` # You can run this test via `run-tests.sh -s clightningReplication`
makeTestVM: pkgs: let
nixpkgs = (import ../pkgs/nixpkgs-pinned.nix).nixpkgs;
in
import "${nixpkgs}/nixos/tests/make-test-python.nix" ({ pkgs, ... }:
with pkgs.lib; with pkgs.lib;
let let
keyDir = pkgs.path + "/nixos/tests/initrd-network-ssh"; keyDir = "${nixpkgs}/nixos/tests/initrd-network-ssh";
keys = { keys = {
server = keyDir + "/ssh_host_ed25519_key"; server = "${keyDir}/ssh_host_ed25519_key";
client = keyDir + "/id_ed25519"; client = "${keyDir}/id_ed25519";
serverPub = readFile (keys.server + ".pub"); serverPub = readFile "${keys.server}.pub";
clientPub = readFile (keys.client + ".pub"); clientPub = readFile "${keys.client}.pub";
}; };
clientBaseConfig = { clientBaseConfig = {
imports = [ ../modules/modules.nix ]; imports = [ ../modules/modules.nix ];
nixpkgs.pkgs = pkgs;
nix-bitcoin.generateSecrets = true; nix-bitcoin.generateSecrets = true;
services.clightning = { services.clightning = {
@ -28,7 +29,7 @@ let
}; };
}; };
in in
makeTestVM { {
name = "clightning-replication"; name = "clightning-replication";
nodes = let nodes = { nodes = let nodes = {
@ -56,9 +57,7 @@ makeTestVM {
services.clightning.replication.encrypt = true; services.clightning.replication.encrypt = true;
}; };
server = { server = { ... }: {
nixpkgs.pkgs = pkgs;
environment.etc."ssh-host-key" = { environment.etc."ssh-host-key" = {
source = keys.server; source = keys.server;
mode = "400"; mode = "400";
@ -132,8 +131,8 @@ makeTestVM {
# A gocryptfs has been created # A gocryptfs has been created
client.succeed("ls /var/backup/clightning/lightningd-db/gocryptfs.conf") client.succeed("ls /var/backup/clightning/lightningd-db/gocryptfs.conf")
switch_to_system("replicationRemote")
server.wait_for_unit("sshd.service") server.wait_for_unit("sshd.service")
switch_to_system("replicationRemote")
with subtest("remote replication"): with subtest("remote replication"):
replica_db = "/var/cache/clightning-replication/sshfs/lightningd.sqlite3" replica_db = "/var/cache/clightning-replication/sshfs/lightningd.sqlite3"
client.succeed(f"runuser -u clightning -- ls {replica_db}") client.succeed(f"runuser -u clightning -- ls {replica_db}")
@ -151,4 +150,4 @@ makeTestVM {
# A gocryptfs has been created on the server # A gocryptfs has been created on the server
server.succeed("ls /var/backup/nb-replication/writable/lightningd-db/gocryptfs.conf") server.succeed("ls /var/backup/nb-replication/writable/lightningd-db/gocryptfs.conf")
''; '';
} })

View File

@ -14,7 +14,7 @@ atExit() {
trap "atExit" EXIT trap "atExit" EXIT
# shellcheck disable=SC2154 # shellcheck disable=SC2154
rsync -a --delete "$scriptDir/../" "$tmp/src" rsync -a --delete --exclude='.git*' "$scriptDir/../" "$tmp/src"
echo "Copied src" echo "Copied src"
# shellcheck disable=SC2154 # shellcheck disable=SC2154

View File

@ -0,0 +1,15 @@
# Create and maintain a minimal git repo at the root of the copied src
(
# shellcheck disable=SC2154,SC2164
cd "$scriptDir/.."
amend=(--amend)
if [[ ! -e .git ]] || ! git rev-parse HEAD 2>/dev/null; then
git init
amend=()
fi
git add .
if ! git diff --quiet --cached; then
git commit -a "${amend[@]}" -m -
fi
) >/dev/null

Some files were not shown because too many files have changed in this diff Show More