Skip to content
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
d8f8f33
test(wire): pin golden frame vectors for opcodes 200/217/218/219/220
MichaelTaylor3d Aug 11, 2026
9db6c8a
refactor(deps)!: bump dig-peer-protocol to 0.4 and import chia types …
MichaelTaylor3d Aug 11, 2026
546c7e7
refactor(wire): frame DIG opcodes as DigMessage instead of the forked…
MichaelTaylor3d Aug 11, 2026
e5379dc
refactor(transport): migrate the connection layer to DigLink
MichaelTaylor3d Aug 11, 2026
9967518
refactor(transport): carry both bands over DigLink, retiring the Peer…
MichaelTaylor3d Aug 11, 2026
5742a4f
refactor(discovery): take introducer 218/219 bodies from dig-peer-pro…
MichaelTaylor3d Aug 11, 2026
6e6b27a
feat(deps)!: delete the vendored chia-protocol and chia-sdk-client forks
MichaelTaylor3d Aug 11, 2026
5bb04db
test(transport): port integration tests to the DigLink transport
MichaelTaylor3d Aug 11, 2026
e8bdede
test(connection): key the in-crate unit tests by raw DIG opcode
MichaelTaylor3d Aug 11, 2026
6378f3f
style(types): drop the unused Streamable import in peer.rs
MichaelTaylor3d Aug 11, 2026
6071ec3
style(limits): drop five no-op u8 casts left by the opcode port
MichaelTaylor3d Aug 11, 2026
3f048a0
build(deps): re-pin dig-peer-protocol to 0.5
MichaelTaylor3d Aug 11, 2026
1985806
test(con-005): port the rate-limit tests onto OpcodeRateLimiter
MichaelTaylor3d Aug 11, 2026
82b9039
test(wire): pin the golden vectors in the decode direction too
MichaelTaylor3d Aug 11, 2026
94fcd53
fix(con-001): a refused dial is a LinkError now the dial is DigLink's
MichaelTaylor3d Aug 11, 2026
174d224
docs(ci): state the real crates.io publish blocker after the chia for…
MichaelTaylor3d Aug 11, 2026
90db40e
docs(spec): correct the Section 1 crate-reuse claims to the DigLink t…
MichaelTaylor3d Aug 11, 2026
5788a23
docs(spec): retire the vendored-fork claims and the Peer/connect_peer…
MichaelTaylor3d Aug 11, 2026
0cb8c6e
docs(requirements): retarget the crate-structure and prompt specs at …
MichaelTaylor3d Aug 11, 2026
2539aab
docs(requirements): retarget the domain specs at DigLink and the DIG …
MichaelTaylor3d Aug 11, 2026
94403ff
docs(devlog): record the fork deletion and salvage the patch-not-used…
MichaelTaylor3d Aug 11, 2026
d879f33
docs(manifest): drop the last vendored-fork references from the comme…
MichaelTaylor3d Aug 11, 2026
7a84bcb
docs(connection): describe the DigLink transport, not the deleted forks
MichaelTaylor3d Aug 11, 2026
ff48301
docs(discovery): fix references to deleted vendor directories
MichaelTaylor3d Aug 11, 2026
1e29f2e
test(dsc-004): handle LinkError in connect_fail test
MichaelTaylor3d Aug 11, 2026
a033518
docs(manifest): the DIG extension band runs to 222, not 219
MichaelTaylor3d Aug 11, 2026
1e3dd11
docs(tests): update stale references to vendor paths and legacy trans…
MichaelTaylor3d Aug 11, 2026
661133e
docs(handshake): cite the real outbound dial, not the retired connect…
MichaelTaylor3d Aug 11, 2026
2ce46c3
fix(connection): report a handshake-policy rejection as ClientError o…
MichaelTaylor3d Aug 11, 2026
7b2a171
ci: run the suite with --no-fail-fast so a count is a total, not a floor
MichaelTaylor3d Aug 12, 2026
4ed6f14
docs(spec): correct the dependency, transport-type and rate-limiter c…
MichaelTaylor3d Aug 12, 2026
da4c23e
test(dsc-005): a refused dial is a LinkError, matching the dsc-004 twin
MichaelTaylor3d Aug 12, 2026
ce4c08e
fix: return MissingHandshake typed client errors
Copilot Aug 12, 2026
91bca94
fix(keepalive): send the liveness probe uncorrelated (#2767)
MichaelTaylor3d Aug 12, 2026
3392ce8
test(keepalive): pin the uncorrelated probe against a parked correlat…
MichaelTaylor3d Aug 12, 2026
3880a29
test(keepalive): regression + fail-open coverage for the probe collis…
MichaelTaylor3d Aug 12, 2026
5a37486
fix(dial): classify a non-Handshake first frame as policy, not transp…
MichaelTaylor3d Aug 12, 2026
7db09b9
docs(con-004): record that the keepalive probe must be uncorrelated (…
MichaelTaylor3d Aug 12, 2026
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
15 changes: 13 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,23 @@ name: CI
# the merge on transient flakiness. Coverage instrumentation still runs via
# `cargo llvm-cov nextest` so the 80% floor is measured the same way.
#
# `--no-fail-fast` (dig_ecosystem#2228) is what makes the numbers this job prints
# TOTALS rather than floors. Without it nextest stops at the first failing target,
# and the run reports a pass count that reads exactly like a complete one: a red
# head here stopped at 531 of 977, so 446 tests never executed AND the 80% line
# floor below was never measured at all — the job failed for the one broken test
# while silently declining to answer the coverage question it exists to answer.
# "Unmeasured" and "measured and under" are different verdicts and must not look
# alike. The job still fails on any real failure; it just finishes counting first.
#
# Coverage notes:
# - Measured against the production-shaped **default** feature set
# (`native-tls,relay,erlay,compact-blocks,dandelion`). The `tor` and `rustls`
# features are opt-in and pull heavy / alternate-TLS dependencies, so they are
# not part of the coverage gate (their cfg-gated code is excluded from the
# default-feature report rather than counted as "uncovered").
# - `vendor/` (the patched chia-protocol / chia-sdk-client / native-tls crates)
# is excluded via `--ignore-filename-regex` — we only gate on our own `src/`.
# - `vendor/` (the patched `native-tls` crate — the only remaining fork) is
# excluded via `--ignore-filename-regex` — we only gate on our own `src/`.
# - Integration tests bind loopback TLS listeners; they run single-threaded
# (`--test-threads=1`) to match `publish.yml` and avoid port/handshake races.

Expand Down Expand Up @@ -112,6 +121,7 @@ jobs:
--no-default-features
--features rustls,relay,erlay,compact-blocks,dandelion
--lib
--no-fail-fast
--
--test-threads=1

Expand Down Expand Up @@ -146,6 +156,7 @@ jobs:
--ignore-filename-regex 'vendor/'
--fail-under-lines 80
--lcov --output-path lcov.info
--no-fail-fast
--test-threads=1
--retries 2

Expand Down
39 changes: 23 additions & 16 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ name: Publish to crates.io
# Tag-driven release. Pushing a version tag `vX.Y.Z` (cut by release.yml on merge) runs this
# workflow, which cuts a GitHub Release for the tag.
#
# crates.io publish is GUARDED OFF for now (#2228). dig-gossip has three vendored fork dependencies
# in [patch.crates-io] (chia-protocol, chia-sdk-client, native-tls) that `cargo publish` strips
# from the published metadata. This causes `cargo package --locked` to fail with 19 compile errors
# against the bare crates.io versions, making it impossible to publish the crate.
# crates.io publish is GUARDED OFF (dig_ecosystem#2647). dig-gossip carries ONE vendored fork in
# [patch.crates-io] — `native-tls`, patched so the OpenSSL server acceptor sets CERT_REQUIRED plus
# Chia CA trust for inbound mTLS (CON-009); upstream `TlsAcceptorBuilder` offers no way to require a
# client certificate. `cargo publish` STRIPS [patch.crates-io] from the published metadata, so a
# published dig-gossip would build against upstream `native-tls`, compile cleanly, and silently
# accept inbound peers presenting no client certificate at all. That is a silent security
# regression, not a build break — which is exactly why the guard is a workflow step and not a
# reliance on the compiler.
# So the crates.io steps run ONLY on a manual `workflow_dispatch`; a tag push just cuts the GitHub
# Release. Flip this to per-tag once #2228 has resolved the vendored-dependency blocker.
# Release. Flip this to per-tag once dig_ecosystem#2647 removes the need for the `native-tls` patch.

on:
push:
Expand All @@ -28,27 +32,30 @@ env:
CARGO_TERM_COLOR: always

jobs:
# crates.io publish. GUARDED to `workflow_dispatch` only (#2228): a tag push does NOT publish (the
# crate has three vendored fork dependencies in [patch.crates-io] that cargo publish strips,
# causing cargo package --locked to fail with 19 compile errors — see the header note). The job
# crates.io publish. GUARDED to `workflow_dispatch` only (dig_ecosystem#2647): a tag push does NOT
# publish, because `cargo publish` strips the [patch.crates-io] `native-tls` fork and the published
# crate would then accept inbound peers with no client certificate — see the header note. The job
# stays present and explicitly FAILs on tag push (exit 1) so the `create-release` job below can
# `needs: publish` with `if: always()` and still cut a GitHub Release on every tag.
publish:
name: Publish to crates.io
runs-on: ubuntu-latest
steps:
- name: Fail crates.io publish on tag push (#2228)
- name: Fail crates.io publish on tag push (dig_ecosystem#2647)
if: github.event_name != 'workflow_dispatch'
run: |
echo "Cannot publish to crates.io: dig-gossip carries [patch.crates-io] vendored fork"
echo "dependencies (chia-protocol, chia-sdk-client, native-tls) that cargo publish"
echo "strips from the published metadata. A published dig-gossip would silently resolve"
echo "to the bare upstream crates, which lack the necessary opcodes 218/219 (peer"
echo "registration), full-duplex RPC application channel, and inbound mTLS acceptor."
echo "External consumers would obtain a broken crate."
echo "Cannot publish to crates.io: dig-gossip carries one [patch.crates-io] vendored fork,"
echo "native-tls, whose OpenSSL server acceptor sets CERT_REQUIRED plus Chia CA trust for"
echo "inbound mTLS (CON-009). Upstream TlsAcceptorBuilder cannot require a client"
echo "certificate at all."
echo ""
echo "cargo publish STRIPS [patch.crates-io] from the published metadata, so a published"
echo "dig-gossip would build against upstream native-tls, compile cleanly, and silently"
echo "accept inbound peers presenting no client certificate. The failure mode is a silent"
echo "security regression, not a build error."
echo ""
echo "Flipping this job to manual dispatch does NOT make it safe; the publish blocker"
echo "is structural. The forks must be resolved first (dig_ecosystem#2228)."
echo "is structural. The native-tls patch must be removable first (dig_ecosystem#2647)."
echo ""
echo "The git + Cargo.lock consumer path (dig-node) is unaffected."
exit 1
Expand Down
16 changes: 13 additions & 3 deletions Cargo.lock

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

47 changes: 29 additions & 18 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
# - Specs: docs/requirements/domains/crate_structure/specs/STR-001.md, STR-004.md
# - Master spec: docs/resources/SPEC.md (Sections 1.2, 10.3, 10.4)
#
# Rationale for `chia-sdk-client` shape:
# Rationale for the `dig-peer-protocol` shape:
# STR-001 requires both `native-tls` and `rustls` feature forwards to
# `chia-sdk-client/*`. If we hard-coded `features = ["native-tls"]` on the
# dependency itself, `cargo check --no-default-features --features rustls` could
# not cleanly select the rustls backend. We therefore set `default-features = false`
# on the dependency and enable TLS exclusively via our feature flags.
# `dig-peer-protocol/*` (which forwards them on to `chia-sdk-client`). If we
# hard-coded `features = ["native-tls"]` on the dependency itself,
# `cargo check --no-default-features --features rustls` could not cleanly select
# the rustls backend. We therefore set `default-features = false` on the
# dependency and enable TLS exclusively via our feature flags.
#
# Rationale for optional `siphasher` / `minisketch-rs`:
# STR-001's implementation notes state these are gated behind `compact-blocks`
Expand All @@ -20,7 +21,7 @@

[package]
name = "dig-gossip"
version = "0.22.2"
version = "0.23.0"
edition = "2021"
license = "Apache-2.0"
description = "Peer-to-peer networking and gossip for the DIG Network L2 blockchain"
Expand All @@ -33,13 +34,19 @@ categories = ["network-programming", "cryptography::cryptocurrencies"]

[dependencies]
# DIG peer protocol — superset of chia-protocol, re-exports all chia-* crate types plus
# DIG extension opcodes (200-219), DigMessage, DigMessageType, introducer wire types.
# Single import replaces: chia-protocol, chia-sdk-client, chia-ssl, chia-traits, chia_streamable_macro.
# DIG extension opcodes (200-222), DigMessage, DigMessageType, introducer wire types.
# The band runs to 222, not 219: 220 is DIG_MESSAGE, 221 STORE_MELTED, 222 HOLDINGS_ANNOUNCE, and
# all three are live. dig-relay vendors this wire byte-identically, so an understated band here is
# the kind of number that gets copied into a second implementation.
# Single import replaces chia-sdk-client and chia-ssl outright. chia-protocol, chia-traits and
# chia_streamable_macro stay declared below: the streamable proc-macro reads this manifest and
# generates `chia_protocol::` paths, so they must be nameable here even though the code prefers
# the re-exports.
# `dig-peer-protocol` is the rename of the former `dig-protocol` crate (#1383); the crate name in
# code is `dig_peer_protocol`. TLS backends are forwarded through it to chia-sdk-client, so we keep
# `default-features = false` and select the backend exclusively via our own `native-tls` / `rustls`
# feature flags (see the `chia-sdk-client` shape rationale at the top of this manifest).
dig-peer-protocol = { version = "0.2", default-features = false }
# feature flags (see the `dig-peer-protocol` shape rationale at the top of this manifest).
dig-peer-protocol = { version = "0.5", default-features = false }
# Unified DIG Node peer transport (L7 peer-network spec): mTLS `connect(peer)` over the NAT-traversal
# ladder (direct → UPnP → NAT-PMP → PCP → hole-punch → relay-last) yielding a yamux-multiplexed
# `PeerConnection`, plus `peer_id = SHA256(TLS SPKI DER)` verification, the relay client, and the
Expand Down Expand Up @@ -144,7 +151,7 @@ tokio = { version = "1", features = ["full"] }
tokio-tungstenite = { version = "0.24", features = ["native-tls"] }
# Inbound TLS termination (CON-002) — paired with `native-tls` / `rustls` features (STR-004).
# Inbound listener (CON-002) uses `native_tls::TlsAcceptor` even when outbound uses rustls — `tokio_tungstenite::MaybeTlsStream::Rustls`
# only wraps **client** `tokio_rustls` streams; [`chia_sdk_client::Peer::from_websocket`] matches `NativeTls` / client `Rustls` (STR-004 note).
# only wraps **client** `tokio_rustls` streams; [`dig_peer_protocol::DigLink::from_websocket`] matches `NativeTls` / client `Rustls` (STR-004 note).
native-tls = { version = "0.2", optional = true }
tokio-native-tls = { version = "0.3", optional = true }

Expand All @@ -153,7 +160,7 @@ tokio-native-tls = { version = "0.3", optional = true }
# vendored `native-tls` [patch] (which does not propagate through a git dependency — the root cause of
# the "peer cert never requested → peer_id underivable → inbound dropped on Linux" bug). rustls
# requests + captures the client cert directly, sidestepping the [patch] propagation entirely. Pinned
# to the SAME rustls 0.23 + aws_lc_rs backend the vendored `chia-sdk-client` outbound connector uses,
# to the SAME rustls 0.23 + aws_lc_rs backend the upstream `chia-sdk-client` outbound connector uses,
# so ONE rustls resolves across the peer stack.
rustls = { version = "0.23", optional = true, default-features = false, features = ["aws_lc_rs", "std"] }
tokio-rustls = { version = "0.26", optional = true, default-features = false, features = ["aws_lc_rs"] }
Expand All @@ -164,7 +171,7 @@ serde = { version = "1", features = ["derive"] }
serde_json = "1"
bincode = "1"

# `StreamExt` / `SinkExt` for raw WebSocket framing in CON-002 (before [`chia_sdk_client::Peer`]).
# `StreamExt` / `SinkExt` for raw WebSocket framing in CON-002 (before [`dig_peer_protocol::DigLink`]).
futures-util = "0.3"

# Cancellation tokens for task lifecycle (DSC-006 discovery loop, CNC-004 shutdown).
Expand Down Expand Up @@ -337,12 +344,16 @@ name = "dsc_005_tests"
path = "tests/dsc_005_tests.rs"
required-features = ["native-tls"]

# Patched `chia-sdk-client`: forwards inbound `RequestPeers` with remote-issued ids to the
# application channel (full-duplex RPC). See `vendor/chia-sdk-client/src/peer.rs`.
[patch.crates-io]
# DSC-005: `RegisterPeer` / `RegisterAck` opcodes 218/219 on `ProtocolMessageTypes` (see vendor/chia-protocol/README.dig-gossip.md).
chia-protocol = { path = "vendor/chia-protocol" }
chia-sdk-client = { path = "vendor/chia-sdk-client" }
# Patched `native-tls`: OpenSSL server acceptor sets CERT_REQUIRED + Chia CA trust for inbound mTLS
# (CON-009). See `vendor/native-tls/README.dig-gossip.md`.
#
# This is the ONLY remaining vendored fork. It is NOT removable: upstream
# `TlsAcceptorBuilder` exposes only `min_protocol_version` / `max_protocol_version` /
# `accept_alpn` / `build`, with no way to require a client certificate. Dropping it would
# still compile and would silently accept inbound peers presenting no client cert at all.
#
# The `chia-protocol` and `chia-sdk-client` forks were deleted in dig_ecosystem#2228: both
# existed because Chia's `ProtocolMessageTypes` cannot name a DIG opcode (200-222), which
# `dig_peer_protocol::DigLink` solves by framing a raw opcode byte instead.
native-tls = { path = "vendor/native-tls" }
Loading
Loading