Skip to content

dash-spv: support Dash Core's devnet LLMQ routing overrides (-llmqchainlocks / -llmqinstantsenddip0024 / -llmqplatform) #785

@QuantumExplorer

Description

@QuantumExplorer

Background

PR #784 adds -llmqdevnetparams=<size>:<threshold> support, which faithfully mirrors Dash Core's flag of the same name. In Dash Core, that flag only adjusts the size/threshold of LLMQ_DEVNET (type 101) — confirmed in chainparams.cpp:

auto params = std::ranges::find_if(consensus.llmqs, [](const auto& llmq){
    return llmq.type == Consensus::LLMQType::LLMQ_DEVNET;});  // only 101

LLMQ_DEVNET_DIP0024 (105) and LLMQ_DEVNET_PLATFORM (107) keep their hardcoded defaults regardless of that flag.

The gap

Dash Core ships three companion flags that small devnets routinely rely on (declared in chainparams.cpp):

-llmqchainlocks=<quorum name>          (default: llmq_devnet)
-llmqinstantsenddip0024=<quorum name>  (default: llmq_devnet_dip0024)
-llmqplatform=<quorum name>            (default: llmq_devnet_platform)

These don't change a quorum's size — they change which LLMQ type fulfills each role. The typical small-devnet recipe is to shrink LLMQ_DEVNET (via -llmqdevnetparams) to fit the masternode count, then reroute ChainLocks / InstantSend DIP24 / Platform onto it, because the default 105/107 quorums (8 and 12 members) can't form on a small MN set.

In rust-dashcore today, the routing is hardcoded in dash/src/sml/llmq_type/network.rs:

fn is_llmq_type(&self) -> LLMQType { ... Network::Devnet => LlmqtypeDevnet, ... }
fn isd_llmq_type(&self) -> LLMQType { ... Network::Devnet => LlmqtypeDevnetDIP0024, ... }
fn chain_locks_type(&self) -> LLMQType { ... Network::Devnet => LlmqtypeDevnet, ... }
fn platform_type(&self) -> LLMQType { ... Network::Devnet => LlmqtypeDevnetPlatform, ... }

Consequence: an SPV client talking to a devnet started with, say, -llmqinstantsenddip0024=llmq_devnet will keep hunting for LlmqtypeDevnetDIP0024 quorums, find none, and silently fail to verify InstantSend locks. Same story for rerouted ChainLocks / Platform.

Proposed solution

Allow per-instance overrides of the four NetworkLLMQExt lookups on devnet, surfaced through ClientConfig and the CLI.

ClientConfig (dash-spv)

pub struct ClientConfig {
    // ...
    pub llmq_devnet_params: Option<LlmqDevnetParams>,         // already in PR #784
    pub llmq_chainlocks_type: Option<LLMQType>,                // new
    pub llmq_instantsend_dip0024_type: Option<LLMQType>,       // new
    pub llmq_platform_type: Option<LLMQType>,                  // new
    // (and a builder method for each — Devnet-only validation, same as llmq_devnet_params)
}

CLI (dash-spv binary)

--llmq-chainlocks=<quorum-name>
--llmq-instantsend-dip0024=<quorum-name>
--llmq-platform=<quorum-name>

Mirroring Dash Core's flag names. Quorum name strings should accept llmq_devnet, llmq_devnet_dip0024, llmq_devnet_platform at minimum (the set of LLMQ types valid on devnet).

Routing change

NetworkLLMQExt currently takes &self (a Network). The cleanest way to thread overrides through is to either:

  • Option A — add a NetworkLLMQContext { network: Network, overrides: DevnetRouting } and have callers use that instead of Network. Clean, but touches many call sites.
  • Option B — apply the same OnceLock global-override pattern PR feat: devnet support for dash-spv #784 introduced for LLMQ_DEVNET params: set_devnet_chainlocks_type(t), set_devnet_isd_type(t), set_devnet_platform_type(t). Smaller diff, idempotent contract is already established. Tradeoff: same process-global limitation as the existing override.

Option B is consistent with what's already there and probably the right pragmatic call.

Out of scope

  • Changes to mainnet/testnet/regtest routing — these flags are devnet-only in Dash Core.
  • Per-quorum size overrides beyond LLMQ_DEVNET — Dash Core itself doesn't expose those.

Acceptance criteria

  • CLI accepts the three flags; rejected on non-devnet networks
  • ClientConfig carries the overrides through to startup
  • chain_locks_type / isd_llmq_type / platform_type return the overridden values when set
  • enabled_llmq_types includes the overridden types
  • Unit tests cover override-set / override-unset / cross-network rejection
  • Existing PR feat: devnet support for dash-spv #784 test (test_llmq_devnet_override_lifecycle) stays green

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions