Skip to content
Merged
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

172 changes: 86 additions & 86 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,86 +1,86 @@
[workspace]
resolver = "2"
# The canonical dig-node repo is a small workspace of the node ENGINE + its two
# DIG-Browser host shells:
# * dig-node-core — the NODE engine library (crate `dig_node_core`): RPC dispatch,
# serve/fetch/redirect, chain-watch, subscriptions, gap-fill,
# cache, P2P. The single node implementation shared by BOTH host
# shells below. (Renamed from `dig-node` so the engine library and
# the produced `dig-node` binary no longer share a name, #216.)
# * dig-node-service — the OS-service binary (`dig-node`): axum transport + control
# plane + CLI + service install. Depends on the engine library.
# * dig-runtime — the DIG Browser's in-process node: a cdylib (`dig_runtime.dll`)
# exposing the `dig_rpc`/`dig_wallet_rpc` C-ABI the browser links.
# * dig-wallet — the DIG Browser's built-in Chia wallet host (loopback UI + BLS
# signing), brought up by dig-runtime beside the node.
# For the `.dig` STORE FORMAT the node depends on digstore's store-format LIBRARY crates
# (digstore-core/-crypto/-chain/-host/-remote/-stage) as GIT dependencies — dig-node-core
# -> store-lib, never the reverse. digstore is only ever an RPC client of a node.
members = [
"crates/dig-node-core",
"crates/dig-chat-protocol",
"crates/dig-node-service",
"crates/dig-runtime",
"crates/dig-wallet",
]
[workspace.package]
edition = "2021"
# The RELEASE version of the repo's shipped artifact — the `dig-node` binary
# (`dig-node-service`, which inherits this via `version.workspace = true`). This is
# the version the nightly-release.yml stable channel + version-increment CI reads from
# the ROOT manifest (`[workspace.package].version`), so it MUST be set here for a
# release to fire (§3.6). The library crates (dig-node-core/dig-runtime/dig-wallet)
# keep their own independent versions — only the released binary tracks the workspace version.
version = "0.173.0"
# Release hardening, matching digstore: keep integer-overflow checks ON in release.
# The node parses untrusted serialized input and does offset/length arithmetic over
# it, so silent wrapping in release would turn a length bug into a memory/logic hazard.
[profile.release]
overflow-checks = true
# -- Retired: the dig-gossip vendored-fork patches (L7 peer network) ----------------------------------
#
# This workspace used to re-declare `[patch.crates-io]` entries redirecting `chia-protocol` and
# `chia-sdk-client` to the ADDITIVE forks dig-gossip vendored, because a git dependency's own patches
# do not apply transitively (cargo honours patches only from the ROOT manifest being built).
#
# dig-gossip 0.23.0 DELETED both forks (dig_ecosystem#2228). The DIG introducer opcodes
# (`RegisterPeer=218` / `RegisterAck=219`), `send_protocol_message` and the DIG rate-limit rows now
# live in the crates.io crate `dig-peer-protocol` 0.6, a superset of plain upstream `chia-protocol`,
# which dig-gossip depends on directly. There is nothing left at that rev to patch to, so the patch
# section — and the #1529 three-rev lockstep it forced — is retired rather than re-pointed.
# The dig-nat unification patch is RETIRED (#1280 crates.io cascade): the ENTIRE peer stack takes
# dig-nat from crates.io, so cargo resolves ONE dig-nat instance without any git redirect.
# dig-constants is likewise a plain crates.io dep everywhere now.
#
# Do NOT read a version out of this comment. `tests/dependency_tree.rs` asserts the single-instance
# invariant against the resolved LOCK, which is the only claim about a version that cannot go stale.
# An earlier revision of this block asserted "dig-nat 0.7 ... resolves ONE dig-nat 0.7 instance",
# which was eleven minors stale by the time anyone read it.
#
# THE PEER STACK IS ON THE ^0.21 TIER (dig-node#412 step 7, 2026-08-30).
#
# Two walls have now been cleared here in sequence, and both cleared UPSTREAM rather than by an edit
# in this file. The first was chia-bls: the stack required `dig-nat ^0.20` -> `dig-tls ^0.4` (the
# chia-bls 0.36.1 uplift) while dig-gossip was pinned at a rev reaching chia-protocol 0.26 through
# `dig-peer-protocol 0.6.0`. dig-gossip v0.30.0 cleared it. The second was dig-nat itself: that same
# dig-gossip release declared `dig-nat ^0.20`, so the ^0.21 tier resolved TWO dig-nat lines while
# cargo printed success. **dig-gossip v0.32.0 (`main`, rev 1a339166) declares `dig-nat = "0.21"`,
# which cleared it.**
#
# The resolved stack is dig-nat 0.21, dig-dht 0.13, dig-download 0.21, dig-peer 0.13,
# dig-peer-selector 0.10 -- and dig-nat, dig-dht, dig-tls, chia-bls and chia-protocol each resolve to
# exactly the line count they had before the move.
#
# THE ONE THING A FUTURE LANE WILL GET WRONG: **dig-dht 0.15 is NOT takeable, and the blocker has
# moved down a level.** dig-download 0.21.0 and dig-peer-selector 0.10.0 -- the LATEST published of
# each -- both require `dig-dht ^0.13`, measured from the crates.io index and not from a caret.
# Declaring `dig-dht = "0.15"` resolves TWO dig-dht lines while cargo prints success, and dig-dht
# values cross from this crate into both of them. dig-dht 0.15 carries
# `ProviderRecord::unverified_mirror_coin_id` (dig-dht#23), so that field is unreachable here until a
# dig-download AND a dig-peer-selector release against `dig-dht ^0.15` exist -- upstream, never an
# edit in this file. One line per family beats the highest version numbers (CLAUDE.md §2.4b), and
# bridging two lines with a shim is the §4.1 byte-drift class.
[workspace]
resolver = "2"
# The canonical dig-node repo is a small workspace of the node ENGINE + its two
# DIG-Browser host shells:
# * dig-node-core — the NODE engine library (crate `dig_node_core`): RPC dispatch,
# serve/fetch/redirect, chain-watch, subscriptions, gap-fill,
# cache, P2P. The single node implementation shared by BOTH host
# shells below. (Renamed from `dig-node` so the engine library and
# the produced `dig-node` binary no longer share a name, #216.)
# * dig-node-service — the OS-service binary (`dig-node`): axum transport + control
# plane + CLI + service install. Depends on the engine library.
# * dig-runtime — the DIG Browser's in-process node: a cdylib (`dig_runtime.dll`)
# exposing the `dig_rpc`/`dig_wallet_rpc` C-ABI the browser links.
# * dig-wallet — the DIG Browser's built-in Chia wallet host (loopback UI + BLS
# signing), brought up by dig-runtime beside the node.
# For the `.dig` STORE FORMAT the node depends on digstore's store-format LIBRARY crates
# (digstore-core/-crypto/-chain/-host/-remote/-stage) as GIT dependencies — dig-node-core
# -> store-lib, never the reverse. digstore is only ever an RPC client of a node.
members = [
"crates/dig-node-core",
"crates/dig-chat-protocol",
"crates/dig-node-service",
"crates/dig-runtime",
"crates/dig-wallet",
]

[workspace.package]
edition = "2021"
# The RELEASE version of the repo's shipped artifact — the `dig-node` binary
# (`dig-node-service`, which inherits this via `version.workspace = true`). This is
# the version the nightly-release.yml stable channel + version-increment CI reads from
# the ROOT manifest (`[workspace.package].version`), so it MUST be set here for a
# release to fire (§3.6). The library crates (dig-node-core/dig-runtime/dig-wallet)
# keep their own independent versions — only the released binary tracks the workspace version.
version = "0.175.1"

# Release hardening, matching digstore: keep integer-overflow checks ON in release.
# The node parses untrusted serialized input and does offset/length arithmetic over
# it, so silent wrapping in release would turn a length bug into a memory/logic hazard.
[profile.release]
overflow-checks = true

# -- Retired: the dig-gossip vendored-fork patches (L7 peer network) ----------------------------------
#
# This workspace used to re-declare `[patch.crates-io]` entries redirecting `chia-protocol` and
# `chia-sdk-client` to the ADDITIVE forks dig-gossip vendored, because a git dependency's own patches
# do not apply transitively (cargo honours patches only from the ROOT manifest being built).
#
# dig-gossip 0.23.0 DELETED both forks (dig_ecosystem#2228). The DIG introducer opcodes
# (`RegisterPeer=218` / `RegisterAck=219`), `send_protocol_message` and the DIG rate-limit rows now
# live in the crates.io crate `dig-peer-protocol` 0.6, a superset of plain upstream `chia-protocol`,
# which dig-gossip depends on directly. There is nothing left at that rev to patch to, so the patch
# section — and the #1529 three-rev lockstep it forced — is retired rather than re-pointed.

# The dig-nat unification patch is RETIRED (#1280 crates.io cascade): the ENTIRE peer stack takes
# dig-nat from crates.io, so cargo resolves ONE dig-nat instance without any git redirect.
# dig-constants is likewise a plain crates.io dep everywhere now.
#
# Do NOT read a version out of this comment. `tests/dependency_tree.rs` asserts the single-instance
# invariant against the resolved LOCK, which is the only claim about a version that cannot go stale.
# An earlier revision of this block asserted "dig-nat 0.7 ... resolves ONE dig-nat 0.7 instance",
# which was eleven minors stale by the time anyone read it.
#
# THE PEER STACK IS ON THE ^0.21 TIER (dig-node#412 step 7, 2026-08-30).
#
# Two walls have now been cleared here in sequence, and both cleared UPSTREAM rather than by an edit
# in this file. The first was chia-bls: the stack required `dig-nat ^0.20` -> `dig-tls ^0.4` (the
# chia-bls 0.36.1 uplift) while dig-gossip was pinned at a rev reaching chia-protocol 0.26 through
# `dig-peer-protocol 0.6.0`. dig-gossip v0.30.0 cleared it. The second was dig-nat itself: that same
# dig-gossip release declared `dig-nat ^0.20`, so the ^0.21 tier resolved TWO dig-nat lines while
# cargo printed success. **dig-gossip v0.32.0 (`main`, rev 1a339166) declares `dig-nat = "0.21"`,
# which cleared it.**
#
# The resolved stack is dig-nat 0.21, dig-dht 0.13, dig-download 0.21, dig-peer 0.13,
# dig-peer-selector 0.10 -- and dig-nat, dig-dht, dig-tls, chia-bls and chia-protocol each resolve to
# exactly the line count they had before the move.
#
# THE ONE THING A FUTURE LANE WILL GET WRONG: **dig-dht 0.15 is NOT takeable, and the blocker has
# moved down a level.** dig-download 0.21.0 and dig-peer-selector 0.10.0 -- the LATEST published of
# each -- both require `dig-dht ^0.13`, measured from the crates.io index and not from a caret.
# Declaring `dig-dht = "0.15"` resolves TWO dig-dht lines while cargo prints success, and dig-dht
# values cross from this crate into both of them. dig-dht 0.15 carries
# `ProviderRecord::unverified_mirror_coin_id` (dig-dht#23), so that field is unreachable here until a
# dig-download AND a dig-peer-selector release against `dig-dht ^0.15` exist -- upstream, never an
# edit in this file. One line per family beats the highest version numbers (CLAUDE.md §2.4b), and
# bridging two lines with a shim is the §4.1 byte-drift class.
37 changes: 29 additions & 8 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -7953,12 +7953,33 @@ itself (SYSTEM.md §4.1).
> **Two things in §25 remain PENDING**, tracked as
> <https://github.com/DIG-Network/dig-node/issues/412>:
>
> * **CREATES are refused, by name.** `dig_mirror_coin::create` takes its `Vec<Cat>` from the
> caller, and this node has no $DIG coin selector scoped to the OPERATOR puzzle hash — the
> node-custodied selector reads a different wallet's coins. `NodeMirrorEffects::create` therefore
> returns a named error, the pass reports it, and §25.8 keeps reporting the bond as uncovered,
> which is true. Tracked as <https://github.com/DIG-Network/dig-node/issues/421>. **RECLAIMS are
> implemented** and are supported at `fee = 0` with no fee coins, which is §25.4.4.
> * **CREATES select their collateral from the OPERATOR wallet, and are refused for want of an
> ADVERTISED URL.** `mirror::funding::select_operator_dig_cats` scans the chain at the CAT wrapping
> of this node's operator puzzle hash under `dig_mirror_coin::DIG_ASSET_ID`, withholds coins
> committed to a bundle whose audit record is not terminal, selects largest-first, and
> reconstructs each selected candidate's lineage from its creating spend — refusing the WHOLE
> selection on a shortfall, an unauthenticatable candidate, an unreadable chain, or an unreadable
> audit record, never funding a smaller coin (dig-node#421). The reservation is FED by every
> successful broadcast and not only by one whose created coin is derivable: on a `broadcast` that
> reaches the mempool, `mirror::lifecycle::NodeMirrorEffects::sign_and_broadcast` records a
> `spend_audit::Submission` UNCONDITIONALLY, carrying the coins the signed bundle consumes. The
> coin CREATED is a separate, optional field of that submission — a create names none, because its
> output coin takes its parent from whichever input the builder drew it from and this node does not
> derive it — so an underivable target no longer suppresses the record of the coins consumed, and
> `control.mirror.*` and `dign spend-audit` MUST show a create's consumed coins rather than an
> empty list. **Two creates MUST NOT select the same coin**, whether or not they fall in the same
> pass, and the two halves of that are separate mechanisms: ACROSS passes the durable journal
> above is re-read before each pass, and WITHIN one pass — where a pass emits a create per bond of
> the affordable prefix — `NodeMirrorEffects` extends its own committed set from each bundle that
> reaches the mempool, so a later create in the same pass selects against what the pass has
> already spent. The journal alone does not cover the second: it is read once, before the pass,
> and the chain reports a broadcast coin as unspent for the whole confirmation window. What is
> still missing is the
> advertisement: `dig_mirror_coin::create` requires at least one URL its store can be fetched
> from, this node has no configured public name, and `NodeMirrorEffects::create` therefore refuses
> by name BEFORE any chain read (dig-node#426). **RECLAIMS are implemented** and are supported at `fee = 0` with
> no fee coins, which is §25.4.4 — and are never gated on any funding read, including the
> committed-coin read.
> * **§25.6's DHT pointer is not attached.** `ProviderRecord::unverified_mirror_coin_id` lives in
> dig-dht 0.15, and `dig-download` 0.21.0 and `dig-peer-selector` 0.10.0 both require
> `dig-dht ^0.13` — semver-incompatible on a `0.x` line, so taking 0.15 here would resolve two
Expand Down Expand Up @@ -8271,8 +8292,8 @@ one setting to turn off** (§6.0/#207).
> oracle read — a real amplification surface, since a paired token is a much weaker predicate than
> "trusted". A node whose first pass has not yet completed answers
> `unknown { reason: "chain_unreadable" }`, which remains the honest answer and is never an empty
> page. A bond whose create is refused for want of an operator-scoped $DIG selector
> (dig-node#421) reports as uncovered, which is what it is.
> page. A bond whose create is refused for want of an advertised URL, for want of uncommitted
> operator $DIG, or because the chain could not be read — reports as uncovered, which is what it is.

The lifecycle exposes, per `(store, root)`, over the control plane and with a `dign` verb (§8.6
CLI parity): the bond state — `bonded { coin_id, epoch, amount }`, `pending` (in-flight create),
Expand Down
5 changes: 5 additions & 0 deletions crates/dig-node-service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,11 @@ dig-wallet = { path = "../dig-wallet" }
# (its series skips 0.32 -> 0.42) and pins the primitives to its own version, so it cannot
# sit on the chia-wallet-sdk ceiling without re-splitting the family (dig_ecosystem#3161).
chia-bls = "0.36.1"
# `mirror_operator_funding.rs` DERIVES its fixture discriminators instead of spelling byte literals:
# CodeQL reads a byte literal reaching a hash as a hard-coded cryptographic salt (dig-node#917, #950),
# and deriving clears the finding at SOURCE rather than justifying it once per call site. Pinned to
# the same 0.36.1 line as every other chia primitive here -- a second line would be a second `Sha256`.
chia-sha2 = "0.36.1"
# The census-runner unit tests implement `ChainSource` over a double, whose method signatures are
# spelled in `chia-protocol` types. The SAME 0.36.1 line `dig-chainsource-interface` and
# `dig-mirror-coin` compile against -- a second line would make the double's `Bytes32` a different
Expand Down
Loading
Loading