Skip to main content

HoprTicketFactory

Struct HoprTicketFactory 

Source
pub struct HoprTicketFactory<S> {
    out_idx_tracker: OutgoingIndexCache,
    queue_map: Weak<dyn UnrealizedValue + Send + Sync + 'static>,
    store: Arc<RwLock<S>>,
}
Expand description

Keeps track of outgoing ticket indices and provides an interface for creating multihop tickets.

It is therefore always used on all noded types (Entry/Relay/Exit) in the outgoing packet pipeline, as it handles the outgoing ticket indices for new tickets.

For Entry/Exit nodes, the HoprTicketFactory is typically created as standalone (via HoprTicketFactory::new).

To synchronize the on-chain state with the store, it is advised to call sync_outgoing_channels early after the construction of the factory, to make sure outgoing indices are up to date. This is typically done only once after construction and not needed to be done during the life-time of the factory.

The factory is safe to be shared via an Arc.

§Usage in the outgoing packet pipeline

The outgoing packet pipeline usually just calls new_multihop_ticket to create a ticket for the next hop on a multi-hop path. To create zero/last-hop tickets, the factory is not needed as these tickets essentially contain bogus data and there’s no channel required.

The outgoing indices are not automatically synchronized back to the underlying store for performance reasons. The user is responsible for calling save_outgoing_indices to save the outgoing indices to the store.

This usage is typical for all kinds of nodes (Entry/Relay/Exit).

§Usage in the incoming packet pipeline in Relay nodes

There is additional usage of the HoprTicketFactory in the incoming pipeline in Relay nodes. The Relay nodes typically need to validate incoming tickets in their incoming packet pipeline before they forward the packet to the outgoing packet pipeline (out to the next hop).

The HoprTicketFactory in this case maintains a weak reference to HoprTicketManager if they were created together via HoprTicketManager::new_with_factory.

By using this weak reference, it can get the remaining channel stake on the given channel by subtracting the value of unredeemed tickets in the matching channel queue of the associated HoprTicketManager.

This is useful for Relay nodes that need to validate incoming tickets before forwarding them to the outgoing packet pipeline.

NOTE: if the HoprTicketFactor is not created with a HoprTicketManager, it cannot evaluate the remaining stake on the given channel and will always return the channel balance.

§Locking and lock-contention

§Outgoing ticket creation

The new_multihop_ticket method is designed to be high-performance and to be called per each outgoing packet. It is using only atomics to track the outgoing ticket index for a channel. The synchronization to the underlying storage is done on-demand by calling save_outgoing_indices, making quick snapshots of the current state of outgoing indices. No significant contention is expected unless save_outgoing_indices is called very frequently.

§Remaining channel stake calculation

The remaining_incoming_channel_stake method is designed to be high-performance and to be called per each incoming packet before it is forwarded to a next hop.

This operation acquires the read-part of an RW lock in HoprTicketManager (per incoming channel). This may block the hot-path only if one of the following (write) operations is performed at the same moment: 1. A new incoming winning ticket is inserted into the same incoming channel queue of the HoprTicketManager. 2. Ticket redemption has just finished in that particular channel, and the redeemed ticket is dropped from the same incoming channel queue of the HoprTicketManager. 3. Ticket neglection has just finished in that particular channel, and the neglected ticket is dropped from the same incoming channel queue of the HoprTicketManager.

All 3 of these operations are not expected to happen very often on a single channel; therefore, high contention on the RW lock is not expected.

Fields§

§out_idx_tracker: OutgoingIndexCache§queue_map: Weak<dyn UnrealizedValue + Send + Sync + 'static>§store: Arc<RwLock<S>>

Implementations§

Source§

impl<S: OutgoingIndexStore + 'static> HoprTicketFactory<S>

Source

pub fn new(store: S) -> Self

Creates a new independent ticket factory instance backed by the given store.

The store must be an OutgoingIndexStore.

Source

pub(crate) fn new_shared<Q: UnrealizedValue + Send + Sync + 'static>( store: Arc<RwLock<S>>, queue_map: Weak<Q>, ) -> Self

Source§

impl<S> HoprTicketFactory<S>
where S: OutgoingIndexStore + Send + Sync + 'static,

Source

pub fn next_outgoing_ticket_index(&self, channel: &ChannelEntry) -> u64

Gets the next usable ticket index for an outgoing ticket in the given channel and epoch.

This operation is fast and does not immediately put the index into the OutgoingIndexStore.

The returned value is always guaranteed to be greater or equal to the ticket index on the given channel.

Source

pub fn save_outgoing_indices(&self) -> Result<(), TicketManagerError>

Saves updated outgoing ticket indices back to the store.

The operation does nothing if there were no new tickets created on any tracked channel, or the indices were not updated.

Source

pub fn sync_from_outgoing_channels( &self, outgoing_channels: &[ChannelEntry], ) -> Result<(), TicketManagerError>

Synchronizes the outgoing index counters based on the current on-chain channel state given by outgoing_channels.

Outgoing indices for channels that either are not present in outgoing_channels or not present as opened channels will be removed from the store.

Outgoing indices for existing open channels in outgoing_channels will be either:

  • added to the store with their current index and epoch (if not present in the store), or
  • updated to the maximum of the two index values (if present in the store)

It is advised to call this function early after the construction of the HoprTicketFactory to ensure pruning of dangling or out-of-date values.

Trait Implementations§

Source§

impl<S> TicketFactory for HoprTicketFactory<S>
where S: OutgoingIndexStore + Send + Sync + 'static,

Source§

fn new_multihop_ticket( &self, channel: &ChannelEntry, path_position: NonZeroU8, winning_probability: WinningProbability, price_per_hop: HoprBalance, ) -> Result<TicketBuilder, Self::Error>

Method fulfills the implementation of TicketFactory::new_multihop_ticket.

§Implementation details

The current_path_pos indicates the position of the current hop in the multi-hop path. It is used to determine the value of the ticket: price * (current_path_pos - 1) / winning_prob. The function does not make sense for current_path_pos <= 1 and returns an error if such an argument is provided.

For last-hop tickets (current_path_pos equal to 1), a zero hop ticket should be created instead.

The function will fail for channels that are not opened or do not have enough funds to cover the ticket value. The ticket index of the returned ticket is guaranteed to be greater or equal to the ticket index on the given channel argument.

Source§

fn remaining_incoming_channel_stake( &self, channel: &ChannelEntry, ) -> Result<HoprBalance, Self::Error>

Method fulfills the implementation of TicketFactory::remaining_incoming_channel_stake.

§Implementation details

If this instance is created as standalone (via HoprTicketFactory::new), or the HoprTicketManager that has been initially created with this instance is dropped, this method returns Ok(channel.balance).

Otherwise, as per requirements, this method returns the balance of the channel diminished by the total value of unredeemed tickets tracked by the associated HoprTicketManager.

Source§

type Error = TicketManagerError

Auto Trait Implementations§

§

impl<S> Freeze for HoprTicketFactory<S>

§

impl<S> !RefUnwindSafe for HoprTicketFactory<S>

§

impl<S> Send for HoprTicketFactory<S>
where S: Send + Sync,

§

impl<S> Sync for HoprTicketFactory<S>
where S: Send + Sync,

§

impl<S> Unpin for HoprTicketFactory<S>

§

impl<S> !UnwindSafe for HoprTicketFactory<S>

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.

§

impl<T> Instrument for T

§

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

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

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
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

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

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: 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
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: 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> 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 = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.
§

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

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

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
§

fn with_current_subscriber(self) -> WithDispatch<Self>

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