Improve small-network sync and build safety

This commit is contained in:
root
2026-05-02 07:07:02 +00:00
parent 83e0085a60
commit 37e006a65f
2 changed files with 247 additions and 4 deletions
+198 -2
View File
@@ -7,6 +7,10 @@ HOST_WIN64="${HOST_WIN64:-x86_64-w64-mingw32}"
MENU_CHOICE="${AGRARIAN_MENU_CHOICE:-}"
ROOT=""
DAEMON_WAS_RUNNING=0
DAEMON_RESTART_MODE=""
DAEMON_RESTART_CMD=()
DAEMON_SYSTEMD_SERVICE=""
detect_script_branch() {
local script_dir
@@ -91,6 +95,192 @@ confirm() {
[[ "$answer" == "y" || "$answer" == "Y" || "$answer" == "yes" || "$answer" == "YES" ]]
}
process_pids() {
local name="$1"
pgrep -u "$(id -u)" -x "$name" 2>/dev/null || true
}
all_process_pids() {
local name="$1"
pgrep -x "$name" 2>/dev/null || true
}
other_user_process_pids() {
local name="$1"
local pid owner current_user
current_user="$(id -un)"
while IFS= read -r pid; do
[[ -n "$pid" ]] || continue
owner="$(ps -o user= -p "$pid" 2>/dev/null | awk '{print $1}')"
[[ -n "$owner" && "$owner" != "$current_user" ]] && printf '%s %s\n' "$pid" "$owner"
done < <(all_process_pids "$name")
}
process_cmdline() {
local pid="$1"
tr '\0' '\n' < "/proc/$pid/cmdline" 2>/dev/null || true
}
daemon_cli_path() {
if [[ -x "$ROOT/src/agrarian-cli" ]]; then
echo "$ROOT/src/agrarian-cli"
elif has_cmd agrarian-cli; then
command -v agrarian-cli
else
return 1
fi
}
daemon_args_from_cmdline() {
local pid="$1"
local arg
while IFS= read -r arg; do
case "$arg" in
-conf=*|-datadir=*|-testnet|-regtest)
printf '%s\n' "$arg"
;;
esac
done < <(process_cmdline "$pid")
}
remember_daemon_restart() {
local pid="$1"
local arg exe
DAEMON_RESTART_MODE="command"
DAEMON_RESTART_CMD=()
exe="$(readlink -f "/proc/$pid/exe" 2>/dev/null || true)"
[[ -n "$exe" ]] || exe="$ROOT/src/agrariand"
DAEMON_RESTART_CMD+=("$exe")
while IFS= read -r arg; do
DAEMON_RESTART_CMD+=("$arg")
done < <(daemon_args_from_cmdline "$pid")
case " ${DAEMON_RESTART_CMD[*]} " in
*" -daemon "*) ;;
*) DAEMON_RESTART_CMD+=("-daemon") ;;
esac
}
active_user_daemon_service() {
has_cmd systemctl || return 1
systemctl --user is-active --quiet agrariand.service 2>/dev/null || return 1
echo "agrariand.service"
}
stop_running_daemon() {
local pids pid cli args=() service
pids="$(process_pids agrariand)"
[[ -n "$pids" ]] || return 0
DAEMON_WAS_RUNNING=1
service="$(active_user_daemon_service || true)"
if [[ -n "$service" ]]; then
DAEMON_RESTART_MODE="systemd"
DAEMON_SYSTEMD_SERVICE="$service"
echo "Detected running user service: $service"
else
pid="$(printf '%s\n' "$pids" | head -n 1)"
remember_daemon_restart "$pid"
echo "Detected running agrariand process: $pid"
fi
if ! confirm "Stop agrariand gracefully before building?"; then
fail "Refusing to build while agrariand is running."
fi
if [[ "$DAEMON_RESTART_MODE" == "systemd" ]]; then
systemctl --user stop "$DAEMON_SYSTEMD_SERVICE"
else
pid="$(printf '%s\n' "$pids" | head -n 1)"
cli="$(daemon_cli_path)" || fail "agrarian-cli is required to stop the running daemon gracefully."
mapfile -t args < <(daemon_args_from_cmdline "$pid")
"$cli" "${args[@]}" stop
fi
local waited=0
while [[ -n "$(process_pids agrariand)" && "$waited" -lt 120 ]]; do
sleep 1
waited=$((waited + 1))
done
[[ -z "$(process_pids agrariand)" ]] || fail "agrariand did not stop within 120 seconds. Build was not started."
}
stop_running_qt_wallet() {
local pids
pids="$(process_pids agrarian-qt)"
[[ -n "$pids" ]] || return 0
cat >&2 <<EOF
Detected a running Agrarian Qt wallet for the current user:
$pids
For wallet safety, this script will not force-close the GUI wallet. Close the
wallet normally and wait for it to finish shutting down before the build starts.
EOF
while [[ -n "$(process_pids agrarian-qt)" ]]; do
if ! confirm "I have closed agrarian-qt; check again?"; then
fail "Refusing to build while agrarian-qt is running."
fi
done
}
prepare_running_processes_for_build() {
local other
other="$(other_user_process_pids agrarian-qt)"
[[ -z "$other" ]] || fail "agrarian-qt is running under another user. Stop it before building: $other"
other="$(other_user_process_pids agrariand)"
[[ -z "$other" ]] || fail "agrariand is running under another user. Stop it before building: $other"
stop_running_qt_wallet
stop_running_daemon
}
restart_previous_daemon() {
[[ "$DAEMON_WAS_RUNNING" == "1" ]] || return 0
if [[ -n "$(process_pids agrariand)" ]]; then
echo "agrariand is already running."
return 0
fi
if ! confirm "Restart agrariand now using the previous startup method?"; then
echo "agrariand was running before the build and is currently stopped."
return 0
fi
if [[ "$DAEMON_RESTART_MODE" == "systemd" ]]; then
if [[ "$MENU_CHOICE" == "linux-daemon" || "$MENU_CHOICE" == "linux-qt" ]]; then
mkdir -p "$HOME/.local/bin"
[[ -x "$ROOT/src/agrariand" ]] && install -m 0755 "$ROOT/src/agrariand" "$HOME/.local/bin/agrariand"
[[ -x "$ROOT/src/agrarian-cli" ]] && install -m 0755 "$ROOT/src/agrarian-cli" "$HOME/.local/bin/agrarian-cli"
fi
systemctl --user start "$DAEMON_SYSTEMD_SERVICE"
elif [[ "${#DAEMON_RESTART_CMD[@]}" -gt 0 ]]; then
"${DAEMON_RESTART_CMD[@]}"
else
fail "Could not determine how to restart agrariand."
fi
sleep 5
if [[ -n "$(process_pids agrariand)" ]]; then
echo "agrariand restarted."
else
fail "agrariand did not appear to restart."
fi
}
select_target() {
if [[ -n "$MENU_CHOICE" ]]; then
return 0
@@ -448,7 +638,9 @@ show_completion() {
echo " $ROOT/src/agrariand"
echo " $ROOT/src/agrarian-cli"
echo " $ROOT/src/agrarian-tx"
if confirm "Start agrariand now and enable automatic start at boot for the current user?"; then
if [[ "$DAEMON_WAS_RUNNING" == "1" ]]; then
echo "agrariand was running before the build and has been handled by the restart step."
elif confirm "Start agrariand now and enable automatic start at boot for the current user?"; then
install_user_daemon_service
else
echo "Start manually with: $ROOT/src/agrariand -daemon"
@@ -459,7 +651,9 @@ show_completion() {
echo " $ROOT/src/qt/agrarian-qt"
echo " $ROOT/src/agrariand"
echo " $ROOT/src/agrarian-cli"
if confirm "Start agrariand now and enable automatic start at boot for the current user?"; then
if [[ "$DAEMON_WAS_RUNNING" == "1" ]]; then
echo "agrariand was running before the build and has been handled by the restart step."
elif confirm "Start agrariand now and enable automatic start at boot for the current user?"; then
install_user_daemon_service
fi
;;
@@ -496,7 +690,9 @@ main() {
ensure_repo
reexec_from_checkout
run_step 40 "Installing required Ubuntu packages" install_packages
run_step 43 "Preparing running Agrarian processes" prepare_running_processes_for_build
build_selected
restart_previous_daemon
show_completion
}
+49 -2
View File
@@ -240,7 +240,7 @@ void CMasternodeSync::Process()
/*
Resync if we lose all masternodes from sleep/wake or failure to sync originally
*/
if (mnodeman.CountEnabled() == 0) {
if (mnodeman.CountEnabled() == 0 && IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) {
Reset();
} else
return;
@@ -261,6 +261,49 @@ void CMasternodeSync::Process()
if (Params().NetworkID() != CBaseChainParams::REGTEST &&
!IsBlockchainSynced() && RequestedMasternodeAssets > MASTERNODE_SYNC_SPORKS) return;
// Small networks can have every connected peer marked fulfilled before an
// empty masternode stage reaches its per-peer timeout check. Advance empty
// stages here so staking is not blocked forever on networks with no
// masternodes, winners, or budgets.
if (GetTime() - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5) {
if (RequestedMasternodeAssets == MASTERNODE_SYNC_SPORKS) {
GetNextAsset();
return;
}
if (RequestedMasternodeAssets == MASTERNODE_SYNC_LIST && lastMasternodeList == 0) {
if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) {
LogPrintf("CMasternodeSync::Process - ERROR - Sync has failed, will retry later\n");
RequestedMasternodeAssets = MASTERNODE_SYNC_FAILED;
RequestedMasternodeAttempt = 0;
lastFailure = GetTime();
nCountFailures++;
} else {
GetNextAsset();
}
return;
}
if (RequestedMasternodeAssets == MASTERNODE_SYNC_MNW && lastMasternodeWinner == 0) {
if (IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) {
LogPrintf("CMasternodeSync::Process - ERROR - Sync has failed, will retry later\n");
RequestedMasternodeAssets = MASTERNODE_SYNC_FAILED;
RequestedMasternodeAttempt = 0;
lastFailure = GetTime();
nCountFailures++;
} else {
GetNextAsset();
}
return;
}
if (RequestedMasternodeAssets == MASTERNODE_SYNC_BUDGET && lastBudgetItem == 0) {
GetNextAsset();
activeMasternode.ManageStatus();
return;
}
}
TRY_LOCK(cs_vNodes, lockRecv);
if (!lockRecv) return;
@@ -284,11 +327,15 @@ void CMasternodeSync::Process()
//set to synced
if (RequestedMasternodeAssets == MASTERNODE_SYNC_SPORKS) {
if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD) {
GetNextAsset();
return;
}
if (pnode->HasFulfilledRequest("getspork")) continue;
pnode->FulfilledRequest("getspork");
pnode->PushMessage("getsporks"); //get current network sporks
if (RequestedMasternodeAttempt >= 2) GetNextAsset();
RequestedMasternodeAttempt++;
return;