Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5223312
feat(dash-spv-bench): minimal single-scenario sync benchmark
ZocoLini Jun 22, 2026
d08aae3
refactor(dash-spv): refactor network module
ZocoLini Jul 11, 2026
55b40e0
wiring
ZocoLini Jul 15, 2026
fed5b64
dash-spv-bench extra features
ZocoLini Jul 16, 2026
f4591f3
dash spv storage versioning
ZocoLini Jul 16, 2026
ab97c54
drop peer storage until a new one adjusted to the changes is written
ZocoLini Jul 16, 2026
515886c
removed mem and perf signals
ZocoLini Jul 16, 2026
5ded5d3
correctly read tip at sync start
ZocoLini Jul 16, 2026
5ab5fa8
Merge branch 'dev' into refactor/network-mod
ZocoLini Jul 16, 2026
3e4fa1c
fix(dash-spv): stop infinite filter rescan when wallet birth is below…
ZocoLini Jul 16, 2026
e6b667c
fix(dash-spv): start filter bodies at the first verifiable height on …
ZocoLini Jul 16, 2026
c23c2ed
fix(dash-spv): drain in-flight requests before retiring displaced peers
ZocoLini Jul 16, 2026
c42dabd
chore(dash-spv-bench): bump indicatif 0.17 -> 0.18 to drop unmaintain…
ZocoLini Jul 16, 2026
96c796d
ci: include dash-spv-bench in the excluded ci group
ZocoLini Jul 16, 2026
a976adc
fix(dash-spv): keep internal impl guidance off the public SyncManager…
ZocoLini Jul 16, 2026
6cd7aae
refactor(dash-spv): network manager cares about download coordination…
ZocoLini Jul 16, 2026
4b918a6
feat(dash-spv): per-peer request dyn limit
ZocoLini Jul 17, 2026
4c83af3
fix: run.sh works on macOS in theory
ZocoLini Jul 17, 2026
a24bc53
fix(dash-spv): reject peers with missing services
ZocoLini Jul 17, 2026
e2c6952
timeout per iveness
ZocoLini Jul 17, 2026
210243c
hope this works
ZocoLini Jul 17, 2026
e69cbd7
drop the task that connected th cliento to more peers udner pressure
ZocoLini Jul 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/ci-groups.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ excluded:
- dash-fuzz # Honggfuzz binary targets, tested by fuzz.yml
- masternode-seeds-fetcher # Tooling binary; needs live dashd RPC, exercised by update-masternode-seeds.yml
- git-state # Compile-time proc-macro with no tests, exercised via dash-spv
- dash-spv-bench # Benchmarking binary
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["dash", "dash-network", "hashes", "internals", "fuzz", "rpc-client", "rpc-json", "rpc-integration-test", "key-wallet", "key-wallet-manager", "key-wallet-ffi", "dash-spv", "dash-spv-ffi", "git-state", "dash-network-seeds", "masternode-seeds-fetcher"]
members = ["dash", "dash-network", "hashes", "internals", "fuzz", "rpc-client", "rpc-json", "rpc-integration-test", "key-wallet", "key-wallet-manager", "key-wallet-ffi", "dash-spv", "dash-spv-ffi", "git-state", "dash-network-seeds", "masternode-seeds-fetcher", "dash-spv-bench"]
resolver = "2"

[workspace.package]
Expand Down
21 changes: 21 additions & 0 deletions dash-spv-bench/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
bench-results/
bench-storage/
profiles/

*.lock

# Local bench config (copied from .env.example).
.env

# Persistent testnet chain snapshot grown by snapshot-chain.sh (multi-GB; never committed).
chain-data/

# Transient per-peer CoW clones created by run.sh + the file that remembers their dir.
.bench-clones.*
.clonedir

# Scenario matrix outputs (bench-scenarios.sh): generated reports/logs/compose, and the
# bootstrapped yq binary. Reports are meant to be copied out, not committed.
.scenario.*.yml
results/
.bin/
25 changes: 25 additions & 0 deletions dash-spv-bench/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "dash-spv-bench"
version = { workspace = true }
edition = "2021"
license = "MIT"
publish = false

[dependencies]
dash-spv = { path = "../dash-spv" }
dashcore = { path = "../dash", features = ["serde", "core-block-hash-use-x11", "message_verification", "bls", "quorum_validation"] }
key-wallet = { path = "../key-wallet" }
key-wallet-manager = { path = "../key-wallet-manager", features = ["parallel-filters"] }

tokio = { version = "1.0", features = ["full"] }

anyhow = "1.0"
tempfile = "3.0"

tracing = "0.1"
tracing-subscriber = { version = "0.3.20", features = ["env-filter"] }
indicatif = "0.18"

[[bin]]
name = "dash-spv-bench"
path = "src/main.rs"
23 changes: 23 additions & 0 deletions dash-spv-bench/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM debian:bookworm-slim

ARG DASHVERSION=23.1.4

RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl iproute2 \
&& rm -rf /var/lib/apt/lists/*

# Download the Linux dashd matching the host CPU arch (amd64 -> x86_64, arm64 -> aarch64),
# keeping the same release used by contrib/setup-dashd.py.
RUN set -eux; \
arch="$(dpkg --print-architecture)"; \
case "$arch" in \
amd64) dlarch=x86_64 ;; \
arm64) dlarch=aarch64 ;; \
*) echo "unsupported arch $arch" >&2; exit 1 ;; \
esac; \
url="https://github.com/dashpay/dash/releases/download/v${DASHVERSION}/dashcore-${DASHVERSION}-${dlarch}-linux-gnu.tar.gz"; \
curl -fsSL "$url" -o /tmp/dashcore.tgz; \
tar -xzf /tmp/dashcore.tgz -C /tmp; \
cp "/tmp/dashcore-${DASHVERSION}/bin/dashd" /usr/local/bin/dashd; \
rm -rf /tmp/dashcore*; \
dashd --version | head -1
88 changes: 88 additions & 0 deletions dash-spv-bench/bench-scenarios.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/bin/bash
#
# dash-spv-bench scenario matrix (LOCAL mode only).
#
# ./bench-scenarios.sh [-d scenarios]
#
# Thin loop over scenario files: for each scenarios/*.yml it calls `run.sh scenario <file>`
# once per its `repeats:` count, captures the timings run.sh prints, and writes an organized
# Markdown report (median over repeats). All the real work — compose generation, bring-up,
# CPU pinning, teardown — lives in run.sh; this only orchestrates and aggregates.
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
cd "${SCRIPT_DIR}"

SCN_DIR="${SCRIPT_DIR}/scenarios"
RUN_CMD="${RUN_CMD:-${SCRIPT_DIR}/run.sh}" # overridable for testing the loop without docker
while [ $# -gt 0 ]; do
case "$1" in
-d | --dir) SCN_DIR="$2"; shift 2 ;;
-h | --help) sed -n '3,10p' "$0"; exit 0 ;;
*) echo "unknown arg: $1" >&2; exit 1 ;;
esac
done

shopt -s nullglob
FILES=("${SCN_DIR}"/*.yml)
[ "${#FILES[@]}" -gt 0 ] || { echo "Error: no scenarios (*.yml) in ${SCN_DIR}" >&2; exit 1; }

RUN_TS="$(date +%Y%m%d-%H%M%S)"
OUT_DIR="${SCRIPT_DIR}/results/${RUN_TS}"
mkdir -p "${OUT_DIR}"
REPORT="${OUT_DIR}/report.md"
TSV="${OUT_DIR}/results.tsv"
: >"${TSV}"

metric() { awk -F':[[:space:]]*' -v k="$2" '$1==k {gsub(/[[:space:]]+$/,"",$2); print $2; exit}' "$1"; }
median() { sort -n | awk '{a[NR]=$1} END{if(NR==0){print"-";exit} print (NR%2)?a[(NR+1)/2]:int((a[NR/2]+a[NR/2+1])/2)}'; }

for f in "${FILES[@]}"; do
name="$(basename "${f}" .yml)"
repeats="$(awk '/^repeats:/{print $2; exit}' "${f}")"; repeats="${repeats:-1}"
echo "===== scenario '${name}' × ${repeats} ====="
for r in $(seq 1 "${repeats}"); do
echo "-- ${name} repeat ${r}/${repeats}"
log="${OUT_DIR}/${name}.r${r}.log"
"${RUN_CMD}" "${f}" >"${log}" 2>&1 || echo " (run.sh exited non-zero; see ${log})"

# Scenario metadata comes straight from run.sh's own echo lines, so we never re-parse the YAML.
meta="$(grep -m1 "==> scenario '" "${log}" || true)"
cpus="$(sed -n "s/.*cpus=\([^,]*\),.*/\1/p" <<<"${meta}")"
blocks="$(sed -n "s/.*blocks=\([0-9]*\).*/\1/p" <<<"${meta}")"
peers="$(sed -n "s/.*\[\(.*\)\], cpus=.*/\1/p" <<<"${meta}")"
desc="$(grep -m1 "==> description:" "${log}" | sed 's/.*==> description: //' || true)"

printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
"${name}" "${cpus}" "${blocks}" "${peers}" "${r}" \
"$(metric "${log}" completed)" "$(metric "${log}" total_ms)" \
"$(metric "${log}" block_headers_ms)" "$(metric "${log}" filter_headers_ms)" \
"$(metric "${log}" filters_ms)" "$(metric "${log}" filter_hdr_lag_ms)" "${desc}" \
>>"${TSV}"
done
done

# --- report ---------------------------------------------------------------------------------
{
echo "# dash-spv-bench scenario report"
echo
echo "- **Date:** $(date -u '+%Y-%m-%d %H:%M:%SZ')"
echo "- **Host:** $(nproc) cores — $(grep -m1 'model name' /proc/cpuinfo 2>/dev/null | cut -d: -f2 | sed 's/^ //' || uname -m)"
echo "- **git:** $(git -C "${REPO_ROOT}" rev-parse --abbrev-ref HEAD 2>/dev/null)@$(git -C "${REPO_ROOT}" rev-parse --short HEAD 2>/dev/null)"
echo "- **Scenarios:** \`$(basename "${SCN_DIR}")/\` (${#FILES[@]} files)"
echo
echo "Timings are the **median** over each scenario's repeats (ms)."
echo
echo "| scenario | description | cpus | blocks | peers | completed | total | block_hdrs | filter_hdrs | filters | fh_lag |"
echo "|---|---|---|---|---|---|---|---|---|---|---|"
for name in $(cut -f1 "${TSV}" | awk '!seen[$0]++'); do
row() { awk -F'\t' -v n="${name}" '$1==n{print $'"$1"'; exit}' "${TSV}"; }
med() { awk -F'\t' -v n="${name}" '$1==n && $'"$1"'!="" && $'"$1"'!="-"{print $'"$1"'}' "${TSV}" | median; }
echo "| ${name} | $(row 12) | $(row 2) | $(row 3) | $(row 4) | $(row 6) | $(med 7) | $(med 8) | $(med 9) | $(med 10) | $(med 11) |"
done
echo
echo "Raw per-repeat data: \`results.tsv\`; per-run logs alongside this report."
} >"${REPORT}"

echo "==> wrote ${REPORT}"
Loading
Loading