Compare commits

..

116 Commits

Author SHA1 Message Date
nixbitcoin
f2529154d4 joinmarket: 0.9.8 -> 0.9.9 2023-06-01 02:56:23 -07:00
Erik Arvstedt
376b344b90 lnd: fix non-static patch URL 2023-06-01 02:56:23 -07:00
Erik Arvstedt
d04549c0dc lnd: fix cert key format bug 2023-06-01 02:56:23 -07:00
Erik Arvstedt
de4bd2fb6f update nixpkgs
fulcrum: 1.9.0 -> 1.9.1
lightning-loop: 0.20.0-beta -> 0.23.0-beta
lnd: 0.15.5-beta -> 0.16.2-beta
2023-06-01 02:56:23 -07:00
Jonas Nick
82b2a95ccb Extend expiration date of key-jonasnick.bin
Exported with
`gpg --export-options export-minimal --export 0x4861DBF262123605! > key-jonasnick.bin`.
2023-06-01 02:56:23 -07:00
Otto Sabart
a0f2839817 docs: trustedcoin: add info about possible problems 2023-06-01 02:56:23 -07:00
Otto Sabart
fd000e7a14 trustedcoin: explicitly use the HTTPS_PROXY for external connections 2023-06-01 02:56:23 -07:00
Otto Sabart
bf6f9f8fae tests: add tests for trustedcoin clightning plugin 2023-06-01 02:56:23 -07:00
Otto Sabart
e99937991c trustedcoin: update to v0.6.1 2023-06-01 02:56:23 -07:00
Otto Sabart
60bf5fb8de trustedcoin: fix shellcheck 2023-06-01 02:56:23 -07:00
neverupdate
925492fc70 clightning-plugins: add trustedcoin 2023-06-01 02:56:23 -07:00
neverupdate
0c4ec63231 readme: reference trustedcoin source 2023-06-01 02:56:23 -07:00
neverupdate
cf10fbb74f trustedcoin: add module 2023-06-01 02:56:23 -07:00
neverupdate
fbe8f7c6cb trustedcoin: add pkg 2023-06-01 02:56:23 -07:00
Jonas Nick
356c5df9de update nixpkgs
electrs: 0.9.11 -> 0.9.13
elementsd: 22.1 -> 22.1.1
2023-06-01 02:56:23 -07:00
Jonas Nick
f6708ca2d7 update nixpkgs 2023-06-01 02:56:23 -07:00
Jonas Nick
4a28d53bcb update nixpkgs
clightning: 23.02 -> 23.02.2
2023-06-01 02:56:23 -07:00
Jonas Nick
c2d87b0b68 obsolete options: fix typo in removed lndconnectOnion option 2023-06-01 02:56:23 -07:00
Erik Arvstedt
0daf52bd3f nodeinfo: enable required option nix-bitcoin.operator 2023-06-01 02:56:23 -07:00
Erik Arvstedt
52810e6c88 nodeinfo/lnd: add onion_rest_address 2023-06-01 02:56:23 -07:00
Erik Arvstedt
5b6cd9fd49 nodeinfo/lnd: add rest_address 2023-06-01 02:56:23 -07:00
Erik Arvstedt
5f1e747270 add presets/wireguard.nix
This allows using `lndconnect` via a direct WireGuard connection.
2023-06-01 02:56:23 -07:00
Erik Arvstedt
05310fc02b lndconnect: update to Zeus 0.7.1
- Generate lndconnect URLs with protocol `c-lightning-rest` for clightning.
  (Zeus now auto-detects the lightning implementation by the URL protocol.)
- Use improved QR code format (via qrencode)  .
2023-06-01 02:56:23 -07:00
Erik Arvstedt
64304b6d66 lnd, clightning-rest: remove lndconnectOnion, add generic option lndconnect
For both lnd and clightning-rest, `lndconnectOnion` is replaced by
options `lndconnect.enable` and `lndconnect.onion`.

This allows using lndconnect without Tor.
2023-06-01 02:56:23 -07:00
Erik Arvstedt
992946f20e rename lndconnect-onion.nix -> lndconnect.nix 2023-06-01 02:56:23 -07:00
Erik Arvstedt
22de1a5353 docs/services: improve title, fix numbering 2023-06-01 02:56:23 -07:00
Jonas Nick
d04cad8ed1 update nixpkgs
clightning: 22.11.1 -> 23.02
hwi: 2.2.0 -> 2.2.1
2023-06-01 02:56:23 -07:00
Jonas Nick
ce332177be rtl: set DB_DIRECTORY_PATH
This prevents RTL from trying to create a database in the directory that
contains the RTL executable.
2023-06-01 02:56:23 -07:00
Jonas Nick
560efcb7f1 rtl: 0.13.4 -> 0.13.6 2023-06-01 02:56:23 -07:00
Erik Arvstedt
2344acbf42 btcpayserver: support restarting from the web interface
This is required since version 1.7.4.
See: https://github.com/btcpayserver/btcpayserver/releases/tag/v1.7.4
2023-06-01 02:56:23 -07:00
Jonas Nick
f26216b624 update nixpkgs
btcpayserver: 1.7.3 -> 1.7.12
elementsd: 22.0.2 -> 22.1
nbxplorer: 2.3.54 -> 2.3.62

Also add new required argument to flake-info in CI test script.
2023-06-01 02:56:23 -07:00
Erik Arvstedt
5b672fe82a README: add mempool extension module 2023-06-01 02:56:23 -07:00
Erik Arvstedt
7489c10999 README: add some module descriptions 2023-06-01 02:56:23 -07:00
Erik Arvstedt
6244e3a6ed dev/features: improve enter_service
Read uid/gid directly from the service pid.

This makes this fn work with arbitrary services, and with `bitcoind`,
where, for historical reasons, the service user name (`bitcoin`) doesn't
equal the service name.
2023-06-01 02:56:23 -07:00
Erik Arvstedt
a71c60bfe4 fulcrum: allow access to /proc/meminfo
This still hides the proc subdirectories for other processes.

Without this setting, fulcrum fails when the config value of
`fast-sync` is greater than 2^31 bytes.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
e9b6b3123d dev/dev-features: add enter_service helper 2023-06-01 02:56:22 -07:00
Erik Arvstedt
b5293b7e53 test: support run, debug commands in basic NixOS tests
Currently, this only affects the basic NixOS test `clightning-replication`.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
72f09458b6 tests/clightning-replication: reuse pkgs instance
This reduces eval time by 30%.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
2a073a1d64 tests: rename clightningReplication -> clightning-replication
The test name now matches the file name.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
3550ed1e32 secrets: use type lines for generateSecretsCmds
This allows users to amend secrets cmds.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
336a3fccf1 bitcoind, liquid: increase start/stop timeouts 2023-06-01 02:56:22 -07:00
Erik Arvstedt
c8f9e167c1 netns-isolation: improve formatting 2023-06-01 02:56:22 -07:00
Erik Arvstedt
9cb5a7295a netns-isolation: reserve netns id for mempool
This allows using the old id in the extension flake, so that
existing configs are not changed.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
11f91f83e6 add option nix-bitcoin.pkgOverlays
This simplifies extending `nix-bitcoin.pkgs` and is required for
extension flakes.
For now, mark this as `internal`.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
1645451275 helper: add start-bash-session.sh 2023-06-01 02:56:22 -07:00
Erik Arvstedt
a7bc488b17 nodeinfo: extract fn mkInfoLong
This is required by the mempool extension flake.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
9184db69dd improve comments
The comment in python-packackges was obsolete.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
0c354ee9eb rtl: make extraConfig recursively mergeable
Previously, when merging different definitions of `extraConfig`,
only the top-level attrset was merged.

Example:
The two separate settings
  nodes.lnd.extraConfig.Settings.userPersona = "MERCHANT";
  nodes.lnd.extraConfig.Settings.logLevel = "DEBUG";
were previously merged into
  nodes.lnd.extraConfig.Settings = { logLevel = "DEBUG" };
(The last definition has precedence.)
2023-06-01 02:56:22 -07:00
Erik Arvstedt
c9cfcf695f treewide: use bool literals for systemd
Run this from the repo root to check that there are no more remaining
bool strings:
grep -P '"true"|"false"' -r --exclude-dir=.git
2023-06-01 02:56:22 -07:00
Erik Arvstedt
f0ca489867 rtl: 0.13.2 -> 0.13.4 2023-06-01 02:56:22 -07:00
Erik Arvstedt
de49082f2a update nixpkgs
btcpayserver: 1.7.2 -> 1.7.3
electrs: 0.9.10 -> 0.9.11
hwi: 2.1.1 -> 2.2.0
2023-06-01 02:56:22 -07:00
Erik Arvstedt
22e41d5c06 add dev helper and docs 2023-06-01 02:56:22 -07:00
Erik Arvstedt
740dd666ad docs: move test docs from examples/README to test/README 2023-06-01 02:56:22 -07:00
Erik Arvstedt
1e21feb257 docs/configuration: fix typo 2023-06-01 02:56:22 -07:00
Erik Arvstedt
e7407d9efe tests: add example scenario customTest 2023-06-01 02:56:22 -07:00
Erik Arvstedt
cfeddd44aa tests: formatting
Move line next to `services.lnd` config for clarity.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
49229a3e2d tests: fix broken unit file when clightning is disabled
Previously, an incomplete clightning unit was always created because
attr `clightning` was always defined in option attrset `systemd.services`.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
c237f1302f run-tests: use arg instead of env var for scenario overrides
This removes a source of implicit state and guarantees that regular
calls to `run-tests.sh` always run the builtin tests.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
d119c207b9 versioning: add fulcrum db change info 2023-06-01 02:56:22 -07:00
Jonas Nick
4d637adf57 update nixpkgs
btcpayserver: 1.7.1 -> 1.7.2
fulcrum: 1.8.2 -> 1.9.0
nbxplorer: 2.3.49 -> 2.3.54
2023-06-01 02:56:22 -07:00
Erik Arvstedt
94659f3326 examples/deploy-container: fix sudo env propagation
Env vars can't be reliably passed through `sudo`, so always
call nix-shell to setup the env after running sudo.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
0e35b8a79a nix-bitcoin/runAsUserCmd: remove workaround 2023-06-01 02:56:22 -07:00
Erik Arvstedt
e6ce10a478 joinmarket: fix Python packages 2023-06-01 02:56:22 -07:00
Erik Arvstedt
d6cb65fbde clightning: fix Python packages
Patching `pyln-proto` to use cryptography 38 lets
us avoid adding many older Python pkg versions.

The backwards incompatible changes from cryptography 36 to 38
only include the removal of deprecated fns that pyln-proto
doesn't use.
See string "BACKWARDS INCOMPATIBLE" in
https://cryptography.io/en/latest/changelog/
2023-06-01 02:56:22 -07:00
Erik Arvstedt
2737e8374c pythonPackages: improve layout
- Move the creation of the joinmarket Python pkgs from
  `joinmarket/default.nix` to `pkgs/python-packages/default.nix`.

- Move definitions of old pkg versions from the main Python pkgs
  to the joinmarket Python pkgs.
  These old versions are only required by joinmarket.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
c3d2072b58 pythonPackages: add indentation
This makes the following commit more readable.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
f603cb6101 treewide: use mdDoc for descriptions
Enable markdown syntax (instead of docbook) for descriptions.
This only affects external doc tooling that renders the descriptions.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
e96ff7075e treewide: rename maintainer earvstedt -> erikarvstedt 2023-06-01 02:56:22 -07:00
Erik Arvstedt
ba54d3d699 shellcheck-services.nix: update to NixOS 22.11 2023-06-01 02:56:22 -07:00
Erik Arvstedt
2e5b287bc8 test: update to NixOS 22.11 2023-06-01 02:56:22 -07:00
Erik Arvstedt
7a2c1efd5d flake: remove 32-bit systems 2023-06-01 02:56:22 -07:00
Erik Arvstedt
2156b4410d update to NixOS 22.11
This includes no pkg version updates.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
bf7dc0f27a helper/update-flake: support updating NixOS versions 2023-06-01 02:56:22 -07:00
JayDeLux
85aa6f8ede minor typo 2023-06-01 02:56:22 -07:00
Erik Arvstedt
f3fdab1d76 rtl: 0.13.1 -> 0.13.2 2023-06-01 02:56:22 -07:00
nixbitcoin
de4dccb006 joinmarket: 0.9.7 -> 0.9.8 2023-06-01 02:56:22 -07:00
Jonas Nick
bc72ad94b3 clightning: set "database-upgrade=true" for 22.11.1 2023-06-01 02:56:22 -07:00
Jonas Nick
6b7b23cd6e update nixpkgs
btcpayserver: 1.6.12 -> 1.7.1
bitcoind: 24.0 -> 24.0.1
clightning: 0.12.1 -> 22.11.1
lnd: 0.15.4-beta -> 0.15.5-beta
nbxplorer: 2.3.41 -> 2.3.49
2023-06-01 02:56:22 -07:00
Jonas Nick
de4797be1f update nixpkgs
bitcoin: 23.0 -> 24.0
bitcoind: 23.0 -> 24.0
charge-lnd: 0.2.12 -> 0.2.13
2023-06-01 02:56:22 -07:00
Erik Arvstedt
761898f380 lnd: support INADDR_ANY addresses for bitcoind.zmqpubraw*
Also use `mkDefault` when defining `bitcoind.zmqpubraw*` to simplify
overriding for users.
2023-06-01 02:56:22 -07:00
Jonas Nick
206deaf2b3 update nixpkgs
electrs: 0.9.9 -> 0.9.10
elementsd: 22.0 -> 22.0.2
extra-container: 0.10 -> 0.11
lnd: 0.15.2-beta -> 0.15.4-beta
2023-06-01 02:56:22 -07:00
Jonas Nick
c263aec335 Revert "pkgs: add lnd 0.15.4 (hotfix)"
This reverts commit 57b76d4461.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
9c61850621 clightning-replication: switch system before waiting for server sshd
This is primarily a cosmetic change.
- Increases code clarity because all system test blocks now start with `switch_to_system`
- Optimizes dependency ordering because `switch_to_system` has no
  dependency on the server sshd
2023-06-01 02:56:22 -07:00
Erik Arvstedt
45bfc181fc clightning: extract var bitcoind
Follow the default module formatting style.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
4bb95d1e29 examples/vm-config: fix syntax error 2023-06-01 02:56:22 -07:00
Erik Arvstedt
a1a27857e7 examples/minimal-vm: add lightning-cli demo command 2023-06-01 02:56:22 -07:00
Erik Arvstedt
6dd365e719 treewide: set shebang for bash scripts
These scripts previously failed when called with syscalls like
`execve` (used by, e.g., Python's `subprocess.run`) that use no default
interpreter for scripts without a shebang.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
e68cb010ba tests: define tests via flake
Advantages:
- Pure test evaluations
- The test framework can now be used by flakes that extend nix-bitcoin
- Most features of `run-tests.sh` are now accessible via `nix build`/`nix run`.
  We keep `run-tests.sh` for advanced features like `scenarioOverridesFile` and adhoc scenarios.

Other changes:
- `run-tests.sh` now builds aggregate VM tests like `basic` or
  `buildable` by creating all VMs in a single evaluation.
  This speeds up the tests and eases debugging by separating the eval and build steps.
- Use the new `nix` CLI which has improved build output logging
  by prefixing output lines with the origin drv name.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
f4f4808d59 nodeinfo: rename nodeinfoLib -> lib 2023-06-01 02:56:22 -07:00
Erik Arvstedt
32db35d1bf tests: move mkIfTest to nix-bitcoin.lib 2023-06-01 02:56:22 -07:00
Erik Arvstedt
bd5d70813f flake: expose supportedSystems 2023-06-01 02:56:22 -07:00
Erik Arvstedt
d70fc7d71b nixos-search/flake: formatting 2023-06-01 02:56:22 -07:00
Erik Arvstedt
820a71f34f flake: rename input nixpkgsUnstable -> nixpkgs-unstable
This follows common flake naming conventions.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
ab23466fb7 tests/container: don't require services.clightning to be defined 2023-06-01 02:56:22 -07:00
Erik Arvstedt
365068d763 tests/run-tests.sh: print examples before running
This eases debugging example failures.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
e2d653e7cb tests/copy-src: always copy .git dir
This is required by a later commit that introduces flakes-based test
evaluation. Evaluating local flakes needs a repo dir.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
f405a2ceda make-container.sh: improve root handling
Don't auto-switch to root when executing make-container.sh, because
auto root switching is also implemented in extra-container.

Besides simplifying the code, this is useful for a later commit that
introduces flakes-based container building.
With this change, the container is built under the regular user
instead of root, thereby utilizing the user's regular fetcher and
evaluation caches.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
6a2d4ab1d7 profiles/hardened: support pure eval mode 2023-06-01 02:56:22 -07:00
Erik Arvstedt
ada564c1ea add compatibility with Nix PR #6530 (Source tree abstraction)
Avoid adding flake resource paths to the store (via string
interpolation).
This reduces performance and can lead to modules getting imported
twice, once through a local path and once through a store path.

This might not be needed in a future Nix release, in which case we can
revert this.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
514c05ee47 tests/vmWithoutTests: poweroff on shell exit
This allows quitting the VM with Ctrl-D like in the minimal example VM.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
c12489d838 tests, example: avoid lengthy documentation build
This options manual rebuild takes 30-60s and is triggered by the extra
NixOS options defined by nix-bitcoin.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
d5e50191d6 test/shellcheck-services: add configurable source prefix
This allows using this module for services defined outside of nix-bitcoin.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
b2bae90584 bitcoind: fix rare startup error
Previously, dhcpcd and bitcoind starting up in parallel could lead to
the following error in bitcoind:
```
bitcoind: libevent: getaddrinfo: address family for nodename not supported
bitcoind: Binding RPC on address 127.0.0.1 port 8332 failed.
bitcoind: Unable to bind any endpoint for
```
After the initial failure, the bitcoind service would always restart successfully.

This race condition, where both applications were simultaneously
manipulating network resources, was only triggered under specific
hardware conditions.

Fix it by running bitcoind after dhcp has started (by running after
`network-online.target`).
This bug and the fix only affect the default NixOS scripted
networking backend.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
f874c3b563 pkgs: add lnd 0.15.4 (hotfix)
Includes an emergency hotfix:
https://github.com/lightningnetwork/lnd/releases/tag/v0.15.4-beta
2023-06-01 02:56:22 -07:00
Erik Arvstedt
b3c134c01d lnd: fix missing RPC permissions when bitcoind is pruned 2023-06-01 02:56:22 -07:00
Erik Arvstedt
29d1a6b8a8 test/shellcheck-services: fix error by excluding unavailable services 2023-06-01 02:56:22 -07:00
Erik Arvstedt
425a411e2b test/shellcheck-services: simplify accessing service definitions
This also improves performance by removing the extra module evaluation.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
5e6b560fcf tests: run flake-info in sandbox
Don't use sandboxing in Cirrus CI where namespace support is missing.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
bdb4ee0e0b revert "tests: disable nixosSearch" 2023-06-01 02:56:22 -07:00
Erik Arvstedt
d96c0a628a btcpayserver: use new option certfilepath for lnd 2023-06-01 02:56:22 -07:00
Erik Arvstedt
589860b842 Revert "pkgs: add lnd 0.15.2"
This reverts commit cf836b5d3b.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
ac4c01c374 update nixpkgs
btcpayserver: 1.6.10 -> 1.6.12
clightning: 0.12.0 -> 0.12.1
fulcrum: 1.8.1 -> 1.8.2
nbxplorer: 2.3.33 -> 2.3.41
2023-06-01 02:56:22 -07:00
Erik Arvstedt
effc1ce0a7 defaultHardening: allow syscall set_mempolicy
This syscall is safe to allow.
It's required by the dotnet runtime (btcpayserver, nbxplorer) update
introduced in the following commit.
2023-06-01 02:56:22 -07:00
Erik Arvstedt
48170b241c pkgs: add lnd 0.15.2
Includes an emergency hotfix:
https://github.com/lightningnetwork/lnd/releases/tag/v0.15.2-beta
2023-06-01 02:56:22 -07:00
Jonas Nick
5a063aff00 update nixpkgs
electrs: 0.9.7 -> 0.9.9
elementsd: 0.21.0.2 -> 22.0
fulcrum: 1.7.0 -> 1.8.1
2023-06-01 02:56:22 -07:00
Jonas Nick
b25bccbdc6 clightning-plugins: update packages 2023-06-01 02:56:22 -07:00
115 changed files with 3351 additions and 1349 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.05 image: nixpkgs/nix-flakes:nixos-22.11
matrix: matrix:
- name: modules_test - name: modules_test
@ -27,14 +27,16 @@ 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,gawk,cachix} -c ./test/ci/build.sh - nix shell --inputs-from . nixpkgs#{bash,coreutils,cachix} -c ./test/ci/build.sh $scenario
- 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,6 +53,8 @@ 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)
@ -77,19 +79,22 @@ 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 clightning via a REST onion service * [lndconnect](https://github.com/LN-Zap/lndconnect): connect your wallet to lnd or
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) * [electrs](https://github.com/romanz/electrs): Electrum server
* [fulcrum](https://github.com/cculianu/Fulcrum) (see [the module](modules/fulcrum.nix) for a comparison to electrs) * [fulcrum](https://github.com/cculianu/Fulcrum): Electrum server (see [the module](modules/fulcrum.nix) for a comparison with electrs)
* [btcpayserver](https://github.com/btcpayserver/btcpayserver) * [btcpayserver](https://github.com/btcpayserver/btcpayserver)
* [liquid](https://github.com/elementsproject/elements) * [liquid](https://github.com/elementsproject/elements): federated sidechain
* [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)
@ -97,7 +102,13 @@ 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): adds non-root user `operator` who has access to client tools (e.g. `bitcoin-cli`, `lightning-cli`) * [operator](modules/operator.nix): configures a non-root user 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
--- ---
@ -118,6 +129,10 @@ 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.\

104
dev/README.md Normal file
View File

@ -0,0 +1,104 @@
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

65
dev/dev-env/create.sh Executable file
View File

@ -0,0 +1,65 @@
#!/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

16
dev/dev-env/dev-shell.nix Normal file
View File

@ -0,0 +1,16 @@
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

@ -0,0 +1,25 @@
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

@ -0,0 +1,20 @@
{ 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;
};
}

300
dev/dev-features.sh Normal file
View File

@ -0,0 +1,300 @@
# 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

78
dev/dev-scenarios.nix Normal file
View File

@ -0,0 +1,78 @@
# 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;
};
}

128
dev/dev.sh Normal file
View File

@ -0,0 +1,128 @@
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# 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

@ -0,0 +1,64 @@
#―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
# 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

47
dev/topics/rtl.sh Normal file
View File

@ -0,0 +1,47 @@
# 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 nodes # 1. Stop bitcoind on your node
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 exists, you should continue the installation for UEFI otherwise for Legacy Boot. If the file 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,60 +142,154 @@ 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 LND or clightning with Zeus (mobile wallet) via Tor # Use Zeus (mobile lightning wallet) via Tor
1. Install [Zeus](https://zeusln.app) 1. Install [Zeus](https://zeusln.app) (version ≥ 0.7.1)
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.lndconnectOnion.enable = true; services.lnd.lndconnect = {
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;
lndconnectOnion.enable = true; lndconnect = {
enable = true;
onion = true;
};
}; };
``` ```
3. Deploy your configuration 3. Deploy your configuration
3. Run the following command on your node (as user `operator`) to create a QR code 4. 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-onion lndconnect
``` ```
##### For clightning ##### For clightning
``` ```
lndconnect-onion-clightning lndconnect-clightning
``` ```
4. Configure Zeus 5. Configure Zeus
- Add a new node - Add a new node and scan the QR code
- 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 plain text URLs or QR code images: - Create a plain text URL:
``` ```bash
lndconnect-onion --url lndconnect --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
@ -527,3 +621,27 @@ 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,41 +51,11 @@ the node:
``` ```
### Tests ### Tests
The internal test suite is also useful for exploring features.\ The [nix-bitcoin test suite](../test/README.md) 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 nix-bitcoin node that's used in production. to see the configuration of a Flakes-based 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,13 +56,18 @@
# #
# == 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-onion-clightning` to the system environment. # This also adds binary `lndconnect-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 (see ../docs/services.md). # via the REST onion service.
# 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;
# lndconnectOnion.enable = true; # lndconnect = {
# enable = true;
# onion = true;
# };
# }; # };
### LND ### LND
@ -78,11 +83,17 @@
# 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 an lnd REST onion service. # Set this to create a lnd REST onion service.
# This also adds binary `lndconnect-onion` to the system environment. # This also adds binary `lndconnect` 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 (see ../docs/services.md). # REST onion service.
# services.lnd.lndconnectOnion.enable = true; # You can also connect via WireGuard instead of Tor.
# 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
@ -287,10 +298,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.05"; # Did you read the comment? system.stateVersion = "22.11"; # 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.70"; nix-bitcoin.configVersion = "0.0.85";
} }

View File

@ -1,17 +1,11 @@
#!/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 '
@ -31,4 +25,4 @@ cat > "$tmpDir/configuration.nix" <<EOF
} }
EOF EOF
"${BASH_SOURCE[0]%/*}/deploy-container.sh" "$tmpDir/configuration.nix" "$@" ./deploy-container.sh "$tmpDir/configuration.nix" "$@"

View File

@ -8,23 +8,21 @@ set -euo pipefail
# Run with option `--interactive` or `-i` to start a shell for interacting with # Run with option `--interactive` or `-i` to start a shell for interacting with
# the node. # the node.
if [[ ! -v NIX_BITCOIN_EXAMPLES_DIR ]]; then if [[ $EUID != 0 ]]; then
echo "Running script in nix shell env..." # NixOS containers require root permissions
cd "${BASH_SOURCE[0]%/*}" exec sudo "${BASH_SOURCE[0]}" "$@"
exec nix-shell --run "./${BASH_SOURCE[0]##*/} $*"
else
cd "$NIX_BITCOIN_EXAMPLES_DIR"
fi fi
if [[ $(sysctl -n net.ipv4.ip_forward || sudo sysctl -n net.ipv4.ip_forward) != 1 ]]; then if [[ $(sysctl -n net.ipv4.ip_forward) != 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 [[ $EUID != 0 ]]; then if [[ ! -v DEPLOY_CONTAINER_NIX_SHELL ]]; then
# NixOS containers require root permissions echo "Running script in nix shell env..."
exec sudo "PATH=$PATH" "NIX_PATH=$NIX_PATH" "NIX_BITCOIN_EXAMPLES_DIR=$NIX_BITCOIN_EXAMPLES_DIR" "${BASH_SOURCE[0]}" "$@" cd "${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,6 +29,9 @@ 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}" ];
@ -40,6 +43,7 @@ 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,12 +1,38 @@
{ {
"nodes": { "nodes": {
"flake-utils": { "extra-container": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": { "locked": {
"lastModified": 1659877975, "lastModified": 1679648217,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", "narHash": "sha256-aq2J5Hj5IE8X8X/7v3n0wcv8n+FLzzENbcCF9xqhxAc=",
"owner": "erikarvstedt",
"repo": "extra-container",
"rev": "40c73f5e3292e73d6ce91625d9751be84fde17cb",
"type": "github"
},
"original": {
"owner": "erikarvstedt",
"repo": "extra-container",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1681202837,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", "rev": "cfacdce06f30d2b68473a46042957675eebb3401",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -17,27 +43,27 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1662099760, "lastModified": 1683207485,
"narHash": "sha256-MdZLCTJPeHi/9fg6R9fiunyDwP3XHJqDd51zWWz9px0=", "narHash": "sha256-gs+PHt/y/XQB7S8+YyBLAM8LjgYpPZUVFQBwpFSmJro=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "67e45078141102f45eff1589a831aeaa3182b41e", "rev": "cc45a3f8c98e1c33ca996e3504adefbf660a72d1",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-22.05", "ref": "nixos-22.11",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"nixpkgsUnstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1662096612, "lastModified": 1683353485,
"narHash": "sha256-R+Q8l5JuyJryRPdiIaYpO5O3A55rT+/pItBrKcy7LM4=", "narHash": "sha256-Skp5El3egmoXPiINWjnoW0ktVfB7PR/xc4F4bhD+BJY=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "21de2b973f9fee595a7a1ac4693efff791245c34", "rev": "caf436a52b25164b71e0d48b671127ac2e2a5b75",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -49,9 +75,25 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"extra-container": "extra-container",
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"nixpkgsUnstable": "nixpkgsUnstable" "nixpkgs-unstable": "nixpkgs-unstable"
}
},
"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,27 +5,42 @@
''; '';
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.05"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.11";
nixpkgsUnstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; nixpkgs-unstable.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, nixpkgsUnstable, flake-utils }: outputs = { self, nixpkgs, nixpkgs-unstable, flake-utils, ... }:
let let
supportedSystems = [ supportedSystems = [
"x86_64-linux" "x86_64-linux"
"i686-linux"
"aarch64-linux" "aarch64-linux"
"armv7l-linux" # On these 32-bit platforms, Python pkg `pymemcache` 4.0.0 (required by
# `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 ? nixpkgsUnstable.legacyPackages.${system} , pkgsUnstable ? nixpkgs-unstable.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
@ -91,7 +106,12 @@
# 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 = nbPkgs; legacyPackages =
nbPkgs //
(test.pkgs self pkgs) //
{
extra-container = self.inputs.extra-container.packages.${system}.default;
};
apps = rec { apps = rec {
default = vm; default = vm;
@ -102,6 +122,8 @@
program = toString packages.runVM; program = toString packages.runVM;
}; };
}; };
devShells.default = import ./dev/dev-env/dev-shell.nix pkgs;
} }
)); ));
} }

Binary file not shown.

View File

@ -0,0 +1,12 @@
# 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,6 +12,19 @@ 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]%/*}"
@ -21,7 +34,7 @@ if [[ $(nix flake 2>&1) != *"requires a sub-command"* ]]; then
exit 1 exit 1
fi fi
if [[ ${1:-} != -f ]] && ! git diff --quiet ../flake.{nix,lock}; then if [[ $forceRun ]] && ! 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
@ -36,6 +49,9 @@ 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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = "List of database names to backup."; description = mdDoc "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 = "Additional files to be appended to filelist."; description = mdDoc "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 = "Address to listen for peer connections."; description = mdDoc "Address to listen for peer connections.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 8333; default = 8333;
description = "Port to listen for peer connections."; description = mdDoc "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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
Listen for peer connections at `address:port` Listen for peer connections at `address:port`
and `address:onionPort` (if `onionPort` is set). and `address:onionPort` (if {option}`onionPort` is set).
''; '';
}; };
listenWhitelisted = mkOption { listenWhitelisted = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = mdDoc ''
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 = "See `listenWhitelisted`."; description = mdDoc "See `listenWhitelisted`.";
}; };
getPublicAddressCmd = mkOption { getPublicAddressCmd = mkOption {
type = types.str; type = types.str;
default = ""; default = "";
description = '' description = mdDoc ''
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 = "The package providing bitcoin binaries."; description = mdDoc "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 = "Extra lines appended to <filename>bitcoin.conf</filename>."; description = mdDoc "Extra lines appended to {file}`bitcoin.conf`.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/bitcoind"; default = "/var/lib/bitcoind";
description = "The data directory for bitcoind."; description = mdDoc "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 = '' description = mdDoc ''
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 = "Port to listen for JSON-RPC connections."; description = mdDoc "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 = "The number of threads to service RPC calls."; description = mdDoc "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 = '' description = mdDoc ''
Allow JSON-RPC connections from specified sources. Allow JSON-RPC connections from specified sources.
''; '';
}; };
users = mkOption { users = mkOption {
default = {}; default = {};
description = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = "Enable regtest mode."; description = mdDoc "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 = "Connect through SOCKS5 proxy"; description = mdDoc "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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = "Override the default database cache size in MiB."; description = mdDoc "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 = '' description = mdDoc ''
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 = "Enable the transaction index."; description = mdDoc "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 = "ZMQ address for zmqpubrawblock notifications"; description = mdDoc "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 = "ZMQ address for zmqpubrawtx notifications"; description = mdDoc "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 = '' description = mdDoc ''
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 = "Add nodes to connect to and attempt to keep the connections open"; description = mdDoc "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 = "Discover own IP addresses"; description = mdDoc "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 = "The type of addresses to use"; description = mdDoc "The type of addresses to use";
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "bitcoin"; default = "bitcoin";
description = "The user as which to run bitcoind."; description = mdDoc "The user as which to run bitcoind.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = "The group as which to run bitcoind."; description = mdDoc "The group as which to run bitcoind.";
}; };
cli = mkOption { cli = mkOption {
readOnly = true; readOnly = true;
type = types.package; type = types.package;
default = pkgs.writeScriptBin "bitcoin-cli" '' default = pkgs.writers.writeBashBin "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 = "Binary to connect with the bitcoind instance."; description = mdDoc "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.target" "nix-bitcoin-secrets.target" ]; after = [ "network-online.target" "nix-bitcoin-secrets.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
preStart = let preStart = let
@ -422,8 +422,8 @@ in {
NotifyAccess = "all"; NotifyAccess = "all";
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;
TimeoutStartSec = "10min"; TimeoutStartSec = "30min";
TimeoutStopSec = "10min"; TimeoutStopSec = "30min";
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";

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 = "Address to listen on."; description = mdDoc "Address to listen on.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 23000; default = 23000;
description = "Port to listen on."; description = mdDoc "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 = "The package providing btcpayserver binaries."; description = mdDoc "The package providing btcpayserver binaries.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/btcpayserver"; default = "/var/lib/btcpayserver";
description = "The data directory for btcpayserver."; description = mdDoc "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 = "The lightning node implementation to use."; description = mdDoc "The lightning node implementation to use.";
}; };
lbtc = mkOption { lbtc = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = "Enable liquid support in btcpayserver."; description = mdDoc "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 = "The prefix for root-relative btcpayserver URLs."; description = mdDoc "The prefix for root-relative btcpayserver URLs.";
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "btcpayserver"; default = "btcpayserver";
description = "The user as which to run btcpayserver."; description = mdDoc "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 = "The group as which to run btcpayserver."; description = mdDoc "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 = '' description = mdDoc ''
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 = "The package providing nbxplorer binaries."; description = mdDoc "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 = "Address to listen on."; description = mdDoc "Address to listen on.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 24444; default = 24444;
description = "Port to listen on."; description = mdDoc "Port to listen on.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/nbxplorer"; default = "/var/lib/nbxplorer";
description = "The data directory for nbxplorer."; description = mdDoc "The data directory for nbxplorer.";
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "nbxplorer"; default = "nbxplorer";
description = "The user as which to run nbxplorer."; description = mdDoc "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 = "The group as which to run nbxplorer."; description = mdDoc "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 "config" ('' configFile = builtins.toFile "btcpayserver-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,42 +212,40 @@ 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.lbtc '' '' + optionalString (cfg.btcpayserver.lightningBackend == "lnd")
(
"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='${cfg.btcpayserver.dataDir}/settings.config' \ ${cfg.btcpayserver.package}/bin/btcpayserver --conf=${configFile} \
--datadir='${cfg.btcpayserver.dataDir}' --datadir='${cfg.btcpayserver.dataDir}'
''; '';
User = cfg.btcpayserver.user; User = cfg.btcpayserver.user;
Restart = "on-failure"; # Also restart after the program has exited successfully.
RestartSec = "10s"; # This is required to support restarting from the web interface after
# 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,18 +9,17 @@ let
type = listOf str; type = listOf str;
default = []; default = [];
example = [ "--verbose" "--dry-run" ]; example = [ "--verbose" "--dry-run" ];
description = "Extra flags to pass to the charge-lnd command."; description = mdDoc "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 = '' description = mdDoc ''
Systemd calendar expression when to adjust fees. Systemd calendar expression when to adjust fees.
See <citerefentry><refentrytitle>systemd.time</refentrytitle> See {man}`systemd.time(7)` for possible values.
<manvolnum>7</manvolnum></citerefentry> for possible values.
Default is once a day. Default is once a day.
''; '';
@ -29,7 +28,7 @@ let
randomDelay = mkOption { randomDelay = mkOption {
type = str; type = str;
default = "1h"; default = "1h";
description = '' description = mdDoc ''
Random delay to add to scheduled time. Random delay to add to scheduled time.
''; '';
}; };
@ -55,7 +54,7 @@ let
[default] [default]
strategy = ignore strategy = ignore
''; '';
description = '' description = mdDoc ''
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
@ -126,7 +125,6 @@ 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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 this amount is smaller than clboss will only open new channels if the funds in your clightning wallet are
the funds in your clightning wallet. larger than this amount.
''; '';
}; };
min-channel = mkOption { min-channel = mkOption {
type = types.ints.positive; type = types.ints.positive;
default = 500000; default = 500000;
description = "The minimum size (in satoshi) of channels created by CLBOSS."; description = mdDoc "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 = "The maximum size (in satoshi) of channels created by CLBOSS."; description = mdDoc "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 = '' description = mdDoc ''
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 = "The package providing clboss binaries."; description = mdDoc "The package providing clboss binaries.";
}; };
}; };

View File

@ -17,6 +17,7 @@ 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 = '' description = mdDoc ''
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 = "Enable update threshold randomization and hysteresis."; description = mdDoc "Enable update threshold randomization and hysteresis.";
}; };
adjustOnForward = mkOption { adjustOnForward = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = "Automatically update fees on forward events."; description = mdDoc "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 = '' description = mdDoc ''
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 = "Automatically update fees daily."; description = mdDoc "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 = "The currency to look up on btcaverage."; description = mdDoc "The currency to look up on btcaverage.";
}; };
currencyPrefix = mkOption { currencyPrefix = mkOption {
type = types.str; type = types.str;
default = "USD $"; default = "USD $";
description = "The prefix to use for the currency."; description = mdDoc "The prefix to use for the currency.";
}; };
availabilityInterval = mkOption { availabilityInterval = mkOption {
type = types.int; type = types.int;
default = 300; default = 300;
description = "How often in seconds the availability should be calculated."; description = mdDoc "How often in seconds the availability should be calculated.";
}; };
availabilityWindow = mkOption { availabilityWindow = mkOption {
type = types.int; type = types.int;
default = 72; default = 72;
description = "How many hours the availability should be averaged over."; description = mdDoc "How many hours the availability should be averaged over.";
}; };
}; };

View File

@ -0,0 +1,28 @@
{ 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 = "Endpoint for ${name}"; description = mdDoc "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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = "SSH port of the remote server."; description = mdDoc "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 = "SSH options used for mounting the SSHFS."; description = mdDoc "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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 `$secretsDir/clightning-replication-password`. in file {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 = "REST server port."; description = mdDoc "REST server port.";
}; };
docPort = mkOption { docPort = mkOption {
type = types.port; type = types.port;
default = 4001; default = 4001;
description = "Swagger API documentation server port."; description = mdDoc "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 = "The data directory for clightning-rest."; description = mdDoc "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 = '' description = mdDoc ''
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 = "The group under which clightning-rest is run."; description = mdDoc "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 = "Address to listen for peer connections."; description = mdDoc "Address to listen for peer connections.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 9735; default = 9735;
description = "Port to listen for peer connections."; description = mdDoc "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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = "The data directory for clightning."; description = mdDoc "The data directory for clightning.";
}; };
networkDir = mkOption { networkDir = mkOption {
readOnly = true; readOnly = true;
default = "${cfg.dataDir}/${network}"; default = "${cfg.dataDir}/${network}";
description = "The network data directory."; description = mdDoc "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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 `lightningd --help`. or by running {command}`lightningd --help`.
''; '';
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "clightning"; default = "clightning";
description = "The user as which to run clightning."; description = mdDoc "The user as which to run clightning.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = "The group as which to run clightning."; description = mdDoc "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 = "The package providing clightning binaries."; description = mdDoc "The package providing clightning binaries.";
}; };
cli = mkOption { cli = mkOption {
readOnly = true; readOnly = true;
default = pkgs.writeScriptBin "lightning-cli" '' default = pkgs.writers.writeBashBin "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 = "Binary to connect with the clightning instance."; description = mdDoc "Binary to connect with the clightning instance.";
}; };
getPublicAddressCmd = mkOption { getPublicAddressCmd = mkOption {
type = types.str; type = types.str;
default = ""; default = "";
description = '' description = mdDoc ''
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,19 +102,28 @@ let
nbLib = config.nix-bitcoin.lib; nbLib = config.nix-bitcoin.lib;
nbPkgs = config.nix-bitcoin.pkgs; nbPkgs = config.nix-bitcoin.pkgs;
network = config.services.bitcoind.makeNetworkName "bitcoin" "regtest"; inherit (config.services) bitcoind;
network = bitcoind.makeNetworkName "bitcoin" "regtest";
configFile = pkgs.writeText "config" '' configFile = pkgs.writeText "config" ''
network=${network} network=${network}
bitcoin-datadir=${config.services.bitcoind.dataDir} ${optionalString (!cfg.plugins.trustedcoin.enable) "bitcoin-datadir=${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-rpcport=${toString config.services.bitcoind.rpc.port} bitcoin-rpcconnect=${nbLib.address bitcoind.rpc.address}
bitcoin-rpcuser=${config.services.bitcoind.rpc.users.public.name} bitcoin-rpcport=${toString bitcoind.rpc.port}
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}
''; '';
@ -154,6 +163,7 @@ 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 = "Address to listen for RPC connections."; description = mdDoc "Address to listen for RPC connections.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 50001; default = 50001;
description = "Port to listen for RPC connections."; description = mdDoc "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 = "The data directory for electrs."; description = mdDoc "The data directory for electrs.";
}; };
monitoringPort = mkOption { monitoringPort = mkOption {
type = types.port; type = types.port;
default = 4224; default = 4224;
description = "Prometheus monitoring port."; description = mdDoc "Prometheus monitoring port.";
}; };
extraArgs = mkOption { extraArgs = mkOption {
type = types.separatedString " "; type = types.separatedString " ";
default = ""; default = "";
description = "Extra command line arguments passed to electrs."; description = mdDoc "Extra command line arguments passed to electrs.";
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "electrs"; default = "electrs";
description = "The user as which to run electrs."; description = mdDoc "The user as which to run electrs.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = "The group as which to run electrs."; description = mdDoc "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 = '' description = mdDoc ''
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
`extraConfig`. {option}`extraConfig`.
''; '';
}; };
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = "Address to listen for RPC connections."; description = mdDoc "Address to listen for RPC connections.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 50001; default = 50001;
description = "Port to listen for RPC connections."; description = mdDoc "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 = "The data directory for fulcrum."; description = mdDoc "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 = '' description = mdDoc ''
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 = "The user as which to run fulcrum."; description = mdDoc "The user as which to run fulcrum.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = "The group as which to run fulcrum."; description = mdDoc "The group as which to run fulcrum.";
}; };
tor.enforce = nbLib.tor.enforce; tor.enforce = nbLib.tor.enforce;
}; };
@ -126,6 +126,7 @@ 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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = "HTTP server address."; description = mdDoc "HTTP server address.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 62601; default = 62601;
description = "HTTP server port."; description = mdDoc "HTTP server port.";
}; };
dataDir = mkOption { dataDir = mkOption {
readOnly = true; readOnly = true;
default = "/var/lib/joinmarket-ob-watcher"; default = "/var/lib/joinmarket-ob-watcher";
description = "The data directory for JoinMarket orderbook watcher."; description = mdDoc "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 = "The user as which to run JoinMarket."; description = mdDoc "The user as which to run JoinMarket.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = "The group as which to run JoinMarket."; description = mdDoc "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 = '' description = mdDoc ''
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 = "The port corresponding to option `payjoinAddress`."; description = mdDoc "The port corresponding to option {option}`payjoinAddress`.";
}; };
messagingAddress = mkOption { messagingAddress = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = '' description = mdDoc ''
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 = "The port corresponding to option `messagingAddress`."; description = mdDoc "The port corresponding to option {option}`messagingAddress`.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/joinmarket"; default = "/var/lib/joinmarket";
description = "The data directory for JoinMarket."; description = mdDoc "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 = '' description = mdDoc ''
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 = "The user as which to run JoinMarket."; description = mdDoc "The user as which to run JoinMarket.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = "The group as which to run JoinMarket."; description = mdDoc "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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = 3kxw6lf5vf6y26emzwgibzhrzhmhqiw6ekrek3nqfjjmhwznb2moonad.onion:5222,jmdirjmioywe2s5jad7ts6kgcqg66rj6wujj6q77n6wbdrgocqwexzid.onion:5222,bqlpq6ak24mwvuixixitift4yu42nxchlilrcqwk2ugn45tdclg42qid.onion:5222 directory_nodes = g3hv4uynnmynqqq2mchf3fcm3yd46kfzmcdogejuckgwknwyq5ya6iad.onion:5222,3kxw6lf5vf6y26emzwgibzhrzhmhqiw6ekrek3nqfjjmhwznb2moonad.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 = "Address to listen for gRPC connections."; description = mdDoc "Address to listen for gRPC connections.";
}; };
rpcPort = mkOption { rpcPort = mkOption {
type = types.port; type = types.port;
default = 11010; default = 11010;
description = "Port to listen for gRPC connections."; description = mdDoc "Port to listen for gRPC connections.";
}; };
restAddress = mkOption { restAddress = mkOption {
type = types.str; type = types.str;
default = cfg.rpcAddress; default = cfg.rpcAddress;
description = "Address to listen for REST connections."; description = mdDoc "Address to listen for REST connections.";
}; };
restPort = mkOption { restPort = mkOption {
type = types.port; type = types.port;
default = 8081; default = 8081;
description = "Port to listen for REST connections."; description = mdDoc "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 = "The package providing lightning-loop binaries."; description = mdDoc "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 = "The data directory for lightning-loop."; description = mdDoc "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 = "host:port of SOCKS5 proxy for connnecting to the loop server."; description = mdDoc "`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 = '' description = mdDoc ''
Extra `subjectAltName` IPs added to the certificate. Extra `subjectAltName` IPs added to the certificate.
This works the same as loop option `tlsextraip`. This works the same as loop option {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 = '' description = mdDoc ''
Extra `subjectAltName` domain names added to the certificate. Extra `subjectAltName` domain names added to the certificate.
This works the same as loop option `tlsextradomain`. This works the same as loop option {option}`tlsextradomain`.
''; '';
}; };
}; };
@ -66,21 +66,21 @@ let
example = '' example = ''
debuglevel=trace debuglevel=trace
''; '';
description = '' description = mdDoc ''
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.writeScriptBin "loop" '' default = pkgs.writers.writeBashBin "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 = "Binary to connect with the lightning-loop instance."; description = mdDoc "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 = "Address to listen for gRPC connections."; description = mdDoc "Address to listen for gRPC connections.";
}; };
rpcPort = mkOption { rpcPort = mkOption {
type = types.port; type = types.port;
default = 12010; default = 12010;
description = "Port to listen for gRPC connections."; description = mdDoc "Port to listen for gRPC connections.";
}; };
restAddress = mkOption { restAddress = mkOption {
type = types.str; type = types.str;
default = cfg.rpcAddress; default = cfg.rpcAddress;
description = "Address to listen for REST connections."; description = mdDoc "Address to listen for REST connections.";
}; };
restPort = mkOption { restPort = mkOption {
type = types.port; type = types.port;
default = 8281; default = 8281;
description = "Port to listen for REST connections."; description = mdDoc "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 = "The package providing lightning-pool binaries."; description = mdDoc "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 = "The data directory for lightning-pool."; description = mdDoc "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 = "host:port of SOCKS5 proxy for connnecting to the pool auction server."; description = mdDoc "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 = "Extra lines appended to the configuration file."; description = mdDoc "Extra lines appended to the configuration file.";
}; };
cli = mkOption { cli = mkOption {
default = pkgs.writeScriptBin "pool" '' default = pkgs.writers.writeBashBin "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 = "Binary to connect with the lightning-pool instance."; description = mdDoc "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 = "Address to listen for peer connections."; description = mdDoc "Address to listen for peer connections.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 7042; default = 7042;
description = "Override the default port on which to listen for connections."; description = mdDoc "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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
Listen for peer connections at `address:port` Listen for peer connections at `address:port`
and `address:onionPort` (if `onionPort` is set). and `address:onionPort` (if {option}`onionPort` is set).
''; '';
}; };
listenWhitelisted = mkOption { listenWhitelisted = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = mdDoc ''
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 = "See `listenWhitelisted`."; description = mdDoc "See {option}`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 = "Extra lines appended to <filename>elements.conf</filename>."; description = mdDoc "Extra lines appended to {file}`elements.conf`.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/liquidd"; default = "/var/lib/liquidd";
description = "The data directory for liquidd."; description = mdDoc "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 = "Address to listen for JSON-RPC connections."; description = mdDoc "Address to listen for JSON-RPC connections.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 7041; default = 7041;
description = "Port to listen for JSON-RPC connections."; description = mdDoc "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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = "Username for JSON-RPC connections"; description = mdDoc "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 = "Connect through SOCKS5 proxy"; description = mdDoc "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 = "Override the default database cache size in megabytes."; description = mdDoc "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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = "The user as which to run liquidd."; description = mdDoc "The user as which to run liquidd.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = "The group as which to run liquidd."; description = mdDoc "The group as which to run liquidd.";
}; };
cli = mkOption { cli = mkOption {
readOnly = true; readOnly = true;
default = pkgs.writeScriptBin "elements-cli" '' default = pkgs.writers.writeBashBin "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 = "Binary to connect with the liquidd instance."; description = mdDoc "Binary to connect with the liquidd instance.";
}; };
swapCli = mkOption { swapCli = mkOption {
default = pkgs.writeScriptBin "liquidswap-cli" '' default = pkgs.writers.writeBashBin "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 = "Binary for managing liquid swaps."; description = mdDoc "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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = "10min"; TimeoutStartSec = "2h";
TimeoutStopSec = "10min"; TimeoutStopSec = "2h";
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 = "Address to listen for peer connections"; description = mdDoc "Address to listen for peer connections";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 9735; default = 9735;
description = "Port to listen for peer connections"; description = mdDoc "Port to listen for peer connections";
}; };
rpcAddress = mkOption { rpcAddress = mkOption {
type = types.str; type = types.str;
default = "localhost"; default = "localhost";
description = "Address to listen for RPC connections."; description = mdDoc "Address to listen for RPC connections.";
}; };
rpcPort = mkOption { rpcPort = mkOption {
type = types.port; type = types.port;
default = 10009; default = 10009;
description = "Port to listen for gRPC connections."; description = mdDoc "Port to listen for gRPC connections.";
}; };
restAddress = mkOption { restAddress = mkOption {
type = types.str; type = types.str;
default = "localhost"; default = "localhost";
description = "Address to listen for REST connections."; description = mdDoc "Address to listen for REST connections.";
}; };
restPort = mkOption { restPort = mkOption {
type = types.port; type = types.port;
default = 8080; default = 8080;
description = "Port to listen for REST connections."; description = mdDoc "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 = "The data directory for LND."; description = mdDoc "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 = "The network data directory."; description = mdDoc "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 = "Socks proxy for connecting to Tor nodes"; description = mdDoc "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 = "User who owns the macaroon."; description = mdDoc "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 = "List of granted macaroon permissions."; description = mdDoc "List of granted macaroon permissions.";
}; };
}; };
}); });
description = '' description = mdDoc ''
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 = '' description = mdDoc ''
Extra `subjectAltName` IPs added to the certificate. Extra `subjectAltName` IPs added to the certificate.
This works the same as lnd option `tlsextraip`. This works the same as lnd option {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 = '' description = mdDoc ''
Extra `subjectAltName` domain names added to the certificate. Extra `subjectAltName` domain names added to the certificate.
This works the same as lnd option `tlsextradomain`. This works the same as lnd option {option}`tlsextradomain`.
''; '';
}; };
}; };
@ -96,8 +96,8 @@ let
example = '' example = ''
autopilot.active=1 autopilot.active=1
''; '';
description = '' description = mdDoc ''
Extra lines appended to `lnd.conf`. Extra lines appended to {file}`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 = "The package providing lnd binaries."; description = mdDoc "The package providing lnd binaries.";
}; };
cli = mkOption { cli = mkOption {
default = pkgs.writeScriptBin "lncli" default = pkgs.writers.writeBashBin "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 = "Binary to connect with the lnd instance."; description = mdDoc "Binary to connect with the lnd instance.";
}; };
getPublicAddressCmd = mkOption { getPublicAddressCmd = mkOption {
type = types.str; type = types.str;
default = ""; default = "";
description = '' description = mdDoc ''
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 = "The user as which to run LND."; description = mdDoc "The user as which to run LND.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = "The group as which to run LND."; description = mdDoc "The group as which to run LND.";
}; };
certPath = mkOption { certPath = mkOption {
readOnly = true; readOnly = true;
default = "${secretsDir}/lnd-cert"; default = "${secretsDir}/lnd-cert";
description = "LND TLS certificate path."; description = mdDoc "LND TLS certificate path.";
}; };
tor = nbLib.tor; tor = nbLib.tor;
}; };
@ -174,19 +174,26 @@ 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.public.name} bitcoind.rpcuser=${bitcoind.rpc.users.${rpcUser}.name}
bitcoind.zmqpubrawblock=${bitcoind.zmqpubrawblock} bitcoind.zmqpubrawblock=${zmqHandleSpecialAddress bitcoind.zmqpubrawblock}
bitcoind.zmqpubrawtx=${bitcoind.zmqpubrawtx} bitcoind.zmqpubrawtx=${zmqHandleSpecialAddress 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 { config = mkIf cfg.enable (mkMerge [ {
assertions = [ assertions = [
{ assertion = { assertion =
!(config.services ? clightning) !(config.services ? clightning)
@ -207,8 +214,8 @@ in {
# under high bitcoind rpc load # under high bitcoind rpc load
rpc.threads = 16; rpc.threads = 16;
zmqpubrawblock = "tcp://${bitcoindRpcAddress}:28332"; zmqpubrawblock = mkDefault "tcp://${bitcoindRpcAddress}:28332";
zmqpubrawtx = "tcp://${bitcoindRpcAddress}:28333"; zmqpubrawtx = mkDefault "tcp://${bitcoindRpcAddress}:28333";
}; };
environment.systemPackages = [ cfg.package (hiPrio cfg.cli) ]; environment.systemPackages = [ cfg.package (hiPrio cfg.cli) ];
@ -226,7 +233,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-public)" echo "bitcoind.rpcpass=$(cat ${secretsDir}/bitcoin-rpcpassword-${rpcUser})"
${optionalString (cfg.getPublicAddressCmd != "") '' ${optionalString (cfg.getPublicAddressCmd != "") ''
echo "externalip=$(${cfg.getPublicAddressCmd})" echo "externalip=$(${cfg.getPublicAddressCmd})"
''} ''}
@ -304,5 +311,22 @@ 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

@ -1,126 +0,0 @@
{ 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";
}
)];
})
];
}

205
modules/lndconnect.nix Normal file
View File

@ -0,0 +1,205 @@
{ 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-onion.nix # Requires onion-addresses.nix ./lndconnect.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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = "Exposes netns parameters."; description = mdDoc "Exposes netns parameters.";
}; };
bridgeIp = mkOption { bridgeIp = mkOption {
readOnly = true; readOnly = true;
default = bridgeIp; default = bridgeIp;
description = "IP of the netns bridge interface."; description = mdDoc "IP of the netns bridge interface.";
}; };
}; };
@ -215,9 +215,11 @@ in {
}; };
}; };
in foldl (services: n: in
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
@ -297,6 +299,7 @@ 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, pkgs, lib, ... }: { config, options, pkgs, lib, ... }:
with lib; with lib;
{ {
@ -8,11 +8,23 @@ 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; default = import ../pkgs/lib.nix lib pkgs config;
defaultText = "nix-bitcoin/pkgs/lib.nix"; defaultText = "nix-bitcoin/pkgs/lib.nix";
}; };
@ -27,7 +39,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.writeScriptBin "torify" '' default = pkgs.writers.writeBashBin "torify" ''
${pkgs.tor}/bin/torify \ ${pkgs.tor}/bin/torify \
--address ${config.services.tor.client.socksListenAddress.addr} \ --address ${config.services.tor.client.socksListenAddress.addr} \
"$@" "$@"
@ -39,8 +51,7 @@ with lib;
runAsUserCmd = mkOption { runAsUserCmd = mkOption {
readOnly = true; readOnly = true;
default = if config.security.doas.enable default = if config.security.doas.enable
# TODO-EXTERNAL: Use absolute path until https://github.com/NixOS/nixpkgs/pull/133622 is available. then "doas -u"
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 = '' description = mdDoc ''
Nodeinfo service definitions. Nodeinfo service definitions.
''; '';
}; };
nodeinfoLib = mkOption { lib = mkOption {
internal = true; internal = true;
readOnly = true; readOnly = true;
default = nodeinfoLib; default = nodeinfoLib;
defaultText = "(See source)"; defaultText = "(See source)";
description = '' description = mdDoc ''
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 set_onion_address(info, name, port): def get_onion_address(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,11 +71,12 @@ 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
info["onion_address"] = f"{onion_address}:{port}" return f"{onion_address}:{port}"
def add_service(service, make_info): def add_service(service, make_info, systemd_service = None):
if not is_active(service): systemd_service = systemd_service or service
infos[service] = "service is not running" if not is_active(systemd_service):
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())
@ -96,14 +97,19 @@ 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: ''
set_onion_address(info, "${name}", ${onionPort}) info["onion_address"] = get_onion_address("${name}", ${onionPort})
'') + extraCode + '' '') + extraCode + ''
""") """, "${systemdServiceName}")
''; '';
mkIfOnionPort = name: fn: mkIfOnionPort = name: fn:
@ -117,8 +123,10 @@ let
in { in {
inherit options; inherit options;
config = { config = mkIf cfg.enable {
environment.systemPackages = optional cfg.enable script; environment.systemPackages = [ script ];
nix-bitcoin.operator.enable = true;
nix-bitcoin.nodeinfo.services = with nodeinfoLib; { nix-bitcoin.nodeinfo.services = with nodeinfoLib; {
bitcoind = mkInfo ""; bitcoind = mkInfo "";
@ -127,9 +135,13 @@ 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 = mkInfo '' lnd = name: cfg: 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 "";
@ -140,7 +152,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", """set_onion_address(info, "sshd", ${onionPort})""") add_service("sshd", """info["onion_address"] = get_onion_address("sshd", ${onionPort})""")
''); '');
}; };
}; };

View File

@ -33,7 +33,6 @@ 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" ])
@ -46,6 +45,28 @@ 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,23 +12,25 @@ let
access = mkOption { access = mkOption {
type = with types; attrsOf (listOf str); type = with types; attrsOf (listOf str);
default = {}; default = {};
description = '' description = mdDoc ''
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
/var/lib/onion-addresses/myuser. {file}`/var/lib/onion-addresses/myuser`.
''; '';
}; };
services = mkOption { services = mkOption {
type = with types; listOf str; type = with types; listOf str;
default = []; default = [];
description = '' description = mdDoc ''
Services that can access their onion address via file Services that can access their onion address via file
`/var/lib/onion-addresses/$service` {file}`/var/lib/onion-addresses/<service>`
The file is readable only by the service user. The file is readable only by the service user.
''; '';
}; };
@ -53,8 +55,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 = '' description = mdDoc ''
Create an onion service for the given service. Create an onion service for the given service.
The service must define options 'address' and 'onionPort' (or `port`). The service must define options {option}'address' and {option}'onionPort' (or `port`).
''; '';
}; };
public = mkOption { public = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = mdDoc ''
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 `getPublicAddressCmd`. Only available for services that define option {option}`getPublicAddressCmd`.
''; '';
}; };
externalPort = mkOption { externalPort = mkOption {
type = types.nullOr types.port; type = types.nullOr types.port;
default = null; default = null;
description = "Override the external port of the onion service."; description = mdDoc "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 = '' description = mdDoc ''
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 = "Name of the operator user."; description = mdDoc "Name of the operator user.";
}; };
groups = mkOption { groups = mkOption {
type = with types; listOf str; type = with types; listOf str;
default = []; default = [];
description = "Extra groups of the operatur user."; description = mdDoc "Extra groups of the operatur user.";
}; };
allowRunAsUsers = mkOption { allowRunAsUsers = mkOption {
type = with types; listOf str; type = with types; listOf str;
default = []; default = [];
description = "Users as which the operator is allowed to run commands."; description = mdDoc "Users as which the operator is allowed to run commands.";
}; };
}; };

View File

@ -5,7 +5,9 @@ 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,7 +1,8 @@
{ { modulesPath, ... }: {
imports = [ imports = [
# Source: https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/profiles/hardened.nix # Source:
<nixpkgs/nixos/modules/profiles/hardened.nix> # https://github.com/NixOS/nixpkgs/blob/master/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

@ -0,0 +1,214 @@
{ 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 = "HTTP server address."; description = mdDoc "HTTP server address.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 3000; default = 3000;
description = "HTTP server port."; description = mdDoc "HTTP server port.";
}; };
dataDir = mkOption { dataDir = mkOption {
type = types.path; type = types.path;
default = "/var/lib/rtl"; default = "/var/lib/rtl";
description = "The data directory for RTL."; description = mdDoc "The data directory for RTL.";
}; };
nodes = { nodes = {
clightning = { clightning = {
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = "Enable the clightning node interface."; description = mdDoc "Enable the clightning node interface.";
}; };
extraConfig = mkOption { extraConfig = mkOption {
type = types.attrs; type = with types; attrsOf anything;
default = {}; default = {};
example = { example = {
Settings.userPersona = "MERCHANT"; Settings.userPersona = "MERCHANT";
Settings.logLevel = "DEBUG"; Settings.logLevel = "DEBUG";
}; };
description = '' description = mdDoc ''
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 = "Enable the lnd node interface."; description = mdDoc "Enable the lnd node interface.";
}; };
loop = mkOption { loop = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = "Enable swaps with lightning-loop."; description = mdDoc "Enable swaps with lightning-loop.";
}; };
extraConfig = mkOption { extraConfig = mkOption {
type = types.attrs; type = with types; attrsOf anything;
default = {}; default = {};
example = { example = {
Settings.userPersona = "MERCHANT"; Settings.userPersona = "MERCHANT";
Settings.logLevel = "DEBUG"; Settings.logLevel = "DEBUG";
}; };
description = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = "Enable the Night UI Theme."; description = mdDoc "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 = '' description = mdDoc ''
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
`tor.enforce` is automatically disabled. {option}`tor.enforce` is automatically disabled.
''; '';
}; };
user = mkOption { user = mkOption {
type = types.str; type = types.str;
default = "rtl"; default = "rtl";
description = "The user as which to run RTL."; description = mdDoc "The user as which to run RTL.";
}; };
group = mkOption { group = mkOption {
type = types.str; type = types.str;
default = cfg.user; default = cfg.user;
description = "The group as which to run RTL."; description = mdDoc "The group as which to run RTL.";
}; };
tor.enforce = nbLib.tor.enforce; tor.enforce = nbLib.tor.enforce;
}; };
@ -191,6 +191,7 @@ 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 = "Directory to store secrets"; description = mdDoc "Directory to store secrets";
}; };
setupSecrets = mkOption { setupSecrets = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = mdDoc ''
Set permissions for existing secrets in `nix-bitcoin.secretsDir` Set permissions for existing secrets in {option}`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 = '' description = mdDoc ''
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.str; type = types.attrsOf types.lines;
default = {}; default = {};
description = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 = '' description = mdDoc ''
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 `systemctl status`. is also used internally by {command}`systemctl status`.
''; '';
}; };
}; };

View File

@ -7,22 +7,22 @@ let
address = mkOption { address = mkOption {
type = types.str; type = types.str;
default = "localhost"; default = "localhost";
description = "http(s) server address."; description = mdDoc "http(s) server address.";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 9737; default = 9737;
description = "http(s) server port."; description = mdDoc "http(s) server port.";
}; };
extraArgs = mkOption { extraArgs = mkOption {
type = types.separatedString " "; type = types.separatedString " ";
default = ""; default = "";
description = "Extra command line arguments passed to spark-wallet."; description = mdDoc "Extra command line arguments passed to spark-wallet.";
}; };
getPublicAddressCmd = mkOption { getPublicAddressCmd = mkOption {
type = types.str; type = types.str;
default = ""; default = "";
description = '' description = mdDoc ''
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 = "The user as which to run spark-wallet."; description = mdDoc "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 = "The group as which to run spark-wallet."; description = mdDoc "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 = '' description = mdDoc ''
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,7 +228,16 @@ 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-onion`. The `lndconnect-rest-onion` binary has been renamed to `lndconnect`.
'';
}
{
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

@ -6,8 +6,8 @@ let
src = pkgs.fetchFromGitHub { src = pkgs.fetchFromGitHub {
owner = "lightningd"; owner = "lightningd";
repo = "plugins"; repo = "plugins";
rev = "59bad754cb338872c622ad716e8ed0063edf4052"; rev = "e625369423b00c70b23641662f62ccd898286edc";
sha256 = "19nnmv2jvb0xmcha79dij399avasn2x521n9qg11lqj8xnzadm6a"; sha256 = "04f30xlfr7pgdmdgka87x7sc9j82wc4zv7fbiqrjsc83dkmly81i";
}; };
version = builtins.substring 0 7 src.rev; version = builtins.substring 0 7 src.rev;
@ -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.13.1" "--replace prometheus-client==0.6.0 prometheus-client==0.15.0"
+ " --replace pyln-client~=0.9.3 pyln-client~=0.11.1"; + " --replace pyln-client~=0.9.3 pyln-client~=23.02";
}; };
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 earvstedt ]; maintainers = with maintainers; [ nixbitcoin erikarvstedt ];
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 earvstedt ]; maintainers = with maintainers; [ nixbitcoin erikarvstedt ];
platforms = platforms.unix; platforms = platforms.unix;
}; };
}; in self }; in self

View File

@ -13,17 +13,24 @@ 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 { nbPythonPackageOverrides = import ./python-packages self; }; joinmarket = pkgs.callPackage ./joinmarket { inherit (self) nbPython3PackagesJoinmarket; };
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 { };
nbPython3Packages = (pkgs.python3.override { # TODO-EXTERNAL:
packageOverrides = import ./python-packages self; # Remove this when https://github.com/lightningnetwork/lnd/pull/7672
}).pkgs; # has been resolved
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,23 +1,15 @@
{ stdenv, lib, fetchurl, python3, nbPythonPackageOverrides, pkgs }: { stdenv, lib, fetchFromGitHub, python3, nbPython3PackagesJoinmarket }:
let let
version = "0.9.7"; version = "0.9.9";
src = fetchurl { src = fetchFromGitHub {
url = "https://github.com/JoinMarket-Org/joinmarket-clientserver/archive/v${version}.tar.gz"; owner = "joinmarket-org";
sha256 = "13bfr8ha6bka8wiai8m79ki43dn2r311lrfffr39ni2wy1v12l93"; repo = "joinmarket-clientserver";
rev = "v${version}";
sha256 = "sha256-dkeSgAhjNl8o/ATKYAlQxxCrur5fLdXuMDXSnWaxYP8=";
}; };
pyPkgs = (python3.override { runtimePackages = with nbPython3PackagesJoinmarket; [
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,25 +1,23 @@
#!/usr/bin/env bash #!/usr/bin/env nix-shell
#!nix-shell -i bash -p git gnupg jq
set -euo pipefail set -euo pipefail
. "${BASH_SOURCE[0]%/*}/../../helper/run-in-nix-env" "git gnupg" "$@" newVersion=$(curl -s "https://api.github.com/repos/joinmarket-org/joinmarket-clientserver/releases" | jq -r '.[0].tag_name')
TMPDIR="$(mktemp -d -p /tmp)" # Fetch release and GPG-verify the content hash
trap 'rm -rf $TMPDIR' EXIT tmpdir=$(mktemp -d /tmp/joinmarket-verify-gpg.XXX)
cd "$TMPDIR" repo=$tmpdir/repo
git clone --depth 1 --branch "${newVersion}" -c advice.detachedHead=false https://github.com/joinmarket-org/joinmarket-clientserver "$repo"
echo "Fetching latest release" export GNUPGHOME=$tmpdir
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 "Verifying latest release" echo
git verify-tag "$latest" echo "Verifying commit"
git -C "$repo" verify-commit HEAD
rm -rf "$repo"/.git
newHash=$(nix hash path "$repo")
rm -rf "$tmpdir"
echo
echo "tag: $latest" echo "tag: $newVersion"
# The prefix option is necessary because GitHub prefixes the archive contents in this format echo "hash: $newHash"
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: lib: pkgs: config:
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 set_mempolicy 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 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,4 +115,8 @@ 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

12
pkgs/lnd/default.nix Normal file
View File

@ -0,0 +1,12 @@
{ 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; [ earvstedt ]; maintainers = with maintainers; [ erikarvstedt ];
}; };
} }

View File

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

View File

@ -4,21 +4,20 @@ pkgs: pkgsUnstable:
inherit (pkgs) inherit (pkgs)
bitcoin bitcoin
bitcoind bitcoind
electrs
elementsd
extra-container extra-container
lightning-pool lightning-pool
lndconnect lndconnect;
nbxplorer;
inherit (pkgsUnstable) inherit (pkgsUnstable)
btcpayserver btcpayserver
charge-lnd charge-lnd
clightning clightning
electrs
elementsd
fulcrum fulcrum
hwi hwi
lightning-loop lightning-loop
lnd; nbxplorer;
inherit pkgs pkgsUnstable; inherit pkgs pkgsUnstable;
} }

View File

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

View File

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

View File

@ -1,4 +1,4 @@
{ version, src, lib, buildPythonPackage, fetchurl, urldecode, pyaes, python-bitcointx, joinmarketbase }: { version, src, lib, buildPythonPackage, fetchurl, 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 = [ urldecode pyaes python-bitcointx ]; propagatedBuildInputs = [ 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==21.8.0'" --replace "'klein==20.6.0'" "'klein>=20.6.0'"
substituteInPlace setup.py \ substituteInPlace setup.py \
--replace "'pyjwt==2.1.0'" "'pyjwt==2.4.0'" --replace "'pyjwt==2.4.0'" "'pyjwt==2.5.0'"
''; '';
meta = with lib; { meta = with lib; {

View File

@ -8,6 +8,12 @@ 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,13 +16,5 @@ 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

@ -1,16 +0,0 @@
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,4 +27,8 @@ 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,17 +6,50 @@
, cryptography , cryptography
, pyasn1 , pyasn1
, idna , idna
, pytest , pytestCheckHook
, pretend , pretend
, flaky , flaky
, glibcLocales , glibcLocales
, six , six
}: }:
let buildPythonPackage rec {
pname = "pyopenssl";
version = "21.0.0";
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 # https://github.com/pyca/pyopenssl/issues/791
# These tests, we disable in the case that libressl is passed in as openssl. # These tests, we disable in the case that libressl is passed in as openssl.
failingLibresslTests = [
"test_op_no_compression" "test_op_no_compression"
"test_npn_advertise_error" "test_npn_advertise_error"
"test_npn_select_error" "test_npn_select_error"
@ -29,64 +62,21 @@ let
"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"
]; ];
disabledTests = [ meta = with lib; {
# https://github.com/pyca/pyopenssl/issues/692 description = "Python wrapper around the OpenSSL library";
# These tests, we disable always. homepage = "https://github.com/pyca/pyopenssl";
"test_set_default_verify_paths" license = licenses.asl20;
"test_fallback_default_verify_paths" maintainers = with maintainers; [ SuperSandro2000 ];
# 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

@ -0,0 +1,173 @@
{ 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

@ -1,68 +0,0 @@
{ 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

@ -1,16 +0,0 @@
{ 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,22 +10,11 @@
}: }:
let self = stdenvNoCC.mkDerivation { let self = stdenvNoCC.mkDerivation {
pname = "rtl"; pname = "rtl";
version = "0.13.1"; version = "0.13.6";
src = applyPatches {
src = fetchurl { src = fetchurl {
url = "https://github.com/Ride-The-Lightning/RTL/archive/refs/tags/v${self.version}.tar.gz"; url = "https://github.com/Ride-The-Lightning/RTL/archive/refs/tags/v${self.version}.tar.gz";
hash = "sha256-k40xwDDJxny1nPN2xz60WfbinxMNM0QPdglibO2anZw="; hash = "sha256-eyRM28h2TV3IyW4hDPHj/wMJxLEZin7AqWQZGQt5mV4=";
};
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 = {
@ -34,7 +23,10 @@ let self = stdenvNoCC.mkDerivation {
nodeModules = fetchNodeModules { nodeModules = fetchNodeModules {
inherit (self) src nodejs; inherit (self) src nodejs;
hash = "sha256-bYZ6snfXhDZ3MMga45EHVrPZxC0/Q0e3AgCgMBire64="; # TODO-EXTERNAL: Remove `npmFlags` when no longer required
# See: https://github.com/Ride-The-Lightning/RTL/issues/1182
npmFlags = "--legacy-peer-deps";
hash = "sha256-C4yK6deYXPrTa383aXiHoO0w3JAMIfAaESCEy9KKY2k=";
}; };
}; };
@ -68,7 +60,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 earvstedt ]; maintainers = with maintainers; [ nixbitcoin erikarvstedt ];
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.1" version="0.13.6"
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 "${toString pkgs.path}/pkgs/development/node-packages/node-env.nix" { nodeEnv = import (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 earvstedt ]; maintainers = with maintainers; [ nixbitcoin erikarvstedt ];
platforms = platforms.unix; platforms = platforms.unix;
}; };
} }

View File

@ -0,0 +1,23 @@
{ 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;
};
}

20
pkgs/trustedcoin/get-sha256.sh Executable file
View File

@ -0,0 +1,20 @@
#! /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 .

84
test/README.md Normal file
View File

@ -0,0 +1,84 @@
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,12 +1,14 @@
#!/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:
# scenario=default ./build.sh # ./build.sh <scenario>
# #
# 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."
@ -16,5 +18,5 @@ if [[ -v CIRRUS_CI ]]; then
chmod o+rw /dev/kvm chmod o+rw /dev/kvm
fi fi
# shellcheck disable=SC2154 cd "${BASH_SOURCE[0]%/*}"
"${BASH_SOURCE[0]%/*}/../run-tests.sh" --ci --scenario "$scenario" exec ./build-to-cachix.sh --expr "(builtins.getFlake (toString ../..)).legacyPackages.\${builtins.currentSystem}.tests.$scenario"

View File

@ -1,22 +1,21 @@
# You can run this test via `run-tests.sh -s clightningReplication` # You can run this test via `run-tests.sh -s clightning-replication`
let makeTestVM: pkgs:
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 = "${nixpkgs}/nixos/tests/initrd-network-ssh"; keyDir = pkgs.path + "/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 = {
@ -29,7 +28,7 @@ let
}; };
}; };
in in
{ makeTestVM {
name = "clightning-replication"; name = "clightning-replication";
nodes = let nodes = { nodes = let nodes = {
@ -57,7 +56,9 @@ in
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";
@ -131,8 +132,8 @@ in
# 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")
server.wait_for_unit("sshd.service")
switch_to_system("replicationRemote") switch_to_system("replicationRemote")
server.wait_for_unit("sshd.service")
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}")
@ -150,4 +151,4 @@ in
# 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 --exclude='.git*' "$scriptDir/../" "$tmp/src" rsync -a --delete "$scriptDir/../" "$tmp/src"
echo "Copied src" echo "Copied src"
# shellcheck disable=SC2154 # shellcheck disable=SC2154

View File

@ -1,15 +0,0 @@
# 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