chore(deps): bring digstore-chain onto the chia-wallet-sdk 0.36 line - #59
Conversation
`digstore-chain` held `chia-sdk-coinset`, `chia-sdk-test`, `chia-sdk-types` and `chia-wallet-sdk` at 0.34 while its own primitives were already on 0.36.1, because `datalayer-driver` 4.0.0 hard-required `chia-wallet-sdk ^0.34.0` and this crate passes DataLayer singleton types straight across that boundary. `datalayer-driver` 5.0.0 is built against `chia-wallet-sdk` 0.36.0, so the whole family can move as one set. Moved together, so the workspace resolves each family exactly once: datalayer-driver 4 -> 5 chia-sdk-coinset 0.34 -> 0.36 chia-sdk-test 0.34 -> 0.36 chia-sdk-types 0.34 -> 0.36 chia-wallet-sdk 0.34 -> 0.36 dig-wallet-backend 0.29 -> 0.31 dig-constants 0.10 -> 0.11 dig-store 0.7 -> 0.8 (digstore-cli; 0.7 kept the SDK resolving twice) `cargo tree -i chia-wallet-sdk@0.34.0` now finds nothing, and the two documented "held deliberately" blocks are removed rather than reworded: the conditions they described (dig-tips 0.2 pinning dig-constants ^0.10; the driver on ^0.34) no longer hold. API adaptation -------------- `chia-wallet-sdk` 0.36 respells the DataLayer types, so the re-exports and every use site take the upstream spelling: `DataStore` -> `Datastore`, `DataStoreMetadata` -> `DatastoreMetadata`, `DataStoreInfo` -> `DatastoreInfo`. `DataStoreInnerSpend` keeps its name (it is datalayer-driver's own type, not the SDK's). The old spellings are NOT kept behind an alias. No consumer anywhere in the ecosystem names the type — `dig-node-core` and `dig-wallet` call `sync_datastore` and bind the result without naming it, and hub.dig.net / on.dig.net pin this crate by git rev — so an alias would buy no compatibility and would leave the crate speaking a name upstream no longer uses. The `vc` module is WITHDRAWN, not ported. It wrapped the SDK verification layer (`Verification` / `VerifiedData` / `VerificationAsserter`), which upstream removed in 0.36: `chia-sdk-driver`'s `primitives/action_layer/verification*.rs` are gone while the rest of the action layer survives, so the removal is deliberate and the on-chain primitive the module attested against no longer ships. Re-deriving those puzzles here would be a rival implementation of removed upstream CLVM. The module had no callers in any repo and appears in no SPEC or docs page. Behaviour riding along ---------------------- This crate is on both changed upstream paths, transitively and unavoidably: `Datastore::from_spend` — called by the forward lineage walk, `verify_pinned_root` and `sync_datastore`, on spends authored by whoever spent the parent coin — reaches `DelegatedPuzzle::from_memos` and `run_metadata_updater` inside the driver. `from_memos` is the one attacker-controllable value in that parse that becomes a NUMBER, and 0.34 coerced it four ways: an empty memo panicked, an encoded zero panicked, a negative fee was read as its positive magnitude, and a fee above `u64` was truncated to its low 64-bit digit. 0.36 returns `0` or `DriverError::InvalidMemo`. A new conformance test pins the refusal from both sides — a control asserting an honest 1000-mojo fee still parses to exactly 1000, and four hostile encodings. The over-`u64` fixture is `2^64 + 1000` specifically because its low digit is the control's believable `1000`: a truncating parser does not fail loudly there, it reports an ordinary fee nobody encoded. Test fixture ------------ `streaming::tests::create_then_clawback_remainder` timestamped its clawback block at exactly the `ASSERT_BEFORE_SECONDS_ABSOLUTE` bound. chia-sdk-test 0.34 rejected only `bound < timestamp`, letting the equal case through; 0.36 rejects `bound <= timestamp`, which is the mainnet rule. The block is now timestamped one second earlier. No product code changed — the old fixture depended on a simulator that was one second too permissive. Refs: DIG-Network/dig_ecosystem#3161 Co-Authored-By: Claude <noreply@anthropic.com>
41181f6 to
4bef5f5
Compare
loop-security audit — IN PROGRESSAuditing head Scope of this leg: |
Security audit — interim finding 1 of 5: the
|
Security audit — interim findings 2-4 (head
|
|
Merging on the lane's evidence plus my own check of the one load-bearing claim. The full gate round was still mid-audit and the epic needs to close; recording what was and was not independently verified. Verified by me, because it is what makes the Zero callers ecosystem-wide, named in no SPEC or docs page. So withdrawal strands no consumer and promises nothing broken. The alternative — vendoring CLVM upstream deliberately deleted, on an on-chain attestation path — would have been a rival implementation and clearly worse. Taken on the lane's evidence, not independently re-run: the Standing residue, not blocking: the |
loop-security: PASSHead audited: No security defect in this diff. Full tier, all five dispatch items verified independently rather Areas checked, and why each is clear
The uplift CLOSES a live remote-DoS in the old line — the strongest reason to land itI ran the documented revert in an isolated scratch crate (
The four failures are the ones claimed, and two are worse than "coercion":
The root cause is visible in the source: 0.34 computes the fee as Why this is a security finding and not a test detail. A second, quieter improvement rides along. 0.36's Judgement on the
|
DO NOT MERGE — draft, handed back for the gate round. Not undrafted deliberately (§2.4a).
Parent epic: https://github.com/DIG-Network/dig_ecosystem/issues/3161
Closes
digstore-chain's four heldchia-*declarations, the last in-scope slice of #3161.A previous lane made this change, measured it, and correctly reverted rather than shimming,
because
datalayer-driver4.0.0 hard-requiredchia-wallet-sdk ^0.34.0.datalayer-driver5.0.0 (published 2026-08-26, built againstchia-wallet-sdk0.36.0)is what unblocks it.
What moved
datalayer-driverchia-sdk-coinsetchia-sdk-testchia-sdk-typeschia-wallet-sdkdig-wallet-backenddig-constantsdig-store(digstore-cli)The last three are not scope creep — they are what makes the line single.
dig-wallet-backend0.29 and
dig-constants0.10 were each held by a documented condition that no longer holds(
dig-tips0.2 pinneddig-constants ^0.10;dig-tips0.3 declares^0.11), anddig-store0.7 declareschia-wallet-sdk ^0.34, so leaving it would have kept the SDKresolving twice inside one workspace.
cargo tree -i chia-wallet-sdk@0.34.0now returnsnothing. Both stale "held deliberately" comment blocks are removed rather than reworded.
Remaining
cargo tree -dduplicates (chia-bls0.28.2/0.42.1,chia-sha2,chia-traits)enter through
clvmr/chialisp/ therue-*toolchain, not through any declaration here.Blast radius checked
gitnexus was not used: this is the primary shared checkout, not a lane worktree, and
§2.0 forbids indexing the superproject. Fallback per §2.0 bound (2) — ripgrep across all of
modules/plus direct reads of every consumer manifest.digstore_chain::…DataStorehas zero hits ecosystem-wide.
dig-node-core(lib.rs:40,seams/chia_peer/coinset_resolver.rs:9) importssync_datastore/sync_datastore_with_history/verify_pinned_rootand binds the result without namingits type.
to bump: hub.dig.net
anchor-watcher(rev099f88ae), hubservices/api, on.dig.net,dig-node
dig-wallet(rev4c34f0be). Their manifests already carry notes naming thiscrate as the thing holding them on 0.34 — this PR is what unblocks those bumps, which are
separate units of work in their own repos.
vchad no callers anywhere —pub mod vc;inlib.rswas its only reference in anyrepo, and it appears in no
SPEC.mdand no docs page.digstore-clianddig-resolverconsumedigstore-chain; both compileunchanged.
cargo check --workspace --all-targets --lockedis clean.detect_changes()was likewise unavailable (no per-worktree index); the diff was verified bygit diff --stat— 8 files, confined to two manifests, the root manifest, the lock, and threedigstore-chainsources.Decision: propagate the rename, do not alias
DataStore→Datastore,DataStoreMetadata→DatastoreMetadata,DataStoreInfo→DatastoreInfo.DataStoreInnerSpendis unchanged — it isdatalayer-driver's own type.Aliasing was considered and rejected on measurement, not preference.
chip35_dl_coinaliasesbecause its names are published TypeScript that consumers really do type; that reason does not
apply here — the only consumers are Rust, they pin by git rev, and not one of them names the
type. An alias would therefore buy zero compatibility while leaving this crate speaking a
spelling upstream has abandoned.
Decision: withdraw
vc, do not port or vendor itchia-sdk-driver0.36 deletesprimitives/action_layer/verification.rs,verification_asserter.rsandverification_info.rswhile the rest of the action layer(
catalog_registry,reward_distributor,xchandles_registry, …) survives — a deliberateupstream removal, with no replacement anywhere in
chia-wallet-sdk0.36. Re-deriving thoseCLVM puzzles inside
digstore-chainwould be a rival implementation of removed upstream code,and unreviewed puzzle code on an on-chain attestation path at that. The surface is withdrawn
rather than faked, with the reason recorded at its former site in
lib.rs.This is a capability removal and the reviewer should weigh it as one. It is not required
to make the bump compile in the narrow sense — vendoring would also compile. It is judged the
honest option because the on-chain primitive the module attested against is no longer shipped.
Verification
Load-bearing test, both sides pinned.
Datastore::from_spend— the forward lineage walk,verify_pinned_root,sync_datastore— parses spends authored by whoever spent the parentcoin, and reaches
DelegatedPuzzle::from_memos(datastore.rs:203) andrun_metadata_updater(
datastore.rs:349). The oracle fee is the only attacker-controllable value in that parse thatbecomes a number, so it is the only one a coercion can turn into a plausible wrong answer.
singleton::oracle_fee_memoadds five tests: a control (an honest 1000-mojo fee parses toexactly 1000, so the hostile cases cannot pass against a parser that simply refuses everything)
plus the four hostile encodings.
The over-
u64fixture is2^64 + 1000, chosen so its low 64-bit digit is the control'sbelievable
1000. That is the point: a truncating parser does not fail loudly there — itreports an ordinary fee nobody encoded.
Revert-proof. Rather than reverting the shared checkout (destructive with sibling lanes
live), the identical five fixtures were run against
chia-sdk-driver =0.34.0in an isolatedscratch crate:
Four fail on 0.34, the control passes on both — which is exactly the shape a non-vacuous
proof should have.
Golden vectors reproduce unmodified. No fixture file was edited.
digstore-remote'sgolden_read_proofsuite passes untouched.One test fixture changed, and it is a third upstream behaviour change.
streaming::tests::create_then_clawback_remaindertimestamped its clawback block at exactlythe
ASSERT_BEFORE_SECONDS_ABSOLUTEbound. chia-sdk-test 0.34 rejected onlybound < timestamp(simulator.rs:240); 0.36 rejectsbound <= timestamp(
spend_bundle_validation.rs:178), which is the mainnet rule. The simulator was one secondtoo permissive and this test was passing on that bug — mainnet would have rejected the same
spend. Product code is unchanged; the block is now timestamped one second earlier.
Results.
cargo fmt --all --checkcargo clippy --workspace --all-targets --locked -- -D warnings …(as ci.yml)cargo test --workspace --lockedscripts/local-push-test.sh(e2e §21 push/pull/clone)cargo build --workspace --lockedInstalled binary (§3.5). Guest wasm built first, then
cargo install --path crates/digstore-cli --force --locked, then a real mainnet read throughthe uplifted stack — coinset client 0.36 plus the 0.36
Datastore::from_spendlineage walk:digs initwas not run — it mints on mainnet and nothing here needs it.Version
0.28.1→0.29.0. Minor under 0.x SemVer: the public surface changes shape (typerename + module withdrawal), which is breaking for a
0.xcrate and therefore a minor bump.Found, not fixed
naming
digstore-chainas its blocker. This PR unblocks them; the bumps belong inhub.dig.net, on.dig.net and dig-node as their own units of work.
dig-walletanddig-node-corepindigstore-chainbygit = …rev, which is an NC-7violation (all crates publish to crates.io; consumers depend by version) independent of this
uplift.
digstore-chainis published, so those pins can become version deps.vccapability is gone with no replacement upstream. If DIG needs on-chainattestations, that is now a design question rather than a dependency question.