mirror of
https://github.com/fort-nix/nix-bitcoin.git
synced 2024-08-17 10:50:23 +03:00
joinmarket-jam: init module
This commit is contained in:
parent
60119b1b74
commit
7551b6df82
@ -94,6 +94,7 @@ NixOS modules ([src](modules/modules.nix))
|
||||
* [liquid](https://github.com/elementsproject/elements): federated sidechain
|
||||
* [JoinMarket](https://github.com/joinmarket-org/joinmarket-clientserver)
|
||||
* [JoinMarket Orderbook Watcher](https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master/docs/orderbook.md)
|
||||
* [Jam](https://github.com/joinmarket-webui/jam): simplified user-friendly JoinMarket web interface
|
||||
* [bitcoin-core-hwi](https://github.com/bitcoin-core/HWI)
|
||||
* Helper
|
||||
* [netns-isolation](modules/netns-isolation.nix): isolates applications on the network-level via network namespaces
|
||||
|
@ -557,6 +557,16 @@ See [here](https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/master
|
||||
|
||||
3. Profit
|
||||
|
||||
## Run the Jam, the JoinMarket web interface
|
||||
|
||||
The [Jam](https://github.com/joinmarket-webui/jam) is a static web interface
|
||||
which is served by nginx. It connects to the jmwalled daemon which gets started
|
||||
in the background.
|
||||
|
||||
TODO
|
||||
- How to access the web interface using e.g. ssh proxy: `ssh -L 61851:localhost:61851 root@<nix-bitcoin-node-host>`
|
||||
- how to access interface over onion?
|
||||
|
||||
# clightning
|
||||
|
||||
## Plugins
|
||||
|
@ -249,6 +249,13 @@
|
||||
#
|
||||
# Set this to enable the JoinMarket order book watcher.
|
||||
# services.joinmarket-ob-watcher.enable = true;
|
||||
#
|
||||
# Set this to enable Jam, the JoinMarket web interface.
|
||||
# services.joinmarket-jam.enable = true;
|
||||
#
|
||||
# Set this to create an onion service to make the Jam web interface
|
||||
# available via Tor:
|
||||
# nix-bitcoin.onionServices.joinmarket-jam.enable = true;
|
||||
|
||||
### Nodeinfo
|
||||
# Set this to add command `nodeinfo` to the system environment.
|
||||
|
180
modules/joinmarket-jam.nix
Normal file
180
modules/joinmarket-jam.nix
Normal file
@ -0,0 +1,180 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
let
|
||||
options.services.joinmarket-jam = {
|
||||
enable = mkEnableOption "Enable the JoinMarket Jam web interface.";
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
description = mdDoc "HTTP server address.";
|
||||
};
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 61851;
|
||||
description = mdDoc "HTTP server port.";
|
||||
};
|
||||
staticContentRoot = mkOption {
|
||||
type = types.path;
|
||||
default = nbPkgs.joinmarket-jam;
|
||||
defaultText = "config.nix-bitcoin.pkgs.joinmarket-jam";
|
||||
description = mdDoc "Path of the static content root.";
|
||||
};
|
||||
nginxConfig = mkOption {
|
||||
readOnly = true;
|
||||
default = nginxConfig;
|
||||
defaultText = "(See source)";
|
||||
description = mdDoc ''
|
||||
An attrset of nginx config snippets for assembling a custom
|
||||
joinmarket's jam nginx config.
|
||||
'';
|
||||
};
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = nbPkgs.joinmarket-jam;
|
||||
defaultText = "config.nix-bitcoin.pkgs.joinmarket-jam";
|
||||
description = mdDoc "The package providing joinmarket's jam files.";
|
||||
};
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "joinmarket-jam";
|
||||
description = mdDoc "The user as which to run Jam.";
|
||||
};
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = cfg.user;
|
||||
description = mdDoc "The group as which to run Jam.";
|
||||
};
|
||||
tor.enforce = nbLib.tor.enforce;
|
||||
|
||||
#settings = mkOption {
|
||||
#};
|
||||
};
|
||||
|
||||
cfg = config.services.joinmarket-jam;
|
||||
nbLib = config.nix-bitcoin.lib;
|
||||
nbPkgs = config.nix-bitcoin.pkgs;
|
||||
|
||||
inherit (config.services) joinmarket-ob-watcher joinmarket-jmwalletd;
|
||||
|
||||
# Nginx configuration is highgly inspired by official jam-docker ui-only container.
|
||||
# https://github.com/joinmarket-webui/jam-docker/tree/master/ui-only/nginx
|
||||
nginxConfig = {
|
||||
staticContent = ''
|
||||
index index.html;
|
||||
|
||||
add_header Cache-Control "public, no-transform";
|
||||
add_header Vary Accept-Language;
|
||||
add_header Vary Cookie;
|
||||
'';
|
||||
|
||||
proxyApi = let
|
||||
jmwalletd_api_backend = "https://${nbLib.addressWithPort joinmarket-jmwalletd.address joinmarket-jmwalletd.port}";
|
||||
jmwalletd_wss_backend = "https://${nbLib.addressWithPort joinmarket-jmwalletd.address joinmarket-jmwalletd.wssPort}/";
|
||||
ob_watcher_backend = "http://${nbLib.addressWithPort joinmarket-ob-watcher.address joinmarket-ob-watcher.port}";
|
||||
in ''
|
||||
location / {
|
||||
#include /etc/nginx/snippets/proxy-params.conf;
|
||||
|
||||
try_files $uri $uri/ /index.html;
|
||||
add_header Cache-Control no-cache;
|
||||
}
|
||||
location /api/ {
|
||||
proxy_pass ${jmwalletd_api_backend};
|
||||
|
||||
#include /etc/nginx/snippets/proxy-params.conf;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
proxy_set_header Authorization $http_x_jm_authorization;
|
||||
proxy_set_header x-jm-authorization "";
|
||||
proxy_read_timeout 300s;
|
||||
proxy_connect_timeout 300s;
|
||||
}
|
||||
location = /jmws {
|
||||
proxy_pass ${jmwalletd_wss_backend};
|
||||
|
||||
#include /etc/nginx/snippets/proxy-params.conf;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Authorization "";
|
||||
|
||||
# allow 10m without socket activity (default is 60 sec)
|
||||
proxy_read_timeout 600s;
|
||||
proxy_send_timeout 600s;
|
||||
}
|
||||
location /obwatch/ {
|
||||
proxy_pass ${ob_watcher_backend};
|
||||
|
||||
#include /etc/nginx/snippets/proxy-params.conf;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
proxy_read_timeout 300s;
|
||||
proxy_connect_timeout 300s;
|
||||
}
|
||||
location = /jam/internal/auth {
|
||||
internal;
|
||||
proxy_pass http://$server_addr:$server_port/api/v1/session;
|
||||
|
||||
#if ($jm_auth_present != 1) {
|
||||
# return 401;
|
||||
#}
|
||||
|
||||
#include /etc/nginx/snippets/proxy-params.conf;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
proxy_pass_request_body off;
|
||||
proxy_set_header Content-Length "";
|
||||
}
|
||||
location = /jam/api/v0/features {
|
||||
auth_request /jam/internal/auth;
|
||||
default_type application/json;
|
||||
return 200 '{ "features": { "logs": false } }';
|
||||
}
|
||||
location /jam/api/v0/log/ {
|
||||
auth_request /jam/internal/auth;
|
||||
return 501; # Not Implemented
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
in {
|
||||
inherit options;
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services = {
|
||||
joinmarket-ob-watcher.enable = true;
|
||||
joinmarket-jmwalletd.enable = true;
|
||||
|
||||
nginx = {
|
||||
enable = true;
|
||||
enableReload = true;
|
||||
recommendedBrotliSettings = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
# TODO: Use this to define "map"? See: https://github.com/joinmarket-webui/jam-docker/blob/master/ui-only/nginx/templates/default.conf.template#L20
|
||||
#commonHttpConfig = nginxConfig.httpConfig;
|
||||
virtualHosts."joinmarket-jam" = {
|
||||
serverName = "_";
|
||||
listen = [ { addr = cfg.address; port = cfg.port; } ];
|
||||
root = cfg.staticContentRoot;
|
||||
extraConfig = nginxConfig.staticContent + nginxConfig.proxyApi;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
users = {
|
||||
users.${cfg.user} = {
|
||||
isSystemUser = true;
|
||||
group = cfg.group;
|
||||
};
|
||||
groups.${cfg.group} = {};
|
||||
};
|
||||
};
|
||||
}
|
@ -40,6 +40,24 @@ let
|
||||
default = "/var/lib/joinmarket";
|
||||
description = mdDoc "The data directory for JoinMarket.";
|
||||
};
|
||||
max_cj_fee_abs = mkOption {
|
||||
type = types.ints.unsigned;
|
||||
default = 30000; # in sats
|
||||
description = mdDoc ''
|
||||
Maximum absolute coinjoin fee in satoshi to pay to a single market
|
||||
maker for a transaction.
|
||||
'';
|
||||
};
|
||||
max_cj_fee_rel = mkOption {
|
||||
type = types.float;
|
||||
default = 0.0003; # 0.03 %
|
||||
description = mdDoc ''
|
||||
Maximum relative coinjoin fee, in fractions of the coinjoin value e.g.
|
||||
if your coinjoin amount is 2 btc (200 million satoshi) and
|
||||
max_cj_fee_rel = 0.001 (0.1%), the maximum fee allowed would be 0.002
|
||||
btc (200 thousand satoshi).
|
||||
'';
|
||||
};
|
||||
rpcWalletFile = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = "jm_wallet";
|
||||
@ -217,6 +235,8 @@ let
|
||||
tx_fees_factor = 0.2
|
||||
absurd_fee_per_kb = 350000
|
||||
max_sweep_fee_change = 0.8
|
||||
max_cj_fee_abs = ${toString cfg.max_cj_fee_abs}
|
||||
max_cj_fee_rel = ${toString cfg.max_cj_fee_rel}
|
||||
tx_broadcast = self
|
||||
minimum_makers = 4
|
||||
max_sats_freeze_reuse = -1
|
||||
|
@ -28,6 +28,7 @@
|
||||
./joinmarket.nix
|
||||
./joinmarket-ob-watcher.nix
|
||||
./joinmarket-jmwalletd.nix
|
||||
./joinmarket-jam.nix
|
||||
./hardware-wallets.nix
|
||||
|
||||
# Support features
|
||||
|
@ -356,6 +356,7 @@ in {
|
||||
};
|
||||
|
||||
services.joinmarket-ob-watcher.address = netns.joinmarket-ob-watcher.address;
|
||||
services.joinmarket-jam.address = netns.nginx.address;
|
||||
|
||||
services.lightning-pool.rpcAddress = netns.lightning-pool.address;
|
||||
|
||||
|
@ -149,6 +149,11 @@ in {
|
||||
liquidd = mkInfo "";
|
||||
joinmarket-ob-watcher = mkInfo "";
|
||||
joinmarket-jmwalletd = mkInfo "";
|
||||
joinmarket-jam = name: cfg: mkInfoLong {
|
||||
inherit name cfg;
|
||||
systemdServiceName = "nginx";
|
||||
extraCode = "";
|
||||
};
|
||||
rtl = mkInfo "";
|
||||
mempool = mkInfo "";
|
||||
mempool-frontend = name: cfg: mkInfoLong {
|
||||
|
@ -110,6 +110,9 @@ in {
|
||||
joinmarket-ob-watcher = {
|
||||
externalPort = 80;
|
||||
};
|
||||
joinmarket-jam = {
|
||||
externalPort = 80;
|
||||
};
|
||||
rtl = {
|
||||
externalPort = 80;
|
||||
};
|
||||
|
@ -133,6 +133,7 @@ let
|
||||
cjfee_r = 0.00003;
|
||||
txfee = 200;
|
||||
};
|
||||
tests.joinmarket-jam = cfg.joinmarket-jam.enable;
|
||||
|
||||
tests.nodeinfo = config.nix-bitcoin.nodeinfo.enable;
|
||||
tests.backups = cfg.backups.enable;
|
||||
@ -207,6 +208,7 @@ let
|
||||
services.joinmarket.enable = true;
|
||||
services.joinmarket-ob-watcher.enable = true;
|
||||
services.joinmarket-jmwalletd.enable = true;
|
||||
services.joinmarket-jam.enable = true;
|
||||
services.backups.enable = true;
|
||||
|
||||
nix-bitcoin.nodeinfo.enable = true;
|
||||
@ -255,6 +257,7 @@ let
|
||||
services.btcpayserver.enable = true;
|
||||
services.joinmarket.enable = true;
|
||||
services.joinmarket-jmwalletd.enable = true;
|
||||
services.joinmarket-jam.enable = true;
|
||||
};
|
||||
|
||||
# netns and regtest, without secure-node.nix
|
||||
|
@ -292,6 +292,12 @@ def _():
|
||||
# Test web server response
|
||||
assert_full_match(f"curl -fsSL --insecure https://{ip('joinmarket')}:28183/api/v1/getinfo | jq -jr keys[0]", "version")
|
||||
|
||||
@test("joinmarket-jam")
|
||||
def _():
|
||||
assert_running("nginx")
|
||||
wait_for_open_port(ip("nginx"), 61851)
|
||||
assert_matches(f"curl -L {ip('nginx')}:61851", "Jam for JoinMarket")
|
||||
|
||||
@test("nodeinfo")
|
||||
def _():
|
||||
status, _ = machine.execute("systemctl is-enabled --quiet onion-addresses 2> /dev/null")
|
||||
|
Loading…
Reference in New Issue
Block a user