Skip to main content

GASPSync

Struct GASPSync 

Source
pub struct GASPSync<'a> {
    pub last_interaction: u64,
    pub unidirectional: bool,
    /* private fields */
}
Expand description

GASP sync orchestrator.

Coordinates between local GASPStorage and a GASPRemote peer to synchronize overlay UTXOs. Supports paginated sync and unidirectional mode.

The lifetime 'a allows the storage and remote to borrow from their environment (e.g., OverlayGASPStorage borrows from the Engine’s storage).

Fields§

§last_interaction: u64

Score of last successful interaction with this peer.

§unidirectional: bool

If true, only pull from remote — don’t push local UTXOs.

Implementations§

Source§

impl<'a> GASPSync<'a>

Source

pub fn new( storage: Box<dyn GASPStorage + 'a>, remote: Box<dyn GASPRemote + 'a>, last_interaction: u64, log_prefix: impl Into<String>, unidirectional: bool, ) -> Self

Create a new GASP sync orchestrator.

The ancestor fetcher is OFF by default. Use with_ancestor_fetcher to opt in to chain-backed ancestry hydration (one-time-migration only).

Source

pub fn with_expired_outpoints( self, expired: Rc<RefCell<HashSet<String>>>, ) -> Self

Share expired outpoints across the topic peers of one engine run.

Source

pub fn with_batch_memo(self, single_only: Rc<Cell<bool>>) -> Self

Share the run’s single-only memo of this peer (engine 0.2.1, #58).

Source

pub fn with_page_slice(self, stop: Rc<dyn Fn() -> bool + 'a>) -> Self

Backfill slices stop after one page or at a caller-owned request bound.

Source

pub fn pages(&self) -> u64

Source

pub fn page_advanced(&self) -> bool

Source

pub fn reached_tip(&self) -> bool

Source

pub fn expired_refused(&self) -> u64

Source

pub fn roots_proven(&self) -> u64

Source

pub fn roots_unproven(&self) -> u64

Source

pub fn cursor_held_by(&self) -> Option<String>

Source

pub fn cursor_yielded(&self) -> bool

Source

pub fn graphs_retained(&self) -> u64

New durable holds the last sync saved holding at least one node the peer served (a walk past its budget, or the graph in flight at the per-peer deadline): work the cursor may pass because the next sync resumes it. A hold of nothing is not counted: the peer served no node of it (the hung peer of bsv-low #555’s H1).

Source

pub fn did_work(&self) -> bool

Whether the last sync did work beyond finalizing a graph or moving the cursor (engine 0.1.8): it refused an expired root not refused before, retained a graph or resumed one with progress. Such a sync is never a failed attempt. Only the refusal also ends the yieldless streak (see Engine::start_gasp_sync).

Source

pub fn graphs_resumed_with_progress(&self) -> u64

Held graphs the last sync resumed that appended at least one node or converged.

Source

pub fn faulted_roots(&self) -> Vec<FaultedRoot>

The roots the last sync dropped, each named once with its fault class (engine 0.1.9): what cursor_held_by cannot say.

Source

pub fn unanchorable_recorded(&self) -> u64

Roots the last sync recorded unanchorable: their walk faulted in UNANCHORABLE_AFTER_FAULTED_RUNS consecutive runs, and the cursor passes them from now on.

Source

pub fn absent_struck(&self) -> u64

Roots the last sync struck unanchorable:not_found (engine 0.1.15): the peers’ word of absence counted on UNANCHORABLE_AFTER_FAULTED_RUNS runs at least ABSENCE_GAP_SECS apart. Counted in Self::unanchorable_recorded too.

Source

pub fn dead_recorded(&self) -> u64

Roots with a fault record (unanchorable or not yet) that the last sync walked again and admitted or refused on a verdict: their record cleared.

Source

pub fn memo_folded(&self) -> u64

Source

pub fn expired_swept(&self) -> u64

Source

pub fn unanchorable_cleared(&self) -> u64

Source

pub fn strikes_refused(&self) -> u64

Strikes the last sync could not write at the storage’s ceiling or on a storage fault. Each is named in Self::faulted_roots with its FaultedRoot::refused; a refused strike of a new root leaves it a gap the cursor holds below.

Source

pub fn with_resume_share(self, share: Box<dyn Fn() -> SleepFuture + 'a>) -> Self

Bound each graph’s walk and retain its pending work. A successfully saved hold permits cursor progress; an unsaved graph remains a gap. Bound the resumes of each pass by share (engine 0.1.11): ONE deadline for every held record walked ahead of the page, started when the held loop starts, so the page keeps the rest of the per-peer slice (see RESUMES_SHARE_OF_PEER_BUDGET_PERCENT). A record reached once it fell due is held back for the next sync. Without one the resumes share one per-graph deadline (the lens fold’s M1).

Source

pub fn with_graph_budget(self, budget: GraphBudget<'a>) -> Self

Source

pub fn deferral_stats(&self) -> DeferralStats

What the last sync did with deferred graphs (bsv-low #555).

Source

pub fn graphs_attempted(&self) -> u64

How many UTXOs the sync set out to ingest (a new walk, a resume, or a record held back): the peer served it work it did not hold. A sync that attempted none was quiet (bsv-low #555, the delta fold’s D-M2: a quiet sync never counts toward PEER_YIELDLESS_SYNCS_ALLOWED).

Source

pub fn with_finalized_graph_hook( self, hook: Box<dyn FinalizedGraphHook + 'a>, ) -> Self

Have hook called after every completed incoming UTXO (bsv-low #552, see FinalizedGraphHook). Without one sync is unchanged.

Source

pub fn completed_cursor(&self) -> u64

The cursor that is safe to persist if sync stopped RIGHT NOW (its future dropped at a deadline; bsv-low #552). It is the gap guard’s rule applied to completed scores: never above a completed output, and strictly below the lowest score of any UTXO of the current page not yet completed (the one in flight included) and of any UTXO whose ingest failed, never below the cursor the sync entered with. The remote serves score >= since, so the next sync is served everything this one did not finish. After a completed sync it equals last_interaction.

last_interaction itself is NOT safe after a drop: it is raised to each UTXO’s score BEFORE that UTXO is ingested, for pagination.

Source

pub fn graph_in_flight(&self) -> bool

Whether a graph was being fetched, walked or anchor-checked when sync last stopped: true only after a sync future dropped mid-graph (bsv-low #552). That graph’s nodes died with the storage adapter; nothing of it was finalized.

Source

pub fn discarded_graphs(&self) -> u64

How many graphs this orchestrator’s last sync discarded because validate_graph_anchor REFUSED them (a root that does not verify, or one the topic manager does not admit at the end of the replay; bsv-low #551). Nothing of a discarded graph is finalized. As in the reference a refused graph is not a failed UTXO: the cursor advances past it. A graph whose anchor could not be CHECKED (GASPError::AnchorUnavailable: a tracker or storage fault, a topic manager error in the replay) is not counted here: that one fails its UTXO and is asked for again.

Source

pub fn anchor_walk_held(&self) -> u64

How many graphs this orchestrator’s last sync HELD because their anchor’s script walk could not run within the engine’s walk budget (GASPError::AnchorWalkHeld; bsv-low #592, the E592 lens fold): not finalized, the UTXO failed and the cursor kept below it, until the peer serves the root proven. Not counted in discarded_graphs.

Source

pub fn pruned_inputs(&self) -> u64

How many manager-named inputs this orchestrator pruned because the peer answered that it does not hold them (the D8 decoy rule, see process_incoming_node). Counted per DISTINCT outpoint per sync call of this orchestrator, which talks to ONE peer: the same decoy seen through two peers is counted by each. A pruned branch is NOT a failed UTXO: the graph completes with what it has and the cursor advances.

Source

pub fn with_ancestor_fetcher( self, fetcher: Option<Rc<dyn AncestorFetcher + 'a>>, ) -> Self

Opt in to chain-backed ancestor hydration (OFF by default).

When set, a peer’s inability to serve a needed ancestor during ingest triggers a fallback fetch of that ancestor’s raw tx from chain. This is a deliberate one-time-migration escape hatch — production should NOT call this. Without it, behavior is unchanged.

Source

pub async fn sync(&mut self, limit: Option<u64>) -> Result<(), GASPError>

Run the sync protocol with the remote peer.

  1. Request remote’s UTXOs since last interaction (paginated)
  2. For each unknown UTXO, request the full graph and ingest it
  3. If bidirectional, push our unknown UTXOs to the remote
Source

pub fn page_floor(&self) -> Option<u64>

The cursor safe before the page whose writes are still queued, if a page was open when sync last stopped (engine 0.2.2): its future was dropped mid-page. The caller writes the queue or, failing that, keeps the cursor at this floor.

Source

pub async fn defer_in_flight(&mut self)

Save the walk of the graph that was in hand when a deadline dropped sync (bsv-low #555): the per-peer deadline (D16) defers it like the per-graph one, so the next pass resumes it instead of walking it again. No-op without a per-graph budget.

The graph in flight is HELD at once, whatever it fetched: its root outpoint and partial walk become a durable record (reason peer_deadline) the next sync resumes ahead of its pages, so the cursor passes it to the page’s last finished score. Before 0.1.8 a graph the deadline met before its root came back was only a retry, and the next run re-read the same page behind it (bsv-low #552: “the graph in flight is lost whole”). A graph the deadline met after its refusal is finished, not held. A graph that cannot be held (no room) stays the cursor’s gap and is named in cursor_held_by.

Auto Trait Implementations§

§

impl<'a> !Freeze for GASPSync<'a>

§

impl<'a> !RefUnwindSafe for GASPSync<'a>

§

impl<'a> !Send for GASPSync<'a>

§

impl<'a> !Sync for GASPSync<'a>

§

impl<'a> !UnwindSafe for GASPSync<'a>

§

impl<'a> Unpin for GASPSync<'a>

§

impl<'a> UnsafeUnpin for GASPSync<'a>

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> 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> Same for T

Source§

type Output = T

Should always be Self
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