question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

PM Ticket Expiration

See original GitHub issue

Why do we want ticket expiration?

  1. Minimize double spending by B
    1. By design B cannot know for any given ticket if it’s a winning ticket until O reveals its recipientRand value, which happens upon redemption on-chain. With no bound on when O redeems tickets, B can easily hand out winning tickets of a value greater than B’s deposit and accidentally double spend.
    2. B can decide to maliciously double spend on many Os, and until enough Os redeem enough winning tickets to trigger double spend detection, B’s additional utility keep growing. Ticket expiration is a way to curb B’s additional utility for such behavior.
  2. Delegators being squeezed by O and B colluding: without expirations O can hold on to many tickets to accrue a significant chunk of revenue, then update their fee sharing params on-chain, and only once those changes take effect redeem all the tickets. Expiration can not only curb this behavior, but further ensure that the right delegators are rewarded for the work (if we agree that the right delegators to reward are those that delegated onto O at the round when the ticket was created).

(for more background on some of these issues see https://github.com/livepeer/prob-pay/issues/5 and https://github.com/livepeer/prob-pay/issues/6).

Assuming we’ve established that we want to have an expiration mechanism, moving on to its design.

Ticket expiration design

  • Expiration must rely on a verifiable data point that is infeasible to know ahead of time, otherwise colluding Bs and Os can easily issue future-dated tickets.
  • The best source of such data in our case seems to be Ethereum block hashes.
  • This problem becomes more challenging since currently in Ethereum we can only query for the block hash of the last 256 blocks.

Initial solution approach:

  • The foundation for our workaround is to rely on smart contract storage for block hashes lookup.
  • To have that we need some mechanism for storing block hashes regularly.
  • The most cost-effective solution we have now is to leverage the existing round initialization mechanism.
  • At every round initialization we would store a mapping from round number to the previous blockhash.
  • Bs can query this mapping to get the latest values, and include them in each PM ticket.
  • Both O and TicketBroker can reference that same map for their ticket validation process:
    • Do the round number and round hash in the ticket match what’s stored on-chain?
    • Are we still within the ticket expiration period?

Round-based expirations challenges

Rounds are currently about 24-hours long. This granularity presents us with a few challenges:

  • If we set the expiration period to be one round, we open the protocol to edge cases of tickets expiring very quickly if B gets the latest block hash just before a new round is initialized (worst case could be one block).
  • From this we deduce that the expiration period should be at least 2 rounds.
  • However, a 2-round expiration means that the worst case for exposing double spending becomes 48 hours, and that’s suboptimal as well.
  • A potential mitigation could be shortening rounds from 24 hours to 12 hours, but that would come at the expense of not giving delegators reasonable time to learn of any delegation params changes (fee share, etc.) - which is an intention currently baked into the protocol.

As mentioned, the ideal solution would be to rely on block hashes, and there are EIPs that present such a possibility, but we have no certainty on if and when they will be included in a mainnet Ethereum version.

What is the best compromise for now?

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
yondonfucommented, Dec 21, 2018

Here is an update on the current proposed roadmap for this feature based on this thread and an offline discussion between @eladmallel and I:

We prefer not to use the approach of storing block hashes on winning ticket redemption because:

  • If we store the latest block number for which a block hash has been stored, then ticket redemption requires 2 additional storage writes: 1 for writing the block hash and 1 for writing the current block number. As a result, the ticket redemption gas cost increases by 40000 gas which is not ideal given that we want to try to keep ticket redemption gas cost as low as possible.
  • If we don’t store the latest block number for which a block hash has been stored, then the client will have to query for the latest ticket redemption event which will provide the latest block number. This still requires an additional storage write which is 20000 gas.
  • We lose the ability to direct ticket pay outs into the fee pool for the round during which a ticket is created and thus delegators that delegated to O during that round will not be compensated for helping O get selected for work during that round.
  • Relying on ticket redemptions for the ticks in a universal clock that both B and O use means that we have irregular time intervals between ticks. Furthermore, the ticks slow down during times of low network demand and speed up during times of high network demand. In the worst case, the ticks stop for a period of time.

We prefer not to directly rely on block numbers i.e. attach a block hash and a block number to a ticket and the Broker checks if the block hash is valid for the block number and use a maximum ticket validity period of 256 blocks which is around 1 hour given ~15 second block times (since contracts cannot look up block hashes past currentBlock - 256) because:

  • If block times ever decrease in the future, the maximum ticket validity period decreases as well. In this scenario, there is not a lot of flexibility with adjusting validity periods to allow Os to opportunistically redeem tickets during times of low gas prices
  • The ~1 hour validity period puts a lot more pressure on the client to force ticket redemption transactions to confirm on-chain quickly. During times of increasing gas price and network congestion, the client needs to make sure to constantly bump gas prices if a transaction is left pending
  • While there are EIPs that propose increasing the range of blocks for which a contract can query block hashes for, at the very earliest they could be included in a post-Constantinople hard fork if at all. Furthermore, they do not seem to allow for querying for block hashes from the full range of past blocks, but only a certain past blocks. See: https://github.com/ethereum/EIPs/issues/1218. It is probably best not to create dependencies on upgrades with unclear timelines.

We propose the use of round initialization to store block hashes that can be used to prove the existence of a block at the time of ticket creation. The workflow for B would be as follows:

  1. Query the RoundsManager for currentBlockHash for the current initialized round. Note: If the current round is not initialized, B will query the RoundsManager for the block hash of the last initialized round - this behavior is to ensure that B is never blocked from streaming if we are in a transitionary period during which the current round is not initialized yet.
  2. B creates a ticket with currentBlockHash and currentRound.
  3. O validates the ticket by checking that currentBlockHash is indeed the block hash for currentRound by querying the RoundsManager.
  4. If the ticket wins, O redeems the ticket on-chain. The Broker will check that currentBlockHash is indeed the block hash for currentRound by querying the RoundsManager. The ticket pay out can then be sent to O’s fee pool for currentRound (which results in fees directed to delegators that delegated to O at the time of ticket creation).

The upsides of this approach are:

  • Greater flexibility around ticket validity period relative to the method of relying on block numbers directly
  • We are able to direct fees to delegators that delegated to a O during ticket creation

The downsides of this approach are:

  • The validity period needs to be at least 2 rounds (i.e. 2 days) in order to prevent cases where a ticket is created toward the end of a round and it expires very quickly
  • A 2 round minimum for the validity period might not ideal for Bs because they could see on-chain deposit updates from winning tickets less often and for Os because there is a larger time period for double spends to occur
  • We add additional logic to global round initialization which is not guaranteed to be executed at the very beginning of a round. One potential additional incentive for more timely round initialization is that if O is being paid by B and the round is not initialized, B will use the previous round thereby reducing the validity period of the ticket from 2 to 1 rounds. So it could be in O’s best interest to initialize the round if it is in this situation.

Our conclusion is that while using round initialization to store block hashes might not be the most ideal solution, it still beats out the other available solutions at the moment.

If anyone has any additional thoughts/concerns we please continue the discussion here!

If there are no additional thoughts/concerns, we can proceed with the following plan:

  • For MVS, remove expiration checks on tickets for the sake of reducing scope.
  • For SS, update RoundsManager to store block hashes upon round initialization and update LivepeerETHTicketBroker to validate the creation round numbers in tickets using the attached block hash. Also, update the client to include these fields in the tickets and add client side validation step for O.
0reactions
j0shcommented, Feb 13, 2019

Thanks for taking the time to dissect alternatives so thoroughly. Is round initialization anticipated to be used for anything other than storing the block hash?

If the block hash is the only reason for round initialization, then it might be nice to continue exploring other avenues to avoid round initialization. Performing global round initialization to accommodate an incidental effect of the payment mechanism feels heavy.

One possible approach is to set the block hash during the first reward call.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Disneyland Ticket Expiration Dates - The Happiest Blog on Earth
Do Disneyland tickets expire? Yes, tickets do have an expiration date listed ...
Read more >
New Ticket Expiration Deadlines & Usage | FAQ
Here are the details: 1-day – The ticket expires on the selected start date.2-day – The ticket expires 4 days after the selected...
Read more >
Required Elements in a Ticket - NYC.gov
The box for “Missing” or Expired” must be checked on the ticket. · If the ticket is for an expired inspection, the expiration...
Read more >
Walt Disney World Ticket and Pass Advice Tips & Tricks
Any current-issue standard Disney World ticket expires after every admission on the ticket has been used, or on the listed expiration date, ...
Read more >
How to escalate a support ticket - PM PrepCast Forum
How to escalate a support ticket I am having an urgent ticket with wrong expiration date of the exam and no helpful reply...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found