From 478b5a8ec9e377e6f4e941bfcc9747e81645844c Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 5 May 2026 18:25:07 +0700 Subject: [PATCH 1/3] feat(dashmate): expose BIP158 compact-filter index for the local preset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without `blockfilterindex=basic` and `peerblockfilters=1` in `dash.conf`, dashcore doesn't build the BIP158 cfilter index and doesn't advertise the NODE_COMPACT_FILTERS service bit. BIP157 SPV clients (e.g. the swift-sdk iOS example app pointed at `local_seed`) then fail mid-sync with `Protocol error: No peers support required capability` once headers land and the filter-header request goes out — the local cluster has no peer that can answer. Adds a new `core.compactFilters` boolean (off by default), threads it through the `dash.conf.dot` template, and flips it on in `getLocalConfigFactory.js` so fresh `dashmate setup local` runs ship with cfilters enabled. Mainnet / testnet / devnet keep the default off since the cfilter index is non-trivial disk + CPU on long chains and those operators rarely run BIP157 SPV against their nodes. Schema declares the field as optional (not in `required`) so existing configs validate without a migration; users on already-set-up local clusters can opt in by editing their `~/.dashmate/config.json` directly and restarting the seed (`dashmate config set` won't touch a path that isn't already populated). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../dashmate/configs/defaults/getBaseConfigFactory.js | 6 ++++++ .../configs/defaults/getLocalConfigFactory.js | 8 ++++++++ packages/dashmate/src/config/configJsonSchema.js | 7 +++++++ packages/dashmate/templates/core/dash.conf.dot | 11 +++++++++++ 4 files changed, 32 insertions(+) diff --git a/packages/dashmate/configs/defaults/getBaseConfigFactory.js b/packages/dashmate/configs/defaults/getBaseConfigFactory.js index 615381179b1..f1732d200b2 100644 --- a/packages/dashmate/configs/defaults/getBaseConfigFactory.js +++ b/packages/dashmate/configs/defaults/getBaseConfigFactory.js @@ -155,6 +155,12 @@ export default function getBaseConfigFactory() { }, }, indexes: [], + // BIP158 cfilter index + NODE_COMPACT_FILTERS service bit. + // Off by default — mainnet / testnet operators rarely want + // the disk + CPU overhead of the cfilter index. The `local` + // preset overrides this to `true` so dev SPV clients can + // sync filters against dashmate's seed node. + compactFilters: false, }, platform: { quorumList: { diff --git a/packages/dashmate/configs/defaults/getLocalConfigFactory.js b/packages/dashmate/configs/defaults/getLocalConfigFactory.js index 409c36b1cee..da252443ab0 100644 --- a/packages/dashmate/configs/defaults/getLocalConfigFactory.js +++ b/packages/dashmate/configs/defaults/getLocalConfigFactory.js @@ -36,6 +36,14 @@ export default function getLocalConfigFactory(getBaseConfig) { zmq: { port: 49998, }, + // Build the BIP158 cfilter index and advertise + // NODE_COMPACT_FILTERS to peers so BIP157 SPV clients + // (e.g. the swift-sdk iOS example app pointed at + // `local_seed`) can sync filter headers + filters against + // the local cluster. Local-only — other presets keep this + // off to avoid the disk + CPU overhead of the cfilter + // index on long mainnet/testnet chains. + compactFilters: true, }, dashmate: { helper: { diff --git a/packages/dashmate/src/config/configJsonSchema.js b/packages/dashmate/src/config/configJsonSchema.js index 3b53f61a5b2..7964f31ef23 100644 --- a/packages/dashmate/src/config/configJsonSchema.js +++ b/packages/dashmate/src/config/configJsonSchema.js @@ -487,6 +487,13 @@ export default { description: 'List of core indexes to enable. `platform.enable`, ' + ' `core.masternode.enable`, and `core.insight.enabled` add indexes dynamically', }, + compactFilters: { + type: 'boolean', + description: 'Build the BIP158 cfilter index and advertise ' + + 'NODE_COMPACT_FILTERS to peers, so BIP157 SPV clients can sync ' + + 'filter headers + filters from this node. Defaults to false; ' + + 'enabled by the local preset for the dev SPV flow.', + }, }, required: ['docker', 'p2p', 'rpc', 'zmq', 'spork', 'masternode', 'miner', 'devnet', 'log', 'indexes', 'insight'], diff --git a/packages/dashmate/templates/core/dash.conf.dot b/packages/dashmate/templates/core/dash.conf.dot index c07f8f18cba..c86b84bcccd 100644 --- a/packages/dashmate/templates/core/dash.conf.dot +++ b/packages/dashmate/templates/core/dash.conf.dot @@ -69,6 +69,17 @@ spentindex=1 {{~}} {{?}} +# BIP157/158 compact block filters. Building the cfilter index plus +# advertising NODE_COMPACT_FILTERS lets BIP157 SPV clients sync +# headers + filters from this node. Off by default (mainnet/testnet +# usage doesn't justify the disk + CPU overhead); enabled on the +# `local` preset where the chain is tiny and the iOS dev flow needs +# filter sync against dashmate's `local_seed` to test the wallet. +{{? it.core.compactFilters }} +blockfilterindex=basic +peerblockfilters=1 +{{?}} + # ZeroMQ notifications zmqpubrawtx=tcp://0.0.0.0:{{=it.core.zmq.port}} zmqpubrawtxlock=tcp://0.0.0.0:{{=it.core.zmq.port}} From df3978856bfe360b706bd0f529f5449ade96d530 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 5 May 2026 18:28:24 +0700 Subject: [PATCH 2/3] feat(dashmate): default compactFilters to true on every preset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flips `core.compactFilters` to true in `getBaseConfigFactory.js` so every dashmate-managed node — mainnet, testnet, devnet, local — ships with the BIP158 cfilter index built and NODE_COMPACT_FILTERS advertised out of the box. Operators who can't spare the disk overhead can opt out via `dashmate config set core.compactFilters false`. The explicit `compactFilters: true` on the local factory stays as self-documenting belt-and-suspenders for the dev SPV flow against `local_seed` — the local preset is the canonical surface where the flag has to be on, and keeping it explicit insulates that case from any future flip of the base default. Comment updated accordingly. Schema description updated to match the new defaults-true semantics. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../configs/defaults/getBaseConfigFactory.js | 11 ++++++----- .../configs/defaults/getLocalConfigFactory.js | 14 +++++++------- packages/dashmate/src/config/configJsonSchema.js | 5 +++-- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/dashmate/configs/defaults/getBaseConfigFactory.js b/packages/dashmate/configs/defaults/getBaseConfigFactory.js index f1732d200b2..e21b2111e88 100644 --- a/packages/dashmate/configs/defaults/getBaseConfigFactory.js +++ b/packages/dashmate/configs/defaults/getBaseConfigFactory.js @@ -156,11 +156,12 @@ export default function getBaseConfigFactory() { }, indexes: [], // BIP158 cfilter index + NODE_COMPACT_FILTERS service bit. - // Off by default — mainnet / testnet operators rarely want - // the disk + CPU overhead of the cfilter index. The `local` - // preset overrides this to `true` so dev SPV clients can - // sync filters against dashmate's seed node. - compactFilters: false, + // Default-on across every preset so dashmate-managed nodes + // are BIP157 SPV-friendly out of the box. Operators who + // can't spare the cfilter index disk overhead (~10% of + // chain size on mainnet) can flip this off via + // `dashmate config set core.compactFilters false`. + compactFilters: true, }, platform: { quorumList: { diff --git a/packages/dashmate/configs/defaults/getLocalConfigFactory.js b/packages/dashmate/configs/defaults/getLocalConfigFactory.js index da252443ab0..9c9120b345f 100644 --- a/packages/dashmate/configs/defaults/getLocalConfigFactory.js +++ b/packages/dashmate/configs/defaults/getLocalConfigFactory.js @@ -36,13 +36,13 @@ export default function getLocalConfigFactory(getBaseConfig) { zmq: { port: 49998, }, - // Build the BIP158 cfilter index and advertise - // NODE_COMPACT_FILTERS to peers so BIP157 SPV clients - // (e.g. the swift-sdk iOS example app pointed at - // `local_seed`) can sync filter headers + filters against - // the local cluster. Local-only — other presets keep this - // off to avoid the disk + CPU overhead of the cfilter - // index on long mainnet/testnet chains. + // Mirrors the `core.compactFilters: true` set on the base + // config; restated explicitly here because the local + // preset is the canonical surface where dev BIP157 SPV + // clients (e.g. the swift-sdk iOS example app pointed at + // `local_seed`) need cfilter sync to work, and we want + // that requirement to survive any future flip of the base + // default. compactFilters: true, }, dashmate: { diff --git a/packages/dashmate/src/config/configJsonSchema.js b/packages/dashmate/src/config/configJsonSchema.js index 7964f31ef23..ecf969bde64 100644 --- a/packages/dashmate/src/config/configJsonSchema.js +++ b/packages/dashmate/src/config/configJsonSchema.js @@ -491,8 +491,9 @@ export default { type: 'boolean', description: 'Build the BIP158 cfilter index and advertise ' + 'NODE_COMPACT_FILTERS to peers, so BIP157 SPV clients can sync ' - + 'filter headers + filters from this node. Defaults to false; ' - + 'enabled by the local preset for the dev SPV flow.', + + 'filter headers + filters from this node. Defaults to true on ' + + 'every preset; flip to false to skip the cfilter index ' + + '(~10% chain-size disk overhead on mainnet).', }, }, required: ['docker', 'p2p', 'rpc', 'zmq', 'spork', 'masternode', 'miner', 'devnet', 'log', From 0d5e69682a08d2e1177cd84de70684006ba6a8d9 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 5 May 2026 18:30:06 +0700 Subject: [PATCH 3/3] feat(dashmate): backfill compactFilters=true in the 3.1.0 migration Pre-3.1.0 configs predate the `core.compactFilters` field entirely (the template emitted nothing, dashcore left the cfilter index off), so a config that hits the 3.1.0 migration step always inherited the old implicit-off default rather than opting out explicitly. The base factory now ships `compactFilters: true`; this migration brings every already-set-up cluster up to that line, so the iOS BIP157 SPV flow against `local_seed` (and any other dashmate node) starts working on upgrade without the user having to hand-edit `~/.dashmate/config.json`. Set early in the per-config `forEach`, before the existing non-testnet/non-local early return, so it applies to mainnet / testnet / devnet / local uniformly. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../configs/getConfigFileMigrationsFactory.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/dashmate/configs/getConfigFileMigrationsFactory.js b/packages/dashmate/configs/getConfigFileMigrationsFactory.js index a8d6018cb5e..adaa072685d 100644 --- a/packages/dashmate/configs/getConfigFileMigrationsFactory.js +++ b/packages/dashmate/configs/getConfigFileMigrationsFactory.js @@ -1413,6 +1413,20 @@ export default function getConfigFileMigrationsFactory(homeDir, defaultConfigs) const isLocal = options.network === NETWORK_LOCAL || name === 'local'; const isTestnet = options.network === NETWORK_TESTNET || name === 'testnet'; + // Flip `core.compactFilters` to true for every config — + // pre-3.1.0 configs predate the field entirely (template + // emitted nothing, dashcore left the cfilter index off), + // so a missing-or-false value here always means + // "inherited the old implicit-off default" rather than + // "user explicitly opted out". The base config now + // ships with this flag on; this backfill brings every + // already-set-up cluster up to that line so the iOS + // BIP157 SPV flow against `local_seed` (and any other + // dashmate node) works without manual editing. + if (options.core) { + options.core.compactFilters = true; + } + if (options.platform?.drive?.tenderdash?.docker && defaultConfig.has('platform.drive.tenderdash.docker.image')) { options.platform.drive.tenderdash.docker.image = defaultConfig