From b666bb290307f7a594b3c04a7e3c9afa2ed19939 Mon Sep 17 00:00:00 2001 From: Martin Milata Date: Wed, 2 Jun 2021 03:11:26 +0200 Subject: [PATCH] charge-lnd: add module --- README.md | 5 +- examples/configuration.nix | 9 +++ modules/charge-lnd.nix | 141 ++++++++++++++++++++++++++++++++++++ modules/default.nix | 1 + modules/modules.nix | 1 + modules/netns-isolation.nix | 4 + pkgs/pinned.nix | 1 + test/tests.nix | 4 + test/tests.py | 7 ++ 9 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 modules/charge-lnd.nix diff --git a/README.md b/README.md index f126668..f9ebaf1 100644 --- a/README.md +++ b/README.md @@ -63,13 +63,14 @@ NixOS modules * [summary](https://github.com/lightningd/plugins/tree/master/summary): print a nice summary of the node status * [zmq](https://github.com/lightningd/plugins/tree/master/zmq): publishes notifications via ZeroMQ to configured endpoints * [lnd](https://github.com/lightningnetwork/lnd) with support for announcing an onion service + * [Lightning Loop](https://github.com/lightninglabs/loop) + * [Lightning Pool](https://github.com/lightninglabs/pool) + * [charge-lnd](https://github.com/accumulator/charge-lnd): policy-based channel fee manager * [lndconnect](https://github.com/LN-Zap/lndconnect) via a REST onion service * [spark-wallet](https://github.com/shesek/spark-wallet) * [electrs](https://github.com/romanz/electrs) * [btcpayserver](https://github.com/btcpayserver/btcpayserver) * [liquid](https://github.com/elementsproject/elements) - * [Lightning Loop](https://github.com/lightninglabs/loop) - * [Lightning Pool](https://github.com/lightninglabs/pool) * [JoinMarket](https://github.com/joinmarket-org/joinmarket-clientserver) * [JoinMarket Orderbook Watcher](https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master/docs/orderbook.md) * [recurring-donations](modules/recurring-donations.nix): for periodic lightning payments diff --git a/examples/configuration.nix b/examples/configuration.nix index 1938bfe..65a5f98 100644 --- a/examples/configuration.nix +++ b/examples/configuration.nix @@ -176,6 +176,15 @@ # Set this to create a public onion service for lnd. # nix-bitcoin.onionServices.lnd.public = true; + ### charge-lnd + # Enable this module to use charge-lnd, a simple policy based fee manager for + # LND. With this tool you can set fees to autobalance, recover channel open + # costs, use on-chain fees as reference, or just use static fees. You decide. + # services.charge-lnd.enable = true; + # Define policies as outlined in the project documentation. + # services.charge-lnd.policies = '' + # ''; + ### Backups # Enable this module to use nix-bitcoin's own backups module. By default, it # uses duplicity to incrementally back up all important files in /var/lib to diff --git a/modules/charge-lnd.nix b/modules/charge-lnd.nix new file mode 100644 index 0000000..c926cee --- /dev/null +++ b/modules/charge-lnd.nix @@ -0,0 +1,141 @@ +{ config, options, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.charge-lnd; + nbLib = config.nix-bitcoin.lib; + lnd = config.services.lnd; + electrs = if (options ? services.electrs) && config.services.electrs.enable + then config.services.electrs + else null; + + user = "charge-lnd"; + group = user; + dataDir = "/var/lib/charge-lnd"; + + configFile = builtins.toFile "charge-lnd.config" cfg.policies; + checkedConfig = pkgs.runCommandNoCC "charge-lnd-checked.config" { } '' + ${config.nix-bitcoin.pkgs.charge-lnd}/bin/charge-lnd --check --config ${configFile} + cp ${configFile} $out + ''; +in +{ + options.services.charge-lnd = with types; { + enable = mkEnableOption "charge-lnd, policy-based fee manager"; + + extraFlags = mkOption { + type = listOf str; + default = []; + example = [ "--verbose" "--dry-run" ]; + description = "Extra flags to pass to the charge-lnd command."; + }; + + interval = mkOption { + type = str; + default = "*-*-* 04:00:00"; + example = "hourly"; + description = '' + Systemd calendar expression when to adjust fees. + + See systemd.time + 7 for possible values. + + Default is once a day. + ''; + }; + + randomDelay = mkOption { + type = str; + default = "1h"; + description = '' + Random delay to add to scheduled time. + ''; + }; + + policies = mkOption { + type = types.lines; + default = ""; + example = literalExample '' + [discourage-routing-out-of-balance] + chan.max_ratio = 0.1 + chan.min_capacity = 250000 + strategy = static + base_fee_msat = 10000 + fee_ppm = 500 + + [encourage-routing-to-balance] + chan.min_ratio = 0.9 + chan.min_capacity = 250000 + strategy = static + base_fee_msat = 1 + fee_ppm = 2 + + [default] + strategy = ignore + ''; + description = '' + Policy definitions in INI format. + + See https://github.com/accumulator/charge-lnd/blob/master/README.md#usage + for possible properties and parameters. + + Policies are evaluated from top to bottom. + The first matching policy (or `default`) is applied. + ''; + }; + }; + + config = mkIf cfg.enable { + services.lnd = { + enable = true; + macaroons.charge-lnd = { + user = user; + permissions = ''{"entity":"info","action":"read"},{"entity":"onchain","action":"read"},{"entity":"offchain","action":"read"},{"entity":"offchain","action":"write"}''; + }; + }; + + systemd.services.charge-lnd = { + documentation = [ "https://github.com/accumulator/charge-lnd/blob/master/README.md" ]; + after = [ "lnd.service" ]; + requires = [ "lnd.service" ]; + # lnd's data directory (--lnddir) is not accessible to charge-lnd. + # Instead use directory "lnddir-proxy" as lnddir and link relevant files to it. + preStart = '' + macaroonDir=${dataDir}/lnddir-proxy/data/chain/bitcoin/mainnet + mkdir -p $macaroonDir + ln -sf /run/lnd/charge-lnd.macaroon $macaroonDir + ln -sf ${config.nix-bitcoin.secretsDir}/lnd-cert ${dataDir}/lnddir-proxy/tls.cert + ''; + serviceConfig = nbLib.defaultHardening // { + ExecStart = '' + ${config.nix-bitcoin.pkgs.charge-lnd}/bin/charge-lnd \ + --lnddir ${dataDir}/lnddir-proxy \ + --grpc ${lnd.rpcAddress}:${toString lnd.rpcPort} \ + --config ${checkedConfig} \ + ${optionalString (electrs != null) "--electrum-server ${electrs.address}:${toString electrs.port}"} \ + ${escapeShellArgs cfg.extraFlags} + ''; + Type = "oneshot"; + User = user; + Group = group; + StateDirectory = "charge-lnd"; + } // nbLib.allowLocalIPAddresses; + }; + + systemd.timers.charge-lnd = { + description = "Adjust LND routing fees"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = cfg.interval; + RandomizedDelaySec = cfg.randomDelay; + }; + }; + + users.users.${user} = { + group = group; + isSystemUser = true; + }; + users.groups.${group} = {}; + }; +} diff --git a/modules/default.nix b/modules/default.nix index cc013a5..388cacd 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -9,5 +9,6 @@ spark-wallet = ./spark-wallet.nix; recurring-donations = ./recurring-donations.nix; lnd = ./lnd.nix; + charge-lnd = ./charge-lnd.nix; joinmarket = ./joinmarket.nix; } diff --git a/modules/modules.nix b/modules/modules.nix index f4537fd..2ebe733 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -16,6 +16,7 @@ with lib; ./lnd-rest-onion-service.nix ./lightning-loop.nix ./lightning-pool.nix + ./charge-lnd.nix ./btcpayserver.nix ./electrs.nix ./liquid.nix diff --git a/modules/netns-isolation.nix b/modules/netns-isolation.nix index 6abb5f7..9e8649a 100644 --- a/modules/netns-isolation.nix +++ b/modules/netns-isolation.nix @@ -249,6 +249,10 @@ in { id = 27; connections = [ "lnd" ]; }; + charge-lnd = { + id = 28; + connections = [ "lnd" "electrs" ]; + }; }; services.bitcoind = { diff --git a/pkgs/pinned.nix b/pkgs/pinned.nix index de489b6..2ae8cf9 100644 --- a/pkgs/pinned.nix +++ b/pkgs/pinned.nix @@ -9,6 +9,7 @@ in inherit (nixpkgsUnstable) bitcoin bitcoind + charge-lnd clightning lnd lndconnect diff --git a/test/tests.nix b/test/tests.nix index 6a2fcd9..ef48631 100644 --- a/test/tests.nix +++ b/test/tests.nix @@ -65,6 +65,8 @@ let tests.lightning-pool = cfg.lightning-pool.enable; nix-bitcoin.onionServices.lnd.public = true; + tests.charge-lnd = cfg.charge-lnd.enable; + tests.electrs = cfg.electrs.enable; tests.liquidd = cfg.liquidd.enable; @@ -136,6 +138,7 @@ let services.lnd.restOnionService.enable = true; services.lightning-loop.enable = true; services.lightning-pool.enable = true; + services.charge-lnd.enable = true; services.electrs.enable = true; services.liquidd.enable = true; services.btcpayserver.enable = true; @@ -178,6 +181,7 @@ let services.lnd.enable = true; services.lightning-loop.enable = true; services.lightning-pool.enable = true; + services.charge-lnd.enable = true; services.electrs.enable = true; services.btcpayserver.enable = true; services.joinmarket.enable = true; diff --git a/test/tests.py b/test/tests.py index c009f1d..3f55d57 100644 --- a/test/tests.py +++ b/test/tests.py @@ -199,6 +199,13 @@ def _(): ) +@test("charge-lnd") +def _(): + # charge-lnd is a oneshot service that is started by a timer under regular operation + succeed("systemctl start charge-lnd") + assert_no_failure("charge-lnd") + + @test("btcpayserver") def _(): assert_running("nbxplorer")