pub struct BuyerPoolService<P: Provider + Clone + 'static> { /* private fields */ }Expand description
Buyer-side PaymentPool service. Generic over the alloy Provider (a
wallet-filled provider is required for the approve / openPool / topUp /
closePool / reclaim write paths). Cheap to construct; owns its background
reclaim task.
Implementations§
Source§impl<P: Provider + Clone + 'static> BuyerPoolService<P>
impl<P: Provider + Clone + 'static> BuyerPoolService<P>
Sourcepub async fn bootstrap(
provider: P,
deployment: Deployment,
owner: Address,
store: Arc<dyn BuyerPoolStore>,
signer: Arc<PrivateKeySigner>,
working_deposit: U256,
ensure_max_approval: bool,
metrics: Arc<Metrics>,
) -> Result<Self>
pub async fn bootstrap( provider: P, deployment: Deployment, owner: Address, store: Arc<dyn BuyerPoolStore>, signer: Arc<PrivateKeySigner>, working_deposit: U256, ensure_max_approval: bool, metrics: Arc<Metrics>, ) -> Result<Self>
Bootstrap the service: self-check the contract, read the immutable USDC token, issue the one-time USDC approval if requested, and spawn the reclaim sweep.
deployment is the chain and PaymentPool the service buys on; the
voucher EIP-712 domain derives from it. working_deposit is the deposit a
fresh open escrows and the target a reused pool’s low-water refill tops it
up toward.
§Errors
Returns an error if the usdc() self-check call fails (a bad
payment_pool_address or an unreachable RPC), if the persisted buyer
pools cannot be loaded, or if the one-time approval transaction fails.
The runtime treats the error as non-fatal: the node serves, and only its
paid node-to-node cache-miss leg is off.
Sourcepub async fn open_or_reuse_pool(
&self,
provider_addr: Address,
budget: Duration,
) -> Result<PoolContext>
pub async fn open_or_reuse_pool( &self, provider_addr: Address, budget: Duration, ) -> Result<PoolContext>
Return a PoolContext for paying provider_addr, pinned to that
provider and carrying the node’s self-issued capability: reuse the single
pool the node owns, or lazily open one.
A freshly-opened pool escrows the service’s working_deposit; on reuse
that deposit is ignored (a low-water refill tops a live pool up instead).
§Bounding (#1143)
budget bounds how long the CALLER waits — not how long the open runs. When
it expires this returns PoolOpenPending and the open keeps going in
a detached task: a broadcast openPool tx that is dropped mid-flight would
escrow a deposit against a pool nobody tracks, so the open is never
cancelled, only stopped-waiting-on. The next miss reuses it once it lands.
§Errors
PoolOpenPending when budget expires with the open still running.
Otherwise: store errors, any failure of the openPool transaction (submit,
revert, or receipt — carrying a decdn_incentive::PoolOpenFailureReason
the caller can downcast_ref), or a capability-signing fault.
Sourcepub fn record_progress(
&self,
provider_addr: Address,
pool_id: PoolId,
write: ProgressWrite,
) -> Result<()>
pub fn record_progress( &self, provider_addr: Address, pool_id: PoolId, write: ProgressWrite, ) -> Result<()>
Persist one lane’s voucher progress after a delivery exchange so a later
reuse (or a restart) resumes the (signer, provider) lane at the right
cumulative bytes / amount. The buyer prices cumulative = bytes × rate
from its own BLAKE3-verified bytes, so there is no nonce to track.
ProgressWrite says whether the write rebases the record down first.
§Errors
Errors on a store write fault. A stale write (the owner’s pool was replaced
by a newer open) or a superseded watermark (a concurrent settle wrote a
higher value first) is metered and returns Ok(()) — neither loses a
voucher and neither must fail the already-paid pull.
Sourcepub async fn recover_pool(&self, seen_deposit: U256) -> Result<Recovery>
pub async fn recover_pool(&self, seen_deposit: U256) -> Result<Recovery>
Run this node’s funding recovery step (ADR 003 § Funding recovery): top the
current pool up toward the working deposit, or, when the pool is Closing or
Closed and its topUp reverts PoolNotOpen, open a new pool at the
working deposit and make it the current pool in the store. The closed pool
is not reclaimed here; the reclaim sweep recovers it once its dispute window
ends.
Concurrent fills share one pool, so one step funds them all.
seen_deposit is the deposit the calling fill saw. A row that already
holds more is a sibling’s step that landed: the call returns the row’s
deposit and escrows nothing. A recovery top-up still in flight is a
sibling’s step too: the call waits for it and returns its deposit. When
that top-up reverts PoolNotOpen, the call joins the replacement open.
The step sizes itself from the pool row: the deposit less the spend its
lanes recorded. A fill runs the step only once its own pulls ended, and
each pull records its progress as it ends, so the row holds that spend.
A pool that already holds the working deposit has nothing to add. A
topUp gas estimate (no transaction) then tells a closing or closed
pool, which a new pool replaces. An open pool is the upstreams’ stale
view of a deposit they have not seen yet: the step settles and returns
the row’s deposit, so the fill’s settle window asks them again.
§Errors
No pool is tracked, the topUp or replacement openPool fails, a
joined top-up fails for any reason but PoolNotOpen, or a mined
transaction cannot be recorded
(escrowed and untracked).
Sourcepub fn pool_deposit(&self) -> Option<U256>
pub fn pool_deposit(&self) -> Option<U256>
The deposit the store’s pool row records, or None with no pool
tracked: the deposit a fill sees.
Sourcepub async fn top_up_pool_by(&self, additional: U256) -> Result<TopUpLanded>
pub async fn top_up_pool_by(&self, additional: U256) -> Result<TopUpLanded>
Fund additional of new headroom in the node’s pool and return the pool’s NEW
total deposit with the amount this call added (#1530): the top-up behind
Self::recover_pool.
A topUp already in flight is JOINED, not duplicated. This call counts only
the part of it that no other pull relies on: all of a refill’s amount, none of
another recovery top-up’s. When that part is less than additional, this
method funds the remainder with a further topUp (see top_up_at_least).
added is below additional only when the funding calls run out, or when the
chain credits less than a topUp asked for. The caller compares the two.
Routes through the detached, join-or-spawn funding task (never an inline
.await): topUp waits on an unbounded get_receipt, and this runs inside
the miss-pull future the foreground serve path DROPS on its deadline — an
inline await cancelled mid-receipt would leave the deposit escrowed and
untracked. On the spawned task, a dropped caller loses only the answer.
§Errors
Errors if no pool is tracked, if our own allowance/topUp fails, if a
topUp mined but the local row could not be credited (terminal — the
deposit is escrowed-and-untracked; a retry would escrow again), or if every
funding call joined a topUp that failed.
Sourcepub async fn sweep_reclaimable_once(&self)
pub async fn sweep_reclaimable_once(&self)
Run one reclaim-sweep pass synchronously: complete the grace-window
reclaim of the node’s pool if it has been closed and its dispute window
has elapsed. Best-effort — errors are logged, never propagated. Exposed so
the runtime (or a test) can trigger an immediate pass.
Trait Implementations§
Source§impl<P: Provider + Clone + 'static> PoolOpener for BuyerPoolService<P>
impl<P: Provider + Clone + 'static> PoolOpener for BuyerPoolService<P>
Source§fn open_or_reuse_pool<'life0, 'async_trait>(
&'life0 self,
provider_addr: Address,
budget: Duration,
) -> Pin<Box<dyn Future<Output = Result<PoolContext>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn open_or_reuse_pool<'life0, 'async_trait>(
&'life0 self,
provider_addr: Address,
budget: Duration,
) -> Pin<Box<dyn Future<Output = Result<PoolContext>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
PoolContext pinned to
provider_addr (with the self-issued capability attached). See
BuyerPoolService::open_or_reuse_pool for the full contract.Source§fn record_progress(
&self,
provider_addr: Address,
pool_id: PoolId,
write: ProgressWrite,
) -> Result<()>
fn record_progress( &self, provider_addr: Address, pool_id: PoolId, write: ProgressWrite, ) -> Result<()>
(signer, provider) lane of
pool_id. See BuyerPoolService::record_progress. Read moreSource§fn recover_pool<'life0, 'async_trait>(
&'life0 self,
seen_deposit: U256,
) -> Pin<Box<dyn Future<Output = Result<Recovery>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn recover_pool<'life0, 'async_trait>(
&'life0 self,
seen_deposit: U256,
) -> Pin<Box<dyn Future<Output = Result<Recovery>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
seen_deposit. See BuyerPoolService::recover_pool. Read moreSource§fn pool_deposit(&self) -> Option<U256>
fn pool_deposit(&self) -> Option<U256>
None with no pool
tracked. See BuyerPoolService::pool_deposit.Auto Trait Implementations§
impl<P> !Freeze for BuyerPoolService<P>
impl<P> !RefUnwindSafe for BuyerPoolService<P>
impl<P> !UnwindSafe for BuyerPoolService<P>
impl<P> Send for BuyerPoolService<P>where
PaymentPoolInstance<P>: Send,
impl<P> Sync for BuyerPoolService<P>where
PaymentPoolInstance<P>: Sync,
impl<P> Unpin for BuyerPoolService<P>where
PaymentPoolInstance<P>: Unpin,
impl<P> UnsafeUnpin for BuyerPoolService<P>where
PaymentPoolInstance<P>: UnsafeUnpin,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
Source§fn with_current_context(self) -> WithContext<Self> ⓘ
fn with_current_context(self) -> WithContext<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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 moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request