pub enum WalletSyncPhase {
NotStarted,
Syncing,
Synced,
NoWalletEnrolled,
WalletNotUnlocked,
Unrecognized(UnknownPhaseToken),
}Expand description
How far the node’s wallet chain replica has got — the states a background sync can be in.
Named states rather than a boolean, because “has never started” and “is caught up” are different
facts and a bool can only carry one of them. Paired with a peak_height a boolean forces a
never-started wallet to report some height, and 0 is the only one available — which reads as
synced to the genesis block, a claim about the chain that is simply false.
§Nothing to watch is TWO states, not one
A sync with no addresses to follow is idle for one of two reasons, and they are different
sentences to a user with different remedies. NoWalletEnrolled is the
honest all-clear: there is no wallet, so watching nothing is correct and complete.
WalletNotUnlocked is the opposite — a wallet EXISTS and is not being
watched — and reporting it as the all-clear tells a user with real coins that their balance is
fully accounted for while the node follows none of their addresses. Merging the two would put a
money-lie behind a green tick, so the contract keeps them apart.
§An unrecognised token is a VALUE, not a parse failure
Unrecognized exists because this enum was once closed, and a node that
grew a new phase took every consumer’s whole response down with it — see the variant’s own docs.
Consumers MUST treat an unrecognised phase as unknown, never as progress.
Variants§
NotStarted
No sync has begun: the wallet holds no replica of the chain and is not building one.
Syncing
A sync is running — either the initial catch-up, or the ongoing task that keeps the replica
current. A wallet whose catch-up finished but whose peer connections have all dropped is
Syncing, not Synced: it is trying to be current and is not.
Synced
The initial catch-up completed AND at least one Chia peer connection is currently live: the replica is caught up and CONNECTED, so it is in a position to be kept current.
That is what the predicate delivers, and no more. A live connection to a stalled or lagging peer satisfies it while the replica quietly goes stale, so this phase MUST NOT be read as proof that the data is FRESH — only that nothing is known to be preventing freshness.
NoWalletEnrolled
The honest all-clear: no wallet is enrolled on this node, so there are no addresses to follow and a sync would have nothing to do. Not a degraded state and not an error — a node that has never had a wallet is working exactly as intended.
A consumer MAY present this as settled. It is the ONLY nothing-to-watch phase for which that
is true: WalletNotUnlocked looks identical from inside the sync
loop and means the opposite.
watched_addresses accompanying this phase is
Some(0) — an observed zero, and the zero that is genuinely fine.
WalletNotUnlocked
A wallet IS enrolled, but the node holds no addresses for it, so it is watching nothing. The user’s coins are not being followed and their balance is not being maintained.
This is the common state after every restart, because the address set is derived from key
material the node cannot reach until the wallet is unlocked, and nothing back-fills it while
locked. It is emphatically NOT NoWalletEnrolled: the difference
between them is the difference between nothing to do and something to do that is not being
done.
A consumer MUST NOT render this as synced, settled, or up to date, and MUST NOT present a balance read under it as complete. The honest rendering names the wallet and the remedy — “locked, so it is not being watched yet” — because unlocking is the action that resolves it.
The name says NOT UNLOCKED rather than locked on purpose. An empty address set is what the node can observe; a lock is only the usual cause of it, and a manifest that never carried the keys reaches the same state without anything having been locked. The phase claims the observation, and leaves the cause to whatever the node can actually establish.
Unrecognized(UnknownPhaseToken)
A phase token this build does not know, carried verbatim.
§Why this variant exists
The enum shipped closed. dig-node then grew a phase, and because serde rejects an unknown
variant, the unknown token did not degrade one field — it aborted the entire
WalletSyncStatusResult. dig-app’s sync read became Err, its chain-sync state collapsed
to unknown, and the surface rendered nothing at all (dig_ecosystem#2609). Every consumer
built against an older contract than the node it talks to hit it at once.
§It is deliberately NOT silent
The token is preserved rather than discarded so the state is observable: a consumer can say which token it failed to understand, and a developer can read it out of a log instead of reaching for a packet capture. This incident stayed invisible until somebody built a probe against the published crate; the variant that replaces it should not need one.
Mapping an unknown token onto Synced or Syncing would be
far worse than the parse error it replaces. A parse error is loud and obviously wrong; a
coerced phase is a confident, plausible statement about the user’s money that the node never
made. Consumers MUST render this as unknown and MUST NOT infer progress, completion, or a
trustworthy balance from it.
§The payload is untrusted text
It is whatever the node sent. A consumer that displays it MUST escape and bound it like any
other foreign string rather than splicing it into a message unchecked. Debug escapes it, as
String’s always has; as_wire deliberately does not, because a relay must
be able to hand on the exact bytes.
§Not the same idea as PeerSoftware::Unknown
The two look alike and are not. PeerSoftware::Unknown is the ABSENCE of a report — the peer
said nothing, or said something unparseable, and there is no datum to keep. Here the node DID
report, and the token it used is a real observation this build cannot interpret. That is why
this variant carries a payload and that one does not, and why the names differ: calling it
Unknown would suggest nothing was said.
Implementations§
Source§impl WalletSyncPhase
impl WalletSyncPhase
Sourcepub const ALL: &'static [WalletSyncPhase]
pub const ALL: &'static [WalletSyncPhase]
Every phase this build KNOWS, in progress order — the enumeration a machine reads, and the anchor the conformance KATs pin the wire tokens against.
Unrecognized is absent by definition: it is the absence of a known
token rather than one of them, and it has no fixed wire spelling to pin. A node MUST NOT emit
anything outside this list; a consumer that meets something outside it gets Unrecognized
instead of a failed response.
Sourcepub fn as_wire(&self) -> &str
pub fn as_wire(&self) -> &str
This phase’s exact wire spelling, or the verbatim token for
Unrecognized.
The one place a phase becomes a string, so serialization and any display path cannot drift into two different spellings of the same state.
Sourcepub fn unrecognized_token(&self) -> Option<&str>
pub fn unrecognized_token(&self) -> Option<&str>
The token a build does not understand, or None for every phase it does.
Lets a consumer log or surface the exact unrecognised spelling without matching the variant open-coded, which is how the two spellings drift apart.
Sourcepub fn is_recognized(&self) -> bool
pub fn is_recognized(&self) -> bool
Whether this build understands the phase at all.
The predicate a consumer branches its “your node may be newer than this app” path on.
Sourcepub fn unrecognized_token_value(&self) -> Option<&UnknownPhaseToken>
pub fn unrecognized_token_value(&self) -> Option<&UnknownPhaseToken>
The unrecognised token as its own type, giving access to the escaped renderings.
unrecognized_token hands back a raw &str; this hands back the
UnknownPhaseToken, whose Display escapes and whose
display_bounded also truncates.
Sourcepub fn may_render_as_settled(&self) -> bool
pub fn may_render_as_settled(&self) -> bool
Whether a consumer may present this phase as SETTLED — nothing outstanding, nothing to do.
§Why this is a method and not a rule in the docs
Two phases mean “the sync is idle” and only one of them is good news.
NoWalletEnrolled is complete and correct;
WalletNotUnlocked is a wallet whose coins nobody is following.
Rendering the second as settled is the money-lie this family exists to prevent, and it is one
mistaken || away in every consumer that writes the rule itself.
Stating it once here makes it a compiler-checked fact rather than a paragraph each consumer re-derives — a second implementation of a rule like this is a drift bug waiting to happen. An unrecognised phase is never settled: this build cannot know what the node meant.
use dig_node_control_interface::results::WalletSyncPhase;
assert!(WalletSyncPhase::Synced.may_render_as_settled());
assert!(WalletSyncPhase::NoWalletEnrolled.may_render_as_settled());
// A wallet exists and nothing is watching it — never settled.
assert!(!WalletSyncPhase::WalletNotUnlocked.may_render_as_settled());
assert!(!WalletSyncPhase::from("a_newer_token").may_render_as_settled());Trait Implementations§
Source§impl Clone for WalletSyncPhase
impl Clone for WalletSyncPhase
Source§fn clone(&self) -> WalletSyncPhase
fn clone(&self) -> WalletSyncPhase
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for WalletSyncPhase
impl Debug for WalletSyncPhase
Source§impl<'de> Deserialize<'de> for WalletSyncPhase
impl<'de> Deserialize<'de> for WalletSyncPhase
Source§fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>
Accepts ANY string. A non-string is still a type error — a number or an object where a phase belongs is a malformed response, not a newer node.
impl Eq for WalletSyncPhase
Source§impl From<&str> for WalletSyncPhase
impl From<&str> for WalletSyncPhase
Source§fn from(token: &str) -> Self
fn from(token: &str) -> Self
Every token maps to a phase — an unknown one to
Unrecognized. Total by construction, so no caller can
reintroduce the fail-closed behaviour this type exists to remove.
Source§impl Hash for WalletSyncPhase
impl Hash for WalletSyncPhase
Source§impl PartialEq for WalletSyncPhase
impl PartialEq for WalletSyncPhase
Source§impl Serialize for WalletSyncPhase
impl Serialize for WalletSyncPhase
Source§fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>
A bare JSON string, exactly as the derived rename_all = "snake_case" produced before this
type grew an unrecognised arm — so an Unrecognized token
round-trips back out byte-identical rather than being rewritten or dropped by a relay.