The Ticket Redemption Service allows Orchestrator nodes to redeem winning tickets on-chain using a separate ETH account on the Ticket Redemption Service. Orchestrator nodes no longer need to have an account funded with ETH to pay for transactions on the Ethereum network.
It is responsible for redeeming winning tickets as well as pushing max float updates about broadcasters back to its connected Orchestrators.
Max float is the guaranteed value an Orchestrator will be able to claim from a Broadcaster's reserve. It accounts for the current reserve allocation from a Broadcaster to an Orchestrator as well as pending winning ticket redemptions.
*A more detailed description about max float and it's relation to a broadcaster's reserve can be found in the PM protocol spec.
*This document uses the term sender
, it can be used interchangeably with Broadcaster.
-
The
ticketQueue
is a loop that runs everytime a new block is seen. It will then pop tickets off the queue starting with the oldest ticket first, and sends it to theLocalSenderMonitor
for redemption if therecipientRand
for the ticket has expired. -
When the
LocalSenderMonitor
receives a ticket from theticketQueue
it will substractticket.faceValue
from the outstandingmaxFloat
as long as the ticket is in limbo.
This will trigger a LocalSenderMonitor.SubscribeMaxFloatChange(ticket.sender)
notification
-
The ticket is sent to a remote Ethereum node for redemption
-
When the Ethereum node returns a response the
ticket.faceValue
is added to themaxFloat
again as the ticket is no longer in limbo.
This will trigger a LocalSenderMonitor.SubscribeMaxFloatChange(ticket.sender)
notification
-
When max float for a
sender
is requested from theRedeemerClient
but no local cache is available, an (unary) RPC call will be sent to theRedeemer
. -
A second RPC call to
MonitorMaxFloat(sender)
will open up a server-side gRPC stream to receive future update.
If this call fails the response from step 1 is returned, but not kept in cache to to prevent it becoming stale due to not being able to receive further updates
- The
Redeemer
goroutine started by the RPC call in step 2 will start a subscription to listen for max float changes from theLocalSenderMonitor
for the specifiedsender
usingLocalSenderMonitor.SubscribeMaxFloatChange(sender)
.
Each open server-side stream will have its own subscription that will be closed when the client closes the stream. This means that each client will have a subscription for each sender it is interested in.
-
Once the subscription from step 3 emits an event that indicates a state change for the specified
sender
, theRedeemer
will invokeLocalSenderMonitor.MaxFloat(sender)
to fetch the latest value. -
Upon retrieving the latest max float value for
sender
it will be sent over the server-side gRPC stream. -
Upon receiving a
MaxFloatUpdate
over the server-side gRPC stream forsender
it will update its local cache for thatsender
accordingly. -
Subsequent calls to
RedeemerClient.MaxFloat(sender)
will return the locally cached value forsender
as long as it remains available. -
The local cache for
sender
will be cleaned up if is not requested for 5 minutes.
So far we've discussed LocalSenderMonitor.addFloat()
and LocalSenderMonitor.subFloat()
being responsible for triggering LocalSenderMonitor.SubscribeMaxFloatChange(sender)
notifications, but these can also be triggered by certain Ethereum events related to the Livepeer protocol:
- FundReserve: When a broadcaster funds it's reserve the
maxFloat
allocation increases by the added reserve divided by the active Orchestrator set size. - NewRound: If the active Orchestrator set size changes, the
maxFloat
will become the current broadcaster's reserve divided by the new active set size. Since this event impacts all participants in the protocol theRedeemer
will have to send updates for everysender
it is keeping track of.