aftermath2 / btry

Accountless lottery powered by the Bitcoin Lightning Network
GNU Affero General Public License v3.0
3 stars 1 forks source link

Battles #9

Open aftermath2 opened 9 months ago

aftermath2 commented 9 months ago
Development branch
battles

Description

Battles are a non-custodial PvP game based on HODL contracts where two players compete for a fixed amount of money.

The funds are never in the hands of BTRY, it merely acts as a coordinator and decides which payment to settle (loser -> winner) and which one to cancel (winner -> loser).

Initially, the idea is simple, both users choose one number between 0 and 1000, BTRY generates one randomly and the one that got it closer wins.

However, we may move towards other forms of deciding a winner, like real events outcomes. There has been demand for a sports betting platform based on Lightning on some forums and these technologies may be a great fit for that.

The random number generation is based on provably fair random numbers, so both parties can validate that the results are fair and not manipulated.

Flow

The desired flow for each participant would be the following

Initiator

  1. Createa game selecting the amount (sats)
  2. Select a number between 0 and 1000 and send an invoice for the amount he chose in 1
  3. Wais for a user to join the game and listen for a HODL invoice to determine whether a user joined the game or not
  4. Fund the HODL invoice the service created
  5. Wait for the result and verify the random number

Challenger

  1. Join game
  2. Send a number and an invoice for the amount specified in the game
  3. Fund the HODL invoice
  4. Wait for the result and verify the random number

BTRY

  1. Check if both users chose the same number, in that case, there's a tie and both HODL invoices are cancelled
  2. Pick a random number between 0 and 1000 using provably fair random numbers
  3. Pick winner, settle loser HODL invoice and cancel winner invoice

Details

All battles have a 1h expiration time for another player to join the game.

After the game has finished, the results are saved for the users to verify the numbers.

Provably fair random number generation

Winner number should be generated using provably fair random number generator. For this, we should first generate a random server seed, encrypt it and give it to the players (so they can later verify that the server seed was not modified), get a seed from each of them and calculate

HMAC_SHA256(server_seed, player1_seed, player2_seed, nonce)

Both player's seeds must be shared in the game

Convert the (first) byte/s to number and choose the winner. In the payment description, include the unencrypted server seed and the secret used to encrypt it.

Example

a: server seed
b: client seed
0: nonce

HMAC_SHA256(a,b:0)

First four bytes:
ad  a0  97  d5
173     160     151     213

(173, 160, 151, 213) -> [0, ..., 1000] = 678
    0.675781250000  (173 / (256 ^ 1 ))
+   0.002441406250  (160 / (256 ^ 2 ))
+   0.000009000301  (151 / (256 ^ 3 ))
+   0.000000049593  (213 / (256 ^ 4 ))
=   0.678231706144  (* 1000) -> 1000 is the maximum number the users can choose
=   678.231706144
=   678

Ideas

aftermath2 commented 8 months ago

@conduition Here's a section explaining what would be the implementation of provably fair random numbers in battles.

conduition commented 8 months ago

Thanks for the tag. Neat concept but I think you may want to reconsider some angles.

As described, it sounds like both players are paying the BTRY server with HODL invoices, while also supplying their own invoice which for double the value which will be paid out by the BTRY server if the player wins.

This is custodial. Once the HTLC offer is made by the sender, a HODL invoice can only be refunded by the receiver who knows the preimage, which is BTRY. The server could elect to simply keep the payments from both players. It has no incentive (neither cryptographic nor financial) to release the funds to either player. If it does, neither player can prove BTRY cheated.


As far as provable fairness goes, you need to consider collusion with the server in your fairness model. Neither player has any way to know whether the player they're battling is in cahoots with the BTRY server. Both players receive commitments for the server secret, but not for the opponent player_seed. If player 2 is colluding with BTRY, they could simply wait for the honest player 1 to submit their seed, and then choose a seed for player 2 which results in player 2 winning.

To fix this, both players need to share commitments to their seed values before revealing their own seed value. This gets rid of the who-goes-first collusion problem.


The game-theory on this 'pick-a-number' game is solvable.

A rational first-mover will pick 500 because it bisects the outcome space. Picking any other number, such as 400, allows the second player to one-up them price-is-right-style, by picking e.g. 401, giving the second player adjacency to 600 numbers, thus a 60% chance of winning. The second player must pick 499 or 501, because any other number either results in a tie, or would give the first player control over more of the outcome space. If both contestants play perfectly, the outcome of this game is a coin flip, with a slight 1/1000 advantage to the first-mover. The second player is at a disadvantage by joining a game as the challenger in the first place, so the logical move is not to play this game unless you can choose your number first.

Instead, you could dispense with all that, and use the last bit of the hash's output to pick the winner as a true coin-flip.

Or do rock-paper-scissors with advance commitments - that might at least have some comedy value :P

aftermath2 commented 8 months ago

HODL invoices and funds custody

The players lock funds in HODL invoices that can only be unlocked if the server pays the underlying invoice and obtains the preimage, which means that the server is not able to just keep the users' funds.

If the HODL or underlying invoice expire, then the funds return to the users. The server never keeps custody of the funds.

You can find more information about HODL contracts in https://github.com/supertestnet/hodlcontracts.

Provable fairness

Indeed, the server and one of the players could coordinate to cheat and choose the final result to favor the player. However, they would have to do the calculation in a small period of time which would be virtually impossible. Another thing to take in consideration is the fact that HODL contracts require the invoice of the first player to create the HODL invoice of the second.

Game-theory

I agree with everything you mentioned in this point. Since this idea is still under development and research, I thought the 1-1000 game as a "placeholder" or temporary solution while I studied better (and more fun) ways of deciding a winner, like real event outcomes.

It's by no means expected to be definitive or even reach production, it has many flaws as you mentioned. It could definitely be replaced with a coin-flip game (which I did not choose because it already existed such a service with LN support).

conduition commented 8 months ago

You can find more information about HODL contracts in https://github.com/supertestnet/hodlcontracts.

I tried to watch the video in that repo, but i could barely understand what the guy was saying. The code is rather hard to read given there are SQL/HTML literals and flask code spliced in. Are there any protocol-level docs for these "HODL contracts"? I can't find anything from a google search.

Indeed, the server and one of the players could coordinate to cheat and choose the final result to favor the player. However, they would have to do the calculation in a small period of time which would be virtually impossible.

I'm not sure I follow. What deadline are you referring to? Why would it be impossible?

aftermath2 commented 8 months ago

Are there any protocol-level docs for these "HODL contracts"?

I couldn't find anything neither, the only reference I know is that repository, which I agree is really confusing.

I've implemented some of the code myself here but in case it doesn't help I'll try to explain them simply.

HODL contracts are HODL invoices that were created with another invoice's payment hash (I call it underlying invoice).

In this case, the server would receive one invoice for each player and create two HODL invoices with their payment hashes.

In order to settle a HODL invoice, the server must pay the underlying invoice first, because it needs the preimage. So it can't steal the funds, it will always have to send the funds before receiving them.

I'm not sure I follow. What deadline are you referring to? Why would it be impossible?

Sorry for not being clear. I was referring to the fact that both player seeds are shared when the game starts, so the players and the server get to know the seeds at the same time. If player 2 and the server were to collude, player 1 could notice that the final result was generated with different seeds (there is no penalty mechanism in place though).

conduition commented 8 months ago

HODL contracts are HODL invoices that were created with another invoice's payment hash (I call it underlying invoice).

Interesting. Sounds a lot like a normal lightning HTLC routing protocol

In order to settle a HODL invoice, the server must pay the underlying invoice first, because it needs the preimage. So it can't steal the funds, it will always have to send the funds before receiving them.

Makes sense intuitively, but I don't see how it works practically. Here's my thinking:

  1. Alice and Bob create secret preimages $a$ and $b$ respectively.
  2. Alice gives the server an invoice $I_a$ for the battle's satoshi value $v$, locked with payment hash $H(a)$.
  3. Bob does the same, giving the server an invoice $I_b$ for $v$ sats, locked with payment hash $H(b)$.
  4. The server creates two new invoices $(I_a', I_b')$ for amount $\frac{v}{2}$, locked with $H(a)$ and $H(b)$ respectively.
    • The server still doesn't know $a$ or $b$ at this stage.

I'm not sure what happens beyond this point.

conduition commented 8 months ago

Sorry for not being clear. I was referring to the fact that both player seeds are shared when the game starts, so the players and the server get to know the seeds at the same time. If player 2 and the server were to collude, player 1 could notice that the final result was generated with different seeds (there is no penalty mechanism in place though).

It's impossible to guarantee that both players receive each other's seed at the same time. One player is going to have to send their seed to the server first. Whichever player sends their seed to the BTRY server first is at risk of a collusion attack where the server and the second player pick a second seed to bias the 'provable fairness' hash to their advantage.

I think you can fix this with a commitment round. If players Alice and Bob have seeds $s_a$ and $s_b$ respectively, then they each send a commitment hash $H(s_a)$ and $H(s_b)$ respectively to the server, which forwards the commitment to the opposing player.

Let $\hat{s}$ be the server seed. Once each player knows all three commitment hashes $(H(\hat{s}), H(s_a), H(s_b))$, only then do they reveal their seed. The final fairness hash can then be computed as $H(\hat{s}, s_a, s_b)$.

This way, both players and the server must all commit to their seeds ahead of time. Nobody can compute their seed as a function of the others. The server can reveal $(\hat{s}, s_a, s_b)$ to prove the winner was selected fairly.

aftermath2 commented 6 months ago

I'm not sure what happens beyond this point.

As far as I'm concerned the flow it then follows is the first one.

That's correct, Bob has not way of validating that the payment hash $H(a)$ was indeed generated by Alice. HOLD contracts are non-custodial as long as the oracle is not on the other side of the payment. Would you call that custodial, or non-custodial but trusted?

It's impossible to guarantee that both players receive each other's seed at the same time. One player is going to have to send their seed to the server first. Whichever player sends their seed to the BTRY server first is at risk of a collusion attack where the server and the second player pick a second seed to bias the 'provable fairness' hash to their advantage.

Right, I explained that poorly. I was referring to the fact that the window the server and the colluding player have to compute the winning hash is too short, they wouldn't be able to calculate it in time, assuming the server reveals the seeds immediately. And if it does not, it would be too obvious for the user that he is being scammed. Anyway, the solution you proposed is more robust and should be used instead, a penalty mechanism is also required to avoid misbehavior.