diff --git a/dashd/README.md b/dashd/README.md new file mode 100644 index 0000000..306dbf3 --- /dev/null +++ b/dashd/README.md @@ -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//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//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: + +- +- diff --git a/dashd/dashd-hd b/dashd/dashd-hd new file mode 100644 index 0000000..e188bd6 --- /dev/null +++ b/dashd/dashd-hd @@ -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 diff --git a/dashd/dashd-hd-service-install b/dashd/dashd-hd-service-install new file mode 100644 index 0000000..89e9215 --- /dev/null +++ b/dashd/dashd-hd-service-install @@ -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 "${@:-}" diff --git a/dashd/dashd-testnet b/dashd/dashd-testnet new file mode 100644 index 0000000..a20d30b --- /dev/null +++ b/dashd/dashd-testnet @@ -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 diff --git a/dashd/dashd-testnet-service-install b/dashd/dashd-testnet-service-install new file mode 100644 index 0000000..a22dedc --- /dev/null +++ b/dashd/dashd-testnet-service-install @@ -0,0 +1,5 @@ +#!/bin/sh +set -e +set -u + +dashd-hd-service-install "${1:-}" "testnet" diff --git a/dashd/install.ps1 b/dashd/install.ps1 new file mode 100644 index 0000000..90aaecc --- /dev/null +++ b/dashd/install.ps1 @@ -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 diff --git a/dashd/install.sh b/dashd/install.sh new file mode 100644 index 0000000..e3bb994 --- /dev/null +++ b/dashd/install.sh @@ -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 diff --git a/dashd/releases.js b/dashd/releases.js new file mode 100644 index 0000000..0b9481a --- /dev/null +++ b/dashd/releases.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require('../dashcore/releases.js');