Skip to content
Open
Changes from all commits
Commits
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
166 changes: 166 additions & 0 deletions dip-johnnylaw-dandelion-spv.mediawiki
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<pre>
DIP: ?
Title: Dandelion++ Stem Submission for SPV Clients
Author: JohnnyLawDGB <johnnylaw2021@protonmail.com>
Comments-Summary: No comments yet.
Comments-URI: https://github.com/DigiByte-Core/dips/wiki/Comments:DIP-XXXX
Status: Draft
Type: Standards Track
Created: 2026-03-22
License: BSD-2-Clause
</pre>

==Abstract==

This DIP proposes an extension to DigiByte's Dandelion++ transaction relay protocol that allows Simplified Payment Verification (SPV) and lightweight wallet clients to submit transactions into the stem phase. Currently, Dandelion++ only routes locally-originated full-node transactions through the stem phase. Transactions received from SPV peers bypass the stempool and enter normal diffusion relay, negating privacy benefits for the growing mobile wallet user base. This proposal introduces a lightweight handshake negotiation and rate-limited acceptance path enabling full nodes to route SPV-submitted transactions through existing Dandelion++ stem machinery.

==Copyright==

This DIP is licensed under the BSD 2-clause license.

==Motivation==

DigiByte is one of very few production blockchains shipping Dandelion++ (enabled by default since v8.22). This represents a significant privacy advantage over Bitcoin, Litecoin, and Dogecoin. However, this advantage currently benefits only full-node operators.

SPV wallets connect to a small number of full nodes and submit transactions directly. The receiving full node — and any network observer monitoring that node's connections — can trivially determine which IP address originated a given transaction. The wallet user's real-world identity becomes linkable to their on-chain activity through their IP address alone.

With DigiByte's 15-second block time and active mobile wallet ecosystem, this gap disproportionately affects DigiByte compared to slower chains where users are more likely to run full nodes. As mobile adoption grows, an increasing majority of DigiByte users gain zero benefit from the Dandelion++ infrastructure that full nodes are already maintaining.

Extending Dandelion++ to SPV clients would make DigiByte the first UTXO-chain cryptocurrency to offer stem-phase transaction privacy to lightweight wallet users — a meaningful differentiation in the privacy landscape.

==Specification==

===Overview===

This proposal makes two changes to the existing Dandelion++ implementation:

# A new handshake message pair (<code>dandelionsubmit</code> / <code>dandelionack</code>) allowing SPV clients to negotiate stem submission capability with connected full nodes.
# Modified transaction acceptance logic allowing full nodes to route transactions received from negotiated SPV peers into the stempool rather than the regular mempool.

No changes are made to the stem relay, fluff transition, embargo, or epoch shuffling mechanisms.

===Handshake Negotiation===

After the standard version/verack handshake, an SPV client that wishes to use stem submission sends a <code>dandelionsubmit</code> message with the following payload:

{|
! Field !! Size !! Description
|-
| version || 1 byte || Protocol version for this extension (initially <code>0x01</code>)
|}

If the full node supports SPV stem submission and is willing to accept it, it responds with a <code>dandelionack</code> message with the following payload:

{|
! Field !! Size !! Description
|-
| version || 1 byte || Accepted protocol version
|-
| max_rate || 2 bytes || Maximum stem submissions accepted per epoch (uint16, little-endian)
|}

If the full node does not support this extension, it ignores the <code>dandelionsubmit</code> message. Per existing DigiByte Core behavior, unknown messages generate only debug-level log entries and do not trigger peer disconnection or misbehavior scoring.

If the SPV client does not receive a <code>dandelionack</code> within 30 seconds, it falls back to standard <code>MSG_TX</code> submission for that peer.

===Transaction Submission===

Once negotiation succeeds, the SPV client submits transactions using the existing <code>MSG_DANDELION_TX</code> (type 5) or <code>MSG_DANDELION_WITNESS_TX</code> inventory types, followed by delivery via the existing <code>dandeliontx</code> message upon <code>getdata</code> request.

The full node processes these transactions as follows:

# Validate the transaction through standard validation (signature verification, input availability, fee checks, script validation).
# If valid, accept the transaction into the stempool via <code>AcceptToMemoryPoolForStempool()</code>.
# Set an embargo timer using the same parameters as locally-originated transactions (<code>DANDELION_EMBARGO_MINIMUM</code> + <code>PoissonNextSend(DANDELION_EMBARGO_AVG_ADD)</code>).
# Forward the transaction to the node's selected Dandelion destination via <code>localDandelionDestinationPushInventory()</code>.
# If no Dandelion destinations are available, fall back to regular mempool acceptance and standard diffusion relay.

From this point forward, the transaction follows the identical code path as a locally-originated transaction. Downstream relay nodes cannot distinguish SPV-submitted stem transactions from node-originated stem transactions.

===Rate Limiting===

To prevent stempool abuse, full nodes enforce per-peer rate limits on SPV stem submissions:

* Each SPV peer is allowed a maximum of <code>max_rate</code> stem submissions per Dandelion epoch (default: 5 per 10-minute epoch).
* The rate counter resets each time Dandelion routes are shuffled (<code>ThreadDandelionShuffle</code>).
* Submissions exceeding the rate limit are accepted into the regular mempool (not the stempool) and relayed via standard diffusion. The transaction is not rejected — only the stem routing benefit is denied.
* Persistent rate-limit violations (exceeding 3x <code>max_rate</code> in a single epoch) trigger standard peer misbehavior scoring.

===Configuration===

Full nodes expose the following configuration option:

{|
! Flag !! Default !! Description
|-
| <code>-acceptspvstem</code> || <code>1</code> (enabled) || Accept Dandelion++ stem submissions from SPV peers. Set to <code>0</code> to disable.
|-
| <code>-spvstemrate</code> || <code>5</code> || Maximum stem submissions per SPV peer per Dandelion epoch.
|}

===Privacy Properties===

When an SPV client submits a transaction via stem to a Dandelion++-capable full node:

* The full node knows the SPV client submitted the transaction, but downstream stem relay nodes do not.
* Network observers monitoring diffusion see the transaction originate from the fluff point — not from the SPV client's peer or IP address.
* The transaction's stem path is indistinguishable from a locally-originated transaction at the accepting full node.
* Combined with Tor routing at the SPV layer, even the accepting full node cannot link the transaction to a real IP address.

===Message Type Summary===

{|
! Message !! Direction !! Payload !! Purpose
|-
| <code>dandelionsubmit</code> || SPV → Full Node || 1-byte version || Request stem submission capability
|-
| <code>dandelionack</code> || Full Node → SPV || 1-byte version + 2-byte max_rate || Confirm stem submission capability
|}

No new inventory types are introduced. The existing <code>MSG_DANDELION_TX</code> (type 5) and <code>MSG_DANDELION_WITNESS_TX</code> are reused.

==Rationale==

===Why extend the existing Dandelion++ rather than a new protocol?===

DigiByte already maintains the Dandelion++ stempool, relay routing, embargo timers, and epoch shuffling infrastructure. This proposal adds a thin acceptance layer on top of existing machinery. The alternative — designing a separate privacy relay protocol for SPV clients — would duplicate complexity and fragment the privacy guarantees.

===Why not require SPV clients to use Tor instead?===

Tor provides IP-level privacy and is recommended as a complementary measure. However, Tor has usability challenges on mobile (battery drain, connection latency, blocked in some regions). Dandelion++ stem submission provides transaction-origin privacy at the protocol level, independent of the transport layer. The two approaches compose well: Tor hides the IP from the accepting node, while stem routing hides the origin from the broader network.

===Why rate limiting instead of rejecting over-limit transactions?===

Rejecting transactions would create a poor user experience and could cause wallet failures. By gracefully falling back to standard mempool relay for over-limit transactions, the user's transaction is never lost or delayed — only the enhanced privacy benefit is withdrawn. This follows the principle of graceful degradation.

===Why not use a service bit for signaling?===

Service bits are a scarce resource and are appropriate for advertising persistent node capabilities. Dandelion++ SPV stem acceptance is a policy decision that individual nodes may enable or disable, and the willingness to accept stem submissions may change more frequently than service bits should be toggled. A message-based negotiation is more flexible and follows the precedent set by the original Dandelion++ Bitcoin Core PR (#13947), which also used message-based negotiation rather than service bits.

===Design decisions from Bitcoin Core PR #13947===

The original Bitcoin Core Dandelion++ PR was closed in 2019 due to concerns about stempool interaction with CPFP (Child Pays for Parent) and RBF (Replace-by-Fee) transaction chains. DigiByte's existing Dandelion++ implementation has already addressed these concerns for locally-originated transactions. Since this proposal routes SPV-submitted transactions through the identical stempool code path, no additional CPFP/RBF handling is required.

==Backwards Compatibility==

This proposal is fully backwards compatible:

* '''Full nodes that do not implement this extension''' ignore the <code>dandelionsubmit</code> message per existing unknown-message handling. No disconnection, no misbehavior scoring, no behavioral change.
* '''SPV clients that do not implement this extension''' continue to submit transactions via standard <code>MSG_TX</code> messages with no change in behavior.
* '''Full nodes with <code>-acceptspvstem=0</code>''' ignore the <code>dandelionsubmit</code> message, and SPV clients fall back to standard submission after the 30-second timeout.
* '''The existing Dandelion++ relay protocol is unchanged.''' Stem routing, fluff transitions, embargo timers, and epoch shuffling operate identically regardless of whether this extension is active.

No consensus rule changes are introduced. No changes to block or transaction validity. No changes to the peer-to-peer message format beyond the two new handshake messages.

==Reference Implementation==

A reference implementation is in progress and will be submitted as a pull request to the DigiByte Core repository.

==References==

* Fanti et al., "Dandelion++: Lightweight Cryptocurrency Networking with Formal Anonymity Guarantees" (ACM SIGMETRICS 2018)
* BIP 156: Dandelion - Privacy Enhancing Routing
* DigiByte Core Dandelion++ implementation: <code>src/dandelion.h</code>, <code>src/dandelion.cpp</code>
* Bitcoin Core PR #13947: Dandelion transaction relay (closed)
* DigiByte Core v8.22.0 release notes (Dandelion++ re-enabled)
* DigiByte Core v8.26.0 feature list (Dandelion++ preserved)