Uh oh!
There was an error while loading. Please reload this page.
feat(wallet)!: move the reservation codes off -32044, which dig-node already owns - #28
Merged
Merged
Conversation
…already owns
`-32044` meant two OPPOSITE things. This contract minted it in 0.20.0 as
`WALLET_COINS_RESERVED` ("this is a wait -- retry"); dig-node has shipped it on
every default install as `WALLET_NODE_SPEND_DISABLED` ("retrying cannot help").
A client conflating them either retries forever against a permanent refusal or
abandons a transient one.
The contract moves and dig-node does not. dig-node's meaning is live on every
install and its refusal is a custody decision (dig-node SPEC 18.12); this
crate's is 40 minutes old with ZERO implementors, so moving it costs nobody.
-32044 WALLET_NODE_SPEND_DISABLED registered, with dig-node's semantics
-32046 WALLET_COINS_RESERVED was -32044
-32047 WALLET_RESERVATIONS_UNAVAILABLE was -32045
BREAKING CHANGE: the numeric wire codes of `WalletCoinsReserved` and
`WalletReservationsUnavailable`, published in 0.20.0, change. Deliberately NOT
additive: leaving `-32044` ambiguous is worse than renumbering two codes that
nothing implements yet.
Root cause, and the durable half: dig-node minted a code INSIDE the shared
`-3204x` range without declaring it here, so nothing could detect the clash at
allocation time.MichaelTaylor3dforce-pushed
the
fix/error-code-32044-collision
branch
from
August 25, 2026 01:42
ca62677 to
a5be663CompareMichaelTaylor3d
marked this pull request as ready for review
August 25, 2026 01:45
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 27, 2026
Merged
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Outcome
-32044meant two opposite things across the repo boundary. The contract moves; dig-node does not.-32044WALLET_NODE_SPEND_DISABLED-32046WALLET_COINS_RESERVED-32044-32047WALLET_RESERVATIONS_UNAVAILABLE-32045This reallocation is deliberately NOT additive, and should not read as a routine bump: the
numeric wire codes of two codes published in 0.20.0 change. That is the right trade because 0.20.0
is ~40 minutes old with zero implementors (grepped: neither symbol nor either numeric appears in
dig-node or dig-app, both of which pin 0.17/0.19), while dig-node's
-32044is live on everydefault install and its refusal is a custody decision — the node relays bundles others signed,
but spending its own coins is default-OFF, because a caller could otherwise sign through the node
and hand the bundle straight back. Leaving
-32044ambiguous is worse than renumbering two codesnothing implements.
-32045/-32046/-32047are all unused in dig-node (checked against every-320xxliteral indig-node/crates/);-32045is vacated only so the pair stays adjacent as one coherent block.WALLET_NODE_SPEND_DISABLED's wording is copied from dig-nodeSPEC.md:3027so the two cataloguesagree verbatim on the remedy.
The root cause, and the durable half
dig-node minted a code inside the shared
-3204xrange that was never declared in the sharedcatalogue, so nothing could see the clash at allocation time.
every_catalogued_code_is_numerically_unique— pairwise across the whole catalogue, plus afrom_coderound-trip. The pre-existing per-variant assertions only compared ONE code against therest, so a collision between two codes neither of which was under test was invisible to them.
a_terminal_custody_refusal_and_a_transient_wait_never_share_a_code— pins each numbertogether with its disposition, so a future re-collapse is visible. Asserting only that the
numbers differ would pass for a catalogue that had quietly given both variants the same meaning.
SPEC.md§5 and theerror.rsmodule docs: the-3204xband is owned by this document, and a node or client MUST NOT mint into it privately.SPEC.mdalso no longer claims "all four wallet codes mean the answer is UNKNOWN" — false since0.20.0 and doubly so now. It states per-code dispositions and requires branching on the symbol,
not the band.
Guard proof (a uniqueness test that passes against the colliding version proves nothing). With
WalletRateLimitedmoved to-32044, the named test fails with the exact clash:Reverted; tree restored to the committed state before finalizing.
Expressibility, and what dig-node owes
Only half the guard is expressible here. This crate cannot see dig-node's sources, so uniqueness
within the catalogue is all a test here can assert; the cross-repo half is the range-ownership
rule, which only dig-node can honour. dig-node owes the reciprocal check — assert every
-3204xit mints is declared in this crate'sControlErrorCode::ALL, which it can express becauseit already depends on this crate. Related finding (comment, not a ticket): dig-node also mints
-32033 CONTROL_INGRESS_LIMITEDand-32060 PEER_PING_REFUSED, plus-32001..-32017and-32050..-32052, none declared here. Those are outside-3204xand none currently clash, so theyare not fixed in this PR.
Blast radius checked
Grep-based (gitnexus fallback, per §2.0 bound 2 — a ~10-minute per-worktree analyze is not
justifiable on a lane two others are blocked on, and the radius here is fully enumerable). Targets:
ControlErrorCode::{code,name,origin,description,ALL}and the two moved variants. Every referencein-crate:
error.rs,kats.rs, and doc-links inparams.rs/results.rs/traits.rs/method.rs(symbolic only, no numerics). Out of crate: zero — no consumer references either symbol or
either numeric.
Verification
cargo test --all-features— 152 lib passed, 9 doc passed, 0 failed (baseline 150 + 9; +2 arethe new guards). Parsed from the
test result:lines, one cargo process at a time.cargo clippy --all-features --all-targets -- -D warnings— clean.Cargo.tomldeclares nodig-*and nochia-*dependency (only
serde/serde_json/semver/async-trait/futures); there is nopackage.json, so no@dignetwork/*deps either.Version
0.20.0 → 0.21.0, titled
feat(wallet)!:. Note this crate'scliff.tomldoes not renderbreaking as breaking (#26), so the
!is forgit logand this body, not the changelog.Progress: https://github.com/DIG-Network/dig_ecosystem/issues/3127