Skip to main content

MirrorReconcileResult

Enum MirrorReconcileResult 

Source
pub enum MirrorReconcileResult {
    Planned {
        capsules_stale: u32,
        capsules_affordable: u32,
        collateral_reclaimed_dig_base_units: u64,
        collateral_relocked_dig_base_units: u64,
        fee_estimate_mojos: u64,
        stale_url_sets: Vec<Vec<String>>,
        url_current: Vec<String>,
        targets_seen_last_7_days: u32,
    },
    Refused {
        reason: MirrorReconcileRefusal,
        url_current: Option<Vec<String>>,
    },
    Submitted {
        reclaims_submitted: u32,
        reclaims_rejected: u32,
        recreates_owed: u32,
        left_unchanged: u32,
        left_reason: Option<String>,
        url_current: Vec<String>,
    },
}
Expand description

control.mirror.reconcile — reconcile this node’s mirror coins to its CURRENT advertise URL: reclaim every coin advertising a stale URL, then recreate it advertising the URL this node advertises TODAY. Shared by the manual “reset mirrors” action and the same primitive the node’s DAILY detector runs (dig-node#570) — ONE reconcile primitive, exposed two ways (dig_ecosystem#3203).

§Three outcomes, and a client MUST be able to tell them apart

They mean different things about the user’s money, which is why this is a tagged union rather than a single struct with optional fields:

  • Planneddry_run: true only. A PRICED PLAN; nothing was spent.
  • Refused — nothing was spent. See MirrorReconcileRefusal for why.
  • Submitted — reclaims were SUBMITTED to the mempool; recreates are OWED to a later pass. Neither is confirmed by the time this call returns.

§completed/partial do not exist, and cannot: a reclaim and a create are separate bundles

A create’s $DIG is selected by a chain scan of CONFIRMED coins; a reclaim’s collateral becomes spendable only once the reclaim ITSELF confirms — a LATER pass, never inside this call. So at return time the node can state how many reclaims the mempool accepted or rejected and how many recreates are therefore owed, but it CANNOT state how many creates confirmed: that fact does not exist yet. A completed{created: 3}-shaped answer would be a money statement about the future reported as though it were the present — the exact class of lie dig-node SPEC §25.8 exists to remove. Submitted’s counts are the honest version of the same information: what the node actually knows at the moment it answers.

§Refused MUST mean nothing was spent, unconditionally

A caller distinguishes refused from submitted precisely so it never has to guess whether a “no” cost money. An implementation that spends anything under a Refused outcome breaks the one guarantee this contract exists to give the operator.

§A dry run that would in fact refuse reports Refused, never Planned

Planned prices a plan the node believes it CAN execute — computed against the same validation (corroborated URL, changed URL, affordability) a real run performs. A dry run whose candidate URL is uncorroborated, unchanged, or otherwise refusable answers Refused exactly like a real run would, so a caller previewing a reset sees the same refusal a real attempt would hit rather than a plan for a call that cannot execute.

§The load-bearing invariant: K is sized BEFORE any reclaim, and exactly K are reclaimed

Planned::capsules_affordable and Submitted‘s counts describe the SAME quantity, computed the SAME way: the affordable prefix K, sized against the wallet’s balance AUGMENTED by the K coins’ own collateral (since reclaiming them is what funds their matching recreate), decided BEFORE any reclaim is attempted. An implementation MUST NOT reclaim more than it has already decided it can recreate — reclaiming n and creating only K leaves the node holding uncollateralised capsules it has stopped advertising, which is the half-run failure this whole method exists to prevent. “No worse off” therefore means the bond COUNT is unchanged, never merely that no XCH fee was wasted.

Variants§

§

Planned

dry_run: true only — a priced plan. Nothing was spent.

Fields

§capsules_stale: u32

How many (store, root) capsules this node holds whose bonded coin is stale (n).

§capsules_affordable: u32

Of those n, how many the wallet can actually afford to reconcile right now (K) — sized the SAME way, and BEFORE the same event, that a real run’s Submitted counts are: see “The load-bearing invariant” above. K < capsules_stale is a normal answer, not a warning sign; a client renders it as “will reconcile K of n” rather than treating it as a partial failure.

§collateral_reclaimed_dig_base_units: u64

The $DIG this plan would FREE, summed over the K coins it would reclaim — read from those coins, never recomputed from today’s requirement.

§collateral_relocked_dig_base_units: u64

The $DIG this plan would RE-LOCK, K × this epoch's margined requirement.

Deliberately NOT combined with collateral_reclaimed_dig_base_units into one “cost” figure: collateral is reclaimed and relocked, not spent, and the net $DIG movement is collateral_relocked_dig_base_units - collateral_reclaimed_dig_base_units — zero in the common case where the requirement has not moved. Presenting the round-trip as a single cost teaches an operator their reset burns $DIG, which is the money-lie class in the reassuring-looking direction’s opposite: it makes a free action look expensive rather than a costly one look free.

§fee_estimate_mojos: u64

The ACTUAL cost of this plan: the XCH network fee, in mojos (1e-12 XCH). The one figure in this result that is genuinely spent rather than reclaimed-and-relocked.

§stale_url_sets: Vec<Vec<String>>

The DISTINCT URL set(s) the n stale coins currently advertise, bounded.

A Vec<Vec<String>> rather than one flattened list: coins created at different past times can each carry a DIFFERENT advertise URL, so a single list would either merge them (implying they agree when they may not) or silently show only one coin’s memo. A client renders each inner list as one distinct “was advertising” group.

§url_current: Vec<String>

The URL(s) this node’s mirror coins would advertise once the K creates confirm — this node’s CURRENT target, i.e. what control.config.get’s mirror_advertise reports NOW.

§targets_seen_last_7_days: u32

How many DISTINCT advertise URLs this node has held in the last 7 days.

dig-node SPEC §25.13.8’s rotating-address warning: a node whose public address keeps changing pays reconcile’s fee repeatedly for a problem reconcile cannot fix. A client SHOULD surface this when it is greater than one or two, rather than only after the operator has already paid for several resets.

§

Refused

Refused. Nothing was spent — see MirrorReconcileRefusal for why.

Fields

§reason: MirrorReconcileRefusal

Which of the ten reasons this refusal is.

§url_current: Option<Vec<String>>

The URL(s) this node’s existing mirror coins advertise, where the node can state it. None when the refusal itself means the node cannot say — e.g. no_mirror_coins leaves no bond to read a URL from at all.

§

Submitted

Reclaims were SUBMITTED to the mempool; matching recreates are OWED to a later pass — the only outcome an implementation may report once anything has been spent, because a create’s confirmation is never observable synchronously (see “completed/partial do not exist” above). A left_unchanged of zero means every stale capsule was affordable and submitted; greater than zero is a NORMAL outcome, not an error — the caller can tell because the counts say so, not because a tag says “partial”.

Fields

§reclaims_submitted: u32

How many of the K sized-and-attempted reclaims the mempool ACCEPTED.

§reclaims_rejected: u32

Of the SAME K attempted, how many the mempool REJECTED (e.g. a coin spent elsewhere in a race). Distinct from left_unchanged: a rejected reclaim was ATTEMPTED and failed at runtime, an unchanged capsule was never attempted because K was sized before it.

§recreates_owed: u32

How many recreates are now OWED to the ordinary create pass — always equal to reclaims_submitted: only an accepted reclaim’s collateral will ever confirm and become available to fund its matching create. Never created inside this call; see the type-level doc for why.

§left_unchanged: u32

How many stale capsules (n − K) this call left exactly as they were, because sizing K happened BEFORE any reclaim was attempted.

§left_reason: Option<String>

Why the plan stopped short of every stale capsule. None when left_unchanged is zero — there is nothing to explain when nothing was left behind.

§url_current: Vec<String>

The URL(s) the K submitted recreates are targeting — this node’s CURRENT target, on the same terms as Planned::url_current.

Trait Implementations§

Source§

impl Clone for MirrorReconcileResult

Source§

fn clone(&self) -> MirrorReconcileResult

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for MirrorReconcileResult

Source§

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

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

impl<'de> Deserialize<'de> for MirrorReconcileResult

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for MirrorReconcileResult

Source§

impl PartialEq for MirrorReconcileResult

Source§

fn eq(&self, other: &MirrorReconcileResult) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for MirrorReconcileResult

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for MirrorReconcileResult

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<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<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. 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.