anchor.diff:                bob.passwordHMAC = "b2dd077cb54591a2f3139e69a897ac$4e71f08d48b4347cf8eff3815c0e25ae2e9a4340474079f55705f40574f4ec99";
               }
             '';
  -          type = with types; loaOf (submodule rpcUserOpts);
  +          type = with types; attrsOf (submodule rpcUserOpts);
             description = ''
               RPC user information for JSON-RPC connnections.
             '';
           };
         };
   
  +      pidFile = mkOption {
  +        type = types.path;
  +        default = "${config.dataDir}/bitcoind.pid";
  +        description = "Location of bitcoind pid file.";
  +      };
  +
         testnet = mkOption {
           type = types.bool;
           default = false;
  -        description = "Whether to use the test chain.";
  -      };
  +        description = "Whether to use the testnet instead of mainnet.";
  +      };
  +
         port = mkOption {
           type = types.nullOr types.port;
           default = null;
           description = "Override the default port on which to listen for connections.";
         };
  +
         dbCache = mkOption {
           type = types.nullOr (types.ints.between 4 16384);
           default = null;
           example = 4000;
  -        description = "Override the default database cache size in megabytes.";
  -      };
  +        description = "Override the default database cache size in MiB.";
  +      };
  +
         prune = mkOption {
           type = types.nullOr (types.coercedTo
             (types.enum [ "disable" "manual" ])
  
positive.code:         '';
          description = "Additional configurations to be appended to <filename>bitcoin.conf</filename>.";
        };
        dataDir = mkOption {
          type = types.path;
          default = "/var/lib/bitcoind";
          description = "The data directory for bitcoind.";
        };
  
        user = mkOption {
          type = types.str;
          default = "bitcoin";
          description = "The user as which to run bitcoind.";
        };
        group = mkOption {
          type = types.str;
          default = cfg.user;
          description = "The group as which to run bitcoind.";
        };
  
  
negative.code:           and -rescan. Warning: Reverting this setting requires re-downloading
            the entire blockchain. ("disable" = disable pruning blocks, "manual"
            = allow manual pruning via RPC, >=550 = automatically prune block files
            to stay under the specified target size in MiB).
          '';
        };
  
        extraCmdlineOptions = mkOption {
          type = types.listOf types.str;
          default = [];
          description = ''
            Extra command line options to pass to bitcoind.
            Run bitcoind --help to list all available options.
          '';
        };
      };
    };
  in
  {
  
    options = {
      services.bitcoind = mkOption {
        type = types.attrsOf (types.submodule bitcoindOpts);
        default = {};
        description = "Specification of one or more bitcoind instances.";
      };
    };
  
    config = mkIf (eachBitcoind != {}) {
  
      assertions = flatten (mapAttrsToList (bitcoindName: cfg: [
      {
        assertion = (cfg.prune != null) -> (cfg.prune == "disable" || cfg.prune == "manual") || (cfg.prune == 0 || cfg.prune == 1) || (cfg.prune >= 550);
        message = ''
          If set, services.bitcoind.${bitcoindName}.prune has to be "disable", "manual", 0 , 1 or >= 550
        '';
      }
      {
        assertion = (cfg.rpc.users != {}) -> (cfg.configFile == null);
        message = ''
          You cannot set both services.bitcoind.${bitcoindName}.rpc.users and services.bitcoind.${bitcoindName}.configFile
          as they are exclusive. RPC user setting would have no effect if custom configFile would be used.
        '';
      }
      ]) eachBitcoind);
  
      environment.systemPackages = flatten (mapAttrsToList (bitcoindName: cfg: [ 
        cfg.package 
      ]) eachBitcoind);
  
      systemd.services = mapAttrs' (bitcoindName: cfg: (
        nameValuePair "bitcoind-${bitcoindName}" (
        let
          configFile = pkgs.writeText "bitcoin.conf" ''
            # If Testnet is enabled, we need to add [test] section
            # otherwise, some options (e.g.: custom RPC port) will not work
            ${optionalString cfg.testnet "[test]"}
            # RPC users
            ${concatMapStringsSep  "\n"
              (rpcUser: "rpcauth=${rpcUser.name}:${rpcUser.passwordHMAC}")
              (attrValues cfg.rpc.users)
            }
            # Extra config options (from bitcoind nixos service)
            ${cfg.extraConfig}
          '';
        in {
          description = "Bitcoin daemon";
          after = [ "network.target" ];
          wantedBy = [ "multi-user.target" ];
          serviceConfig = {
            User = cfg.user;
            Group = cfg.group;
            ExecStart = ''
              ${cfg.package}/bin/bitcoind \
              ${if (cfg.configFile != null) then
                "-conf=${cfg.configFile}"
              else
                "-conf=${configFile}"
              } \
              -datadir=${cfg.dataDir} \
              -pid=${cfg.pidFile} \
              ${optionalString cfg.testnet "-testnet"}\
              ${optionalString (cfg.port != null) "-port=${toString cfg.port}"}\
              ${optionalString (cfg.prune != null) "-prune=${toString cfg.prune}"}\
              ${optionalString (cfg.dbCache != null) "-dbcache=${toString cfg.dbCache}"}\
              ${optionalString (cfg.rpc.port != null) "-rpcport=${toString cfg.rpc.port}"}\
              ${toString cfg.extraCmdlineOptions}
            '';
            Restart = "on-failure";
  
            # Hardening measures
            PrivateTmp = "true";
            ProtectSystem = "full";
            NoNewPrivileges = "true";
            PrivateDevices = "true";
            MemoryDenyWriteExecute = "true";
          };
        }
      ))) eachBitcoind;
  
      systemd.tmpfiles.rules = flatten (mapAttrsToList (bitcoindName: cfg: [
        "d '${cfg.dataDir}' 0770 '${cfg.user}' '${cfg.group}' - -"
      ]) eachBitcoind);
  
      users.users = mapAttrs' (bitcoindName: cfg: (
        nameValuePair "bitcoind-${bitcoindName}" {
        name = cfg.user;
        group = cfg.group;
        description = "Bitcoin daemon user";
        home = cfg.dataDir;
        isSystemUser = true;
      })) eachBitcoind;
  
      users.groups = mapAttrs' (bitcoindName: cfg: (
        nameValuePair "${cfg.group}" { }
      )) eachBitcoind;
  
    };
  
  }
  