dig_chainsource_interface/lib.rs
1//! # dig-chainsource-interface — the DIG Network canonical `ChainSource` provider interface
2//!
3//! This crate defines the ONE [`ChainSource`] trait (and its query/result/error types) that every
4//! Chia chain-source provider implements and every DIG consumer depends on. There is a single
5//! canonical contract for reading Chia chain state across the ecosystem — never a per-crate copy
6//! that could byte-drift.
7//!
8//! It is a pure **leaf**: a trait, its typed query inputs and results, a typed error, an optional
9//! in-memory mock, and known-answer tests. It performs NO I/O, holds NO keys, opens NO network,
10//! and ships NO concrete provider. Providers (coinset.org, a local wallet/full node, DIG peers)
11//! live in their own crates; `chia-query` is the registry + aggregating canonical source that
12//! composes them. Consumers depend on THIS trait, not on any provider.
13//!
14//! ## Reads only — no broadcast, ever (custody stance)
15//!
16//! Nothing in this crate can broadcast, push, or submit to the chain: there is no such method, by
17//! design. It is a pure reader. Write/spend/broadcast paths — which touch keys and funds — live
18//! entirely outside this crate, so depending on it can never move value.
19//!
20//! ## Fail-closed: `Ok(None)` vs `Err` (the soundness contract)
21//!
22//! Every read distinguishes two outcomes consumers MUST treat differently:
23//! - `Ok(None)` / an empty `Vec` — the source reliably answered and the thing genuinely does not
24//! exist. Safe to act on.
25//! - `Err(_)` — the source could NOT reliably answer (transport/timeout/malformed/unsupported).
26//! The answer is unknown; the consumer MUST fail closed, never treating it as an absence.
27//!
28//! Absence is NEVER an error variant; an error is NEVER degraded to a value.
29//!
30//! ## Money-critical parent-walk enablement
31//!
32//! A Chia coin's `puzzle_hash` is attacker-chosen, so a `launcher_id ==` equality check is
33//! spoofable. Authenticating a coin as a genuine singleton requires walking
34//! [`ChainSource::parent_spend`] back toward the real launcher, proving each hop from the parent's
35//! actual reveal+solution — a spoofed curried-puzzle coin has no genuine recreation parent-spend,
36//! so the walk fails closed. This crate supplies that primitive (and [`SingletonLineage`], whose
37//! authority is MEMBERSHIP, not tip-equality); consumers supply the trust logic on top.
38//!
39//! ## The canonical lineage walk (feature `lineage-walk`)
40//!
41//! [`ChainSource::resolve_singleton_lineage`] is the one method with no default body, so a source
42//! backed only by primitive reads would have to hand-roll that money-critical authentication. Enable
43//! the non-default `lineage-walk` feature and the whole walk is supplied — the method body becomes a
44//! one-line delegation to [`resolve_singleton_lineage_via_walk`]:
45//!
46//! ```toml
47//! dig-chainsource-interface = { version = "0.3", features = ["lineage-walk"] }
48//! ```
49//!
50//! The feature is OFF by default because the walk needs a CLVM evaluator (it runs each parent's
51//! inner puzzle to DERIVE its successor), and a consumer that only depends on the trait should not
52//! pay for one.
53
54mod error;
55mod lineage;
56mod provider;
57mod record;
58mod source;
59
60#[cfg(feature = "lineage-walk")]
61mod walk;
62
63#[cfg(feature = "testing")]
64mod testing;
65
66pub use error::ChainSourceError;
67pub use lineage::SingletonLineage;
68pub use provider::{ProviderId, ProviderInfo, ProviderKind};
69pub use record::CoinRecord;
70pub use source::{ChainSource, ChainSourceProvider};
71
72#[cfg(feature = "lineage-walk")]
73pub use walk::{
74 resolve_singleton_lineage_via_walk, walk_singleton_lineage, walk_singleton_lineage_bounded,
75 walk_singleton_lineage_within, LineageWalkError, WalkBounds, DEFAULT_WALK_BUDGET,
76 MAX_HOP_CLVM_COST, MAX_LINEAGE_DEPTH, MAX_REVEAL_EXPANDED_BYTES,
77};
78
79#[cfg(feature = "testing")]
80pub use testing::MockChainSource;
81
82/// The crate version, sourced from `Cargo.toml` at build time.
83pub const VERSION: &str = env!("CARGO_PKG_VERSION");
84
85#[cfg(test)]
86mod tests {
87 use super::VERSION;
88
89 #[test]
90 fn version_is_reported() {
91 assert!(!VERSION.is_empty());
92 }
93}