diff --git a/README.md b/README.md index 2f5d5f9..e98cd28 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ NixOS modules * [liquid](https://github.com/elementsproject/elements) * [Lightning Loop](https://github.com/lightninglabs/loop) * [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 * [bitcoin-core-hwi](https://github.com/bitcoin-core/HWI) * Helper diff --git a/examples/configuration.nix b/examples/configuration.nix index 8ebd037..4d92217 100644 --- a/examples/configuration.nix +++ b/examples/configuration.nix @@ -179,6 +179,8 @@ # earn sats by providing CoinJoin liquidity. This makes it impossible to use other # scripts that access your wallet. # services.joinmarket.yieldgenerator.enable = true; + # Enable this option to enable the JoinMarket order book watcher. + # services.joinmarket-ob-watcher.enable = true; # FIXME: Define your hostname. networking.hostName = "nix-bitcoin"; diff --git a/modules/joinmarket-ob-watcher.nix b/modules/joinmarket-ob-watcher.nix new file mode 100644 index 0000000..e65bd7d --- /dev/null +++ b/modules/joinmarket-ob-watcher.nix @@ -0,0 +1,99 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.services.joinmarket-ob-watcher; + inherit (config) nix-bitcoin-services; + nbPkgs = config.nix-bitcoin.pkgs; + torAddress = builtins.head (builtins.split ":" config.services.tor.client.socksListenAddress); + configFile = builtins.toFile "config" '' + [BLOCKCHAIN] + blockchain_source = no-blockchain + + [MESSAGING:server1] + host = darksci3bfoka7tw.onion + channel = joinmarket-pit + port = 6697 + usessl = true + socks5 = true + socks5_host = ${torAddress} + socks5_port = 9050 + + [MESSAGING:server2] + host = ncwkrwxpq2ikcngxq3dy2xctuheniggtqeibvgofixpzvrwpa77tozqd.onion + channel = joinmarket-pit + port = 6667 + usessl = false + socks5 = true + socks5_host = ${torAddress} + socks5_port = 9050 + ''; +in { + options.services.joinmarket-ob-watcher = { + enable = mkEnableOption "JoinMarket orderbook watcher"; + address = mkOption { + type = types.str; + default = "127.0.0.1"; + description = "HTTP server address."; + }; + port = mkOption { + type = types.port; + default = 62601; + description = "HTTP server port."; + }; + dataDir = mkOption { + readOnly = true; + default = "/var/lib/joinmarket-ob-watcher"; + description = "The data directory for JoinMarket orderbook watcher."; + }; + user = mkOption { + type = types.str; + default = "joinmarket-ob-watcher"; + description = "The user as which to run JoinMarket orderbook watcher."; + }; + group = mkOption { + type = types.str; + default = cfg.user; + description = "The group as which to run JoinMarket orderbook watcher."; + }; + # This option is only used by netns-isolation + enforceTor = mkOption { + readOnly = true; + default = true; + }; + }; + + config = mkIf cfg.enable { + services.tor = { + enable = true; + client.enable = true; + }; + + systemd.services.joinmarket-ob-watcher = { + wantedBy = [ "multi-user.target" ]; + requires = [ "tor.service" ]; + after = [ "tor.service" ]; + preStart = '' + ln -snf ${configFile} ${cfg.dataDir}/joinmarket.cfg + ''; + serviceConfig = nix-bitcoin-services.defaultHardening // rec { + StateDirectory = "joinmarket-ob-watcher"; + StateDirectoryMode = "0770"; + WorkingDirectory = "${cfg.dataDir}"; # The service creates dir 'logs' in the working dir + ExecStart = '' + ${nbPkgs.joinmarket}/bin/ob-watcher --datadir=${cfg.dataDir} \ + --host=${cfg.address} --port=${toString cfg.port} + ''; + User = cfg.user; + Restart = "on-failure"; + RestartSec = "10s"; + } // nix-bitcoin-services.allowTor; + }; + + users.users.${cfg.user} = { + group = cfg.group; + home = cfg.dataDir; # The service writes to HOME/.config/matplotlib + }; + users.groups.${cfg.group} = {}; + }; +} diff --git a/modules/modules.nix b/modules/modules.nix index 4788da6..6ca7e18 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -18,6 +18,7 @@ with lib; ./electrs.nix ./liquid.nix ./joinmarket.nix + ./joinmarket-ob-watcher.nix ./hardware-wallets.nix ./recurring-donations.nix diff --git a/modules/netns-isolation.nix b/modules/netns-isolation.nix index 36e5300..e4f02f1 100644 --- a/modules/netns-isolation.nix +++ b/modules/netns-isolation.nix @@ -242,6 +242,9 @@ in { id = 25; connections = [ "bitcoind" ]; }; + joinmarket-ob-watcher = { + id = 26; + }; }; services.bitcoind = { @@ -285,6 +288,8 @@ in { services.joinmarket.cliExec = mkCliExec "joinmarket"; systemd.services.joinmarket-yieldgenerator.serviceConfig.NetworkNamespacePath = "/var/run/netns/nb-joinmarket"; + + services.joinmarket-ob-watcher.address = netns.joinmarket-ob-watcher.address; } ]); } diff --git a/modules/nodeinfo.nix b/modules/nodeinfo.nix index f848d4f..ab27bbd 100644 --- a/modules/nodeinfo.nix +++ b/modules/nodeinfo.nix @@ -19,6 +19,7 @@ let spark-wallet = mkInfo ""; btcpayserver = mkInfo ""; liquidd = mkInfo ""; + joinmarket-ob-watcher = mkInfo ""; # Only add sshd when it has an onion service sshd = name: cfg: mkIfOnionPort "sshd" (onionPort: '' add_service("sshd", """set_onion_address(info, "sshd", ${onionPort})""") diff --git a/modules/onion-services.nix b/modules/onion-services.nix index db0dac1..f73318f 100644 --- a/modules/onion-services.nix +++ b/modules/onion-services.nix @@ -115,6 +115,9 @@ in { btcpayserver = { externalPort = 80; }; + joinmarket-ob-watcher = { + externalPort = 80; + }; }; } ]; diff --git a/modules/presets/enable-tor.nix b/modules/presets/enable-tor.nix index 8d16a9e..7c5fda5 100644 --- a/modules/presets/enable-tor.nix +++ b/modules/presets/enable-tor.nix @@ -28,5 +28,6 @@ in { liquidd.enable = defaultTrue; electrs.enable = defaultTrue; spark-wallet.enable = defaultTrue; + joinmarket-ob-watcher.enable = defaultTrue; }; } diff --git a/pkgs/joinmarket/default.nix b/pkgs/joinmarket/default.nix index db52369..4649953 100644 --- a/pkgs/joinmarket/default.nix +++ b/pkgs/joinmarket/default.nix @@ -1,10 +1,10 @@ { stdenv, lib, fetchurl, python3, nbPython3Packages, pkgs }: let - version = "0.8.0-bcfa7eb"; + version = "0.8.0-a5e8879"; src = fetchurl { - url = "https://github.com/JoinMarket-Org/joinmarket-clientserver/archive/bcfa7eb4ea3ca51b7ecae9aebe65c634a4ab8b0e.tar.gz"; - sha256 = "05akzaxi2vqh3hln6qkr6frfas9xd0d95xa3wd56pj8bzknd410m"; + url = "https://github.com/JoinMarket-Org/joinmarket-clientserver/archive/a5e8879d119c8702476da32957d2cfecc3584c89.tar.gz"; + sha256 = "1l98mjk5rc5kji4yads6iicvyps0blsddwzclsiv0ha1az6dzpci"; }; runtimePackages = with nbPython3Packages; [ @@ -12,6 +12,7 @@ let joinmarketclient joinmarketbitcoin joinmarketdaemon + matplotlib # for ob-watcher ]; pythonEnv = python3.withPackages (_: runtimePackages); @@ -22,15 +23,16 @@ stdenv.mkDerivation { buildInputs = [ pythonEnv ]; - buildCommand = '' - mkdir -p $src-unpacked $out/bin - tar xzf $src --strip 1 -C $src-unpacked + installPhase = '' + mkdir -p $out/bin # add-utxo.py -> bin/jm-add-utxo cpBin() { - cp $src-unpacked/scripts/$1 $out/bin/jm-''${1%.py} + cp scripts/$1 $out/bin/jm-''${1%.py} } - cp $src-unpacked/scripts/joinmarketd.py $out/bin/joinmarketd + + cp scripts/joinmarketd.py $out/bin/joinmarketd + cp scripts/obwatch/ob-watcher.py $out/bin/ob-watcher cpBin add-utxo.py cpBin convert_old_wallet.py cpBin receive-payjoin.py @@ -43,5 +45,8 @@ stdenv.mkDerivation { chmod +x -R $out/bin patchShebangs $out/bin + + # This file must be placed in the same dir as ob-watcher + cp scripts/obwatch/orderbook.html $out/bin/orderbook.html ''; } diff --git a/pkgs/joinmarket/get-sha256.sh b/pkgs/joinmarket/get-sha256.sh index 012bcf5..79e5ca9 100755 --- a/pkgs/joinmarket/get-sha256.sh +++ b/pkgs/joinmarket/get-sha256.sh @@ -9,7 +9,7 @@ cd $TMPDIR echo "Fetching latest release" git clone https://github.com/joinmarket-org/joinmarket-clientserver 2> /dev/null cd joinmarket-clientserver -latest=bcfa7eb4ea3ca51b7ecae9aebe65c634a4ab8b0e +latest=a5e8879d119c8702476da32957d2cfecc3584c89 echo "Latest release is ${latest}" # GPG verification diff --git a/test/tests.nix b/test/tests.nix index 83e4629..95a6604 100644 --- a/test/tests.nix +++ b/test/tests.nix @@ -60,6 +60,7 @@ let testEnv = rec { tests.joinmarket = cfg.joinmarket.enable; tests.joinmarket-yieldgenerator = cfg.joinmarket.yieldgenerator.enable; + tests.joinmarket-ob-watcher = cfg.joinmarket-ob-watcher.enable; services.joinmarket.yieldgenerator = { enable = config.services.joinmarket.enable; customParameters = '' @@ -119,6 +120,7 @@ let testEnv = rec { services.liquidd.enable = true; services.btcpayserver.enable = true; services.joinmarket.enable = true; + services.joinmarket-ob-watcher.enable = true; services.backups.enable = true; nix-bitcoin.nodeinfo.enable = true; diff --git a/test/tests.py b/test/tests.py index 329dcc6..49f881b 100644 --- a/test/tests.py +++ b/test/tests.py @@ -216,6 +216,12 @@ def _(): ) +@test("joinmarket-ob-watcher") +def _(): + assert_running("joinmarket-ob-watcher") + machine.wait_until_succeeds(log_has_string("joinmarket-ob-watcher", "Starting ob-watcher")) + + @test("nodeinfo") def _(): status, _ = machine.execute("systemctl is-enabled --quiet onion-addresses 2> /dev/null")