-
Notifications
You must be signed in to change notification settings - Fork 973
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proof of custody game design #568
Comments
Multi-round game, version 2 We store in the state two lists, There is no longer a 18-hour minimum validator withdrawal time. Instead, the withdrawal queue always picks the 4 validators each epoch that exited the earliest for which all pending data challenges have been answered (data challenges can be made only for validators < 1 week after exiting). However, these validators are not immediately withdrawn; instead, they are assigned a "waiting for challenge games" status. If a validator has been waiting for challenge games for more than 18 hours and no challenge games have been started, the validator can exit. Any validator can start a challenge game against any other validator by putting down 1 ETH as a deposit. The challenge game consists of the following process:
If the respondent can correctly respond to a game, the respondent gains 0.5 ETH and the challenger loses 1 ETH; if the respondent fails to respond, the respondent loses (1 + calculated anti-correlation penalty) ETH and the challenger recovers their deposit plus half of the penalty. If there are N > 1 games in progress, then all rewards and penalties are multipled by 1/N. Hence, with the exception of the first round, challenging and responding is broken up into discrete games with a challenger and respondent. |
Here's a potential strategy to retain the elegance and simplicity of custody bits, and at the same time make them MPC-friendly.
Notice that SNARK proofs are not required in the optimistic case, and when they are required the relevant party has a lot of time (hours, days or however long we want) to build the SNARK. |
MIMC is MPC-friendler than other hash functions, but not super MPC-friendly; it still requires something like 100 rounds of communication. The strategies that require fewer rounds get their mixing properties by mixing different fields, which is unfortunately not a very SNARK-friendly thing to do.... I'm also wary of this particular use case because the SNARK scheme failing would lead not to degradation of security of an isolated component of the system, but to innocent validators getting slashed, possibly undetectably. From my last day of thinking about it I don't think the game complexity difference between a SNARK and a Truebit-style game is that large (certainly much smaller than the internals and circuit construction of the SNARK). In either case, we need a multi-round exit game: the first round for challenging missing bits of In the second case, if we adopt the interactive game approach, once the challenge game starts it's a self-contained gadget, and from the point of view of the rest of the system we'll know at some point that it resolves. We can get rid of complexity involving list handling and 1/N rewards above by allowing only one challenge game per attestation per respondent, whoever starts one first. The possibility that a bad validator will challenge themselves and claim their own money can be handled as above by making the reward only half the penalty. |
The basic proof of custody mechanism works as follows:
p
, each validator calculatesrk[p] = BLS_sign(key=validator_privkey, msg=p)
as their round key.D[0] ... D[size(D)-1]
, for eachD[i]
they computeC[i] = mix(rk[p], D[i])
wheremix
is some function where for anyrk
,mix(rk, x)
depends onx
. They computeR = custody_root(D)
as Merkle root of theC[i]
values and signR mod 2
along with the crosslink (this is their "custody bit")p + 1
, the validator must revealprevseed=rk[p]
, and the chain can verify that it is a correct value viaBLS_verify(key=validator.pubkey, msg=p, sig=prevseed)
There are three types of byzantine behavior that we want to penalize:
rk[p]
too earlyFor (1) we can have a special-purpose slashing condition; the only requirement is that anyone must be able to trigger the condition and gain from doing so, so there should be a commit-reveal game to allow participants to trigger it without the block proposers being able to frontrun them.
(2) and (3) are similar cases, except (3) is more tractable. In case (3), once
rk[p]
is revealed, any third party can recomputecustody_root(D)
, check if the bit matches, and if the bit does not match start a challenge game, which they know ahead of time they will be able to win. First, they challenge to ask for the complete custody root, which must match the bit that has already been provided. At this point, the responder is free to respond with an arbitrary value ofR
that matches the same bit; for anyD
, it is almost always possible to find some dataD'
which differs fromD
in only one block wherecustody_root(D') mod 2
is either 0 or 1. At this point, the responder has (and the challenger knows that the responder has) committed to some value which is not equal tocustody_root(D)
.The next step is for the challenger to ask for the two children of
R'
(we'll call themC0
andC1
). When the responder responds, the challenger can check which of the two don't match the corresponding values in the real custody Merkle tree forD
. The challenger then asks for the two children of eitherC0
orC1
. This repeatslog(size(D))
times until eventually the responder must respond with someC[i]
as well as a Merkle branch for the correspondingD[i]
. The chain will check and find that the providedC[i]
does not matchmix(rk[p], D[i])
, and the responder can be penalized and the challenger can win. At this point, if the responder responds correctly, the challenger can be penalized.Note that this whole process is only possible if all of
D
is available, so challengers can know whether or not they can successfully challenge. IfD
is not available, then we also need a challenge game which allows participants to ask for specific branches ofD
and demand an answer. Because data availability suffers from fisherman's dilemma problems, it's likely participants will not bother challenging unless challenging is free; hence, the proposed solution is to only allow block proposers to challenge, and give them a free allotment of challenges in each block, expecting them to fill the allotment.Now, we have four types of challenges:
A
, validator indexv
, data indexi
. Output: a Merkle branch ofD[i]
with the root matchingA.data_commitment
.A
, validator indexv
. Output: a rootR
matchingget_custody_bit(A, v)
A
, validator indexv
, indexi
, depthd
, branchB
, whereB
has as root theR
value previously submitted by validatorv
. Output: the two children whose parent is the leaf inB
.A
, validator indexv
, indexi
. Output: a Merkle branch ofD[i]
andC[i]
with the roots matchingA.data_commitment
and theR
value previously submitted by validatorv
.Note that we can increase efficiency by merging (1), (2) and (4). We do this as follows:
A
, validator indexv
, data indexi
. Output: a Merkle branch ofD[i]
andC[i]
with the roots matching, for the first branch,A.data_commitment
, and for the second branch, the sameR
value as was submitted during any previous time the same validator answered a challenge for the same attestation.We can also decrease the round count of the game, by asking for 2^k descendants some height k below the provided node (eg. 16 descendants 4 levels down). In this way, in the worst case (eg. a 2**24-sized data tree), the game would take only six rounds, instead of ~24.
How to implement the multi-round game
The main saving grace of all of the above is that the only game where honest challengers are not guaranteed to win (the branch challenge) only requires one round of challenging (all challenges can be done in parallel). Going beyond that, any honest challenger should be assured of victory, and hence willing to put down a deposit.
For each "exited" validator, we will maintain a counter,
challenge_round
, which starts at zero, and a boolwas_challenged_this_round
. When the validator reaches the end of their withdrawal queue, the following happens:challenge_round
of the validator (ie.was_challenged_this_round = False
), or ifchallenge_round = 6
, the validator withdraws successfullywas_challenged_this_round
toTrue
), the validator can skip back to the end of the exit queue as soon as they respond to all extant challenges, withchallenge_round += 1
andwas_challenged_this_round
reset toFalse
.Now, for economics (this is the part I am still less confident about). If a validator successfully answers all challenges, then every validator that challenged can be penalized some amount. If a responder does not answer challenges and the time hits some timeout period, then all validators that challenge get a reward out of the responder's deposit (these rewards could be evenly split, or only given to the first challenger of each challenge round, or split among the challengers of each round in a decreasing schedule, eg. the kth challenger of each round gets a reward of
(6/pi**2) / k**2
(the6/pi**2
constant set so that rewards add up to a maximum of 1 per period).The text was updated successfully, but these errors were encountered: