pub trait ChainSource {
type Error: Display;
// Required methods
fn coin_record(
&self,
coin_id: BytesImpl<32>,
) -> Result<Option<CoinRecord>, Self::Error>;
fn coin_records_by_puzzle_hash(
&self,
puzzle_hash: BytesImpl<32>,
include_spent: bool,
) -> Result<Vec<CoinRecord>, Self::Error>;
fn coin_records_by_parent(
&self,
parent_coin_id: BytesImpl<32>,
) -> Result<Vec<CoinRecord>, Self::Error>;
fn coin_spend(
&self,
coin_id: BytesImpl<32>,
) -> Result<Option<CoinSpend>, Self::Error>;
fn resolve_singleton_lineage(
&self,
launcher_id: BytesImpl<32>,
) -> Result<Option<SingletonLineage>, Self::Error>;
fn peak_height(&self) -> Result<Option<u32>, Self::Error>;
fn block_timestamp(&self, height: u32) -> Result<Option<u64>, Self::Error>;
// Provided method
fn parent_spend(
&self,
coin_id: BytesImpl<32>,
) -> Result<Option<CoinSpend>, Self::Error> { ... }
}Expand description
A reads-only view of Chia chain state — the single canonical contract every provider implements and every consumer depends on.
§Fail-closed None vs Err (the crux)
Every fallible method distinguishes two outcomes that consumers MUST treat differently:
Ok(None)/ an emptyVec— the source reliably answered and the thing genuinely does not exist (an unlaunched singleton, an unspent coin, a melted lineage). Safe to act on.Err(_)— the source could NOT reliably answer (transport, timeout, malformed, unsupported). The answer is unknown; the consumer MUST fail closed and never treat it as an absence.
§Reads only
This trait cannot broadcast, push, or submit anything to the chain — there is no such method, deliberately. It is a pure reader; write/spend paths live entirely outside this crate.
Required Associated Types§
Sourcetype Error: Display
type Error: Display
The source’s own transport/parse error. crate::ChainSourceError is the recommended type
for registry participants, but any Display error is accepted.
Required Methods§
Sourcefn coin_record(
&self,
coin_id: BytesImpl<32>,
) -> Result<Option<CoinRecord>, Self::Error>
fn coin_record( &self, coin_id: BytesImpl<32>, ) -> Result<Option<CoinRecord>, Self::Error>
Reads the coin with id coin_id.
Ok(None) = the coin genuinely does not exist per this source; Err(_) = could not answer.
Sourcefn coin_records_by_puzzle_hash(
&self,
puzzle_hash: BytesImpl<32>,
include_spent: bool,
) -> Result<Vec<CoinRecord>, Self::Error>
fn coin_records_by_puzzle_hash( &self, puzzle_hash: BytesImpl<32>, include_spent: bool, ) -> Result<Vec<CoinRecord>, Self::Error>
Reads all coins paying to puzzle_hash, optionally including already-spent coins.
An empty Vec = no matching coins; Err(_) = could not answer.
Sourcefn coin_records_by_parent(
&self,
parent_coin_id: BytesImpl<32>,
) -> Result<Vec<CoinRecord>, Self::Error>
fn coin_records_by_parent( &self, parent_coin_id: BytesImpl<32>, ) -> Result<Vec<CoinRecord>, Self::Error>
Reads all coins whose parent is parent_coin_id — the direct children created by spending
that coin.
An empty Vec = no known children; Err(_) = could not answer.
Sourcefn coin_spend(
&self,
coin_id: BytesImpl<32>,
) -> Result<Option<CoinSpend>, Self::Error>
fn coin_spend( &self, coin_id: BytesImpl<32>, ) -> Result<Option<CoinSpend>, Self::Error>
Reads the spend that SPENT coin_id (the spend whose input coin is coin_id).
Ok(None) = coin_id is unspent or unknown; Err(_) = could not answer.
Sourcefn resolve_singleton_lineage(
&self,
launcher_id: BytesImpl<32>,
) -> Result<Option<SingletonLineage>, Self::Error>
fn resolve_singleton_lineage( &self, launcher_id: BytesImpl<32>, ) -> Result<Option<SingletonLineage>, Self::Error>
Resolves the singleton launched at launcher_id to its authenticated SingletonLineage
(every coin id from launcher to current tip).
This MUST be a genuine forward walk from the launcher to its tip — each coin the singleton
recreation of the previous — NEVER an echo of a caller-supplied coin, or membership becomes
meaningless (SPEC §4, the money-critical requirement). Ok(None) = the launcher never
existed or the singleton has been fully melted; Err(_) = could not answer.
Provided Methods§
Sourcefn parent_spend(
&self,
coin_id: BytesImpl<32>,
) -> Result<Option<CoinSpend>, Self::Error>
fn parent_spend( &self, coin_id: BytesImpl<32>, ) -> Result<Option<CoinSpend>, Self::Error>
Reads the spend that CREATED coin_id — i.e. the spend of coin_id’s parent — by resolving
the coin’s parent and reading that parent’s spend. This is the money-critical parent-walk
primitive.
A coin’s puzzle_hash is attacker-chosen: anyone can pay a coin whose puzzle hash equals a
victim singleton’s outer hash, so a bare launcher_id == check is spoofable. Authenticating
a coin as a genuine singleton requires walking parent_spend back toward the real launcher,
where each hop is proven from the parent’s actual reveal+solution. A spoofed curried-puzzle
coin has no genuine recreation parent-spend, so the walk fails closed rather than trusting
the cheap equality. Consumers MUST walk this primitive, never trust puzzle-hash equality.
The default implementation composes coin_record +
coin_spend; a source may override it with a direct query. Ok(None) =
the parent is unspent/unknown (a gap → fail closed mid-walk); Err(_) = could not answer.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".