ovtools 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +121 -2
- package/assets/common/bond-inspect.sh +368 -0
- package/assets/common/config.sh +263 -0
- package/assets/common/extract-data.sh +197 -0
- package/assets/common/harden-host.sh +37 -0
- package/assets/common/install-deps.sh +93 -0
- package/assets/common/node-enroll.sh +65 -0
- package/assets/common/node-setup.sh +150 -0
- package/assets/common/node-start.sh +90 -0
- package/assets/common/node-stop.sh +18 -0
- package/assets/common/node-upgrade.sh +45 -0
- package/assets/common/pre-run.sh +497 -0
- package/assets/common/promote-validator.sh +104 -0
- package/assets/deploy/10-prepare-host.sh +98 -0
- package/assets/deploy/20-install-toolchain.sh +93 -0
- package/assets/deploy/30-setup-node.sh +82 -0
- package/assets/deploy/40-start-node.sh +75 -0
- package/assets/deploy/50-verify.sh +259 -0
- package/assets/deploy/60-enroll.sh +304 -0
- package/assets/deploy/70-promote.sh +152 -0
- package/assets/deploy/lib.sh +398 -0
- package/assets/manage/10-bond-increase.sh +149 -0
- package/assets/manage/10-diagnose-node.sh +169 -0
- package/assets/manage/20-exit-validator.sh +259 -0
- package/assets/manage/25-recover-node.sh +291 -0
- package/assets/manage/30-status.sh +64 -0
- package/assets/manage/40-exit-withdraw.sh +133 -0
- package/assets/manage/bond_inc.sh +318 -0
- package/assets/manage/dashboard_monitor/app.js +1544 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/base.css +113 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/components/content.css +133 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/components/controls.css +229 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/components/data.css +374 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/components/icons.css +35 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/components/motion.css +57 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/components/shell.css +51 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/components/sidebar.css +242 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/components/topbar.css +138 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/fonts.css +30 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/synteq-ui-v2.css +25 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/theme-dark.css +38 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/theme-light.css +36 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/css/tokens.css +61 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/fonts/GoogleSansCode-Medium.ttf +0 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/fonts/GoogleSansCode-Regular.ttf +0 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/fonts/GoogleSansCode-SemiBold.ttf +0 -0
- package/assets/manage/dashboard_monitor/assets/v2.2/js/synteq-ui-v2.js +869 -0
- package/assets/manage/dashboard_monitor/deploy-dashboard.sh +230 -0
- package/assets/manage/dashboard_monitor/favicon.svg +13 -0
- package/assets/manage/dashboard_monitor/index.html +1197 -0
- package/assets/manage/dashboard_monitor/nginx-octra.conf +76 -0
- package/assets/manage/dashboard_monitor/octra-dashboard.service +29 -0
- package/assets/manage/dashboard_monitor/octra-node-prune.cron +12 -0
- package/assets/manage/dashboard_monitor/octra-node-prune.service +16 -0
- package/assets/manage/dashboard_monitor/octra-node-prune.timer +12 -0
- package/assets/manage/dashboard_monitor/prune-node-junk.sh +329 -0
- package/assets/manage/dashboard_monitor/server.py +1887 -0
- package/assets/manage/dashboard_monitor/ssl-certbot.sh +90 -0
- package/assets/manage/dashboard_monitor/styles.css +327 -0
- package/assets/manage/lib.sh +347 -0
- package/assets/manifest.json +143 -0
- package/assets/migrate/00-backup-identity.sh +67 -0
- package/assets/migrate/01-prepare-target.sh +145 -0
- package/assets/migrate/02-authorize-pull.sh +43 -0
- package/assets/migrate/03-pull-state.sh +102 -0
- package/assets/migrate/04-stop-source.sh +85 -0
- package/assets/migrate/05-finalize-target.sh +140 -0
- package/assets/migrate/06-start-target.sh +57 -0
- package/assets/migrate/07-verify.sh +237 -0
- package/assets/migrate/08-rollback.sh +54 -0
- package/assets/migrate/lib.sh +149 -0
- package/assets/upgrade/10-preflight.sh +120 -0
- package/assets/upgrade/20-upgrade.sh +142 -0
- package/assets/upgrade/30-manual-upgrade.sh +129 -0
- package/assets/upgrade/40-storage-prune.sh +65 -0
- package/assets/upgrade/50-status.sh +58 -0
- package/assets/upgrade/lib.sh +232 -0
- package/bin/ovtools.js +32 -0
- package/dist/api/checks.d.ts +6 -0
- package/dist/api/checks.d.ts.map +1 -0
- package/dist/api/checks.js +173 -0
- package/dist/api/checks.js.map +1 -0
- package/dist/api/hostkeys.d.ts +10 -0
- package/dist/api/hostkeys.d.ts.map +1 -0
- package/dist/api/hostkeys.js +58 -0
- package/dist/api/hostkeys.js.map +1 -0
- package/dist/api/jobs.d.ts +33 -0
- package/dist/api/jobs.d.ts.map +1 -0
- package/dist/api/jobs.js +483 -0
- package/dist/api/jobs.js.map +1 -0
- package/dist/api/nodes.d.ts +16 -0
- package/dist/api/nodes.d.ts.map +1 -0
- package/dist/api/nodes.js +126 -0
- package/dist/api/nodes.js.map +1 -0
- package/dist/api/server.d.ts +3 -0
- package/dist/api/server.d.ts.map +1 -0
- package/dist/api/server.js +443 -0
- package/dist/api/server.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +301 -0
- package/dist/cli.js.map +1 -0
- package/dist/constants.d.ts +76 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +150 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator/base.d.ts +52 -0
- package/dist/orchestrator/base.d.ts.map +1 -0
- package/dist/orchestrator/base.js +219 -0
- package/dist/orchestrator/base.js.map +1 -0
- package/dist/orchestrator/deploy.d.ts +33 -0
- package/dist/orchestrator/deploy.d.ts.map +1 -0
- package/dist/orchestrator/deploy.js +313 -0
- package/dist/orchestrator/deploy.js.map +1 -0
- package/dist/orchestrator/manage.d.ts +28 -0
- package/dist/orchestrator/manage.d.ts.map +1 -0
- package/dist/orchestrator/manage.js +267 -0
- package/dist/orchestrator/manage.js.map +1 -0
- package/dist/orchestrator/migrate.d.ts +31 -0
- package/dist/orchestrator/migrate.d.ts.map +1 -0
- package/dist/orchestrator/migrate.js +442 -0
- package/dist/orchestrator/migrate.js.map +1 -0
- package/dist/ssh/client.d.ts +39 -0
- package/dist/ssh/client.d.ts.map +1 -0
- package/dist/ssh/client.js +418 -0
- package/dist/ssh/client.js.map +1 -0
- package/dist/test/core.test.d.ts +2 -0
- package/dist/test/core.test.d.ts.map +1 -0
- package/dist/test/core.test.js +188 -0
- package/dist/test/core.test.js.map +1 -0
- package/dist/types.d.ts +267 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/assets.d.ts +28 -0
- package/dist/utils/assets.d.ts.map +1 -0
- package/dist/utils/assets.js +583 -0
- package/dist/utils/assets.js.map +1 -0
- package/dist/utils/browser.d.ts +2 -0
- package/dist/utils/browser.d.ts.map +1 -0
- package/dist/utils/browser.js +23 -0
- package/dist/utils/browser.js.map +1 -0
- package/dist/utils/dashboard.d.ts +16 -0
- package/dist/utils/dashboard.d.ts.map +1 -0
- package/dist/utils/dashboard.js +177 -0
- package/dist/utils/dashboard.js.map +1 -0
- package/dist/utils/helpers.d.ts +29 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +204 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/scripts.d.ts +60 -0
- package/dist/utils/scripts.d.ts.map +1 -0
- package/dist/utils/scripts.js +174 -0
- package/dist/utils/scripts.js.map +1 -0
- package/dist/utils/state.d.ts +12 -0
- package/dist/utils/state.d.ts.map +1 -0
- package/dist/utils/state.js +44 -0
- package/dist/utils/state.js.map +1 -0
- package/dist/utils/tar.d.ts +11 -0
- package/dist/utils/tar.d.ts.map +1 -0
- package/dist/utils/tar.js +93 -0
- package/dist/utils/tar.js.map +1 -0
- package/dist/utils/update.d.ts +9 -0
- package/dist/utils/update.d.ts.map +1 -0
- package/dist/utils/update.js +134 -0
- package/dist/utils/update.js.map +1 -0
- package/dist/utils/websocket.d.ts +10 -0
- package/dist/utils/websocket.d.ts.map +1 -0
- package/dist/utils/websocket.js +203 -0
- package/dist/utils/websocket.js.map +1 -0
- package/package.json +55 -4
- package/public/app.js +2712 -0
- package/public/assets/v2.2/css/base.css +113 -0
- package/public/assets/v2.2/css/components/content.css +133 -0
- package/public/assets/v2.2/css/components/controls.css +229 -0
- package/public/assets/v2.2/css/components/data.css +373 -0
- package/public/assets/v2.2/css/components/icons.css +35 -0
- package/public/assets/v2.2/css/components/motion.css +57 -0
- package/public/assets/v2.2/css/components/shell.css +51 -0
- package/public/assets/v2.2/css/components/sidebar.css +242 -0
- package/public/assets/v2.2/css/components/topbar.css +138 -0
- package/public/assets/v2.2/css/fonts.css +30 -0
- package/public/assets/v2.2/css/synteq-ui-v2.css +25 -0
- package/public/assets/v2.2/css/theme-dark.css +38 -0
- package/public/assets/v2.2/css/theme-light.css +36 -0
- package/public/assets/v2.2/css/tokens.css +61 -0
- package/public/assets/v2.2/fonts/GoogleSansCode-Medium.ttf +0 -0
- package/public/assets/v2.2/fonts/GoogleSansCode-Regular.ttf +0 -0
- package/public/assets/v2.2/fonts/GoogleSansCode-SemiBold.ttf +0 -0
- package/public/assets/v2.2/js/synteq-ui-v2.js +869 -0
- package/public/favicon.svg +7 -0
- package/public/index.html +1080 -0
- package/public/styles.css +552 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ===================================================================
|
|
3
|
+
# scripts/manage/lib.sh - shared helpers for the MANAGE-ACTIVE-NODE program
|
|
4
|
+
#
|
|
5
|
+
# The third program of the console: it does not create or move a node, it
|
|
6
|
+
# operates the validator that is already running (increase the bond, exit it and
|
|
7
|
+
# take the stake back). Everything here runs on the node host as root and calls
|
|
8
|
+
# the node's own controls as the `octra` user, exactly like the other two
|
|
9
|
+
# programs - same status markers, same ERR trap, same tool policy.
|
|
10
|
+
#
|
|
11
|
+
# /root/manage/ this program (/root/deploy, /root/migration = the others)
|
|
12
|
+
# ===================================================================
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
# Tool policy (check -> install -> continue) lives in scripts/config.sh, which is
|
|
16
|
+
# pushed to /root/config.sh next to these scripts.
|
|
17
|
+
CONFIG_FILE="${CONFIG_FILE:-/root/config.sh}"
|
|
18
|
+
if [[ -f "${CONFIG_FILE}" ]]; then
|
|
19
|
+
# shellcheck disable=SC1090
|
|
20
|
+
source "${CONFIG_FILE}"
|
|
21
|
+
fi
|
|
22
|
+
if ! declare -F ensure_tool >/dev/null 2>&1; then
|
|
23
|
+
ensure_tool() { command -v "$1" >/dev/null 2>&1 || die "tool $1 is missing and ${CONFIG_FILE} cannot install it (push the scripts again)"; }
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
MANAGE_DIR="${MANAGE_DIR:-/root/manage}"
|
|
27
|
+
MANAGE_LOG="${MANAGE_LOG:-${MANAGE_DIR}/manage.log}"
|
|
28
|
+
MANAGE_STATUS="${MANAGE_STATUS:-${MANAGE_DIR}/status}"
|
|
29
|
+
|
|
30
|
+
NODE_SRC_DIR="${NODE_SRC_DIR:-/opt/octra/libv_litecore}"
|
|
31
|
+
NODE_DATA_ROOT="${NODE_DATA_ROOT:-/var/lib/octra}"
|
|
32
|
+
NODE_DATA_DIR="${NODE_DATA_DIR:-${NODE_DATA_ROOT}/devnet}"
|
|
33
|
+
NODE_WALLET="${NODE_WALLET:-${NODE_SRC_DIR}/.keys/validator/wallet.json}"
|
|
34
|
+
NODE_ENV="${NODE_ENV:-${NODE_SRC_DIR}/.keys/validator/node.env}"
|
|
35
|
+
NODE_USER="${NODE_USER:-octra}"
|
|
36
|
+
NODE_LOG="${NODE_LOG:-${NODE_SRC_DIR}/data/operator_logs/node.log}"
|
|
37
|
+
TOKEN_DECIMALS=6
|
|
38
|
+
TOKEN_UNIT=1000000
|
|
39
|
+
|
|
40
|
+
mkdir -p "${MANAGE_DIR}"
|
|
41
|
+
|
|
42
|
+
log() { echo -e "[manage] $*" | tee -a "${MANAGE_LOG}"; }
|
|
43
|
+
warn() { echo -e "[warn] $*" | tee -a "${MANAGE_LOG}" >&2; }
|
|
44
|
+
err() { echo -e "[err] $*" | tee -a "${MANAGE_LOG}" >&2; }
|
|
45
|
+
|
|
46
|
+
set_status() { # set_status <STATE> [detail...] - read by the Windows console
|
|
47
|
+
local state="$1" detail
|
|
48
|
+
shift || true
|
|
49
|
+
detail="$*"
|
|
50
|
+
printf '%s %s %s\n' "${state}" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "${detail}" > "${MANAGE_STATUS}"
|
|
51
|
+
log "status = ${state} ${detail}"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
die() { err "$*"; set_status FAILED "$*"; exit 1; }
|
|
55
|
+
|
|
56
|
+
require_root() { [[ $EUID -eq 0 ]] || die "run as root"; }
|
|
57
|
+
|
|
58
|
+
# A step must never die leaving status = RUNNING: the console follows this file.
|
|
59
|
+
_manage_on_err() {
|
|
60
|
+
local rc="$1" line="$2" cmd="$3" state
|
|
61
|
+
state=$(awk 'NR==1 {print $1}' "${MANAGE_STATUS}" 2>/dev/null || true)
|
|
62
|
+
case "${state}" in
|
|
63
|
+
DONE|FAILED|WAITING-*) return 0 ;;
|
|
64
|
+
esac
|
|
65
|
+
err "unexpected failure (exit ${rc}) at line ${line}: ${cmd}"
|
|
66
|
+
set_status FAILED "line ${line}: ${cmd} (exit ${rc})"
|
|
67
|
+
}
|
|
68
|
+
trap '_manage_on_err "$?" "$LINENO" "$BASH_COMMAND"' ERR
|
|
69
|
+
|
|
70
|
+
# --- the node's own controls (always as the octra user) ---------------
|
|
71
|
+
as_octra() { su - "${NODE_USER}" -c "$*"; }
|
|
72
|
+
|
|
73
|
+
# node_script <timeout> <command...>: run one of the node's control scripts from
|
|
74
|
+
# the node directory as the node user, bounded (a control script that waits on
|
|
75
|
+
# the chain must never freeze a step).
|
|
76
|
+
node_script() {
|
|
77
|
+
local limit="$1"
|
|
78
|
+
shift
|
|
79
|
+
timeout "${limit}" su - "${NODE_USER}" -c "cd ${NODE_SRC_DIR} && $*" 2>&1
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
stat_raw() { node_script "${STATE_TIMEOUT:-60}" "sh controls/stat.sh" || true; }
|
|
83
|
+
stat_field() { # an unreadable field is EMPTY, not the string "None" (see deploy/lib.sh)
|
|
84
|
+
awk -F' = ' -v k="$1" '$1==k { v=$2; if (v=="None" || v=="null") v=""; print v; exit }'
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# fill SNAP/ROLE/RPC/ACTIVE/SCHED/ENROLL/BOND/EPOCH/VOTING/PROCESS from the node
|
|
88
|
+
read_state() {
|
|
89
|
+
SNAP=$(stat_raw)
|
|
90
|
+
ROLE=$(printf '%s\n' "${SNAP}" | stat_field role)
|
|
91
|
+
RPC=$(printf '%s\n' "${SNAP}" | stat_field rpc)
|
|
92
|
+
ACTIVE=$(printf '%s\n' "${SNAP}" | stat_field validator_active)
|
|
93
|
+
SCHED=$(printf '%s\n' "${SNAP}" | stat_field validator_scheduled)
|
|
94
|
+
ENROLL=$(printf '%s\n' "${SNAP}" | stat_field validator_enrollment)
|
|
95
|
+
BOND=$(printf '%s\n' "${SNAP}" | stat_field validator_bond)
|
|
96
|
+
EPOCH=$(printf '%s\n' "${SNAP}" | stat_field epoch)
|
|
97
|
+
VOTING=$(printf '%s\n' "${SNAP}" | stat_field voting)
|
|
98
|
+
PROCESS=$(printf '%s\n' "${SNAP}" | stat_field process)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# how often a waiting step re-prints its progress line
|
|
102
|
+
EXIT_PROGRESS_SEC="${EXIT_PROGRESS_SEC:-120}"
|
|
103
|
+
|
|
104
|
+
# --- "when will the stake be back?" -----------------------------------
|
|
105
|
+
# An exit is a chain event, not a command: the set releases the validator at a
|
|
106
|
+
# fold, then the bond unlocks at `withdraw_epoch` (weeks away on this network).
|
|
107
|
+
# The console and the operator need two numbers for that - the epoch and a
|
|
108
|
+
# duration - so the cadence is measured from the chain itself (two head_epoch
|
|
109
|
+
# samples), never hard-coded: a testnet that speeds up changes the answer.
|
|
110
|
+
EPOCH_SAMPLE_SEC="${EPOCH_SAMPLE_SEC:-60}"
|
|
111
|
+
|
|
112
|
+
# fmt_duration <seconds> -> "1 day 18 h" | "3 h 05 min" | "42 min" | "45 s"
|
|
113
|
+
fmt_duration() {
|
|
114
|
+
local secs="${1:-}"
|
|
115
|
+
[[ "${secs}" =~ ^[0-9]+$ ]] || { printf 'unknown'; return 0; }
|
|
116
|
+
if (( secs >= 86400 )); then
|
|
117
|
+
local days=$(( secs / 86400 )) hours=$(( (secs % 86400) / 3600 ))
|
|
118
|
+
printf '%d day%s %d h' "${days}" "$([[ ${days} -eq 1 ]] && printf '' || printf 's')" "${hours}"
|
|
119
|
+
elif (( secs >= 3600 )); then
|
|
120
|
+
printf '%d h %02d min' $(( secs / 3600 )) $(( (secs % 3600) / 60 ))
|
|
121
|
+
elif (( secs >= 60 )); then
|
|
122
|
+
printf '%d min' $(( secs / 60 ))
|
|
123
|
+
else
|
|
124
|
+
printf '%d s' "${secs}"
|
|
125
|
+
fi
|
|
126
|
+
return 0
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
# epoch_seconds: how long one epoch lasts. EPOCH_SECONDS wins (the console sends
|
|
130
|
+
# the cadence it measured, a test pins it); otherwise two stat.sh samples give it.
|
|
131
|
+
epoch_seconds() {
|
|
132
|
+
local e1 e2 t1 t2 de dt
|
|
133
|
+
if [[ "${EPOCH_SECONDS:-}" =~ ^[0-9]+([.][0-9]+)?$ ]]; then
|
|
134
|
+
printf '%s\n' "${EPOCH_SECONDS}"
|
|
135
|
+
return 0
|
|
136
|
+
fi
|
|
137
|
+
[[ "${EPOCH_SAMPLE_SEC}" =~ ^[0-9]+$ ]] && (( EPOCH_SAMPLE_SEC > 0 )) || return 0
|
|
138
|
+
e1=$(stat_raw | stat_field epoch)
|
|
139
|
+
[[ "${e1}" =~ ^[0-9]+$ ]] || return 0
|
|
140
|
+
t1=$(date +%s)
|
|
141
|
+
sleep "${EPOCH_SAMPLE_SEC}"
|
|
142
|
+
e2=$(stat_raw | stat_field epoch)
|
|
143
|
+
[[ "${e2}" =~ ^[0-9]+$ ]] || return 0
|
|
144
|
+
t2=$(date +%s)
|
|
145
|
+
de=$(( e2 - e1 ))
|
|
146
|
+
dt=$(( t2 - t1 ))
|
|
147
|
+
(( de > 0 && dt > 0 )) || return 0
|
|
148
|
+
awk -v dt="${dt}" -v de="${de}" 'BEGIN { printf "%.2f\n", dt / de }'
|
|
149
|
+
return 0
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
# epoch_eta <epochs-left> <seconds-per-epoch> -> "1 day 18 h" (empty when unknown)
|
|
153
|
+
epoch_eta() {
|
|
154
|
+
local left="${1:-}" rate="${2:-}"
|
|
155
|
+
[[ "${left}" =~ ^[0-9]+$ ]] || return 0
|
|
156
|
+
[[ "${rate}" =~ ^[0-9]+([.][0-9]+)?$ ]] || return 0
|
|
157
|
+
awk -v l="${left}" -v r="${rate}" 'BEGIN { printf "%d\n", (l * r) + 0.5 }'
|
|
158
|
+
return 0
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
# --- the withdrawal keeps itself alive on the host ---------------------
|
|
162
|
+
# `controls/enroll.sh withdraw` only signs once the chain allows it (unbonding
|
|
163
|
+
# over AND the validator out of the set). Waiting for that inside a step would
|
|
164
|
+
# block the console for weeks, and only re-running the step by hand would ever
|
|
165
|
+
# withdraw the stake - so the step installs a small systemd timer instead. It
|
|
166
|
+
# survives reboots and console restarts, and disarms itself when bond = 0.
|
|
167
|
+
EXIT_WATCH_UNIT="${EXIT_WATCH_UNIT:-octra-exit-withdraw}"
|
|
168
|
+
EXIT_WATCH_SCRIPT="${EXIT_WATCH_SCRIPT:-/root/manage/40-exit-withdraw.sh}"
|
|
169
|
+
EXIT_WATCH_STATUS="${EXIT_WATCH_STATUS:-${MANAGE_DIR}/exit-watch.status}"
|
|
170
|
+
EXIT_WATCH_LOG="${EXIT_WATCH_LOG:-${MANAGE_DIR}/exit-watch.log}"
|
|
171
|
+
SYSTEMD_DIR="${OCTRA_SYSTEMD_DIR:-/etc/systemd/system}"
|
|
172
|
+
SYSTEMCTL="${OCTRA_SYSTEMCTL:-systemctl}"
|
|
173
|
+
|
|
174
|
+
exit_watch_status() {
|
|
175
|
+
[[ -f "${EXIT_WATCH_STATUS}" ]] && head -1 "${EXIT_WATCH_STATUS}"
|
|
176
|
+
return 0
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
exit_watch_install() {
|
|
180
|
+
local service="${SYSTEMD_DIR}/${EXIT_WATCH_UNIT}.service"
|
|
181
|
+
local timer="${SYSTEMD_DIR}/${EXIT_WATCH_UNIT}.timer"
|
|
182
|
+
if [[ ! -f "${EXIT_WATCH_SCRIPT}" ]]; then
|
|
183
|
+
warn "cannot arm the withdrawal timer: ${EXIT_WATCH_SCRIPT} is missing (push the manage scripts again)"
|
|
184
|
+
return 0
|
|
185
|
+
fi
|
|
186
|
+
mkdir -p "${SYSTEMD_DIR}" 2>/dev/null || true
|
|
187
|
+
cat > "${service}" <<UNIT || warn "could not write ${service}"
|
|
188
|
+
[Unit]
|
|
189
|
+
Description=Octra validator stake withdrawal (retries until the unbonding period is over)
|
|
190
|
+
|
|
191
|
+
[Service]
|
|
192
|
+
Type=oneshot
|
|
193
|
+
ExecStart=/bin/bash ${EXIT_WATCH_SCRIPT}
|
|
194
|
+
UNIT
|
|
195
|
+
cat > "${timer}" <<UNIT || warn "could not write ${timer}"
|
|
196
|
+
[Unit]
|
|
197
|
+
Description=Octra validator stake withdrawal retry (every 15 minutes)
|
|
198
|
+
|
|
199
|
+
[Timer]
|
|
200
|
+
OnBootSec=5min
|
|
201
|
+
OnUnitActiveSec=15min
|
|
202
|
+
AccuracySec=1min
|
|
203
|
+
Unit=${EXIT_WATCH_UNIT}.service
|
|
204
|
+
|
|
205
|
+
[Install]
|
|
206
|
+
WantedBy=timers.target
|
|
207
|
+
UNIT
|
|
208
|
+
if "${SYSTEMCTL}" daemon-reload >/dev/null 2>&1 \
|
|
209
|
+
&& "${SYSTEMCTL}" enable --now "${EXIT_WATCH_UNIT}.timer" >/dev/null 2>&1; then
|
|
210
|
+
log "the withdrawal retry is armed: ${EXIT_WATCH_UNIT}.timer (every 15 min, also after a reboot)"
|
|
211
|
+
else
|
|
212
|
+
warn "could not enable ${EXIT_WATCH_UNIT}.timer - the console still follows the unbonding"
|
|
213
|
+
fi
|
|
214
|
+
return 0
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
exit_watch_disarm() {
|
|
218
|
+
if "${SYSTEMCTL}" disable --now "${EXIT_WATCH_UNIT}.timer" >/dev/null 2>&1; then
|
|
219
|
+
log "the withdrawal retry is off (${EXIT_WATCH_UNIT}.timer)"
|
|
220
|
+
fi
|
|
221
|
+
return 0
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
# The node's own operator log explains a slow set fold / refused readiness post.
|
|
225
|
+
#
|
|
226
|
+
# 2026-11-04: `line=$(... | grep ...)` returned 1 when the log had no
|
|
227
|
+
# `set_post_failed` line (a HEALTHY node) and `set -e` + pipefail made the caller
|
|
228
|
+
# die as `unexpected failure ... HINT=$(post_hint)`. Optional text must never
|
|
229
|
+
# fail - see the same note in scripts/deploy/lib.sh.
|
|
230
|
+
post_hint() {
|
|
231
|
+
local line=""
|
|
232
|
+
[[ -f "${NODE_LOG}" ]] || return 0
|
|
233
|
+
line=$(tail -n 400 "${NODE_LOG}" 2>/dev/null | grep -a "set_post_failed" | tail -1 || true)
|
|
234
|
+
if [[ -n "${line}" ]]; then
|
|
235
|
+
printf '%s' "${line##*reason = }"
|
|
236
|
+
fi
|
|
237
|
+
return 0
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
# --- the node's own RPC (fast path when /status is too slow) ------------
|
|
241
|
+
# `stat.sh` reads /status, which builds a big snapshot; on a node that is stuck
|
|
242
|
+
# in catch-up that call can take longer than the tool timeout and everything
|
|
243
|
+
# reads as "rpc unavailable" even though the RPC answers /rpc in milliseconds.
|
|
244
|
+
# These helpers ask the small endpoints directly.
|
|
245
|
+
api_port() { local p; p=$(node_env_value OCTRA_API_PORT); printf '%s' "${p:-8080}"; }
|
|
246
|
+
|
|
247
|
+
rpc() { # rpc <method> [params-json]
|
|
248
|
+
timeout 20 curl -s -X POST -H 'Content-Type: application/json' \
|
|
249
|
+
-d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"$1\",\"params\":${2:-[]}}" \
|
|
250
|
+
"http://127.0.0.1:$(api_port)/rpc" 2>/dev/null || true
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
rpc_field() { # rpc_field <method> <params-json> <field>
|
|
254
|
+
rpc "$1" "${2:-[]}" | jq -r --arg k "$3" '.result[$k] // empty' 2>/dev/null || true
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
head_epoch() { rpc_field octra_validatorEnrollment '[]' head_epoch; }
|
|
258
|
+
|
|
259
|
+
status_code() { # status_code -> the HTTP code of /status (000 = timed out)
|
|
260
|
+
timeout 8 curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:$(api_port)/status" 2>/dev/null || true
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
pm2_name() { local n; n=$(node_env_value OCTRA_OPERATOR_PM2_NAME); printf '%s' "${n:-octra-validator-01}"; }
|
|
264
|
+
|
|
265
|
+
pm2_state() { # pm2_state -> "<name> <status> <pid>" (empty when pm2 has no such app)
|
|
266
|
+
su - "${NODE_USER}" -c "pm2 jlist" 2>/dev/null \
|
|
267
|
+
| jq -r --arg n "$(pm2_name)" '.[] | select(.name==$n) | "\(.name) \(.pm2_env.status) \(.pid)"' 2>/dev/null \
|
|
268
|
+
| head -1 || true
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
# how far behind the network this node is (epochs), and the network's own idea of
|
|
272
|
+
# the current epoch, both from the operator log - the RPC only knows its own head
|
|
273
|
+
network_epoch() {
|
|
274
|
+
[[ -f "${NODE_LOG}" ]] || return 0
|
|
275
|
+
tail -n 400 "${NODE_LOG}" 2>/dev/null | grep -aoE 'epoch = [0-9]+' | tail -1 | awk '{print $3}' || true
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
catchup_reason() { # the last reason catch-up could not fetch a range
|
|
279
|
+
[[ -f "${NODE_LOG}" ]] || return 0
|
|
280
|
+
tail -n 400 "${NODE_LOG}" 2>/dev/null \
|
|
281
|
+
| grep -a 'range_http_unavailable' | tail -1 \
|
|
282
|
+
| sed -n 's/.*error = //p' || true
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
# 1 OCT = 1000000 raw; the console sends OCT as a string (at most six decimals).
|
|
286
|
+
oct_to_raw() {
|
|
287
|
+
local value="$1" whole fraction pad
|
|
288
|
+
[[ "${value}" =~ ^[0-9]+(\.[0-9]{1,6})?$ ]] || die "amount must be OCT with at most six decimals (got '${value}')"
|
|
289
|
+
whole="${value%%.*}"
|
|
290
|
+
fraction="000000"
|
|
291
|
+
[[ "${value}" == *.* ]] && fraction="${value#*.}"
|
|
292
|
+
pad="${fraction}000000"
|
|
293
|
+
pad="${pad:0:6}"
|
|
294
|
+
printf '%s\n' "$(( 10#${whole} * TOKEN_UNIT + 10#${pad} ))"
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
raw_to_oct() {
|
|
298
|
+
awk -v raw="${1:-0}" -v unit="${TOKEN_UNIT}" 'BEGIN { printf "%.6f\n", raw / unit }' | sed -e 's/0*$//' -e 's/\.$//'
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
wallet_address() {
|
|
302
|
+
if [[ -f "${NODE_WALLET}" ]]; then
|
|
303
|
+
jq -r '.address // empty' "${NODE_WALLET}" 2>/dev/null || true
|
|
304
|
+
fi
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
node_env_value() { # node_env_value <KEY>
|
|
308
|
+
[[ -f "${NODE_ENV}" ]] || return 0
|
|
309
|
+
grep -m1 "^$1=" "${NODE_ENV}" 2>/dev/null | cut -d= -f2- || true
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
# --- the bond increase tool (pushed by the console) -------------------
|
|
313
|
+
BOND_INC_LOCAL="${BOND_INC_LOCAL:-${MANAGE_DIR}/bond_inc.sh}"
|
|
314
|
+
BOND_INC_REMOTE="${BOND_INC_REMOTE:-${NODE_SRC_DIR}/bond_inc.sh}"
|
|
315
|
+
|
|
316
|
+
install_bond_inc() {
|
|
317
|
+
[[ -f "${BOND_INC_LOCAL}" ]] || die "bond_inc.sh was not pushed to ${BOND_INC_LOCAL} - start the increase again from the console"
|
|
318
|
+
if [[ -f "${BOND_INC_REMOTE}" ]] && cmp -s "${BOND_INC_LOCAL}" "${BOND_INC_REMOTE}"; then
|
|
319
|
+
log "bond_inc.sh in the node directory is up to date"
|
|
320
|
+
else
|
|
321
|
+
log "installing bond_inc.sh into ${NODE_SRC_DIR} (owned by ${NODE_USER})"
|
|
322
|
+
install -m 0700 "${BOND_INC_LOCAL}" "${BOND_INC_REMOTE}" \
|
|
323
|
+
|| die "could not write ${BOND_INC_REMOTE}"
|
|
324
|
+
# the tool must be owned by the node user (it reads that wallet as that user)
|
|
325
|
+
chown "${NODE_USER}:${NODE_USER}" "${BOND_INC_REMOTE}" 2>/dev/null \
|
|
326
|
+
|| warn "could not chown ${BOND_INC_REMOTE} to ${NODE_USER} - check the owner"
|
|
327
|
+
fi
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
# bond_inc.sh keeps ONE signed increase in validator-control/bond-increase.json
|
|
331
|
+
# and compares it with the arguments + the registry on every run:
|
|
332
|
+
# * no record -> the first increase, run without --new
|
|
333
|
+
# * a record that is confirmed -> a further increase needs --new
|
|
334
|
+
# * a record pending/staging -> nothing new may be signed (wait)
|
|
335
|
+
saved_increase_path() {
|
|
336
|
+
local path="${NODE_DATA_DIR}/validator-control/bond-increase.json"
|
|
337
|
+
[[ -f "${path}" ]] && printf '%s\n' "${path}"
|
|
338
|
+
return 0
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
show_saved_increase() {
|
|
342
|
+
local path
|
|
343
|
+
path=$(saved_increase_path)
|
|
344
|
+
[[ -n "${path}" ]] || return 0
|
|
345
|
+
log "a signed bond increase is already stored on this host:"
|
|
346
|
+
jq -r '" amount = \(.amount) raw, stage = \(.stage), tx = \(.tx_hash)"' "${path}" 2>/dev/null | sed 's/^/ /' || true
|
|
347
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"description": "Octra validator task assets. The console may clone this repository on the VPS and copy only the task it runs.",
|
|
4
|
+
"entrypoints": {
|
|
5
|
+
"deploy": "assets/deploy/40-start-node.sh",
|
|
6
|
+
"migrate": "assets/migrate/03-pull-state.sh",
|
|
7
|
+
"manage": "assets/manage/30-status.sh",
|
|
8
|
+
"upgrade": "assets/upgrade/20-upgrade.sh",
|
|
9
|
+
"dashboard_monitor": "assets/manage/dashboard_monitor/deploy-dashboard.sh"
|
|
10
|
+
},
|
|
11
|
+
"tasks": {
|
|
12
|
+
"common": {
|
|
13
|
+
"source": "assets/common",
|
|
14
|
+
"target": "/root",
|
|
15
|
+
"dependsOn": [],
|
|
16
|
+
"files": [
|
|
17
|
+
"bond-inspect.sh",
|
|
18
|
+
"config.sh",
|
|
19
|
+
"extract-data.sh",
|
|
20
|
+
"harden-host.sh",
|
|
21
|
+
"install-deps.sh",
|
|
22
|
+
"node-enroll.sh",
|
|
23
|
+
"node-setup.sh",
|
|
24
|
+
"node-start.sh",
|
|
25
|
+
"node-stop.sh",
|
|
26
|
+
"node-upgrade.sh",
|
|
27
|
+
"pre-run.sh",
|
|
28
|
+
"promote-validator.sh"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"deploy": {
|
|
32
|
+
"source": "assets/deploy",
|
|
33
|
+
"target": "/root/deploy",
|
|
34
|
+
"dependsOn": [
|
|
35
|
+
"common"
|
|
36
|
+
],
|
|
37
|
+
"files": [
|
|
38
|
+
"10-prepare-host.sh",
|
|
39
|
+
"20-install-toolchain.sh",
|
|
40
|
+
"30-setup-node.sh",
|
|
41
|
+
"40-start-node.sh",
|
|
42
|
+
"50-verify.sh",
|
|
43
|
+
"60-enroll.sh",
|
|
44
|
+
"70-promote.sh",
|
|
45
|
+
"lib.sh"
|
|
46
|
+
],
|
|
47
|
+
"entrypoint": "assets/deploy/40-start-node.sh"
|
|
48
|
+
},
|
|
49
|
+
"migrate": {
|
|
50
|
+
"source": "assets/migrate",
|
|
51
|
+
"target": "/root/migrate",
|
|
52
|
+
"dependsOn": [
|
|
53
|
+
"common"
|
|
54
|
+
],
|
|
55
|
+
"files": [
|
|
56
|
+
"00-backup-identity.sh",
|
|
57
|
+
"01-prepare-target.sh",
|
|
58
|
+
"02-authorize-pull.sh",
|
|
59
|
+
"03-pull-state.sh",
|
|
60
|
+
"04-stop-source.sh",
|
|
61
|
+
"05-finalize-target.sh",
|
|
62
|
+
"06-start-target.sh",
|
|
63
|
+
"07-verify.sh",
|
|
64
|
+
"08-rollback.sh",
|
|
65
|
+
"lib.sh"
|
|
66
|
+
],
|
|
67
|
+
"entrypoint": "assets/migrate/03-pull-state.sh"
|
|
68
|
+
},
|
|
69
|
+
"manage": {
|
|
70
|
+
"source": "assets/manage",
|
|
71
|
+
"target": "/root/manage",
|
|
72
|
+
"dependsOn": [
|
|
73
|
+
"common"
|
|
74
|
+
],
|
|
75
|
+
"files": [
|
|
76
|
+
"10-bond-increase.sh",
|
|
77
|
+
"10-diagnose-node.sh",
|
|
78
|
+
"20-exit-validator.sh",
|
|
79
|
+
"25-recover-node.sh",
|
|
80
|
+
"30-status.sh",
|
|
81
|
+
"40-exit-withdraw.sh",
|
|
82
|
+
"bond_inc.sh",
|
|
83
|
+
"lib.sh"
|
|
84
|
+
],
|
|
85
|
+
"entrypoint": "assets/manage/30-status.sh"
|
|
86
|
+
},
|
|
87
|
+
"upgrade": {
|
|
88
|
+
"source": "assets/upgrade",
|
|
89
|
+
"target": "/root/upgrade",
|
|
90
|
+
"dependsOn": [
|
|
91
|
+
"common"
|
|
92
|
+
],
|
|
93
|
+
"files": [
|
|
94
|
+
"10-preflight.sh",
|
|
95
|
+
"20-upgrade.sh",
|
|
96
|
+
"30-manual-upgrade.sh",
|
|
97
|
+
"40-storage-prune.sh",
|
|
98
|
+
"50-status.sh",
|
|
99
|
+
"lib.sh"
|
|
100
|
+
],
|
|
101
|
+
"entrypoint": "assets/upgrade/20-upgrade.sh"
|
|
102
|
+
},
|
|
103
|
+
"dashboard_monitor": {
|
|
104
|
+
"source": "assets/manage/dashboard_monitor",
|
|
105
|
+
"target": "/root/dashboard",
|
|
106
|
+
"dependsOn": [],
|
|
107
|
+
"files": [
|
|
108
|
+
"app.js",
|
|
109
|
+
"assets/v2.2/css/base.css",
|
|
110
|
+
"assets/v2.2/css/components/content.css",
|
|
111
|
+
"assets/v2.2/css/components/controls.css",
|
|
112
|
+
"assets/v2.2/css/components/data.css",
|
|
113
|
+
"assets/v2.2/css/components/icons.css",
|
|
114
|
+
"assets/v2.2/css/components/motion.css",
|
|
115
|
+
"assets/v2.2/css/components/shell.css",
|
|
116
|
+
"assets/v2.2/css/components/sidebar.css",
|
|
117
|
+
"assets/v2.2/css/components/topbar.css",
|
|
118
|
+
"assets/v2.2/css/fonts.css",
|
|
119
|
+
"assets/v2.2/css/synteq-ui-v2.css",
|
|
120
|
+
"assets/v2.2/css/theme-dark.css",
|
|
121
|
+
"assets/v2.2/css/theme-light.css",
|
|
122
|
+
"assets/v2.2/css/tokens.css",
|
|
123
|
+
"assets/v2.2/fonts/GoogleSansCode-Medium.ttf",
|
|
124
|
+
"assets/v2.2/fonts/GoogleSansCode-Regular.ttf",
|
|
125
|
+
"assets/v2.2/fonts/GoogleSansCode-SemiBold.ttf",
|
|
126
|
+
"assets/v2.2/js/synteq-ui-v2.js",
|
|
127
|
+
"deploy-dashboard.sh",
|
|
128
|
+
"favicon.svg",
|
|
129
|
+
"index.html",
|
|
130
|
+
"nginx-octra.conf",
|
|
131
|
+
"octra-dashboard.service",
|
|
132
|
+
"octra-node-prune.cron",
|
|
133
|
+
"octra-node-prune.service",
|
|
134
|
+
"octra-node-prune.timer",
|
|
135
|
+
"prune-node-junk.sh",
|
|
136
|
+
"server.py",
|
|
137
|
+
"ssl-certbot.sh",
|
|
138
|
+
"styles.css"
|
|
139
|
+
],
|
|
140
|
+
"entrypoint": "assets/manage/dashboard_monitor/deploy-dashboard.sh"
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ===================================================================
|
|
3
|
+
# 00-backup-identity.sh — snapshot everything that cannot be recreated
|
|
4
|
+
#
|
|
5
|
+
# Run this on a node BEFORE anything destructive (migration switch, VM
|
|
6
|
+
# reinstall, disk swap). The archive is a few KB but it holds the only
|
|
7
|
+
# copy of the validator key that the bond is attached to.
|
|
8
|
+
#
|
|
9
|
+
# Contents:
|
|
10
|
+
# .keys/validator/{wallet.json,enrollment.json,node.env,network.env}
|
|
11
|
+
# devnet/{ready_to_vote.json,HEAD.json}
|
|
12
|
+
# a stat.sh snapshot (context at backup time)
|
|
13
|
+
#
|
|
14
|
+
# Usage:
|
|
15
|
+
# sudo bash 00-backup-identity.sh # → /root/migration/backups/
|
|
16
|
+
# sudo bash 00-backup-identity.sh /root/safe # custom destination
|
|
17
|
+
#
|
|
18
|
+
# Restore (on a freshly copied tree, same absolute paths):
|
|
19
|
+
# tar xzf octra-identity-*.tar.gz -C /
|
|
20
|
+
# ===================================================================
|
|
21
|
+
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
source "$(dirname "$0")/lib.sh"
|
|
24
|
+
|
|
25
|
+
require_root
|
|
26
|
+
|
|
27
|
+
DEST="${1:-${MIG_DIR}/backups}"
|
|
28
|
+
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
|
|
29
|
+
HOST=$(hostname)
|
|
30
|
+
OUT="${DEST}/octra-identity-${HOST}-${STAMP}.tar.gz"
|
|
31
|
+
|
|
32
|
+
mkdir -p "${DEST}"
|
|
33
|
+
|
|
34
|
+
KEY_DIR="${NODE_SRC_DIR}/.keys/validator"
|
|
35
|
+
[[ -f "${KEY_DIR}/wallet.json" ]] || die "wallet.json not found at ${KEY_DIR} — is this the node host?"
|
|
36
|
+
|
|
37
|
+
REL=()
|
|
38
|
+
for f in wallet.json enrollment.json node.env network.env node.env.pre-migration.bak; do
|
|
39
|
+
[[ -f "${KEY_DIR}/${f}" ]] && REL+=("${KEY_DIR#/}/${f}")
|
|
40
|
+
done
|
|
41
|
+
for f in ready_to_vote.json HEAD.json validator-control/last.json; do
|
|
42
|
+
[[ -f "${NODE_DATA_DIR}/${f}" ]] && REL+=("${NODE_DATA_DIR#/}/${f}")
|
|
43
|
+
done
|
|
44
|
+
(( ${#REL[@]} > 0 )) || die "no identity files found to archive"
|
|
45
|
+
|
|
46
|
+
# context snapshot (node may be stopped — node_stat tolerates that)
|
|
47
|
+
node_stat > "${DEST}/stat-${HOST}-${STAMP}.txt" 2>/dev/null || true
|
|
48
|
+
if [[ -f "${KEY_DIR}/wallet.json" ]]; then
|
|
49
|
+
{
|
|
50
|
+
echo "host = ${HOST}"
|
|
51
|
+
echo "taken_at = ${STAMP}"
|
|
52
|
+
echo "address = $(python3 -c 'import json,sys;print(json.load(open(sys.argv[1]))["address"])' "${KEY_DIR}/wallet.json" 2>/dev/null || echo unknown)"
|
|
53
|
+
echo "wallet_sha256 = $(sha256sum "${KEY_DIR}/wallet.json" | awk '{print $1}')"
|
|
54
|
+
} > "${DEST}/identity-${HOST}-${STAMP}.txt"
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
( cd / && tar czf "${OUT}" "${REL[@]}" )
|
|
58
|
+
chmod 600 "${OUT}"
|
|
59
|
+
sha256sum "${OUT}" | tee "${OUT}.sha256" >/dev/null
|
|
60
|
+
|
|
61
|
+
log "=== identity backup written ==="
|
|
62
|
+
log "archive : ${OUT} ($(du -h "${OUT}" | cut -f1))"
|
|
63
|
+
log "sha256 : $(awk '{print $1}' "${OUT}.sha256")"
|
|
64
|
+
log "files :"
|
|
65
|
+
tar tzf "${OUT}" | sed 's/^/ /'
|
|
66
|
+
|
|
67
|
+
set_status DONE "backup-identity" "${OUT}"
|