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>
impl<S: OutgoingIndexStore + 'static> HoprTicketFactory<S>
Sourcepub fn new(store: S) -> Self
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§impl<S> HoprTicketFactory<S>
impl<S> HoprTicketFactory<S>
Sourcepub fn next_outgoing_ticket_index(&self, channel: &ChannelEntry) -> u64
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.
Sourcepub fn save_outgoing_indices(&self) -> Result<(), TicketManagerError>
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.
Sourcepub fn sync_from_outgoing_channels(
&self,
outgoing_channels: &[ChannelEntry],
) -> Result<(), TicketManagerError>
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>
impl<S> TicketFactory for HoprTicketFactory<S>
Source§fn new_multihop_ticket(
&self,
channel: &ChannelEntry,
path_position: NonZeroU8,
winning_probability: WinningProbability,
price_per_hop: HoprBalance,
) -> Result<TicketBuilder, Self::Error>
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>
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.
type Error = TicketManagerError
Auto Trait Implementations§
impl<S> Freeze for HoprTicketFactory<S>
impl<S> !RefUnwindSafe for HoprTicketFactory<S>
impl<S> Send for HoprTicketFactory<S>
impl<S> Sync for HoprTicketFactory<S>
impl<S> Unpin for HoprTicketFactory<S>
impl<S> !UnwindSafe for HoprTicketFactory<S>
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
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§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 more