Skip to main content

DidError

Enum DidError 

Source
#[non_exhaustive]
pub enum DidError {
Show 21 variants Driver(DriverError), Signer(String), Parse(String), NotDid, NotTheOwner, InvalidDidString(String), UnsupportedOwner(&'static str), EvenSingletonAmount(u64), OddAmountCreateCoin, AggSigUnsafeInConditions, NonCanonicalCreateCoinAmount(String), DisallowedCondition(String), InvalidRecovery(String), MissingLineage, MissingHint, Chain(String), NoIdentitySingleton, NotASingleton, NotDidRooted, LauncherMismatch, LineageTooDeep,
}
Expand description

Everything that can go wrong while building or parsing a DID spend.

The variants split into two families: errors delegated to the chia-wallet-sdk driver/signer (wrapped verbatim so the underlying cause is never lost), and DID-domain errors this crate raises itself (parse/hydration/codec guards, all fail-closed per SPEC §5).

Marked #[non_exhaustive]: this taxonomy grows whenever a new fail-closed guard is added, and every such addition would otherwise be a breaking change for any downstream exhaustive match. Downstream code must carry a _ arm. dig-account’s AccountError is #[non_exhaustive] for the same reason; the two now agree.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

Driver(DriverError)

A chia-wallet-sdk driver operation failed (puzzle currying, spend construction, CLVM evaluation). The wrapped DriverError carries the precise cause.

§

Signer(String)

The signing calculator failed to derive the required signatures from the coin spends (invalid puzzle/solution, an infinity public key in an AGG_SIG condition). The message is the underlying signer error rendered as a string, so this crate does not leak the signer’s error type into its public surface.

§

Parse(String)

A coin/puzzle/solution could not be parsed as the expected shape.

§

NotDid

The supplied puzzle parsed successfully but is not a DID singleton.

§

NotTheOwner

The caller could not prove it controls the DID: the supplied crate::Owner key does not curry to the DID’s current p2_puzzle_hash.

Raised by irreversible operations — [crate::melt] — before any spend is built. Such a spend could never confirm (the caller cannot produce its AGG_SIG_ME), but a melt is unrecoverable, so authority is refused up front rather than discovered at signing time (SPEC §5, fail-closed).

§

InvalidDidString(String)

A did:chia:1… string was malformed or failed bech32m decoding.

§

UnsupportedOwner(&'static str)

The operation cannot honour the crate::Owner variant it was given, because it must add conditions of its own and a caller-supplied pre-built inner spend emits one fixed condition set. Rather than silently dropping those conditions — which yields a well-formed bundle that creates none of the coins it reports — the operation refuses. The message names the alternative the caller should use instead (SPEC §5, fail-closed).

§

EvenSingletonAmount(u64)

A funding coin with an EVEN amount was supplied to a DID launch. The u64 is that amount.

Chia’s singleton top layer recognises only the launcher’s ODD-amount output as the singleton, and this crate’s launch gives the singleton the funding coin’s entire amount. An even-amount funding coin therefore produces a bundle that spends the money and creates no DID at all — a total, silent loss of the funding coin, not a rejected spend. Arbitrary wallet coins are even about half the time.

Split the funding coin down to exactly the odd amount the singleton should carry first (dig-account splits to 1 mojo) and pass that coin (SPEC §3, fail-closed).

§

OddAmountCreateCoin

A caller supplied an odd-amount CREATE_COIN to a DID-preserving spend. A singleton’s inner puzzle may emit exactly ONE odd-amount CREATE_COIN, and the DID’s own recreation occupies it, so a caller’s odd-amount CREATE_COIN can never be valid here — most often an attempt to parent a foreign singleton launcher (an amount-1 coin) to the DID coin.

Refused at build time because the alternative is opaque: the bundle would assemble and report a child DID, then be rejected at mempool admission. It never enters a block, so no fee is paid — but the caller pays a wasted round-trip and gets no explanation. Parent the launcher to an ordinary coin instead and bind it to the DID by an announcement this spend asserts, or by the launched singleton’s owner puzzle hash (SPEC §5, fail-closed).

§

AggSigUnsafeInConditions

A caller supplied an AGG_SIG_UNSAFE requirement in the conditions of a DID spend.

Unlike every other AGG_SIG_* condition, AGG_SIG_UNSAFE is signed with no coin binding and no domain separation — the signed message is the caller’s bytes verbatim. A DID owner induced to sign one produces a permanent, replayable assertion under their identity key, reusable in any spend or challenge-response the attacker later constructs. Since this crate’s contract is that the caller signs every message required_signatures reports, such a requirement is never legitimate in a DID spend and is refused (SPEC §5, fail-closed).

This refusal removes the UNBOUNDED shape, not every shape whose damage outlives the bundle. A permitted AGG_SIG_PARENT also outlives it: that signature is bound to the DID coin’s PARENT id, so it stays satisfiable by any future spend of any coin sharing that parent — the other outputs of the DID’s PREVIOUS spend, not anything this spend creates. That set was fixed before this spend was built and MAY include a coin an earlier caller paid to a third party, under a puzzle that third party chose. What the refusal buys is a BOUND, not an end to persistence: unlike AGG_SIG_UNSAFE, a permitted signature can never reach a later generation of the DID and can never become an off-domain assertion.

Nor does it make a hostile condition set safe. The permitted shapes still move the caller’s own bundled funds to caller-chosen puzzle hashes and still emit announcements under the DID’s authority. A caller composing conditions from an untrusted source MUST review the bundle before signing — and, where an AGG_SIG_PARENT is present, MUST also account for what the DID’s PREVIOUS spend created, which this bundle does not show.

§

NonCanonicalCreateCoinAmount(String)

A caller supplied a CREATE_COIN whose amount atom is not chia’s canonical integer encoding.

CLVM integers are SIGNED and chia additionally requires a canonical encoding, but the typed CreateCoin::amount this crate’s allowlist reads is a u64 decoded from the atom UNSIGNED. The two disagree on exactly the encodings chia refuses: a leading byte with the sign bit set (0x80 reads as 128, chain says CoinAmountNegative), a redundant leading zero (0x000002 reads as 2, chain says InvalidCoinAmount), and an atom with more bytes than the value needs (chain says the amount overflows). Such a spend assembles here, reports a child DID, and is then dropped at mempool admission telling the caller nothing — the opaque failure this guard exists to prevent.

The rule mirrors chia’s sanitize_uint exactly, so it can refuse nothing the chain would accept (SPEC §5, fail-closed).

§

DisallowedCondition(String)

A caller supplied a condition that is not on the allowlist of shapes a DID-preserving spend may carry. The string renders the offending condition.

The guard is an allowlist rather than a list of refusals for a structural reason: chia_sdk_types::Condition is #[non_exhaustive] and carries a catch-all Other variant that serializes to CLVM verbatim, so any caller can hand a refused condition over under a name a denylist does not recognise while the chain still sees the condition itself. Only a guard that refuses everything it does not explicitly permit can fail closed — and it stays closed when a future SDK release adds a variant nobody here has considered (SPEC §5).

§

InvalidRecovery(String)

A recovery operation supplied an inconsistent recovery configuration (list hash / required verifications mismatch).

§

MissingLineage

Hydration could not establish the lineage proof required to spend the DID (SPEC §5, fail-closed).

§

MissingHint

A parsed DID coin was missing the owner hint memo required to recreate its child (SPEC §5, fail-closed).

§

Chain(String)

A chain-level precondition was violated (e.g. a supplied coin does not match the expected launcher). The string states the specific violation. Also carries a crate::resolve::ChainSource read error verbatim — a failed read NEVER degrades to “assume owned” (SPEC §5, fail-closed).

§

NoIdentitySingleton

The DID’s identity singleton has no current on-chain coin — it was never launched, or has been melted, so there is no lineage to root a coin against (SPEC §5, fail-closed).

§

NotASingleton

The coin under proof could not be authenticated as a genuine singleton: its parent-spend chain does not resolve to a singleton launcher (an ordinary payment/change coin, or a pay-to coin that merely wears a singleton puzzle hash without a genuine recreation parent spend). SPEC §5.

§

NotDidRooted

The coin authenticates as a genuine singleton, but neither IS the DID singleton nor was launched from a coin in the DID singleton’s lineage — it is not rooted in the DID’s identity (SPEC §5).

§

LauncherMismatch

The DID’s current tip authenticated as a genuine singleton, but its GENUINE launcher (walked from the parent-spend chain) is not the launcher that was requested. This is the money-critical guard for crate::resolve_xch_address: a dishonest crate::ChainSource can echo an attacker DID’s tip for a victim launcher, and the curried launcher_id on that tip is attacker-chosen, so only the parent-walk-authenticated launcher may be trusted. Resolving an address from a mismatched launcher would pay the wrong recipient, so this fails closed (SPEC §5).

§

LineageTooDeep

The parent-spend walk exceeded crate::resolve::MAX_LINEAGE_DEPTH — a DoS guard against an unbounded (possibly adversarial) lineage. The proof fails closed rather than walk forever.

Trait Implementations§

Source§

impl Debug for DidError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for DidError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for DidError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0:

use the Display impl or to_string()

1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<DriverError> for DidError

Source§

fn from(source: DriverError) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> FmtForward for T

Source§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
Source§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
Source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
Source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
Source§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
Source§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
Source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
Source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
Source§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pipe for T
where T: ?Sized,

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
Source§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
Source§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more