feat: add dashd Dash Full Node service

This commit is contained in:
AJ ONeal
2023-06-21 21:55:18 +00:00
parent 731d3c95c1
commit ce2f07ef26
8 changed files with 626 additions and 0 deletions
+223
View File
@@ -0,0 +1,223 @@
---
title: Dash Core Full Node Daemon
homepage: https://github.com/dashpay/dash
tagline: |
dashd is the Full Node service for Digital Cash (DASH)
---
To update or switch versions, run `webi dashd@stable` (or `@v0.19`, `@beta`,
etc).
### Recommended Hardware
- 100GB Block Storage
- 8GB RAM
- 4 vCPUs
- 4 hours for initial sync
### Files
These are the files / directories that are created and/or modified with this
install:
```txt
~/.config/envman/PATH.env
~/.dashcore/dash.conf
~/.dashcore/wallets/
~/.local/bin/bin/dashd-hd-service-install
~/.local/opt/dashcore/
/mnt/<BLK_VOL>/dashcore/
```
## Cheat Sheet
> A DASH _Full Node_ syncs and indexes the DASH blockchain and can be used to
> broadcast transactions (sending money) and retrieve information about
> transactions, balances, etc. This "Dash Core" implementation is maintained by
> DCG.
To install as **a system service** with reasonable defaults, \
you can use these convenience scripts provided by Webi:
```sh
# USAGE
# dashd-hd-service-install [storage-volume] [testnet]
#
# EXAMPLE
dashd-hd-service-install
```
After it completes the initial sync (about 4 hours), \
you can query address information:
```sh
# Balances
dash-cli getaddressbalance '{"addresses": ["XchrTJFPGFiror4zjXQRR7XTSN25YtLYhC"]}'
# UTXOs
dash-cli getaddressutxos '{"addresses": ["XpLVjhDd6vNJamtcJXcrpQYA1sE6fmxVDa"]}'
# TXes
dash-cli getaddresstxids '{
"addresses": ["XchrTJFPGFiror4zjXQRR7XTSN25YtLYhC"],
"start":5000,
"end":7500
}'
# Broadcast TX
dash-cli -testnet sendrawtransaction 01000000...0c0226b428a488ac00000000
```
To run **in the foreground**: \
(add `-testnet` to run on testnet)
```sh
dashd \
-usehd \
-conf="$HOME/.dashcore/dash.conf" \
-settings="$HOME/.dashcore/settings.json" \
-walletdir="$HOME/.dashcore/wallets/" \
-datadir="/mnt/100gb/dashcore/_data/"
-blocksdir="/mnt/100gb/dashcore/_caches/"
```
**Warning**: killing the process with ctrl+c before the first full sync may
corrupt the data and require starting over (see below)
### Server Requirements
150MB for Applications on OS Storage
For **mainnet**:
- 100GB Block Storage Volume \
(min 40GB as of 2022, plus 4GB/year)
- 8GB RAM \
(min 4GB RAM + 4GB swap, otherwise it crashes during indexing)
- 4 vCPUs \
(min 2x 2.0GHz vCPUs)
- 100 megabit network
- 4 hours to sync and index in ideal conditions
For **testnet**:
- 10GB Block Storage Volume \
(min 4GB as of 2022, plus 400MB/year)
- 2GB RAM
- 1 vCPU
- 1 hour to sync and index in ideal conditions
### How to Separate Caches from Data
You can make your data much safer by separating it from the caches you may need
to delete by setting:
- `-walletdir=` your money!!
- `-settings=` desktop app settings!
- `-conf=` server settings
- `-datadir=` generic caches
```sh
dashd \
-usehd \
-conf="$HOME/.config/dashcore/dash.conf" \
-walletdir="$HOME/.config/dashcore/wallets/" \
-datadir="/mnt/dashcore/dashcore/"
```
### How to Run as a System Service
You can use [`serviceman`](../serviceman/):
**Linux**
```sh
sudo env PATH="$PATH" \
serviceman add \
--system \
--username "$(id -n -u)" \
--path "$PATH" \
--name dashd \
--force \
-- \
dashd \
-usehd \
-conf="$HOME/.dashcore/dash.conf" \
-settings="$HOME/.dashcore/settings.json" \
-walletdir="$HOME/.dashcore/wallets/" \
-datadir="/mnt/100gb/dashcore/_data/" \
-blocksdir="/mnt/100gb/dashcore/_caches/"
```
**Mac**
```sh
serviceman add \
--path "$PATH" \
--name dashd \
--force \
-- \
dashd \
-usehd \
-conf="$HOME/.dashcore/dash.conf" \
-settings="$HOME/.dashcore/settings.json" \
-walletdir="$HOME/.dashcore/wallets/" \
-datadir="/Volumes/100gb/dashcore/_data/" \
-blocksdir="/Volumes/100gb/dashcore/_caches/"
```
**Windows**
(be sure modify variables appropriately for `cmd.exe` or `powershell`)
```sh
& serviceman add \
--name dashd \
--force \
-- \
dashd \
-usehd \
-conf="$Env:UserProfile/.dashcore/dash.conf" \
-settings="$Env:UserProfile/.dashcore/settings.json" \
-walletdir="$Env:UserProfile/.dashcore/wallets/" \
-datadir="D:/100gb/dashcore/_data/" \
-blocksdir="D:/100gb/dashcore/_caches/"
```
### How to Trim Excessive Storage
If the service **crashes** during the initial syncing and indexing (such as when
using less than 4GB RAM + 4GB Swap) it **will not resume** (typically).
Instead it will create duplicate new data, and not clean up the old data.
You may need to **delete /mnt/<BLK_VOL>/dashcore/** and start from scratch
(being careful not to delete any wallet information, if you have any).
Generally I wouldn't recommend storing money on a Full Node -since it's
primarily used for creating APIs for transactions and validations - but if you
do, please always make sure to use `-usehd` and print out your Wallet Phrase as
a failsafe.
### More Tools
In particular, you may find these useful:
- [`dashphrase`](https://github.com/dashhive/dashphrase-cli) for generating
secure Wallet Phrases
- [`dashsight`](https://github.com/dashhive/dashphrase-cli) for inspecting
balances, transactions, etc via API (without downloading the indexes)
### More Documentation
All of the **command line flags and options** for the Dash Core Desktop Wallet
are documented between these two pages:
- https://docs.dash.org/projects/core/en/stable/docs/dashcore/wallet-arguments-and-commands-dash-qt.html
- https://docs.dash.org/projects/core/en/stable/docs/dashcore/wallet-arguments-and-commands-dashd.html
The **config files** `dash.conf` (mainly for _Full Nodes_) and `settings.json`
(mainly for Desktop Wallets) are documented at:
- <https://github.com/dashpay/dash/blob/master/contrib/debian/examples/dash.conf>
- <https://docs.dash.org/projects/core/en/stable/docs/dashcore/wallet-configuration-file.html>
+46
View File
@@ -0,0 +1,46 @@
#!/bin/sh
set -e
set -u
# Unfortunately we can't know that datadir won't be used
# for other non-cache files, but we can at least protect
# the ones we're aware of.
my_netname="${1:-}"
if test -n "${my_netname}"; then
if test "${my_netname}" != mainnet &&
test "${my_netname}" != testnet &&
test "${my_netname}" != regnet &&
test "${my_netname}" != devnet; then
echo ""
echo "ERROR"
echo " '${my_netname}' is not one of 'testnet', 'regnet', 'devnet'"
echo ""
echo ""
fi
if test "${my_netname}" != mainnet; then
my_netname=''
fi
fi
my_net_arg=''
if test -n "${my_netname}"; then
my_net_arg="-${my_netname}"
fi
# shellcheck disable=2086
dashd \
-usehd \
${my_net_arg} \
-conf="$HOME/.dashcore/dash.conf" \
-settings="$HOME/.dashcore/settings.json" \
-walletdir="$HOME/.dashcore/wallets/" \
-datadir="$HOME/.dashcore/_data/" \
-blocksdir="$HOME/.dashcore/_data/"
# -enablecoinjoin=1 \
# -coinjoinautostart=1 \
# -coinjoinrounds=16 \
# -coinjoindenomsgoal=10 \
# -coinjoindenomshardcap=25
+170
View File
@@ -0,0 +1,170 @@
#!/bin/sh
set -e
set -u
fn_usage() { (
echo >&2 ""
echo >&2 "USAGE"
echo >&2 " dashd-hd-service-install [datadir] ['testnet']"
echo >&2 ""
echo >&2 "EXAMPLE"
echo >&2 " dashd-hd-service-install /mnt/vol_slc1_60g/dashcore/"
echo >&2 ""
echo >&2 "NOTE"
echo >&2 " If a directory matching '/mnt/*/dashcore/' is found,"
echo >&2 " it will be used automatically."
echo >&2 ""
); }
fn_datadir_help() { (
my_vol="${1:-}"
my_user="$(
id -n -u
)"
my_group="$(
id -n -g
)"
echo >&2 ""
echo >&2 "ERROR"
echo >&2 " '${my_vol}' is not writable"
echo >&2 ""
echo >&2 "SOLUTION"
echo >&2 " 1. Mount a large (50gb+) volume"
echo >&2 ""
echo >&2 " sudo mkdir -p /mnt/EXAMPLE"
echo >&2 " sudo mount /dev/sdx1 /mnt/EXAMPLE"
echo >&2 ""
echo >&2 " 2. Create a 'dashcore' inside of it"
echo >&2 ""
echo >&2 " sudo mkdir -p '${my_vol}'"
echo >&2 ""
echo >&2 " 3. Make it writable to this user"
echo >&2 ""
echo >&2 " sudo chown -R '${my_user}':'${my_group}' '${my_vol}'"
echo >&2 ""
echo >&2 ""
); }
fn_srv_install() { (
my_vol="${1:-}"
my_netname="${2:-}"
my_name='dashd'
# both of these will get '/testnet3' suffixes with -testnet
my_datadir="${my_vol}/_data"
my_blocksdir="${my_vol}/_caches"
if test -n "${my_netname}"; then
if test "mainnet" = "${my_netname}"; then
my_netname=""
elif test "testnet" != "${my_netname}"; then
fn_usage
return 1
fi
fi
if ! test -d "${my_datadir}"; then
mkdir "${my_datadir}"
chmod 0700 "${my_datadir}"
fi
if ! test -d "${my_blocksdir}"; then
mkdir -p "${my_blocksdir}"
chmod 0700 "${my_blocksdir}"
fi
my_net_flag=''
if test -n "${my_netname}"; then
# ex: -testnet
my_net_flag="-${my_netname}"
# ex: dashd-testnet
my_name="dashd-${my_netname}"
fi
my_system_args=""
my_kernel="$(
uname -s
)"
if test "Darwin" != "${my_kernel}"; then
my_user="$(
id -u -n
)"
my_system_args="--system --username ${my_user}"
fi
# shellcheck disable=SC2016,SC1090
echo 'sudo env PATH="$PATH"' \
"serviceman add ${my_system_args} --path \"\$PATH\" --name \"${my_name}\" --force --" \
"dashd " \
"${my_net_flag}" \
-usehd \
'-conf="$HOME/.dashcore/dash.conf"' \
'-settings="$HOME/.dashcore/settings.json"' \
'-walletdir="$HOME/.dashcore/wallets/"' \
"-datadir=\"${my_datadir}\"" \
"-blocksdir=\"${my_blocksdir}\""
if ! command -v serviceman > /dev/null; then
echo ""
echo "Installing 'serviceman'..."
echo ""
{
curl -fsSL "${WEBI_HOST}/serviceman" | sh
} > /dev/null
# shellcheck disable=SC1090
. ~/.config/envman/PATH.env || true
fi
mkdir -p "$HOME/.dashcore/wallets/"
chmod 0700 "$HOME/.dashcore/wallets/"
mkdir -p "${my_datadir}"
chmod 0700 "${my_datadir}"
mkdir -p "${my_blocksdir}"
chmod 0700 "${my_blocksdir}"
cd "${my_vol}" || return 1
# leave options unquoted so they're interpreted separately
# shellcheck disable=SC2086
sudo env PATH="${PATH}" \
serviceman add ${my_system_args} --path "${PATH}" --name "${my_name}" --force -- \
dashd \
${my_net_flag} \
-usehd \
-conf="${HOME}/.dashcore/dash.conf" \
-settings="${HOME}/.dashcore/settings.json" \
-walletdir="${HOME}/.dashcore/wallets/" \
-datadir="${my_datadir}" \
-blocksdir="${my_blocksdir}"
); }
main() { (
my_vol="${1:-}"
my_netname="${2:-}"
if test -z "${my_vol}"; then
my_vol="$(
ls -d /mnt/*/dashcore/ 2> /dev/null || true
)"
fi
if test -z "${my_vol}"; then
fn_usage
return 1
fi
if ! test -d "${my_vol}" ||
! test -w "${my_vol}"; then
fn_datadir_help "${my_vol}"
return 1
fi
fn_srv_install "${my_vol}" "${my_netname}"
); }
main "${@:-}"
+13
View File
@@ -0,0 +1,13 @@
#!/bin/sh
set -e
set -u
# NOTE:
# The '-testnet' flag will always cause a './testnet3/' folder
# to be created under '-datadir' (it won't the 'datadir' directly)
#
# Example:
# dashd -testnet -datadir="$HOME/.dashcore/"
# will save to ~/.dashcore/testnet3/, NOT ~/.dashcore/
dashd-hd testnet
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
set -e
set -u
dashd-hd-service-install "${1:-}" "testnet"
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env pwsh
#################
# Install dashd #
#################
# Every package should define these variables
$pkg_cmd_name = "dashd"
$pkg_dst_cmd = "$Env:USERPROFILE\.local\opt\dashcore\bin\dashd.exe"
$pkg_dst_dir = "$Env:USERPROFILE\.local\opt\dashcore"
$pkg_dst = "$pkg_dst_cmd"
$pkg_src_cmd = "$Env:USERPROFILE\.local\opt\dashcore-v$Env:WEBI_VERSION\bin\dashd.exe"
$pkg_src_bin = "$Env:USERPROFILE\.local\opt\dashcore-v$Env:WEBI_VERSION\bin"
$pkg_src_dir = "$Env:USERPROFILE\.local\opt\dashcore-v$Env:WEBI_VERSION"
$pkg_src = "$pkg_src_cmd"
New-Item "$Env:USERPROFILE\Downloads\webi" -ItemType Directory -Force | out-null
$pkg_download = "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE"
# Fetch archive
IF (!(Test-Path -Path "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE"))
{
echo "Downloading dashd from $Env:WEBI_PKG_URL to $pkg_download"
& curl.exe -A "$Env:WEBI_UA" -fsSL "$Env:WEBI_PKG_URL" -o "$pkg_download.part"
& move "$pkg_download.part" "$pkg_download"
}
IF (!(Test-Path -Path "$pkg_src_dir"))
{
echo "Installing dashd"
# TODO: create package-specific temp directory
# Enter tmp
pushd .local\tmp
# Remove any leftover tmp cruft
Remove-Item -Path ".\dashcore*" -Recurse -ErrorAction Ignore
# Unpack archive file into this temporary directory
# Windows BSD-tar handles zip. Imagine that.
echo "Unpacking $pkg_download"
& tar xf "$pkg_download"
# Settle unpacked archive into place
echo "Install Location: $pkg_src_cmd"
Move-Item -Path ".\dashcore*" -Destination "$pkg_src_dir"
# Exit tmp
popd
}
echo "Copying into '$pkg_dst_cmd' from '$pkg_src_cmd'"
Remove-Item -Path "$pkg_dst_cmd" -Recurse -ErrorAction Ignore | out-null
Copy-Item -Path "$pkg_src" -Destination "$pkg_dst" -Recurse
+110
View File
@@ -0,0 +1,110 @@
#!/bin/sh
# shellcheck disable=SC2034,2317
# "'pkg_cmd_name' appears unused. Verify it or export it."
# "Command appears to be unreachable."
__init_dashd() {
set -e
set -u
#################
# Install dashd #
#################
# Every package should define these 6 variables
pkg_cmd_name="dashd"
pkg_dst_cmd="$HOME/.local/opt/dashcore/bin/dashd"
pkg_dst_dir="$HOME/.local/opt/dashcore"
pkg_dst="$pkg_dst_dir"
pkg_src_cmd="$HOME/.local/opt/dashcore-v$WEBI_VERSION/bin/dashd"
pkg_src_dir="$HOME/.local/opt/dashcore-v$WEBI_VERSION"
pkg_src="$pkg_src_dir"
# pkg_install must be defined by every package
pkg_install() {
# mv ./dashcore-* ~/.local/opt/dashcore-v0.19.1
mv ./dashcore-* "${pkg_src_dir}"
if ! test -e "${HOME}/.dashcore"; then
mkdir -p "${HOME}/.dashcore"
chmod 0700 "${HOME}/.dashcore"
fi
if ! test -e "${HOME}/.dashcore/dash.conf"; then
touch "${HOME}/.dashcore/dash.conf"
chmod 0600 "${HOME}/.dashcore/dash.conf"
fi
if ! grep -q rpcuser "${HOME}/.dashcore/dash.conf"; then
my_main_pass="$(xxd -l16 -ps /dev/urandom)"
my_test_pass="$(xxd -l16 -ps /dev/urandom)"
{
echo '[main]'
echo "rpcuser=$(id -u -n)"
echo "rpcpassword=${my_main_pass}"
echo ''
echo '[test]'
echo "rpcuser=$(id -u -n)-test"
echo "rpcpassword=${my_test_pass}"
echo ''
} >> "${HOME}/.dashcore/dash.conf"
fi
# Always try to correct the permissions due to
# https://github.com/dashpay/dash/issues/5420
chmod -R og-rwx "${HOME}/.dashcore/" || true
echo "WEBI_HOST: $WEBI_HOST"
if ! test -e "$HOME/.local/bin/dashd-hd"; then
webi_download \
"$WEBI_HOST/packages/dashd/dashd-hd" \
"$HOME/.local/bin/dashd-hd"
chmod a+x "$HOME/.local/bin/dashd-hd"
fi
if ! test -e "$HOME/.local/bin/dashd-testnet"; then
webi_download \
"$WEBI_HOST/packages/dashd/dashd-testnet" \
"$HOME/.local/bin/dashd-testnet"
chmod a+x "$HOME/.local/bin/dashd-testnet"
fi
webi_download \
"$WEBI_HOST/packages/dashd/dashd-hd-service-install" \
"$HOME/.local/bin/dashd-hd-service-install"
chmod a+x "$HOME/.local/bin/dashd-hd-service-install"
webi_download \
"$WEBI_HOST/packages/dashd/dashd-testnet-service-install" \
"$HOME/.local/bin/dashd-testnet-service-install"
chmod a+x "$HOME/.local/bin/dashd-testnet-service-install"
}
pkg_done_message() {
echo "Installed 'dashd@v$WEBI_VERSION' to ~/.local/opt/dashcore/"
echo ""
echo "TO START THE DAEMON"
echo ""
echo " # mainnet"
echo " dashd-hd-service-install"
echo ""
echo ""
echo " # testnet"
echo " dashd-testnet-service-install"
echo ""
}
# pkg_get_current_version is recommended, but not required
pkg_get_current_version() {
# 'dashd --version' has output in this format:
# Dash Core Daemon version v19.1.0
# This trims it down to just the version number:
# 19.1.0
dashd --version 2> /dev/null |
head -n 1 |
cut -d ' ' -f 5 |
sed 's:^v::'
}
}
__init_dashd
+3
View File
@@ -0,0 +1,3 @@
'use strict';
module.exports = require('../dashcore/releases.js');