Two minimal scenarios where equivocation harms progress #380
Replies: 2 comments 1 reply
-
|
Ah, if you want to make it even funnier, starting from
This means that |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for sharing that. I think from the consensus state machine the situation is clear in this write-up. Could you please also say a bit about the attack surface of accepting all messages from Byzantine nodes? |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Equivocation is probably the most powerful artifice that can be used by Byzantine validators to harm the protocol.
There are two issues, https://github.com/informalsystems/malachite/issues/309 and https://github.com/informalsystems/malachite/issues/103 , describing scenarios and implications. But I feel that is still relevant to fully describe two scenarios where equivocation from at most
fvalidators can harm Tendermint's liveneess.Model
First, two main assumptions:
We consider a minimal set of four validators
A,B,C, andD:Ais an asynchronous validator. It is correct but slow. Therefore, we cannot rely on it to receive messages before the associated timeouts expire while we are not past GST. We should assume it is likely to prevote and precommitnilmostly;Bis a Byzantine validator, it can do whatever it wants;CandDare correct and synchronous validators, we rely on them for progress.Overview
CorD, that proposes a valueXCandDreceiveX, validate it and issue a prevote forid(X)at round0Atimes out in the propose step and prevote fornilSo, the initial scenario, only considering correct validators, is the following:
Notice that
Bultimately defines the fate of this round of consensus. If it prevotesid(X), we have a polka forX, which is likely to be the decision value. If it prevotes any other value, includingnil, the round is doomed, as we can only see precommits fornil. But sinceBis Byzantine, it can just do both, producing two follow-up scenarios:Scenario
1.acan lead to progress, i.e. the decision ofXin the round, with the following scenario in the precommit step:Notice that we are still assuming that validator
Ais slow and precommitsnil. This can be caused because it timeouts while in scenario(1), i.e., it does not receive the prevote fromB, or because it did not even receive the proposal forX.It is simple to see that scenario
2has the same problem as scenario1: the success or not of the round depends on the vote of the Byzantine validatorB. Which can equivocate or can just omit itself. This is the basis for the two described scenarios.Precommit equivocation
In this scenario,
Bdoes not need to equivocate in the prevote step, it can just prevote forid(X)and we get to scenario1.a, then to scenario2. At this point,Bcan literally define who is going to decideXand who is not, as follows:The correct validators that see scenario
2.awill decideXand move to round(H+1, 0). The correct validators that see scenario2.b, or after a timeout still have scenario2, will move to the next round(H, 1).The problem is when no enough validators move to round
(H, 1), namely, less thanfvalidators. In this case, they are stuck in that round, since they will never receive2f + 1vote messages. The same applies, of course, if less thanfvalidators move to the next height, where they will be stuck until at least one more correct validator joins the first round of heightH+1.This scenario, although tricky, should be addressed by a synchronization protocol. Once a correct validator has moved to height
H+1, all correct validators should eventually learn the decision valueXof heightH, plus aCommitcertificate for that value.Prevote Equivocation and Hidden Lock
In the second scenario, the Byzantine validator does not want any validator to decide
Xin heightH. So we should consider the scenarios2and2.b. All validators move to round(H, 1). The problem, however, is what is the state they bring for this round, in terms of the locked and valid value. The equivocation here therefore occurs on the prevote step.Starting from scenario
1, the Byzantine validator can produce at different validators scenarios1.aand1.b. Scenario1.ameans that that validator has probably locked onXat round0, or at least has setXas valid value at round0. In scenario1.b, there is no locked or valid value in any correct validator, namely, they can accept any proposed value.No, lets assume that:
Chas seen scenario1.aand has locked onX, which is also its valid valueDhas seen scenario1.band has no locked or valid valueCis the next proposerIn this case,
Cwill re-proposeX, as it is a valid value. It will send aProposal(H, 1, X, 0), notice thatvr == 0.This scenario is covered by line 28 of the pseudo-code. Validator
D, however, has seen scenario1.b. So it does not know a Polka forXin round0. Even though it eventually receive the second prevote fromB, by assumption it is not considered.As a result,
Cwill prevote forid(X), whileDwill prevote fornil. Even ifAprevotes forid(X)we are back to a scenario very similar to1, when is the Byzantine validatorBthat will decide whether the round can succeed or not.Dis the next proposerIn this case,
Ddoes have any know valid value and will propose a new value, sayY.This scenario is covered by line 22 of the pseudo-code. Validator
Cis locked on round0and valueX != Y. Therefore it has to prevotenil, whileDwill prevote forid(Y). ValidatorAcan prevote fornilor forid(Y). But even in the latter case, we have a scenario where is the Byzantine validatorBthey will decide whether the round can succeed or not.Summary
In summary, we are stuck. The only two validators that are correct and synchronous (
CandD) have conflicting states. One of them is locked, while the other is not. One of them will always propose a value that the other will reject.To form a prevote quorum, a Polka, we need 3 prevotes for the same value ID. Having a good vote from slow validator
Ais not enough. We need to rely on the votes of the Byzantine validatorB, that can block the system forever.How do we solve this problem? In the pseudo-code this is not a problem. Once we get past GST, every correct validator (
AandD) will eventually see that there was a polka forXat round0. But for that, specially in the case of validatorD, it needs to "replace" the prevote fromBat round0from the value it has stored,nil, by the value that validatorChas seen,id(X).Without the ability to override the existing vote set upon seeing a Polka certificate, we cannot solve this scenario.
Beta Was this translation helpful? Give feedback.
All reactions