Compare commits

...

108 Commits

Author SHA1 Message Date
Greg Shuflin
ed567d67f2 Patch electrs to avoid chmod 2023-02-05 03:00:49 -08:00
Greg Shuflin
9538c63a76 Patch to prevent chmod 2023-02-05 03:00:49 -08:00
Jonas Nick
479e21a122
Merge fort-nix/nix-bitcoin#587: Fulcrum: Fix available memory detection
86dc7e2669 fulcrum: allow access to `/proc/meminfo` (Erik Arvstedt)
c948af2e18 dev/dev-features: add `enter_service` helper (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK 86dc7e2669

Tree-SHA512: 5c2b7bc5e2247a7fb45e6c805162c02d87b4c917e4a1306134d634f418534b03e3152e402d17e054c410d3d72f3f5eb3d270fcb53019b2f96ea6b27ecae53755
2023-02-03 13:21:56 +00:00
Jonas Nick
475af2d6cb
Merge fort-nix/nix-bitcoin#586: Misc. improvements
addfa8ec6b test: support `run`, `debug` commands in basic NixOS tests (Erik Arvstedt)
ae733d887e tests/clightning-replication: reuse `pkgs` instance (Erik Arvstedt)
6cbd0d93ae tests: rename `clightningReplication` -> `clightning-replication` (Erik Arvstedt)
85310b533a secrets: use type `lines` for `generateSecretsCmds` (Erik Arvstedt)
bc2f66d4f1 bitcoind, liquid: increase start/stop timeouts (Erik Arvstedt)
519ae31202 netns-isolation: improve formatting (Erik Arvstedt)
a1023696e6 netns-isolation: reserve netns id for mempool (Erik Arvstedt)
34fe8675bd add option `nix-bitcoin.pkgOverlays` (Erik Arvstedt)
a3bdecb10b helper: add start-bash-session.sh (Erik Arvstedt)
690a8f6256 nodeinfo: extract fn `mkInfoLong` (Erik Arvstedt)
2af642f56a improve comments (Erik Arvstedt)
5634f08873 rtl: make `extraConfig` recursively mergeable (Erik Arvstedt)
b76728a1ec treewide: use bool literals for systemd (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK addfa8ec6b

Tree-SHA512: 46f779f8477b566ffc6d0dfb024f2098757f509b2b3e0cbb509cf3308de7029e913f6e6c3d6d3d226cc72f8a5031fd5586b2efdf7c2d9d15f4bdd7ed08b27425
2023-02-03 13:11:41 +00:00
Erik Arvstedt
addfa8ec6b
test: support run, debug commands in basic NixOS tests
Currently, this only affects the basic NixOS test `clightning-replication`.
2023-02-02 10:51:41 +01:00
Erik Arvstedt
ae733d887e
tests/clightning-replication: reuse pkgs instance
This reduces eval time by 30%.
2023-02-02 10:51:41 +01:00
Erik Arvstedt
6cbd0d93ae
tests: rename clightningReplication -> clightning-replication
The test name now matches the file name.
2023-02-02 10:51:41 +01:00
Erik Arvstedt
85310b533a
secrets: use type lines for generateSecretsCmds
This allows users to amend secrets cmds.
2023-02-02 10:51:41 +01:00
Erik Arvstedt
bc2f66d4f1
bitcoind, liquid: increase start/stop timeouts 2023-02-02 10:51:41 +01:00
Erik Arvstedt
519ae31202
netns-isolation: improve formatting 2023-02-02 10:51:41 +01:00
Erik Arvstedt
a1023696e6
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-02-02 10:51:41 +01:00
Erik Arvstedt
34fe8675bd
add option nix-bitcoin.pkgOverlays
This simplifies extending `nix-bitcoin.pkgs` and is required for
extension flakes.
For now, mark this as `internal`.
2023-02-02 10:51:40 +01:00
Erik Arvstedt
a3bdecb10b
helper: add start-bash-session.sh 2023-02-02 10:51:40 +01:00
Jonas Nick
397d2bab9b
Merge fort-nix/nix-bitcoin#589: rtl: 0.13.2 -> 0.13.4
6291d4fbea rtl: 0.13.2 -> 0.13.4 (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK 6291d4fbea

Tree-SHA512: bc52cbdb12f311446eb79960c6500261c97ff5d12baaf1248056a1eb3507c64cb788db2ee25d05bf0bec6d4f78a544fdd037cf34fd3b56adcc6b0fe556e1158b
2023-01-28 22:42:48 +00:00
Jonas Nick
0e4af28df0
Merge fort-nix/nix-bitcoin#588: update nixpkgs
56c2abd91a update nixpkgs (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK 56c2abd91a

Tree-SHA512: b2acbd4e944007448b821c4a02f2f8e925d006b3e92011497019db9fe247d6a130cf875203c2c2830a83042f87d1916163d2b1604077812edc7d11b073047a7f
2023-01-28 10:55:04 +00:00
Erik Arvstedt
6291d4fbea
rtl: 0.13.2 -> 0.13.4 2023-01-26 23:08:05 +01:00
Erik Arvstedt
690a8f6256
nodeinfo: extract fn mkInfoLong
This is required by the mempool extension flake.
2023-01-26 11:17:03 +01:00
Erik Arvstedt
2af642f56a
improve comments
The comment in python-packackges was obsolete.
2023-01-26 11:17:02 +01:00
Erik Arvstedt
56c2abd91a
update nixpkgs
btcpayserver: 1.7.2 -> 1.7.3
electrs: 0.9.10 -> 0.9.11
hwi: 2.1.1 -> 2.2.0
2023-01-25 23:57:29 +01:00
Erik Arvstedt
86dc7e2669
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-01-21 13:28:32 +01:00
Erik Arvstedt
c948af2e18
dev/dev-features: add enter_service helper 2023-01-21 13:20:49 +01:00
Erik Arvstedt
5634f08873
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-01-20 13:46:08 +01:00
Erik Arvstedt
b76728a1ec
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-01-20 13:46:08 +01:00
Jonas Nick
84fc4d48d3
Merge fort-nix/nix-bitcoin#574: Add dev helper and docs
b4d7e1aa8f add dev helper and docs (Erik Arvstedt)
b35d08d3f2 docs: move test docs from `examples/README` to `test/README` (Erik Arvstedt)
4d76eb9183 docs/configuration: fix typo (Erik Arvstedt)
dc0710f3f4 tests: add example scenario `customTest` (Erik Arvstedt)
9e30d2728b tests: formatting (Erik Arvstedt)
c6d85c6fe3 tests: fix broken unit file when clightning is disabled (Erik Arvstedt)
a51f7b419e run-tests: use arg instead of env var for scenario overrides (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK b4d7e1aa8f

Tree-SHA512: f0ed8f8fe326c64eac3b7e9f48597dd00eedb9244333e199d18d1c2c06f369cd015f77aefd48e87235a68aee0b352057249525bf015e0a564fda380bdf7bb9d1
2023-01-18 20:53:24 +00:00
Erik Arvstedt
b4d7e1aa8f
add dev helper and docs 2023-01-15 20:28:49 +01:00
Erik Arvstedt
b35d08d3f2
docs: move test docs from examples/README to test/README 2023-01-15 20:28:48 +01:00
Erik Arvstedt
4d76eb9183
docs/configuration: fix typo 2023-01-15 20:28:48 +01:00
Erik Arvstedt
dc0710f3f4
tests: add example scenario customTest 2023-01-15 20:28:48 +01:00
Jonas Nick
dfeff7b17b
Merge fort-nix/nix-bitcoin#582: update nixpkgs
9019a17bfc versioning: add fulcrum db change info (Erik Arvstedt)
aae4b6bfc5 update nixpkgs (Jonas Nick)

Pull request description:

ACKs for top commit:
  erikarvstedt:
    ACK 9019a17bfc

Tree-SHA512: d1620431beca7841d0e16deedef2c77364db1d7d2f8edf61cdf4ee2d2f8759736acf64fe9764bef0687a283e6d4eb45e4533e92fa1db601a0f2b331182135e10
2023-01-08 10:57:06 +00:00
Erik Arvstedt
9019a17bfc
versioning: add fulcrum db change info 2023-01-07 19:32:54 +00:00
Jonas Nick
aae4b6bfc5
update nixpkgs
btcpayserver: 1.7.1 -> 1.7.2
fulcrum: 1.8.2 -> 1.9.0
nbxplorer: 2.3.49 -> 2.3.54
2023-01-06 22:53:47 +00:00
Erik Arvstedt
9e30d2728b
tests: formatting
Move line next to `services.lnd` config for clarity.
2023-01-06 23:46:43 +01:00
Erik Arvstedt
c6d85c6fe3
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-01-06 23:46:43 +01:00
Erik Arvstedt
a51f7b419e
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-01-06 23:46:43 +01:00
Jonas Nick
da612fe84f
Merge fort-nix/nix-bitcoin#577: Upgrade to NixOS 22.11
4b5b4eac58 examples/deploy-container: fix `sudo` env propagation (Erik Arvstedt)
8d476cfeaf nix-bitcoin/runAsUserCmd: remove workaround (Erik Arvstedt)
00cceca861 joinmarket: fix Python packages (Erik Arvstedt)
e4b8e14d3a clightning: fix Python packages (Erik Arvstedt)
d1ef2a6e1e pythonPackages: improve layout (Erik Arvstedt)
74c8593407 pythonPackages: add indentation (Erik Arvstedt)
109dccca27 treewide: use `mdDoc` for descriptions (Erik Arvstedt)
a9c1995ed9 treewide: rename maintainer `earvstedt` -> `erikarvstedt` (Erik Arvstedt)
9e456ea3a9 shellcheck-services.nix: update to NixOS 22.11 (Erik Arvstedt)
77d58162e7 test: update to NixOS 22.11 (Erik Arvstedt)
142cbcfb37 flake: remove 32-bit systems (Erik Arvstedt)
c9b1e59f20 update to NixOS 22.11 (Erik Arvstedt)
62515a5696 helper/update-flake: support updating NixOS versions (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK 4b5b4eac58

Tree-SHA512: b6ff443c4c6721dee9e6bf8f068d72c819851d54cb52d3fec64475cd884825063c28a87b2e9d1645617b7d0e7c1d52ee1ccd898f833c720c25f1b07add938cd5
2023-01-06 22:37:46 +00:00
Erik Arvstedt
4b5b4eac58
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-01-06 23:23:54 +01:00
Erik Arvstedt
8d476cfeaf
nix-bitcoin/runAsUserCmd: remove workaround 2023-01-03 16:18:27 +01:00
Jonas Nick
700b6d8c90
Merge fort-nix/nix-bitcoin#580: minor typo
1b4c5749f6 minor typo (JayDeLux)

Pull request description:

Top commit has no ACKs.

Tree-SHA512: 917421f7076cee73cdbac925b20cd84fc94fe350b35bb736a5b15d193200a72b5be80cc10e9adf5ffdb640e36db0a977be8aef8a5bb4d3a42224ebd7b4a62f29
2023-01-02 20:32:13 +00:00
JayDeLux
1b4c5749f6
minor typo 2022-12-28 16:31:03 +01:00
Jonas Nick
a6ab131e7d
Merge fort-nix/nix-bitcoin#578: rtl: 0.13.1 -> 0.13.2
314020b246 rtl: 0.13.1 -> 0.13.2 (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK 314020b246

Tree-SHA512: 553dd1b34fce8847f650a187ab39c0827461bf49693c11c5329186fba7864538e13700f50bb30c59e1988ce72fcecb5a06c491c30e7a1fcc2d0457f398234dc2
2022-12-22 22:18:13 +00:00
Erik Arvstedt
314020b246
rtl: 0.13.1 -> 0.13.2 2022-12-20 23:24:24 +01:00
Erik Arvstedt
00cceca861
joinmarket: fix Python packages 2022-12-18 20:01:53 +01:00
Erik Arvstedt
e4b8e14d3a
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/
2022-12-18 20:01:53 +01:00
Erik Arvstedt
d1ef2a6e1e
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.
2022-12-18 20:01:52 +01:00
Erik Arvstedt
74c8593407
pythonPackages: add indentation
This makes the following commit more readable.
2022-12-18 20:01:52 +01:00
Erik Arvstedt
109dccca27
treewide: use mdDoc for descriptions
Enable markdown syntax (instead of docbook) for descriptions.
This only affects external doc tooling that renders the descriptions.
2022-12-18 20:01:52 +01:00
Erik Arvstedt
a9c1995ed9
treewide: rename maintainer earvstedt -> erikarvstedt 2022-12-18 20:01:52 +01:00
Erik Arvstedt
9e456ea3a9
shellcheck-services.nix: update to NixOS 22.11 2022-12-18 20:01:52 +01:00
Erik Arvstedt
77d58162e7
test: update to NixOS 22.11 2022-12-18 20:01:52 +01:00
Erik Arvstedt
142cbcfb37
flake: remove 32-bit systems 2022-12-18 20:01:52 +01:00
Erik Arvstedt
c9b1e59f20
update to NixOS 22.11
This includes no pkg version updates.
2022-12-18 20:01:52 +01:00
Erik Arvstedt
62515a5696
helper/update-flake: support updating NixOS versions 2022-12-18 20:01:48 +01:00
Jonas Nick
932e4c93bc
Merge fort-nix/nix-bitcoin#576: joinmarket: 0.9.7 -> 0.9.8
81166a012e joinmarket: 0.9.7 -> 0.9.8 (nixbitcoin)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK 81166a012e

Tree-SHA512: 1a6416ed9b4829017411cec23e2c2f2fd28b02a26893339926b26e0ec4c55f087ec042b81aae5f4d34143cd78f4edc16d6e82b4b70e29fc1427f94417ed0dd3b
2022-12-17 13:52:42 +00:00
Jonas Nick
84382e3338
Merge fort-nix/nix-bitcoin#573: update nixpkgs
d1b3a4617d clightning: set "database-upgrade=true" for 22.11.1 (Jonas Nick)
875fac6862 update nixpkgs (Jonas Nick)

Pull request description:

ACKs for top commit:
  erikarvstedt:
    ACK d1b3a4617d

Tree-SHA512: 91c347006e0c47e3f365597be95469c2a547a442cd4adb9f906fb6ef63a3ce78ed788304a81870652b3b91f9dd180124a8b048cb69389889e346ab1420d8722b
2022-12-17 13:33:38 +00:00
Jonas Nick
d1b3a4617d
clightning: set "database-upgrade=true" for 22.11.1 2022-12-17 12:43:33 +00:00
nixbitcoin
81166a012e
joinmarket: 0.9.7 -> 0.9.8 2022-12-15 17:47:35 +00:00
Jonas Nick
875fac6862
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
2022-12-14 14:48:54 +00:00
Jonas Nick
5cafafd027
Merge fort-nix/nix-bitcoin#572: update nixpkgs
d9fdc49e9a update nixpkgs (Jonas Nick)

Pull request description:

ACKs for top commit:
  erikarvstedt:
    ACK d9fdc49e9a

Tree-SHA512: b4e1ecfae7c5d549739d79b11bd379bd8e85206097301280a69301dd41e1b4fe1f82dedb7cf3dd805e1ac530d3ac43f108043af6b54a07519898d71a016b55fc
2022-11-28 14:40:13 +00:00
Jonas Nick
d9fdc49e9a
update nixpkgs
bitcoin: 23.0 -> 24.0
bitcoind: 23.0 -> 24.0
charge-lnd: 0.2.12 -> 0.2.13
2022-11-28 12:54:11 +00:00
Jonas Nick
8b091eb661
Merge fort-nix/nix-bitcoin#571: lnd: support INADDR_ANY addresses for bitcoind.zmqpubraw*
c5493717b7 lnd: support `INADDR_ANY` addresses for `bitcoind.zmqpubraw*` (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK c5493717b7

Tree-SHA512: 227e047a0c114beaed82c417d6c400aa8bc16763b9ebf5aa94e8132d68c0641af0b79cd7e5ab6f5ad16412dc9efb83080760f75aa22fc67ec9d93f623adb27b9
2022-11-20 22:11:28 +00:00
Erik Arvstedt
c5493717b7
lnd: support INADDR_ANY addresses for bitcoind.zmqpubraw*
Also use `mkDefault` when defining `bitcoind.zmqpubraw*` to simplify
overriding for users.
2022-11-11 12:10:00 +01:00
Jonas Nick
81350a03c9
Merge fort-nix/nix-bitcoin#570: Update nixpkgs
a333989ca8 update nixpkgs (Jonas Nick)
313e374774 Revert "pkgs: add lnd 0.15.4 (hotfix)" (Jonas Nick)

Pull request description:

ACKs for top commit:
  erikarvstedt:
    ACK a333989ca8

Tree-SHA512: cf9a0c42002f00eadcb6e97211358210c6ab214f467b25af23c70477c40134b3d9a26c7ff00ec15d5a06f2a4bfe9832b11e6ae0faa136249c1180f5ae2e59734
2022-11-10 12:56:47 +00:00
Jonas Nick
4a533d90ea
Merge fort-nix/nix-bitcoin#568: Minor improvements
0de16095e1 clightning-replication: switch system before waiting for server sshd (Erik Arvstedt)
d332177d3e clightning: extract var `bitcoind` (Erik Arvstedt)
1b5e51b7fe examples/vm-config: fix syntax error (Erik Arvstedt)
565deb770a examples/minimal-vm: add `lightning-cli` demo command (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK 0de16095e1

Tree-SHA512: cafcc7a51152b480d26a55c926b21a01ef7565c948cf28926017565c1ef180e7500494eefb4b114ab371d4d0a62f9efd2ebf3722877d1c62f890827cd7b34574
2022-11-10 12:56:12 +00:00
Jonas Nick
1800ed7cb3
Merge fort-nix/nix-bitcoin#569: treewide: set shebang for bash scripts
0447c5bacb treewide: set shebang for bash scripts (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK 0447c5bacb

Tree-SHA512: a3160833ae445a8b25f559f9e76a2c86537041d731b7404db05e388ec4e2afd7028a06cfbd1ba05b827b1270c3278836b603dab4b9bf3551795298e22bf9e734
2022-11-10 11:08:24 +00:00
Jonas Nick
a333989ca8
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
2022-11-10 11:03:23 +00:00
Jonas Nick
313e374774
Revert "pkgs: add lnd 0.15.4 (hotfix)"
This reverts commit 57b76d4461.
2022-11-10 10:56:12 +00:00
Erik Arvstedt
0447c5bacb
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.
2022-11-08 23:04:56 +01:00
Erik Arvstedt
0de16095e1
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
2022-11-04 11:51:44 +01:00
Erik Arvstedt
d332177d3e
clightning: extract var bitcoind
Follow the default module formatting style.
2022-11-04 11:07:36 +01:00
Erik Arvstedt
1b5e51b7fe
examples/vm-config: fix syntax error 2022-11-04 00:33:53 +01:00
Erik Arvstedt
565deb770a
examples/minimal-vm: add lightning-cli demo command 2022-11-04 00:33:31 +01:00
Jonas Nick
a576fa3afe
Merge fort-nix/nix-bitcoin#559: Define tests via flake
edbaeb9813 tests: define tests via flake (Erik Arvstedt)
90e942e5ae nodeinfo: rename `nodeinfoLib` -> `lib` (Erik Arvstedt)
8eaa4cce30 tests: move `mkIfTest` to `nix-bitcoin.lib` (Erik Arvstedt)
47a09ec214 flake: expose `supportedSystems` (Erik Arvstedt)
b0dfa69e84 nixos-search/flake: formatting (Erik Arvstedt)
d428755399 flake: rename input `nixpkgsUnstable` -> `nixpkgs-unstable` (Erik Arvstedt)
a12b701e75 tests/container: don't require `services.clightning` to be defined (Erik Arvstedt)
450de19803 tests/run-tests.sh: print examples before running (Erik Arvstedt)
5f1bb2a8fc tests/copy-src: always copy .git dir (Erik Arvstedt)
a87a59a86b make-container.sh: improve root handling (Erik Arvstedt)
b616d7ac1b profiles/hardened: support pure eval mode (Erik Arvstedt)
73d2fbb448 add compatibility with Nix PR #6530 (`Source tree abstraction`) (Erik Arvstedt)
3c816b862c tests/vmWithoutTests: poweroff on shell exit (Erik Arvstedt)
1d3f49f8da tests, example: avoid lengthy documentation build (Erik Arvstedt)
b840548d40 test/shellcheck-services: add configurable source prefix (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK edbaeb9813

Tree-SHA512: 824c028917816725fb12cd6808947994b13646514ae4dca092e11e6237314ac13157adbba7e79110820d54657eca4f5f4c80946216fa3cb4c7801aec2d0b517d
2022-11-03 22:15:05 +00:00
Erik Arvstedt
edbaeb9813
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.
2022-11-03 23:08:06 +01:00
Erik Arvstedt
90e942e5ae
nodeinfo: rename nodeinfoLib -> lib 2022-11-03 23:08:06 +01:00
Erik Arvstedt
8eaa4cce30
tests: move mkIfTest to nix-bitcoin.lib 2022-11-03 23:08:06 +01:00
Erik Arvstedt
47a09ec214
flake: expose supportedSystems 2022-11-03 23:08:05 +01:00
Erik Arvstedt
b0dfa69e84
nixos-search/flake: formatting 2022-11-03 23:08:05 +01:00
Erik Arvstedt
d428755399
flake: rename input nixpkgsUnstable -> nixpkgs-unstable
This follows common flake naming conventions.
2022-11-03 23:08:05 +01:00
Erik Arvstedt
a12b701e75
tests/container: don't require services.clightning to be defined 2022-11-03 23:08:05 +01:00
Erik Arvstedt
450de19803
tests/run-tests.sh: print examples before running
This eases debugging example failures.
2022-11-03 23:08:05 +01:00
Erik Arvstedt
5f1bb2a8fc
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.
2022-11-03 23:08:05 +01:00
Erik Arvstedt
a87a59a86b
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.
2022-11-03 23:08:05 +01:00
Erik Arvstedt
b616d7ac1b
profiles/hardened: support pure eval mode 2022-11-03 23:08:05 +01:00
Erik Arvstedt
73d2fbb448
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.
2022-11-03 23:08:05 +01:00
Erik Arvstedt
3c816b862c
tests/vmWithoutTests: poweroff on shell exit
This allows quitting the VM with Ctrl-D like in the minimal example VM.
2022-11-03 23:08:04 +01:00
Erik Arvstedt
1d3f49f8da
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.
2022-11-03 23:08:04 +01:00
Erik Arvstedt
b840548d40
test/shellcheck-services: add configurable source prefix
This allows using this module for services defined outside of nix-bitcoin.
2022-11-03 23:08:04 +01:00
Jonas Nick
dcca4fb262
Merge fort-nix/nix-bitcoin#567: bitcoind: fix rare startup error
b412de3ad7 bitcoind: fix rare startup error (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK b412de3ad7

Tree-SHA512: 217f9c220b2906b4c5df2d9fbd2116c693eef25af18672ddf9065428a0946af45d704ece05963f4c8c41678397627580610b949bb0a086d8f9c559c08b3d308c
2022-11-03 22:02:59 +00:00
Erik Arvstedt
b412de3ad7
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.
2022-11-02 12:02:03 +01:00
Jonas Nick
a174dc8093
Merge fort-nix/nix-bitcoin#565: pkgs: add lnd 0.15.4 (hotfix)
57b76d4461 pkgs: add lnd 0.15.4 (hotfix) (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK 57b76d4461

Tree-SHA512: ab3ee937ffea5bae3b16bad8488c49a440d7c52ba77b9588badabd011798190c2592caf8039ec72615e803bc7a9ac337b055739888a69ae9203fc5bde3548bae
2022-11-01 13:30:34 +00:00
Erik Arvstedt
57b76d4461
pkgs: add lnd 0.15.4 (hotfix)
Includes an emergency hotfix:
https://github.com/lightningnetwork/lnd/releases/tag/v0.15.4-beta
2022-11-01 14:12:56 +01:00
Jonas Nick
7c16fc5865
Merge fort-nix/nix-bitcoin#563: lnd: fix missing RPC permissions when bitcoind is pruned
67949a002a lnd: fix missing RPC permissions when bitcoind is pruned (Erik Arvstedt)
49303be2e0 test/shellcheck-services: fix error by excluding unavailable services (Erik Arvstedt)
46f17fe313 test/shellcheck-services: simplify accessing service definitions (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK 67949a002a

Tree-SHA512: 28652d8ec67a164aef068f3df32d1ae8df4e0920cafedc6e3d568b631333b29e57f7370e54a82e7cde9710a3df0a1494ed94272af101d31dd7859a08bb363e4b
2022-10-28 08:38:28 +00:00
Jonas Nick
a7357c1176
Merge fort-nix/nix-bitcoin#551: tests: Reenable flake-info
277510c7ee tests: run flake-info in sandbox (Erik Arvstedt)
d3b7e8c432 revert "tests: disable `nixosSearch`" (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK 277510c7ee

Tree-SHA512: 2d242aeb65c65c4c3905cc66959092c1da923b9de9ce08ee68319b6475f4fd6f6148b5ac5ca312462b1fb38e8fc61706361f58886afc5052f65a18fb7a61de60
2022-10-26 07:25:27 +00:00
Erik Arvstedt
67949a002a
lnd: fix missing RPC permissions when bitcoind is pruned 2022-10-25 22:56:51 +02:00
Erik Arvstedt
49303be2e0
test/shellcheck-services: fix error by excluding unavailable services 2022-10-25 22:36:30 +02:00
Erik Arvstedt
46f17fe313
test/shellcheck-services: simplify accessing service definitions
This also improves performance by removing the extra module evaluation.
2022-10-25 22:36:30 +02:00
Erik Arvstedt
277510c7ee
tests: run flake-info in sandbox
Don't use sandboxing in Cirrus CI where namespace support is missing.
2022-10-25 22:04:17 +02:00
Jonas Nick
9d074e1985
Merge fort-nix/nix-bitcoin#560: Update nixpgks
c88acbb1bb btcpayserver: use new option `certfilepath` for lnd (Erik Arvstedt)
13a835e88f Revert "pkgs: add lnd 0.15.2" (Erik Arvstedt)
3549725b51 update nixpkgs (Erik Arvstedt)
61c539d5b6 defaultHardening: allow syscall `set_mempolicy` (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK c88acbb1bb

Tree-SHA512: 450fc27bb738d7465be829bc6ceda0030cdfc6bb75d15001986450c8189d675fe0fd0a0e6875c0224a239be0aae3acbecb74fb3b970fb6a8dfedd1d463a93d55
2022-10-25 07:57:01 +00:00
Erik Arvstedt
c88acbb1bb
btcpayserver: use new option certfilepath for lnd 2022-10-24 12:47:01 +02:00
Erik Arvstedt
13a835e88f
Revert "pkgs: add lnd 0.15.2"
This reverts commit cf836b5d3b.
2022-10-24 11:50:36 +02:00
Erik Arvstedt
3549725b51
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
2022-10-24 11:49:03 +02:00
Erik Arvstedt
61c539d5b6
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.
2022-10-22 23:54:08 +02:00
Jonas Nick
9fc05e384c
Merge fort-nix/nix-bitcoin#553: pkgs: add lnd 0.15.2
cf836b5d3b pkgs: add lnd 0.15.2 (Erik Arvstedt)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK cf836b5d3b

Tree-SHA512: 499cf4989f432946e0ec476cb0c22975614f05e8958c616a5897026098613dd7a20be83e144defdf19b0bf86c3cbd2f6cabb8397d40b1e3bcbda96d9b5e12860
2022-10-10 11:52:27 +00:00
Erik Arvstedt
cf836b5d3b
pkgs: add lnd 0.15.2
Includes an emergency hotfix:
https://github.com/lightningnetwork/lnd/releases/tag/v0.15.2-beta
2022-10-10 13:27:49 +02:00
Erik Arvstedt
d3b7e8c432
revert "tests: disable nixosSearch" 2022-09-23 09:04:57 +02:00
Jonas Nick
34f6eb90d7
Merge fort-nix/nix-bitcoin#550: Update nixpkgs
261f7a043f update nixpkgs (Jonas Nick)
09c765368f clightning-plugins: update packages (Jonas Nick)

Pull request description:

ACKs for top commit:
  erikarvstedt:
    ACK 261f7a043f

Tree-SHA512: 30cec6e06dc56b84daf058441a25dc7593b2754c7cbdbb48562528a81727f8a7abbaf5d31497a136903485534e41b171d55a60d9bc91548feb7ff7997985e364
2022-09-22 18:58:27 +00:00
Jonas Nick
261f7a043f
update nixpkgs
electrs: 0.9.7 -> 0.9.9
elementsd: 0.21.0.2 -> 22.0
fulcrum: 1.7.0 -> 1.8.1
2022-09-22 16:57:19 +00:00
Jonas Nick
09c765368f
clightning-plugins: update packages 2022-09-22 16:57:00 +00:00
95 changed files with 2304 additions and 1076 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
@ -30,11 +30,12 @@ task:
# 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)
@ -118,6 +120,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;
};
}

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

@ -0,0 +1,299 @@
# 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() {
local name=$1
nsenter --all -t "$(systemctl show -p MainPID --value "$name")" \
--setuid "$(id -u "$name")" --setgid "$(id -g "$name")" 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

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

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

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

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

@ -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

@ -287,10 +287,10 @@
# this value at the release version of the first install of this system. # this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option # Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "22.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,35 @@
{ {
"nodes": { "nodes": {
"extra-container": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1671802034,
"narHash": "sha256-mkv2u5nQJEV3KlWiopkt/gMz0OM4nmEXSfzkSw6welQ=",
"owner": "erikarvstedt",
"repo": "extra-container",
"rev": "e34f0cca15f6f0f2e598dad0b329196d0dab6d4f",
"type": "github"
},
"original": {
"owner": "erikarvstedt",
"repo": "extra-container",
"type": "github"
}
},
"flake-utils": { "flake-utils": {
"locked": { "locked": {
"lastModified": 1659877975, "lastModified": 1667395993,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -17,27 +40,27 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1662099760, "lastModified": 1674407282,
"narHash": "sha256-MdZLCTJPeHi/9fg6R9fiunyDwP3XHJqDd51zWWz9px0=", "narHash": "sha256-2qwc8mrPINSFdWffPK+ji6nQ9aGnnZyHSItVcYDZDlk=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "67e45078141102f45eff1589a831aeaa3182b41e", "rev": "ab1254087f4cdf4af74b552d7fc95175d9bdbb49",
"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": 1674487464,
"narHash": "sha256-R+Q8l5JuyJryRPdiIaYpO5O3A55rT+/pItBrKcy7LM4=", "narHash": "sha256-Jgq50e4S4JVCYpWLqrabBzDp/1mfaxHCh8/OOorHTy0=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "21de2b973f9fee595a7a1ac4693efff791245c34", "rev": "3954218cf613eba8e0dcefa9abe337d26bc48fd0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -49,9 +72,10 @@
}, },
"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"
} }
} }
}, },

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;
} }
)); ));
} }

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;
}; };
@ -367,9 +367,10 @@ in {
proto.sam.enable = true; proto.sam.enable = true;
}; };
systemd.tmpfiles.rules = [ # Commented out to avoid trying to chown the nfs-mounted directory
"d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -" # systemd.tmpfiles.rules = [
]; # "d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -"
# ];
systemd.services.bitcoind = { systemd.services.bitcoind = {
# Use `wants` instead of `requires` so that bitcoind and all dependent services # Use `wants` instead of `requires` so that bitcoind and all dependent services
@ -380,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
@ -412,17 +413,17 @@ in {
''; '';
# Enable RPC access for group # Enable RPC access for group
postStart = '' # postStart = ''
chmod g=r '${cfg.dataDir}/${optionalString cfg.regtest "regtest/"}.cookie' # chmod g=r '${cfg.dataDir}/${optionalString cfg.regtest "regtest/"}.cookie'
''; # '';
serviceConfig = nbLib.defaultHardening // { serviceConfig = nbLib.defaultHardening // {
Type = "notify"; Type = "notify";
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,41 +212,34 @@ 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"; Restart = "on-failure";
RestartSec = "10s"; RestartSec = "10s";
ReadWritePaths = [ cfg.btcpayserver.dataDir ]; ReadWritePaths = [ cfg.btcpayserver.dataDir ];
MemoryDenyWriteExecute = "false"; MemoryDenyWriteExecute = false;
} // nbLib.allowedIPAddresses cfg.btcpayserver.tor.enforce; } // nbLib.allowedIPAddresses cfg.btcpayserver.tor.enforce;
}; in self; }; in self;

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

@ -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

@ -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,26 @@ 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} 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-rpcconnect=${nbLib.address bitcoind.rpc.address}
bitcoin-rpcport=${toString config.services.bitcoind.rpc.port} bitcoin-rpcport=${toString bitcoind.rpc.port}
bitcoin-rpcuser=${config.services.bitcoind.rpc.users.public.name} bitcoin-rpcuser=${bitcoind.rpc.users.public.name}
rpc-file-mode=0660 rpc-file-mode=0660
log-timestamps=false log-timestamps=false
${optionalString (cfg.wallet != null) "wallet=${cfg.wallet}"} ${optionalString (cfg.wallet != null) "wallet=${cfg.wallet}"}
${ # TODO-EXTERNAL: When updating from a version of clightning before 22.11
# to version 22.11.1, then the database upgrade needs to be allowed
# explicitly. Remove this when it's unlikely that this module is used
# with a clightning version 22.11.1 package.
optionalString (cfg.package.version == "22.11.1") "database-upgrade=true"}
${cfg.extraConfig} ${cfg.extraConfig}
''; '';

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;
}; };
@ -61,9 +61,10 @@ in {
listenWhitelisted = true; listenWhitelisted = true;
}; };
systemd.tmpfiles.rules = [ # Commented out to allow nfs mounts
"d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -" # systemd.tmpfiles.rules = [
]; # "d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group} - -"
# ];
systemd.services.electrs = { systemd.services.electrs = {
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];

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.
''; '';
}; };
}; };

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

@ -6,13 +6,13 @@ let
services.lnd.lndconnectOnion.enable = mkOption { services.lnd.lndconnectOnion.enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = mdDoc ''
Create an onion service for the lnd REST server. Create an onion service for the lnd REST server.
Add a `lndconnect-onion` binary to the system environment. Add a `lndconnect-onion` binary to the system environment.
See: https://github.com/LN-Zap/lndconnect See: https://github.com/LN-Zap/lndconnect
Usage: Usage:
``` ```bash
# Print QR code # Print QR code
lndconnect-onion lndconnect-onion
@ -25,13 +25,13 @@ let
services.clightning-rest.lndconnectOnion.enable = mkOption { services.clightning-rest.lndconnectOnion.enable = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = mdDoc ''
Create an onion service for clightning-rest. Create an onion service for clightning-rest.
Add a `lndconnect-onion-clightning` binary to the system environment. Add a `lndconnect-onion-clightning` binary to the system environment.
See: https://github.com/LN-Zap/lndconnect See: https://github.com/LN-Zap/lndconnect
Usage: Usage:
``` ```bash
# Print QR code # Print QR code
lndconnect-onion-clightning lndconnect-onion-clightning

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.
''; '';
}; };
@ -73,9 +73,10 @@ let
return return
info["onion_address"] = f"{onion_address}:{port}" info["onion_address"] = 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}) set_onion_address(info, "${name}", ${onionPort})
'') + extraCode + '' '') + extraCode + ''
""") """, "${systemdServiceName}")
''; '';
mkIfOnionPort = name: fn: mkIfOnionPort = name: fn:

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

@ -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;
}; };

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.
@ -231,6 +231,15 @@ let
The `lndconnect-rest-onion` binary has been renamed to `lndconnect-onion`. The `lndconnect-rest-onion` binary has been renamed to `lndconnect-onion`.
''; '';
} }
{
version = "0.0.85";
condition = config.services.fulcrum.enable;
message = ''
Fulcrum 1.9.0 has changed its database format.
The database update happens automatically and instantly on deployment,
but you can't switch back to an older Fulcrum version afterwards.
'';
}
]; ];
mkOnionServiceChange = service: { mkOnionServiceChange = service: {

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~=22.11rc1";
}; };
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,7 +13,7 @@ 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; };
@ -21,9 +21,10 @@ let self = {
secp256k1 = pkgs.callPackage ./secp256k1 { }; secp256k1 = pkgs.callPackage ./secp256k1 { };
spark-wallet = pkgs.callPackage ./spark-wallet { }; spark-wallet = pkgs.callPackage ./spark-wallet { };
nbPython3Packages = (pkgs.python3.override { pyPkgs = import ./python-packages self pkgs.python3;
packageOverrides = import ./python-packages self; inherit (self.pyPkgs)
}).pkgs; 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,13 @@
{ stdenv, lib, fetchurl, python3, nbPythonPackageOverrides, pkgs }: { stdenv, lib, fetchurl, python3, nbPython3PackagesJoinmarket }:
let let
version = "0.9.7"; version = "0.9.8";
src = fetchurl { src = fetchurl {
url = "https://github.com/JoinMarket-Org/joinmarket-clientserver/archive/v${version}.tar.gz"; url = "https://github.com/JoinMarket-Org/joinmarket-clientserver/archive/v${version}.tar.gz";
sha256 = "13bfr8ha6bka8wiai8m79ki43dn2r311lrfffr39ni2wy1v12l93"; sha256 = "1ab4smpyx966iiiip3g11bcslya37qhac1kgkbmsmlsdkpilw9di";
}; };
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,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

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,9 +4,9 @@ pkgs: pkgsUnstable:
inherit (pkgs) inherit (pkgs)
bitcoin bitcoin
bitcoind bitcoind
electrs
elementsd elementsd
extra-container extra-container
lightning-loop
lightning-pool lightning-pool
lndconnect lndconnect
nbxplorer; nbxplorer;
@ -15,9 +15,9 @@ pkgs: pkgsUnstable:
btcpayserver btcpayserver
charge-lnd charge-lnd
clightning clightning
electrs
fulcrum fulcrum
hwi hwi
lightning-loop
lnd; lnd;
inherit pkgs pkgsUnstable; inherit pkgs pkgsUnstable;

View File

@ -1,51 +1,66 @@
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 {};
urldecode = callPackage ./urldecode {};
};
# 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`)
werkzeug = callPackage ./specific-versions/werkzeug.nix {};
# pyopenssl 20.0.1, required by joinmarketdaemon # pyopenssl 20.0.1, required by joinmarketdaemon
pyopenssl = callPackage ./specific-versions/pyopenssl.nix {}; pyopenssl = callPackage ./specific-versions/pyopenssl.nix {
openssl = super.pkgs.openssl_1_1;
};
# twisted 22.4.0, compatible with pyopenssl 20.0.1
twisted = callPackage ./specific-versions/twisted.nix {};
};
nbPython3Packages = (python3.override {
packageOverrides = pyPkgsOverrides;
}).pkgs;
nbPython3PackagesJoinmarket = (python3.override {
packageOverrides = pyPkgsOverridesJoinmarket;
}).pkgs;
} }

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

@ -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

@ -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

@ -10,22 +10,11 @@
}: }:
let self = stdenvNoCC.mkDerivation { let self = stdenvNoCC.mkDerivation {
pname = "rtl"; pname = "rtl";
version = "0.13.1"; version = "0.13.4";
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-WVldNnmCB7Gi/U3dUDTYF58i480eXkstRnEg+1QCeMM=";
};
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-AG7930RGLxbPp1ErTGuYvUvPur9ppEmg91Taz7Ube6w=";
}; };
}; };
@ -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.4"
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;
}; };
} }

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

View File

@ -53,17 +53,10 @@
set -euo pipefail set -euo pipefail
if [[ $EUID != 0 ]]; then # These vars are set by ../run-tests.sh
# NixOS containers require root permissions. : "${container:=}"
# By using sudo here and not at the user's call-site extra-container can detect if it is running : "${scriptDir:=}"
# inside an existing shell session (by checking an internal environment variable).
#
# shellcheck disable=SC2154
exec sudo scenario="$scenario" scriptDir="$scriptDir" NIX_PATH="$NIX_PATH" PATH="$PATH" \
scenarioOverridesFile="${scenarioOverridesFile:-}" "$scriptDir/lib/make-container.sh" "$@"
fi
export containerName=nb-test
containerCommand=shell containerCommand=shell
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
@ -79,14 +72,17 @@ while [[ $# -gt 0 ]]; do
done done
containerBin=$(type -P extra-container) || true containerBin=$(type -P extra-container) || true
if [[ ! ($containerBin && $(realpath "$containerBin") == *extra-container-0.10*) ]]; then if [[ ! ($containerBin && $(realpath "$containerBin") == *extra-container-0.11*) ]]; then
echo "Building extra-container. Skip this step by adding extra-container 0.10 to PATH." echo
nix-build --out-link /tmp/extra-container "$scriptDir"/../pkgs \ echo "Building extra-container. Skip this step by adding extra-container 0.11 to PATH."
-A pinned.extra-container >/dev/null nix build --out-link /tmp/extra-container "$scriptDir"/..#extra-container
# When this script is run as root, e.g. when run in an extra-container shell,
# chown the gcroot symlink to the regular (login) user so that the symlink can be
# overwritten when this script is run without root.
if [[ $EUID == 0 ]]; then
chown "$(logname):" --no-dereference /tmp/extra-container
fi
export PATH="/tmp/extra-container/bin${PATH:+:}$PATH" export PATH="/tmp/extra-container/bin${PATH:+:}$PATH"
fi fi
read -rd '' src <<EOF || true exec "$container"/bin/container "$containerCommand" "$@"
((import "$scriptDir/tests.nix" {}).getTest "$scenario").container
EOF
exec extra-container "$containerCommand" -E "$src" "$@"

View File

@ -1,25 +1,35 @@
pkgs: pkgs:
let let
pythonTesting = import "${toString pkgs.path}/nixos/lib/testing-python.nix" { pythonTesting = import (pkgs.path + "/nixos/lib/testing-python.nix") {
system = pkgs.stdenv.hostPlatform.system; system = pkgs.stdenv.hostPlatform.system;
inherit pkgs; inherit pkgs;
}; };
in in
args: module:
let let
test = pythonTesting.makeTest args; test = (pythonTesting.evalTest module).config;
runTest = pkgs.stdenv.mkDerivation {
name = "vm-test-run-${test.name}";
requiredSystemFeatures = [ "kvm" "nixos-test" ];
# 1. Save test logging output # 1. Save test logging output
# 2. Add link to driver so that a gcroot to a test prevents the driver from # 2. Add link to driver so that a gcroot to a test prevents the driver from
# being garbage-collected # being garbage-collected
fixedTest = test.overrideAttrs (_: {
# See `runTests` in nixpkgs/nixos/lib/testing-python.nix for the original definition of `buildCommand`
buildCommand = '' buildCommand = ''
mkdir "$out" mkdir "$out"
LOGFILE=$out/output.xml tests='exec(os.environ["testScript"])' ${test.driver}/bin/nixos-test-driver LOGFILE=$out/output.xml tests='exec(os.environ["testScript"])' ${test.driver}/bin/nixos-test-driver
ln -s ${test.driver} "$out/driver" ln -s ${test.driver} "$out/driver"
''; '';
});
inherit (test) meta passthru;
} // test;
in in
fixedTest runTest // {
# A VM runner for interactive use
run = pkgs.writers.writeBashBin "run-vm" ''
. ${./run-vm.sh} ${runTest.driver} "$@"
'';
}

View File

@ -1,29 +1,25 @@
pkgs: flake: pkgs: makeTestVM:
let let
makeVM = import ./make-test-vm.nix pkgs; inherit (flake.inputs) extra-container;
inherit (pkgs) lib; inherit (pkgs.stdenv.hostPlatform) system;
in in
name: testConfig: { name ? "nix-bitcoin-test", config }:
{ let
vm = makeVM { inherit (pkgs) lib;
name = "nix-bitcoin-${name}";
testConfig = config;
test = makeTestVM {
inherit name;
nodes.machine = { config, ... }: { nodes.machine = { config, ... }: {
imports = [ testConfig ]; imports = [
testConfig
commonVmConfig
];
virtualisation = { test.shellcheckServices.enable = true;
# Needed because duplicity requires 270 MB of free temp space, regardless of backup size
diskSize = 1024;
# Min. 800 MiB needed to avoid 'out of memory' errors
memorySize = lib.mkDefault 2048;
cores = lib.mkDefault 2;
};
# Run shellcheck on all nix-bitcoin services during machine build time
system.extraDependencies = [ config.test.shellcheckServices ];
}; };
testScript = nodes: let testScript = nodes: let
@ -48,15 +44,18 @@ name: testConfig:
(builtins.readFile ./../tests.py) (builtins.readFile ./../tests.py)
cfg.test.extraTestScript cfg.test.extraTestScript
# Don't run tests in interactive mode. # Don't run tests in interactive mode.
# is_interactive is set in ../run-tests.sh # is_interactive is set in ./run-vm.sh
'' ''
if not "is_interactive" in vars(): if not "is_interactive" in vars():
run_tests() nb_run_tests()
'' ''
]; ];
}; };
container = { mkContainer = legacyInstallDirs:
extra-container.lib.buildContainers {
inherit system legacyInstallDirs;
config = {
# The container name has a 11 char length limit # The container name has a 11 char length limit
containers.nb-test = { config, ... }: { containers.nb-test = { config, ... }: {
imports = [ imports = [
@ -74,9 +73,9 @@ name: testConfig:
# has been resolved. This will also improve security. # has been resolved. This will also improve security.
( (
let let
clightning = config.config.services.clightning; s = config.config.services;
in in
lib.mkIf (clightning.enable && clightning.replication.enable) { lib.mkIf (s ? clightning && s.clightning.enable && s.clightning.replication.enable) {
bindMounts."/dev/fuse" = { hostPath = "/dev/fuse"; }; bindMounts."/dev/fuse" = { hostPath = "/dev/fuse"; };
allowedDevices = [ { node = "/dev/fuse"; modifier = "rw"; } ]; allowedDevices = [ { node = "/dev/fuse"; modifier = "rw"; } ];
} }
@ -84,26 +83,61 @@ name: testConfig:
]; ];
}; };
}; };
};
container = mkContainer false;
containerLegacy = mkContainer true;
# This allows running a test scenario in a regular NixOS VM. # This allows running a test scenario in a regular NixOS VM.
# No tests are executed. # No tests are executed.
vmWithoutTests = (pkgs.nixos ({ config, ... }: { vm = (pkgs.nixos ({ config, ... }: {
imports = [ imports = [
testConfig testConfig
"${toString pkgs.path}/nixos/modules/virtualisation/qemu-vm.nix" commonVmConfig
(pkgs.path + "/nixos/modules/virtualisation/qemu-vm.nix")
]; ];
virtualisation.graphics = false; virtualisation.graphics = false;
services.getty.autologinUser = "root"; services.getty.autologinUser = "root";
# Provide a shortcut for instant poweroff from within the machine # Avoid lengthy build of the nixos manual
environment.systemPackages = with pkgs; [ documentation.nixos.enable = false;
(lowPrio (writeScriptBin "q" ''
# Power off VM when the user exits the shell
systemd.services."serial-getty@".preStop = ''
echo o >/proc/sysrq-trigger echo o >/proc/sysrq-trigger
'')) '';
];
system.stateVersion = lib.mkDefault config.system.nixos.release; system.stateVersion = lib.mkDefault config.system.nixos.release;
})).config.system.build.vm; })).config.system.build.vm.overrideAttrs (old: {
meta = old.meta // { mainProgram = "run-vm-in-tmpdir"; };
buildCommand = old.buildCommand + "\n" + ''
install -m 700 ${./run-vm-without-tests.sh} $out/bin/run-vm-in-tmpdir
patchShebangs $out/bin/run-vm-in-tmpdir
'';
});
commonVmConfig = {
virtualisation = {
# Needed because duplicity requires 270 MB of free temp space, regardless of backup size
diskSize = 1024;
# Min. 800 MiB needed to avoid 'out of memory' errors
memorySize = lib.mkDefault 2048;
# There are no perf gains beyond 3 cores.
# Benchmark: Ryzen 7 2700 (8 cores), VM test `default` as of 34f6eb90.
# Num. Cores | 1 | 2 | 3 | 4 | 6
# Runtime (sec) | 125 | 95 | 89 | 89 | 90
cores = lib.mkDefault 3;
};
};
in
test // {
inherit
vm
container
# For NixOS with `system.stateVersion` <22.05
containerLegacy;
config = testConfig; config = testConfig;
} }

View File

@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -euo pipefail
# This script uses the following env vars:
# NIX_BITCOIN_VM_ENABLE_NETWORK
# NIX_BITCOIN_VM_DATADIR
# QEMU_OPTS
# QEMU_NET_OPTS
if [[ ${NIX_BITCOIN_VM_DATADIR:-} ]]; then
dataDir=$NIX_BITCOIN_VM_DATADIR
else
dataDir=$(mktemp -d /tmp/nix-bitcoin-vm.XXX)
trap 'rm -rf "$dataDir"' EXIT
fi
if [[ ! ${NIX_BITCOIN_VM_ENABLE_NETWORK:-} ]]; then
QEMU_NET_OPTS='restrict=on'
fi
# TODO-EXTERNAL:
# Pass PATH because run-*-vm is impure (requires coreutils from PATH)
env -i \
PATH="$PATH" \
USE_TMPDIR=1 \
TMPDIR="$dataDir" \
NIX_DISK_IMAGE="$dataDir/img.qcow2" \
QEMU_OPTS="${QEMU_OPTS:-}" \
QEMU_NET_OPTS="${QEMU_NET_OPTS:-}" \
"${BASH_SOURCE[0]%/*}"/run-*-vm

50
test/lib/run-vm.sh Normal file
View File

@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -euo pipefail
# This script uses the following env vars:
# NIX_BITCOIN_VM_ENABLE_NETWORK
# NIX_BITCOIN_VM_DATADIR
# QEMU_OPTS
# QEMU_NET_OPTS
if [[ ${NIX_BITCOIN_VM_DATADIR:-} ]]; then
dataDir=$NIX_BITCOIN_VM_DATADIR
else
dataDir=$(mktemp -d /tmp/nix-bitcoin-vm.XXX)
trap 'rm -rf "$dataDir"' EXIT
fi
testDriver=$1
shift
# Variable 'tests' contains the Python code that is executed by the driver on startup
if [[ ${1:-} == --debug ]]; then
shift
echo "Running interactive testing environment"
# Start REPL.
# Use `code.interact` for the REPL instead of the builtin test driver REPL
# because it supports low featured terminals like Emacs' shell-mode.
tests='
is_interactive = True
exec(open(os.environ["testScript"]).read())
if "machine" in vars(): machine.start()
import code
code.interact(local=globals())
'
echo
echo "Starting VM, data dir: $dataDir"
else
tests='exec(open(os.environ["testScript"]).read())'
fi
if [[ ! ${NIX_BITCOIN_VM_ENABLE_NETWORK:-} ]]; then
QEMU_NET_OPTS='restrict=on'
fi
# The VM creates a VDE control socket in $PWD
env --chdir "$dataDir" -i \
USE_TMPDIR=1 \
TMPDIR="$dataDir" \
QEMU_OPTS="-nographic ${QEMU_OPTS:-}" \
QEMU_NET_OPTS="${QEMU_NET_OPTS:-}" \
"$testDriver/bin/nixos-test-driver" <(echo "$tests") "$@"

View File

@ -1,10 +1,26 @@
{ config, pkgs, lib, extendModules, ... }: { config, pkgs, lib, extendModules, ... }@args:
with lib; with lib;
let let
options = { options.test.shellcheckServices = {
test.shellcheckServices = mkOption { enable = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
Whether to shellcheck services during system build time.
'';
};
sourcePrefix = mkOption {
type = with types; nullOr str;
default = null;
description = mdDoc ''
The definition source path prefix of services to include in the shellcheck.
'';
};
runShellcheck = mkOption {
readOnly = true; readOnly = true;
description = '' description = mdDoc ''
A derivation that runs shellcheck on all bash scripts included A derivation that runs shellcheck on all bash scripts included
in nix-bitcoin services. in nix-bitcoin services.
''; '';
@ -12,70 +28,42 @@ let
}; };
}; };
# TODO-EXTERNAL: cfg = config.test.shellcheckServices;
# This can be removed when https://github.com/NixOS/nixpkgs/pull/189836 is merged.
#
# A list of all systemd service definitions and their locations, with format
# [
# {
# file = ...;
# value = { postgresql = ...; };
# }
# ...
# ]
systemdServiceDefs =
(extendModules {
modules = [
{
# Currently, NixOS modules only allow accessing option definition locations
# via type.merge.
# Override option `systemd.services` and use it to return the list of service defs.
options.systemd.services = lib.mkOption {
type = lib.types.anything // {
merge = loc: defs: defs;
};
};
# Disable all modules that define options.systemd.services so that these # A list of all service names that are defined in source paths prefixed by
# defs don't collide with our definition # `sourcePrefix`.
disabledModules = [
"system/boot/systemd.nix"
# These files amend option systemd.services
"testing/service-runner.nix"
"security/systemd-confinement.nix"
];
config._module.check = false;
}
];
}).config.systemd.services;
# A list of all service names that are defined by nix-bitcoin.
# [ "bitcoind", "clightning", ... ] # [ "bitcoind", "clightning", ... ]
# #
# Algorithm: Parse `systemdServiceDefs` and return all services that # Algorithm: Parse defintions of `systemd.services` and return all services
# only have definitions located in the nix-bitcoin source. # that only have definitions located within `sourcePrefix`.
nix-bitcoin-services = let servicesToCheck = let
nix-bitcoin-source = toString ../..; inherit (cfg) sourcePrefix;
nbServices = collectServices true; systemdServices = args.options.systemd.services;
nonNbServices = collectServices false; configSystemdServices = args.config.systemd.services;
matchingServices = collectServices true;
nonMatchingServices = collectServices false;
# Return set of services ({ service1 = true; service2 = true; ... }) # Return set of services ({ service1 = true; service2 = true; ... })
# which are either defined or not defined by nix-bitcoin, depending # which are either defined or not defined within `sourcePrefix`, depending
# on `fromNixBitcoin`. # on `shouldMatch`.
collectServices = fromNixBitcoin: lib.listToAttrs (builtins.concatLists (map (def: collectServices = shouldMatch: lib.listToAttrs (builtins.concatLists (map (def:
let let
isNbSource = lib.hasPrefix nix-bitcoin-source def.file; services = def.value;
inherit (def) file;
isMatching = lib.hasPrefix sourcePrefix file;
in in
# Nix has nor boolean XOR, so use `if` # Nix has no boolean XOR, so use `if`
lib.optionals (if fromNixBitcoin then isNbSource else !isNbSource) ( lib.optionals (if shouldMatch then isMatching else !isMatching) (
(map (service: { name = service; value = true; }) (builtins.attrNames def.value)) (map (service: { name = service; value = true; }) (builtins.attrNames services))
) )
) systemdServiceDefs)); ) systemdServices.definitionsWithLocations));
in in
# Set difference: nbServices - nonNbServices # Calculate set difference: matchingServices - nonMatchingServices
builtins.filter (nbService: ! nonNbServices ? ${nbService}) (builtins.attrNames nbServices); # and exclude unavailable services (defined via `mkIf false ...`) by checking `configSystemdServices`.
builtins.filter (prefixedService:
configSystemdServices ? ${prefixedService} && (! nonMatchingServices ? ${prefixedService})
) (builtins.attrNames matchingServices);
# The concatenated list of values of ExecStart, ExecStop, ... (`scriptAttrs`) of all `nix-bitcoin-services`. # The concatenated list of values of ExecStart, ExecStop, ... (`scriptAttrs`) of all `servicesToCheck`.
serviceCmds = let serviceCmds = let
scriptAttrs = [ scriptAttrs = [
"ExecStartPre" "ExecStartPre"
@ -99,7 +87,7 @@ let
if builtins.typeOf cmd == "list" then cmd else [ cmd ] if builtins.typeOf cmd == "list" then cmd else [ cmd ]
) )
) scriptAttrs ) scriptAttrs
) nix-bitcoin-services; ) servicesToCheck;
# A list of all binaries included in `serviceCmds` # A list of all binaries included in `serviceCmds`
serviceBinaries = map (cmd: builtins.head ( serviceBinaries = map (cmd: builtins.head (
@ -125,4 +113,15 @@ let
in in
{ {
inherit options; inherit options;
config = mkIf (cfg.enable && cfg.sourcePrefix != null) {
assertions = [
{
assertion = builtins.length servicesToCheck > 0;
message = "test.shellcheckServices: No services found with source prefix `${cfg.sourcePrefix}`";
}
];
system.extraDependencies = [ shellcheckServices ];
};
} }

View File

@ -10,7 +10,7 @@ with lib;
noConnections = mkOption { noConnections = mkOption {
type = types.bool; type = types.bool;
default = !config.test.container.enableWAN; default = !config.test.container.enableWAN;
description = '' description = mdDoc ''
Whether services should be configured to not connect to external hosts. Whether services should be configured to not connect to external hosts.
This can silence some warnings while running the test in an offline environment. This can silence some warnings while running the test in an offline environment.
''; '';
@ -18,9 +18,9 @@ with lib;
data = mkOption { data = mkOption {
type = types.attrs; type = types.attrs;
default = {}; default = {};
description = '' description = mdDoc ''
Attrs that are available in the Python test script under the global Attrs that are available in the Python test script under the global
dictionary variable 'test_data'. The data is exported via JSON. dictionary variable {var}`test_data`. The data is exported via JSON.
''; '';
}; };
extraTestScript = mkOption { extraTestScript = mkOption {

View File

@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -euo pipefail
# Run flake-info for the nix-bitcoin flake in a sandbox:
# - Adds a consistent, reproducible runtime environment
# - Removes the need to trust the flake-info binary
#
# Use bubblewrap instead of a sandboxed Nix build so that we don't have to copy
# the whole repo to the sandbox when running this test.
cd "${BASH_SOURCE[0]%/*}"
nbFlake=$(realpath ../..)
# shellcheck disable=SC2016
PATH=$(nix shell -L .#{flake-info,bubblewrap} -c sh -c 'echo $PATH')
tmpDir=$(mktemp -d /tmp/nix-bitcoin-flake-info.XXX)
trap 'rm -rf $tmpDir' EXIT
echo '
experimental-features = nix-command flakes
flake-registry = /dev/null
' > "$tmpDir/nix.conf"
echo "Running flake-info (nixos-search)"
bwrap \
--unshare-all \
--clearenv \
--setenv PATH "$PATH" \
--setenv NIX_PATH "$NIX_PATH" \
--bind "$tmpDir" / \
--proc /proc \
--dev /dev \
--tmpfs /tmp \
--ro-bind "$nbFlake" "$nbFlake" \
--ro-bind /nix /nix \
--ro-bind /etc /etc \
--tmpfs /etc/nix \
--ro-bind "$tmpDir/nix.conf" /etc/nix/nix.conf \
--ro-bind /usr /usr \
--ro-bind-try /run /run \
-- flake-info flake "$nbFlake"

View File

@ -2,11 +2,11 @@
"nodes": { "nodes": {
"flake-utils": { "flake-utils": {
"locked": { "locked": {
"lastModified": 1659877975, "lastModified": 1667395993,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -18,11 +18,11 @@
"nixos-org-configurations": { "nixos-org-configurations": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1660725019, "lastModified": 1674564797,
"narHash": "sha256-729dr5TzCG3JIYgrcyyZQoG/e+Ugr6r2NB08Izer0q8=", "narHash": "sha256-MgGsFleE8Wzhu8XX3ulcBojkHzFLkII+D9sxkTHg7OU=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixos-org-configurations", "repo": "nixos-org-configurations",
"rev": "569797100aac69780a12542c2143bb741380d4ec", "rev": "3ce43a1fb5181a0e33b1f67d36fa0f3affa6bc6c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -35,14 +35,15 @@
"inputs": { "inputs": {
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"nixos-org-configurations": "nixos-org-configurations", "nixos-org-configurations": "nixos-org-configurations",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs",
"npmlock2nix": "npmlock2nix"
}, },
"locked": { "locked": {
"lastModified": 1661847188, "lastModified": 1674593115,
"narHash": "sha256-GSA60qVevqN2Q+bbD4O6nbWUCzNtjbEQhYBvcSSRIkI=", "narHash": "sha256-P4bjLR/8tJ/jVBBeHDzNS2BgVUdB6vS7Udfh30kULJs=",
"owner": "nixos", "owner": "nixos",
"repo": "nixos-search", "repo": "nixos-search",
"rev": "7d1c1046ba918625fef44a204c219188824f46fb", "rev": "be9a717b8032c7410337139f9dcfd6227b7407a4",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -53,11 +54,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1661450036, "lastModified": 1667629849,
"narHash": "sha256-0/9UyJLtfWqF4uvOrjFIzk8ue1YYUHa6JIhV0mALkH0=", "narHash": "sha256-P+v+nDOFWicM4wziFK9S/ajF2lc0N2Rg9p6Y35uMoZI=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "f3d0897be466aa09a37f6bf59e62c360c3f9a6cc", "rev": "3bacde6273b09a21a8ccfba15586fb165078fb62",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -66,6 +67,22 @@
"type": "indirect" "type": "indirect"
} }
}, },
"npmlock2nix": {
"flake": false,
"locked": {
"lastModified": 1666460237,
"narHash": "sha256-HME6rnysvCwUVtH+BDWDGahmweMaLgD2wqHeRuGp6QI=",
"owner": "nix-community",
"repo": "npmlock2nix",
"rev": "eeed152290ec2425f96c5e74e469c40b621e1468",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "npmlock2nix",
"type": "github"
}
},
"root": { "root": {
"inputs": { "inputs": {
"nixos-search": "nixos-search" "nixos-search": "nixos-search"

View File

@ -3,6 +3,7 @@
# it to the main flake. # it to the main flake.
{ {
inputs.nixos-search.url = "github:nixos/nixos-search"; inputs.nixos-search.url = "github:nixos/nixos-search";
outputs = { self, nixos-search }: { outputs = { self, nixos-search }: {
inherit (nixos-search) packages; inherit (nixos-search) packages;

View File

@ -4,7 +4,7 @@
# The tests (defined in ./tests.nix) use the NixOS testing framework and are executed in a VM. # The tests (defined in ./tests.nix) use the NixOS testing framework and are executed in a VM.
# #
# Usage: # Usage:
# Run all tests # Run the basic set of tests. These are also run on the CI server.
# ./run-tests.sh # ./run-tests.sh
# #
# Test specific scenario # Test specific scenario
@ -57,7 +57,8 @@
# and reading source files. # and reading source files.
# Files are copied to /tmp, a caching scheme helps minimizing copies. # Files are copied to /tmp, a caching scheme helps minimizing copies.
# #
# To add custom scenarios, set the environment variable `scenarioOverridesFile`. # Add custom scenarios from a file
# ./run-tests.sh --extra-scenarios ~/my/scenarios.nix ...
set -eo pipefail set -eo pipefail
@ -66,7 +67,7 @@ scriptDir=$(cd "${BASH_SOURCE[0]%/*}" && pwd)
args=("$@") args=("$@")
scenario= scenario=
outLinkPrefix= outLinkPrefix=
ciBuild= scenarioOverridesFile=
while :; do while :; do
case $1 in case $1 in
--scenario|-s) --scenario|-s)
@ -89,9 +90,15 @@ while :; do
exit 1 exit 1
fi fi
;; ;;
--ci) --extra-scenarios)
if [[ $2 ]]; then
scenarioOverridesFile=$2
shift shift
ciBuild=1 shift
else
>&2 echo "Error: $1 requires an argument."
exit 1
fi
;; ;;
--copy-src|-c) --copy-src|-c)
shift shift
@ -105,228 +112,185 @@ while :; do
esac esac
done done
numCPUs=${numCPUs:-$(nproc)} tmpDir=
# Min. 800 MiB needed to avoid 'out of memory' errors # Sets global var `tmpDir`
memoryMiB=${memoryMiB:-2048} makeTmpDir() {
if [[ ! $tmpDir ]]; then
NIX_PATH=nixpkgs=$(nix eval --raw -f "$scriptDir/../pkgs/nixpkgs-pinned.nix" nixpkgs):nix-bitcoin=$(realpath "$scriptDir/..") tmpDir=$(mktemp -d /tmp/nix-bitcoin-tests.XXX)
export NIX_PATH # shellcheck disable=SC2064
trap "rm -rf '$tmpDir'" EXIT
runAtExit= fi
trap 'eval "$runAtExit"' EXIT }
# Support explicit scenario definitions # Support explicit scenario definitions
if [[ $scenario = *' '* ]]; then if [[ $scenario = *' '* ]]; then
scenarioOverridesFile=$(mktemp "${XDG_RUNTIME_DIR:-/tmp}/nb-scenario.XXX") makeTmpDir
export scenarioOverridesFile scenarioOverridesFile=$tmpDir/scenario-overrides.nix
echo "{ scenarios, pkgs, lib, nix-bitcoin }: with lib; { tmp = $scenario; }" > "$scenarioOverridesFile"
# shellcheck disable=SC2016
runAtExit+='rm -f "$scenarioOverridesFile";'
echo "{ scenarios, pkgs, lib }: with lib; { tmp = $scenario; }" > "$scenarioOverridesFile"
scenario=tmp scenario=tmp
fi fi
# Run the test. No temporary files are left on the host system. # Run the test. No temporary files are left on the host system.
run() { run() {
# TMPDIR is also used by the test driver for VM tmp files makeTmpDir
TMPDIR=$(mktemp -d /tmp/nix-bitcoin-test.XXX) buildTestAttr .run --out-link "$tmpDir/run-vm"
export TMPDIR NIX_BITCOIN_VM_DATADIR=$tmpDir "$tmpDir/run-vm/bin/run-vm" "$@"
runAtExit+="rm -rf ${TMPDIR};"
nix-build --out-link "$TMPDIR/driver" -E "((import \"$scriptDir/tests.nix\" {}).getTest \"$scenario\").vm" -A driver
# Variable 'tests' contains the Python code that is executed by the driver on startup
if [[ $1 == --interactive ]]; then
echo "Running interactive testing environment"
tests=$(
echo 'is_interactive = True'
echo 'exec(open(os.environ["testScript"]).read())'
# Start VM
echo 'if "machine" in vars(): machine.start()'
# Start REPL.
# Use `code.interact` for the REPL instead of the builtin test driver REPL
# because it supports low featured terminals like Emacs' shell-mode.
echo 'import code'
echo 'code.interact(local=globals())'
)
else
tests='exec(open(os.environ["testScript"]).read())'
fi
echo "VM stats: CPUs: $numCPUs, memory: $memoryMiB MiB"
[[ $NB_TEST_ENABLE_NETWORK ]] || QEMU_NET_OPTS='restrict=on'
cd "$TMPDIR" # The VM creates a VDE control socket in $PWD
env -i \
NIX_PATH="$NIX_PATH" \
TMPDIR="$TMPDIR" \
USE_TMPDIR=1 \
QEMU_OPTS="-smp $numCPUs -m $memoryMiB -nographic $QEMU_OPTS" \
QEMU_NET_OPTS="$QEMU_NET_OPTS" \
"$TMPDIR/driver/bin/nixos-test-driver" <(echo "$tests")
} }
debug() { debug() {
run --interactive run --debug
}
evalTest() {
nix-instantiate --eval -E "($(vmTestNixExpr)).outPath"
}
instantiate() {
nix-instantiate -E "$(vmTestNixExpr)" "$@"
} }
container() { container() {
export scriptDir scenario local nixosContainer
if ! nixosContainer=$(type -p nixos-container) \
|| grep -q '"/etc/nixos-containers"' "$nixosContainer"; then
local attr=container
else
# NixOS with `system.stateVersion` <22.05
local attr=containerLegacy
fi
echo "Building container"
makeTmpDir
export container=$tmpDir/container
buildTestAttr ".$attr" --out-link "$container"
export scriptDir
"$scriptDir/lib/make-container.sh" "$@" "$scriptDir/lib/make-container.sh" "$@"
} }
# Run a regular NixOS VM # Run a regular NixOS VM
vm() { vm() {
TMPDIR=$(mktemp -d /tmp/nix-bitcoin-vm.XXX) makeTmpDir
export TMPDIR buildTestAttr .vm --out-link "$tmpDir/vm"
runAtExit+="rm -rf $TMPDIR;" NIX_BITCOIN_VM_DATADIR=$tmpDir "$tmpDir/vm/bin/run-vm-in-tmpdir"
nix-build --out-link "$TMPDIR/vm" -E "((import \"$scriptDir/tests.nix\" {}).getTest \"$scenario\").vmWithoutTests"
echo "VM stats: CPUs: $numCPUs, memory: $memoryMiB MiB"
[[ $NB_TEST_ENABLE_NETWORK ]] || export QEMU_NET_OPTS="restrict=on,$QEMU_NET_OPTS"
# shellcheck disable=SC2211
USE_TMPDIR=1 \
NIX_DISK_IMAGE=$TMPDIR/img.qcow2 \
QEMU_OPTS="-smp $numCPUs -m $memoryMiB -nographic $QEMU_OPTS" \
"$TMPDIR"/vm/bin/run-*-vm
}
doBuild() {
name=$1
shift
if [[ $ciBuild ]]; then
"$scriptDir/ci/build-to-cachix.sh" "$@"
else
if [[ $outLinkPrefix ]]; then
outLink="--out-link $outLinkPrefix-$name"
else
outLink=--no-out-link
fi
nix-build $outLink "$@"
fi
} }
# Run the test by building the test derivation # Run the test by building the test derivation
buildTest() { buildTest() {
vmTestNixExpr | doBuild $scenario "$@" - buildTestAttr "" "$@"
} }
vmTestNixExpr() { evalTest() {
extraQEMUOpts= nixInstantiateTest "" "$@"
# Print out path
if [[ $ciBuild ]]; then nix-store -q "$drv"
# On continuous integration nodes there are few other processes running alongside the # Print drv path
# test, so use more memory here for maximum performance. realpath "$drv"
memoryMiB=4096
memTotalKiB=$(awk '/MemTotal/ { print $2 }' /proc/meminfo)
memAvailableKiB=$(awk '/MemAvailable/ { print $2 }' /proc/meminfo)
# Round down to nearest multiple of 50 MiB for improved test build caching
# shellcheck disable=SC2017
((memAvailableMiB = memAvailableKiB / (1024 * 50) * 50))
((memAvailableMiB < memoryMiB)) && memoryMiB=$memAvailableMiB
>&2 echo "VM stats: CPUs: $numCPUs, memory: $memoryMiB MiB"
>&2 echo "Host memory total: $((memTotalKiB / 1024)) MiB, available: $memAvailableMiB MiB"
# VMX is usually not available on CI nodes due to recursive virtualisation.
# Explicitly disable VMX, otherwise QEMU 4.20 fails with message
# "error: failed to set MSR 0x48b to 0x159ff00000000"
extraQEMUOpts="-cpu host,-vmx"
fi
cat <<EOF
((import "$scriptDir/tests.nix" {}).getTest "$scenario").vm.overrideAttrs (old: rec {
buildCommand = ''
export QEMU_OPTS="-smp $numCPUs -m $memoryMiB $extraQEMUOpts"
echo "VM stats: CPUs: $numCPUs, memory: $memoryMiB MiB"
'' + old.buildCommand;
})
EOF
} }
checkFlakeSupport() { buildTestAttr() {
testName=$1 local attr=$1
if [[ ! -v hasFlakes ]]; then shift
if [[ $(nix flake 2>&1) == *"requires a sub-command"* ]]; then # TODO-EXTERNAL:
hasFlakes=1 # Simplify and switch to pure build when `nix build` can build flake function outputs
nixInstantiateTest "$attr"
nixBuild "$scenario" "$drv" "$@"
}
buildTests() {
local -n tests=$1
shift
# TODO-EXTERNAL:
# Simplify and switch to pure build when `nix build` can instantiate flake function outputs
# shellcheck disable=SC2207
drvs=($(nixInstantiate "pkgs.instantiateTests \"${tests[*]}\""))
for i in "${!tests[@]}"; do
testName=${tests[$i]}
drv=${drvs[$i]}
echo
echo "Building test '$testName'"
nixBuild "$testName" "$drv" "$@"
done
}
# Instantiate an attr of the test defined in global var `scenario`
nixInstantiateTest() {
local attr=$1
shift
if [[ $scenarioOverridesFile ]]; then
local file="extraScenariosFile = \"$scenarioOverridesFile\";"
else else
hasFlakes= local file=
fi fi
nixInstantiate "(pkgs.getTest { name = \"$scenario\"; $file })$attr" "$@" >/dev/null
}
drv=
# Sets global var `drv` to the gcroot link of the instantiated derivation
nixInstantiate() {
local expr=$1
shift
makeTmpDir
drv="$tmpDir/drv"
nix-instantiate --add-root "$drv" -E "
let
pkgs = (builtins.getFlake \"git+file://$scriptDir/..\").legacyPackages.\${builtins.currentSystem};
in
$expr
" "$@"
}
nixBuild() {
local outLinkName=$1
shift
args=(--print-out-paths -L)
if [[ $outLinkPrefix ]]; then
args+=(--out-link "$outLinkPrefix-$outLinkName")
else
args+=(--no-link)
fi fi
if [[ ! $hasFlakes ]]; then nix build "${args[@]}" "$@"
echo "Skipping test '$testName'. Nix flake support is not enabled."
return 1
fi
} }
flake() { flake() {
if ! checkFlakeSupport "flake"; then return; fi
nix flake check "$scriptDir/.." nix flake check "$scriptDir/.."
} }
# Test generating module documentation for search.nixos.org # Test generating module documentation for search.nixos.org
nixosSearch() { nixosSearch() {
# TODO-EXTERNAL:
# Remove this when nixos-search has been fixed
echo "Skipping test nixosSearch"
return
if ! checkFlakeSupport "nixosSearch"; then return; fi
if [[ $_nixBitcoinInCopiedSrc ]]; then
# flake-info requires that its target flake is under version control
. "$scriptDir/lib/create-git-repo.sh"
fi
if [[ $outLinkPrefix ]]; then if [[ $outLinkPrefix ]]; then
# Add gcroots for flake-info # Add gcroots for flake-info
nix build "$scriptDir/nixos-search#flake-info" -o "$outLinkPrefix-flake-info" nix build "$scriptDir/nixos-search#flake-info" -o "$outLinkPrefix-flake-info"
fi fi
echo "Running flake-info (nixos-search)" "$scriptDir/nixos-search/flake-info-sandboxed.sh"
nix run "$scriptDir/nixos-search#flake-info" -- flake "$scriptDir/.."
} }
# A basic subset of tests to keep the total runtime within # A basic subset of tests to keep the total runtime within
# manageable bounds (<4 min on desktop systems). # manageable bounds.
# These are also run on the CI server. # These are also run on the CI server.
basic() { basic=(
scenario=default buildTest "$@" default
scenario=netns buildTest "$@" netns
scenario=netnsRegtest buildTest "$@" netnsRegtest
} )
basic() { buildTests basic "$@"; }
# All tests that only consist of building a nix derivation. # All tests that only consist of building a nix derivation.
# Their output is cached in /nix/store. # shellcheck disable=2034
buildable() { buildable=(
basic "$@" "${basic[@]}"
scenario=full buildTest "$@" full
scenario=regtest buildTest "$@" regtest
scenario=hardened buildTest "$@" hardened
scenario=clightningReplication buildTest "$@" clightning-replication
} lndPruned
)
buildable() { buildTests buildable "$@"; }
examples() { examples() {
script=" # shellcheck disable=SC2016
script='
set -e set -e
./deploy-container.sh runExample() { echo; echo Running example $1; ./$1; }
./deploy-container-minimal.sh runExample deploy-container.sh
./deploy-qemu-vm.sh runExample deploy-container-minimal.sh
./deploy-krops.sh runExample deploy-qemu-vm.sh
" runExample deploy-krops.sh
'
(cd "$scriptDir/../examples" && nix-shell --run "$script") (cd "$scriptDir/../examples" && nix-shell --run "$script")
} }
shellcheck() { shellcheck() {
if ! checkFlakeSupport "shellcheck"; then return; fi
"$scriptDir/shellcheck.sh" "$scriptDir/shellcheck.sh"
} }

View File

@ -1,19 +1,11 @@
# Integration tests, can be run without internet access. # Integration tests, can be run without internet access.
lib:
let let
nixpkgs = (import ../pkgs/nixpkgs-pinned.nix).nixpkgs; # Included in all scenarios
in baseConfig = { config, pkgs, ... }: with lib; let
{ extraScenarios ? { ... }: {}
, pkgs ? import nixpkgs { config = {}; overlays = []; }
}:
with pkgs.lib;
let
globalPkgs = pkgs;
baseConfig = { pkgs, config, ... }: let
cfg = config.services; cfg = config.services;
mkIfTest = test: mkIf (config.tests.${test} or false); inherit (config.nix-bitcoin.lib.test) mkIfTest;
in { in {
imports = [ imports = [
./lib/test-lib.nix ./lib/test-lib.nix
@ -32,9 +24,6 @@ let
}; };
config = mkMerge [{ config = mkMerge [{
# Share the same pkgs instance among tests
nixpkgs.pkgs = mkDefault globalPkgs;
environment.systemPackages = mkMerge (with pkgs; [ environment.systemPackages = mkMerge (with pkgs; [
# Needed to test macaroon creation # Needed to test macaroon creation
(mkIfTest "btcpayserver" [ openssl xxd ]) (mkIfTest "btcpayserver" [ openssl xxd ])
@ -64,12 +53,6 @@ let
clboss.path = "${nbPkgs.clboss}/bin/clboss"; clboss.path = "${nbPkgs.clboss}/bin/clboss";
}; };
in map (plugin: pluginPkgs.${plugin}.path) enabled; in map (plugin: pluginPkgs.${plugin}.path) enabled;
# Torified 'dig' subprocesses of clboss don't respond to SIGTERM and keep
# running for a long time when WAN is disabled, which prevents clightning units
# from stopping quickly.
# Set TimeoutStopSec for faster stopping.
systemd.services.clightning.serviceConfig.TimeoutStopSec =
mkIf config.services.clightning.plugins.clboss.enable "500ms";
tests.clightning-rest = cfg.clightning-rest.enable; tests.clightning-rest = cfg.clightning-rest.enable;
@ -101,6 +84,8 @@ let
}; };
}; };
nix-bitcoin.onionServices.lnd.public = true;
tests.lndconnect-onion-lnd = cfg.lnd.lndconnectOnion.enable; tests.lndconnect-onion-lnd = cfg.lnd.lndconnectOnion.enable;
tests.lndconnect-onion-clightning = cfg.clightning-rest.lndconnectOnion.enable; tests.lndconnect-onion-clightning = cfg.clightning-rest.lndconnectOnion.enable;
@ -108,7 +93,6 @@ let
services.lightning-loop.certificate.extraIPs = [ "20.0.0.1" ]; services.lightning-loop.certificate.extraIPs = [ "20.0.0.1" ];
tests.lightning-pool = cfg.lightning-pool.enable; tests.lightning-pool = cfg.lightning-pool.enable;
nix-bitcoin.onionServices.lnd.public = true;
tests.charge-lnd = cfg.charge-lnd.enable; tests.charge-lnd = cfg.charge-lnd.enable;
@ -151,6 +135,13 @@ let
# Avoid timeout failures on slow CI nodes # Avoid timeout failures on slow CI nodes
systemd.services.postgresql.serviceConfig.TimeoutStartSec = "5min"; systemd.services.postgresql.serviceConfig.TimeoutStartSec = "5min";
} }
(mkIf config.services.clightning.plugins.clboss.enable {
# Torified 'dig' subprocesses of clboss don't respond to SIGTERM and keep
# running for a long time when WAN is disabled, which prevents clightning units
# from stopping quickly.
# Set TimeoutStopSec for faster stopping.
systemd.services.clightning.serviceConfig.TimeoutStopSec = "500ms";
})
(mkIf config.test.features.clightningPlugins { (mkIf config.test.features.clightningPlugins {
services.clightning.plugins = { services.clightning.plugins = {
clboss.enable = true; clboss.enable = true;
@ -176,8 +167,9 @@ let
]; ];
}; };
scenarios = { scenarios = with lib; {
base = baseConfig; # Included in all scenarios # Included in all scenarios by ./lib/make-test.nix
base = baseConfig;
default = scenarios.secureNode; default = scenarios.secureNode;
@ -273,7 +265,7 @@ let
environment.systemPackages = [ pkgs.fping ]; environment.systemPackages = [ pkgs.fping ];
}; };
regtestBase = { config, ... }: { regtestBase = { config, pkgs, ... }: {
tests.regtest = true; tests.regtest = true;
test.data.num_blocks = 100; test.data.num_blocks = 100;
@ -318,8 +310,17 @@ let
services.btcpayserver.lbtc = mkForce false; services.btcpayserver.lbtc = mkForce false;
}; };
## Examples / debug helper # Test the special bitcoin RPC setup that lnd uses when bitcoin is pruned
lndPruned = {
services.lnd.enable = true;
services.bitcoind.prune = 1000;
};
} // (import ../dev/dev-scenarios.nix {
inherit lib scenarios;
});
## Example scenarios that showcase extra features
exampleScenarios = with lib; {
# Run a selection of tests in scenario 'netns' # Run a selection of tests in scenario 'netns'
selectedTests = { selectedTests = {
imports = [ scenarios.netns ]; imports = [ scenarios.netns ];
@ -337,39 +338,106 @@ let
test.container.exposeLocalhost = true; test.container.exposeLocalhost = true;
}; };
adhoc = { ## Scenarios with a custom Python test
# <Add your config here>
# You can also set the env var `scenarioOverridesFile` (used below) to define custom scenarios. # Variant 1: Define testing code that always runs
}; customTestSimple = {
networking.hostName = "myhost";
# Variant 1: Define testing code that always runs
test.extraTestScript = ''
succeed("[[ $(hostname) == myhost ]]")
'';
}; };
overrides = builtins.getEnv "scenarioOverridesFile"; # Variant 2: Define a test that can be enabled/disabled
extraScenarios' = (if (overrides != "") then import overrides else extraScenarios) { # via the Nix module system.
inherit scenarios pkgs; customTestExtended = {
inherit (pkgs) lib; networking.hostName = "myhost";
};
allScenarios = scenarios // extraScenarios';
makeTest = name: config: tests.hostName = true;
makeTest' name { test.extraTestScript = ''
@test("hostName")
def _():
succeed("[[ $(hostname) == myhost ]]")
'';
};
};
in {
inherit scenarios;
pkgs = flake: pkgs: rec {
# A basic test using the nix-bitcoin test framework
makeTestBasic = import ./lib/make-test.nix flake pkgs makeTestVM;
# Wraps `makeTest` in NixOS' testing-python.nix so that the drv includes the
# log output and the test driver
makeTestVM = import ./lib/make-test-vm.nix pkgs;
# A test using the nix-bitcoin test framework, with some helpful defaults
makeTest = { name ? "nix-bitcoin-test", config }:
makeTestBasic {
inherit name;
config = {
imports = [ imports = [
allScenarios.base scenarios.base
config config
]; ];
}; # Share the same pkgs instance among tests
makeTest' = import ./lib/make-test.nix pkgs; nixpkgs.pkgs = pkgs.lib.mkDefault pkgs;
tests = builtins.mapAttrs makeTest allScenarios // {
clightningReplication.vm = import ./clightning-replication.nix {
inherit pkgs;
inherit (pkgs.stdenv) system;
}; };
}; };
getTest = name: tests.${name} or (makeTest name { # A test using the nix-bitcoin test framework, with defaults specific to nix-bitcoin
services.${name}.enable = true; makeTestNixBitcoin = { name, config }:
}); makeTest {
name = "nix-bitcoin-${name}";
config = {
imports = [ config ];
test.shellcheckServices.sourcePrefix = toString ./..;
};
};
makeTests = scenarios: let
mainTests = builtins.mapAttrs (name: config:
makeTestNixBitcoin { inherit name config; }
) scenarios;
in in
tests // { {
inherit getTest; clightning-replication = import ./clightning-replication.nix makeTestVM pkgs;
} // mainTests;
tests = makeTests scenarios;
## Helper for ./run-tests.sh
getTest = { name, extraScenariosFile ? null }:
let
tests = makeTests (scenarios // (
lib.optionalAttrs (extraScenariosFile != null)
(import extraScenariosFile {
inherit scenarios lib pkgs;
nix-bitcoin = flake;
})
));
in
tests.${name} or (makeTestNixBitcoin {
inherit name;
config = {
services.${name}.enable = true;
};
});
instantiateTests = testNames:
let
testNames' = lib.splitString " " testNames;
in
map (name:
let
test = tests.${name};
in
builtins.seq (builtins.trace "Evaluating test '${name}'" test.outPath)
test
) testNames';
};
} }

View File

@ -48,7 +48,8 @@ def test(name):
tests[name] = fn tests[name] = fn
return x return x
def run_tests(): # `run_tests` is already defined by the NixOS test driver
def nb_run_tests():
enabled = enabled_tests.copy() enabled = enabled_tests.copy()
to_run = [] to_run = []
for test in tests: for test in tests: