Skip to main content

ChainSource

Trait ChainSource 

Source
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 empty Vec — 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§

Source

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§

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

fn peak_height(&self) -> Result<Option<u32>, Self::Error>

Reads the current peak (fully-synced) block height, if the source tracks one.

Ok(None) = the source does not expose a peak; Err(_) = could not answer.

Source

fn block_timestamp(&self, height: u32) -> Result<Option<u64>, Self::Error>

Reads the Unix timestamp of the block at height.

Ok(None) = no such block or no timestamp index; Err(_) = could not answer.

Provided Methods§

Source

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".

Implementors§