Skip to content

New Direct Mode - #3630

Draft
ripplebiz wants to merge 1 commit into
devfrom
new-direct-mode
Draft

ripplebiz wants to merge 1 commit into
devfrom
new-direct-mode

Conversation

@ripplebiz

Copy link
Copy Markdown
Member

This is an attempt to carve out a brand new Direct Mode by utilising the as-yet-unused TRANSPORT_DIRECT route type (0x03). ie. Packets with Direct + transport code data.

transport_code[0] is used as such:

  • bits 0..7: sequence number
  • bits 8..13: path cursor (0..63)
  • bits 14..15: DM_MODE_SEQ_* (sub-mode: one of NORMAL, WIDE, WIDE_MODIFIED, LINK_ID)

transport_code[1] is used as such:

  • bits 0..13: session-id
  • bits 14..15: crypto-mode (CRYPTO_LEGACY, CRYPTO_NEW_DIRECT, RESERVED1, RESERVED2)

Some of the things this new encoding/scheme is attempting is:

  • path is not consumed as it propagates along path. Dest node can see what the Full Path was. Instead, a simple 'cursor'/index is incremented at each hop, and path remains untouched (except in 'wide' mode).
  • 8-bit sequence numbers incremented by sender. Dest nodes should be able to do Link Quality calcs, ie. determine how many packets were lost.
  • A new 'wide' / 'fuzzy' sub-mode (DM_MODE_SEQ_WIDE).
  • Possibility for a number of different encryption methods. (a new placeholder one has a minimal impl for the CRYPTO_NEW_DIRECT slot, which attempts to use the seq-no/session-id fields as IV data)

NOTE: The 'wide' mode is inspired from @redxdev and this PR: #2648

Wide sub-mode is fairly simple, where (at each hop) the designated repeater with matching hash forwards, but also all direct neighbors of that repeater also forward. This could be a much more resilient direct mode. New clients could have a strategy, when sending, to use DM_MODE_SEQ_NORMAL (say first 2 attempts), then DM_MODE_SEQ_WIDE (for next attempt), then revert to FLOOD.

Also, if a neighbor repeater forwards it scribbles into the path its own hash, then edits the sub-mode to DM_MODE_SEQ_WIDE_MODIFIED. Dest node can then see if an alternate path was actually taken and use that info.

The _LINK_ID sub-mode is still effectively a reserved sub-mode, and hasn't been properly fleshed-out.

There are still a number of aspects that are yet to be done, like acting on the Link Quality calcs. (just placeholder updateLinkQualityStats() methods ATM)

@mikecarper

Copy link
Copy Markdown

Is this a use case for the blockchain path tracking that you were looking at? Allow one to mine the exact path taken using the discovery db of adverts. First 16 char is all you'd need to add to the blockchain

@ripplebiz

Copy link
Copy Markdown
Member Author

Is this a use case for the blockchain path tracking that you were looking at? Allow one to mine the exact path taken using the discovery db of adverts. First 16 char is all you'd need to add to the blockchain

No, this is unrelated.

@VoxMesh

VoxMesh commented Oct 19, 2026

Copy link
Copy Markdown

I think there's a case where WIDE can break an otherwise working route.

Suppose the path starts with A, B, .... Both A and B can hear the sender, and B has A in its neighbor table.

B can forward on behalf of A, replacing A with its own hash and advancing the cursor. This leaves [B, B, ...], with B still expected to handle the next hop.

However, B has already marked the packet as seen. When A forwards its copy, B will discard it as a duplicate, since calculatePacketHash() doesn't include the cursor. The packet can get stuck even though the original route was valid.

Instead of always advancing the cursor by one, could we check whether the forwarding repeater's own hash appears again later in the remaining path? If it does, we could advance the cursor past that occurrence and continue forwarding, effectively skipping the intermediate hops.

We'd also need to account for the skipped hops in the recorded path so it doesn't misrepresent the actual route.

Am I missing anything in the duplicate handling here?

@ripplebiz

Copy link
Copy Markdown
Member Author

I think there's a case where WIDE can break an otherwise working route.

Suppose the path starts with A, B, .... Both A and B can hear the sender, and B has A in its neighbor table.

B can forward on behalf of A, replacing A with its own hash and advancing the cursor. This leaves [B, B, ...], with B still expected to handle the next hop.

However, B has already marked the packet as seen. When A forwards its copy, B will discard it as a duplicate, since calculatePacketHash() doesn't include the cursor. The packet can get stuck even though the original route was valid.

Instead of always advancing the cursor by one, could we check whether the forwarding repeater's own hash appears again later in the remaining path? If it does, we could advance the cursor past that occurrence and continue forwarding, effectively skipping the intermediate hops.

We'd also need to account for the skipped hops in the recorded path so it doesn't misrepresent the actual route.

Am I missing anything in the duplicate handling here?

Yes, I think you're correct. That scenario would fail. Seems like removing duplicates of 'B' (in that example) before forwarding could be the fix, although it's a little sketchy if it's a 1-byte path hash. It could be conservative and only remove duplicate path hash (ahead of cursor) only if it's the next hop or the one after that(?) rather than scanning whole path.

@VoxMesh

VoxMesh commented Oct 20, 2026

Copy link
Copy Markdown

Yes, I think you're correct. That scenario would fail. Seems like removing duplicates of 'B' (in that example) before forwarding could be the fix, although it's a little sketchy if it's a 1-byte path hash. It could be conservative and only remove duplicate path hash (ahead of cursor) only if it's the next hop or the one after that(?) rather than scanning whole path.

Agreed, with 1-byte path hashes any fix seems like a trade-off.

I also considered keeping the repeated B in the path. When B substitutes for A in [A, B, C], giving [B, B, C], it could first forward with the cursor at C, then send a backup copy pointing at the second B.

That would cover both possibilities: the second B is the same repeater, or a different one with a matching prefix.

The downside is that duplicate handling would need to distinguish these forwarding stages, including on downstream repeaters. Plus the extra airtime.

Might be more complexity than this case warrants.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants