feat(indexer): bound route DFS with an expansion budget + truncated flag (#286) #745
No reviewers
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:implement
agent:implement
agent:open_issues
agent:ready
agent:research
agent:security_audit
agent:verify
architecture
backend
blocker:hybrid
blocker:launch
blocker:limit-orders
blocker:v2
block:log_only
block:security
bug
ci
contracts
correctness
deploy
dev
devops
docs
documentation
duplicate
e2e
enhancement
epic
feature
frontend
functional-completion
gas
good first issue
governance
help wanted
high-risk
hooks
hybrid
indexer
infra
infrastructure
integrators
invalid
launch-blocker
limit-orders
localnet
localterra
low priority
missing-implementation
needs-design
ops
performance
priority
high
priority
medium
product
qa
QA
question
ready
ready
research
scripts
security
security-hardening
smartcontracts
tech-debt
testing
ux
UX
v2
verification
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
code/cl8y-dex-terraclassic!745
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "qa/286-route-dfs-expansion-budget"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Bounds route DFS without lossy truncation by using a goal-distance reachability gate, admissible DFS pruning, and shortest-first iterative deepening. Additional optimization in this update keeps same-hop route capping deterministic by sorting adjacency, avoids max(asset_id)-sized visited allocations for sparse IDs, skips impossible shallow deepening passes, and removes allocation-heavy path sort keys.
This MR intentionally does not add a close keyword for #286: the original issue asked for a truncated flag, but review concluded truncation is the wrong strategy. The implementation now avoids truncation entirely, so the dense-unreachable abuse case is bounded without dropping unknown valid routes.
Verification checklist
glab mr view 27 -R PlasticDigits/cl8y-dex-terraclassic --commentscargo test --manifest-path indexer/Cargo.toml route_paths --libcargo test --manifest-path indexer/Cargo.toml --librustfmt --edition 2021 --check indexer/src/api/route_paths.rs && cargo clippy --manifest-path indexer/Cargo.toml --libhead_pipelineNotes
Per comment on #286 - need to review truncation strategy & if truncation is necessary. If it is necessary, then we need a way to determine which paths are higher priority vs lower ones - such as paths from a list of priority intermediate tokens
Reworked this from scratch — you're right, the expansion budget was the wrong call. Truncation can drop a route that actually exists and we can't say which one, so I pulled it out entirely. No truncated flag anymore.
New approach, nothing dropped:
Reachability gate. One BFS from the goal precomputes each token's minimum hop-distance to the goal (O(V+E)). If the input token can't reach the output token within max_hops, we return "no route" immediately without enumerating anything. That's exactly the abuse case from the issue (dense graph + unreachable goal) and it's now linear instead of O(branching^max_hops). It also covers your point (1): an input/output token with no pairs is just unreachable, so it bails instantly.
Admissible pruning on the walk. The DFS only steps into a neighbor whose own shortest distance to the goal still fits the remaining hops. This provably can't drop a valid route — any real continuation has to fit the hop budget anyway — so it only ever skips dead ends.
Shortest-first via iterative deepening (the priority part). Instead of taking the first 5 paths the walk happens to hit, it deepens one hop at a time and keeps the K shortest routes. Fewest hops is the natural priority (lower fees, less slippage), so a short/direct route can't get crowded out by longer ones. Found a real bug here while doing it: the old max_paths cap could fill all 5 candidate slots with 2-hop routes and miss a 1-hop direct pair entirely — added a regression test that fails on the prior code and passes now. If you want an explicit priority-intermediate-token list on top of this later, this is the right place to hang it, but shortest-hop already gives a principled ordering with zero dropped paths.
Off the executor (your point 3). The enumeration now runs under spawn_blocking so it's off the async worker thread. With the work bounded to O(V+E) it's cheap regardless, but this keeps a big legit pair graph from ever stalling the runtime.
Demonstration (your point 2): added a self-contained test that builds a complete graph on 50 nodes with an unreachable goal. The unpruned reference walk enumerates >100k node expansions — that's the blowup — while the gated version does 0 expansions and returns empty. A second test proves a reachable goal in that same dense graph still resolves and stays bounded (~a dozen expansions), and the crowd-out test above proves the direct route is always kept.
route_paths 8/8, full indexer lib suite green. This is the source + unit-test layer — pure in-memory path enumeration over the pair set, so there's no chain or indexer-state dependency to exercise live. The route_search_truncated field is gone from the response (it was never released, so nothing downstream depended on it).
Branch force-pushed. @PlasticDigits
added 1 commit
e3eb5ec9- feat(indexer): bound route DFS via reachability gate + shortest-path iterative deepening (#286)Compare with previous version
mentioned in issue #286
Excellent. Reviewing for additional optimizations
added 1 commit
26a6d5bf- fix(indexer): tighten route path enumerationCompare with previous version
changed the description
changed the description
mentioned in commit
679cc56fac