Merge #153: Improve bitcoind
4dc6c3ba5dadd option 'dataDirReadableByGroup' (Erik Arvstedt)3e188238d0only update bitcoin.conf when changed (Erik Arvstedt)08322eed9buse [[ test (Erik Arvstedt)201fc33782move line to relevant code section (blocks dir setup) (Erik Arvstedt)1f8fe310d0remove option 'configFileOption' (Erik Arvstedt)4e5c1d7551disable redundant logfile (Erik Arvstedt)a05551fd1cimprove config file formatting (Erik Arvstedt)5e81d60d63improve formatting (Erik Arvstedt)d60a5aa4dbdefine rpc.users submodule inline (Erik Arvstedt)1a2271fb14remove unused variable 'hexStr' (Erik Arvstedt)4e92b1c818remove redundant hardening options (Erik Arvstedt)47fd6cd0f3simplify ExecStart (Erik Arvstedt)64fc63cc40remove pidFile (Erik Arvstedt) Pull request description: ACKs for top commit: nixbitcoin: ACK4dc6c3ba5djonasnick: ACK4dc6c3ba5dTree-SHA512: 370dcabe89cc99480a3f272a5819607bce5e454b3000a95ff5b4a3b04819d0d8341385c2bbf0de361f061a43460bf87be10d2321a0525f19e121b28ede8f722e
This commit is contained in:
commit
e97b132a37
3 changed files with 63 additions and 64 deletions
|
|
@ -5,8 +5,11 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.services.bitcoind;
|
cfg = config.services.bitcoind;
|
||||||
inherit (config) nix-bitcoin-services;
|
inherit (config) nix-bitcoin-services;
|
||||||
pidFile = "${cfg.dataDir}/bitcoind.pid";
|
|
||||||
configFile = pkgs.writeText "bitcoin.conf" ''
|
configFile = pkgs.writeText "bitcoin.conf" ''
|
||||||
|
# We're already logging via journald
|
||||||
|
nodebuglogfile=1
|
||||||
|
|
||||||
${optionalString cfg.testnet "testnet=1"}
|
${optionalString cfg.testnet "testnet=1"}
|
||||||
${optionalString (cfg.dbCache != null) "dbcache=${toString cfg.dbCache}"}
|
${optionalString (cfg.dbCache != null) "dbcache=${toString cfg.dbCache}"}
|
||||||
${optionalString (cfg.prune != null) "prune=${toString cfg.prune}"}
|
${optionalString (cfg.prune != null) "prune=${toString cfg.prune}"}
|
||||||
|
|
@ -14,7 +17,6 @@ let
|
||||||
${optionalString (cfg.disablewallet != null) "disablewallet=${if cfg.disablewallet then "1" else "0"}"}
|
${optionalString (cfg.disablewallet != null) "disablewallet=${if cfg.disablewallet then "1" else "0"}"}
|
||||||
${optionalString (cfg.assumevalid != null) "assumevalid=${cfg.assumevalid}"}
|
${optionalString (cfg.assumevalid != null) "assumevalid=${cfg.assumevalid}"}
|
||||||
|
|
||||||
|
|
||||||
# Connection options
|
# Connection options
|
||||||
${optionalString (cfg.port != null) "port=${toString cfg.port}"}
|
${optionalString (cfg.port != null) "port=${toString cfg.port}"}
|
||||||
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
|
${optionalString (cfg.proxy != null) "proxy=${cfg.proxy}"}
|
||||||
|
|
@ -22,7 +24,6 @@ let
|
||||||
${optionalString (cfg.discover != null) "discover=${if cfg.discover then "1" else "0"}"}
|
${optionalString (cfg.discover != null) "discover=${if cfg.discover then "1" else "0"}"}
|
||||||
${lib.concatMapStrings (node: "addnode=${node}\n") cfg.addnodes}
|
${lib.concatMapStrings (node: "addnode=${node}\n") cfg.addnodes}
|
||||||
|
|
||||||
|
|
||||||
# RPC server options
|
# RPC server options
|
||||||
rpcport=${toString cfg.rpc.port}
|
rpcport=${toString cfg.rpc.port}
|
||||||
${concatMapStringsSep "\n"
|
${concatMapStringsSep "\n"
|
||||||
|
|
@ -39,42 +40,13 @@ let
|
||||||
${optionalString (cfg.zmqpubrawblock != null) "zmqpubrawblock=${cfg.zmqpubrawblock}"}
|
${optionalString (cfg.zmqpubrawblock != null) "zmqpubrawblock=${cfg.zmqpubrawblock}"}
|
||||||
${optionalString (cfg.zmqpubrawtx != null) "zmqpubrawtx=${cfg.zmqpubrawtx}"}
|
${optionalString (cfg.zmqpubrawtx != null) "zmqpubrawtx=${cfg.zmqpubrawtx}"}
|
||||||
|
|
||||||
# Extra config options (from bitcoind nixos service)
|
# Extra options
|
||||||
${cfg.extraConfig}
|
${cfg.extraConfig}
|
||||||
'';
|
'';
|
||||||
cmdlineOptions = concatMapStringsSep " " (arg: "'${arg}'") [
|
|
||||||
"-datadir=${cfg.dataDir}"
|
|
||||||
"-pid=${pidFile}"
|
|
||||||
];
|
|
||||||
hexStr = types.strMatching "[0-9a-f]+";
|
|
||||||
rpcUserOpts = { name, ... }: {
|
|
||||||
options = {
|
|
||||||
name = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
example = "alice";
|
|
||||||
description = ''
|
|
||||||
Username for JSON-RPC connections.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
passwordHMAC = mkOption {
|
|
||||||
type = with types; uniq (strMatching "[0-9a-f]+\\$[0-9a-f]{64}");
|
|
||||||
example = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae";
|
|
||||||
description = ''
|
|
||||||
Password HMAC-SHA-256 for JSON-RPC connections. Must be a string of the
|
|
||||||
format <SALT-HEX>$<HMAC-HEX>.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
config = {
|
|
||||||
name = mkDefault name;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in {
|
in {
|
||||||
options = {
|
options = {
|
||||||
|
|
||||||
services.bitcoind = {
|
services.bitcoind = {
|
||||||
enable = mkEnableOption "Bitcoin daemon";
|
enable = mkEnableOption "Bitcoin daemon";
|
||||||
|
|
||||||
package = mkOption {
|
package = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = pkgs.nix-bitcoin.bitcoind;
|
default = pkgs.nix-bitcoin.bitcoind;
|
||||||
|
|
@ -88,7 +60,6 @@ in {
|
||||||
par=16
|
par=16
|
||||||
rpcthreads=16
|
rpcthreads=16
|
||||||
logips=1
|
logips=1
|
||||||
|
|
||||||
'';
|
'';
|
||||||
description = "Additional configurations to be appended to <filename>bitcoin.conf</filename>.";
|
description = "Additional configurations to be appended to <filename>bitcoin.conf</filename>.";
|
||||||
};
|
};
|
||||||
|
|
@ -97,12 +68,6 @@ in {
|
||||||
default = "/var/lib/bitcoind";
|
default = "/var/lib/bitcoind";
|
||||||
description = "The data directory for bitcoind.";
|
description = "The data directory for bitcoind.";
|
||||||
};
|
};
|
||||||
configFileOption = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
default = configFile;
|
|
||||||
description = "The data directory for bitcoind.";
|
|
||||||
};
|
|
||||||
|
|
||||||
user = mkOption {
|
user = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "bitcoin";
|
default = "bitcoin";
|
||||||
|
|
@ -113,7 +78,6 @@ in {
|
||||||
default = cfg.user;
|
default = cfg.user;
|
||||||
description = "The group as which to run bitcoind.";
|
description = "The group as which to run bitcoind.";
|
||||||
};
|
};
|
||||||
|
|
||||||
rpc = {
|
rpc = {
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
type = types.ints.u16;
|
type = types.ints.u16;
|
||||||
|
|
@ -126,13 +90,33 @@ in {
|
||||||
alice.passwordHMAC = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae";
|
alice.passwordHMAC = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae";
|
||||||
bob.passwordHMAC = "b2dd077cb54591a2f3139e69a897ac$4e71f08d48b4347cf8eff3815c0e25ae2e9a4340474079f55705f40574f4ec99";
|
bob.passwordHMAC = "b2dd077cb54591a2f3139e69a897ac$4e71f08d48b4347cf8eff3815c0e25ae2e9a4340474079f55705f40574f4ec99";
|
||||||
};
|
};
|
||||||
type = with types; loaOf (submodule rpcUserOpts);
|
type = with types; loaOf (submodule ({ name, ... }: {
|
||||||
|
options = {
|
||||||
|
name = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "alice";
|
||||||
|
description = ''
|
||||||
|
Username for JSON-RPC connections.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
passwordHMAC = mkOption {
|
||||||
|
type = with types; uniq (strMatching "[0-9a-f]+\\$[0-9a-f]{64}");
|
||||||
|
example = "f7efda5c189b999524f151318c0c86$d5b51b3beffbc02b724e5d095828e0bc8b2456e9ac8757ae3211a5d9b16a22ae";
|
||||||
|
description = ''
|
||||||
|
Password HMAC-SHA-256 for JSON-RPC connections. Must be a string of the
|
||||||
|
format <SALT-HEX>$<HMAC-HEX>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = {
|
||||||
|
name = mkDefault name;
|
||||||
|
};
|
||||||
|
}));
|
||||||
description = ''
|
description = ''
|
||||||
RPC user information for JSON-RPC connnections.
|
RPC user information for JSON-RPC connnections.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
rpcuser = mkOption {
|
rpcuser = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = "bitcoinrpc";
|
default = "bitcoinrpc";
|
||||||
|
|
@ -143,7 +127,6 @@ in {
|
||||||
default = null;
|
default = null;
|
||||||
description = "Password for JSON-RPC connections";
|
description = "Password for JSON-RPC connections";
|
||||||
};
|
};
|
||||||
|
|
||||||
testnet = mkOption {
|
testnet = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
|
|
@ -166,18 +149,27 @@ in {
|
||||||
If enabled, the bitcoin service will listen.
|
If enabled, the bitcoin service will listen.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
dataDirReadableByGroup = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
If enabled, data dir content is readable by the bitcoind service group.
|
||||||
|
Warning: This disables bitcoind's wallet support.
|
||||||
|
'';
|
||||||
|
};
|
||||||
sysperms = mkOption {
|
sysperms = mkOption {
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)
|
Create new files with system default permissions, instead of umask 077
|
||||||
|
(only effective with disabled wallet functionality)
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
disablewallet = mkOption {
|
disablewallet = mkOption {
|
||||||
type = types.nullOr types.bool;
|
type = types.nullOr types.bool;
|
||||||
default = null;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
Do not load the wallet and disable wallet RPC calls
|
Do not load the wallet and disable wallet RPC calls
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
dbCache = mkOption {
|
dbCache = mkOption {
|
||||||
|
|
@ -257,23 +249,32 @@ in {
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
environment.systemPackages = [ cfg.package (hiPrio cfg.cli) ];
|
environment.systemPackages = [ cfg.package (hiPrio cfg.cli) ];
|
||||||
|
|
||||||
|
services.bitcoind = mkIf cfg.dataDirReadableByGroup {
|
||||||
|
disablewallet = true;
|
||||||
|
sysperms = true;
|
||||||
|
};
|
||||||
|
|
||||||
systemd.services.bitcoind = {
|
systemd.services.bitcoind = {
|
||||||
description = "Bitcoin daemon";
|
description = "Bitcoin daemon";
|
||||||
requires = [ "nix-bitcoin-secrets.target" ];
|
requires = [ "nix-bitcoin-secrets.target" ];
|
||||||
after = [ "network.target" "nix-bitcoin-secrets.target" ];
|
after = [ "network.target" "nix-bitcoin-secrets.target" ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
preStart = ''
|
preStart = ''
|
||||||
if ! test -e ${cfg.dataDir}; then
|
if [[ ! -e ${cfg.dataDir} ]]; then
|
||||||
mkdir -m 0770 -p '${cfg.dataDir}'
|
mkdir -m 0770 -p '${cfg.dataDir}'
|
||||||
fi
|
fi
|
||||||
if ! test -e ${cfg.dataDir}/blocks; then
|
if [[ ! -e ${cfg.dataDir}/blocks ]]; then
|
||||||
mkdir -m 0770 -p '${cfg.dataDir}/blocks'
|
mkdir -m 0770 -p '${cfg.dataDir}/blocks'
|
||||||
fi
|
fi
|
||||||
cp '${cfg.configFileOption}' '${cfg.dataDir}/bitcoin.conf'
|
|
||||||
chmod o-rw '${cfg.dataDir}/bitcoin.conf'
|
|
||||||
chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}'
|
chown -R '${cfg.user}:${cfg.group}' '${cfg.dataDir}'
|
||||||
echo "rpcpassword=$(cat ${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword)" >> '${cfg.dataDir}/bitcoin.conf'
|
|
||||||
chmod -R g+rX '${cfg.dataDir}/blocks'
|
chmod -R g+rX '${cfg.dataDir}/blocks'
|
||||||
|
|
||||||
|
cfg=$(cat ${configFile}; printf "rpcpassword="; cat "${config.nix-bitcoin.secretsDir}/bitcoin-rpcpassword")
|
||||||
|
confFile='${cfg.dataDir}/bitcoin.conf'
|
||||||
|
if [[ ! -e $confFile || $cfg != $(cat $confFile) ]]; then
|
||||||
|
install -o '${cfg.user}' -g '${cfg.group}' -m 640 <(echo "$cfg") $confFile
|
||||||
|
fi
|
||||||
'';
|
'';
|
||||||
# Wait until RPC port is open. This usually takes just a few ms.
|
# Wait until RPC port is open. This usually takes just a few ms.
|
||||||
postStart = ''
|
postStart = ''
|
||||||
|
|
@ -282,19 +283,11 @@ in {
|
||||||
done
|
done
|
||||||
'';
|
'';
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "simple";
|
|
||||||
User = "${cfg.user}";
|
User = "${cfg.user}";
|
||||||
Group = "${cfg.group}";
|
Group = "${cfg.group}";
|
||||||
ExecStart = "${cfg.package}/bin/bitcoind ${cmdlineOptions}";
|
ExecStart = "${cfg.package}/bin/bitcoind -datadir='${cfg.dataDir}'";
|
||||||
PIDFile = "${pidFile}";
|
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
|
UMask = mkIf cfg.dataDirReadableByGroup "0027";
|
||||||
# Hardening measures
|
|
||||||
PrivateTmp = "true";
|
|
||||||
ProtectSystem = "full";
|
|
||||||
NoNewPrivileges = "true";
|
|
||||||
PrivateDevices = "true";
|
|
||||||
MemoryDenyWriteExecute = "true";
|
|
||||||
|
|
||||||
# Permission for preStart
|
# Permission for preStart
|
||||||
PermissionsStartOnly = "true";
|
PermissionsStartOnly = "true";
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,14 @@ in {
|
||||||
PermissionsStartOnly = "true";
|
PermissionsStartOnly = "true";
|
||||||
ExecStart = ''
|
ExecStart = ''
|
||||||
${pkgs.nix-bitcoin.electrs}/bin/electrs -vvv \
|
${pkgs.nix-bitcoin.electrs}/bin/electrs -vvv \
|
||||||
${optionalString (!cfg.high-memory) "--jsonrpc-import --index-batch-size=10"} \
|
${if cfg.high-memory then
|
||||||
|
traceIf (!config.services.bitcoind.dataDirReadableByGroup) ''
|
||||||
|
Warning: For optimal electrs syncing performance, enable services.bitcoind.dataDirReadableByGroup.
|
||||||
|
Note that this disables wallet support in bitcoind.
|
||||||
|
'' ""
|
||||||
|
else
|
||||||
|
"--jsonrpc-import --index-batch-size=10"
|
||||||
|
} \
|
||||||
--db-dir '${cfg.dataDir}' --daemon-dir '${config.services.bitcoind.dataDir}' \
|
--db-dir '${cfg.dataDir}' --daemon-dir '${config.services.bitcoind.dataDir}' \
|
||||||
--electrum-rpc-addr=${toString cfg.address}:${toString cfg.port} ${cfg.extraArgs}
|
--electrum-rpc-addr=${toString cfg.address}:${toString cfg.port} ${cfg.extraArgs}
|
||||||
'';
|
'';
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,7 @@ in {
|
||||||
services.bitcoind = {
|
services.bitcoind = {
|
||||||
enable = true;
|
enable = true;
|
||||||
listen = true;
|
listen = true;
|
||||||
sysperms = if cfg.electrs.enable then true else null;
|
dataDirReadableByGroup = mkIf cfg.electrs.enable true;
|
||||||
disablewallet = if cfg.electrs.enable then true else null;
|
|
||||||
proxy = cfg.tor.client.socksListenAddress;
|
proxy = cfg.tor.client.socksListenAddress;
|
||||||
enforceTor = true;
|
enforceTor = true;
|
||||||
port = 8333;
|
port = 8333;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue