github.com/pokt-network/tendermint@v0.32.11-0.20230426215212-59310158d3e9/docs/architecture/adr-047-handling-evidence-from-light-client.md (about) 1 # ADR 047: Handling evidence from light client 2 3 ## Changelog 4 * 18-02-2020: Initial draft 5 * 24-02-2020: Second version 6 7 ## Context 8 9 If the light client is under attack, either directly -> lunatic/phantom 10 validators (light fork) or indirectly -> full fork, it's supposed to halt and 11 send evidence of misbehavior to a correct full node. Upon receiving an 12 evidence, the full node should punish malicious validators (if possible). 13 14 ## Decision 15 16 When a light client sees two conflicting headers (`H1.Hash() != H2.Hash()`, 17 `H1.Height == H2.Height`), both having 1/3+ of the voting power of the 18 currently trusted validator set, it will submit a `ConflictingHeadersEvidence` 19 to all full nodes it's connected to. Evidence needs to be submitted to all full 20 nodes since there's no way to determine which full node is correct (honest). 21 22 ```go 23 type ConflictingHeadersEvidence struct { 24 H1 types.SignedHeader 25 H2 types.SignedHeader 26 } 27 ``` 28 29 When a full node receives the `ConflictingHeadersEvidence` evidence, it should 30 a) validate it b) figure out if malicious behaviour is obvious (immediately 31 slashable) or the fork accountability protocol needs to be started. 32 33 ### Validating headers 34 35 Check both headers are valid (`ValidateBasic`), have the same height, and 36 signed by 1/3+ of the validator set that the full node had at height 37 `H1.Height-1`. 38 39 - Q: What if light client validator set is not equal to full node's validator 40 set (i.e. from full node's point of view both headers are not properly signed; 41 this includes the case where none of the two headers were committed on the 42 main chain) 43 44 Reject the evidence. It means light client is following a fork, but, hey, at 45 least it will halt. 46 47 - Q: Don't we want to punish validators who signed something else even if they 48 have less or equal than 1/3? 49 50 No consensus so far. Ethan said no, Zarko said yes. 51 https://github.com/tendermint/spec/pull/71#discussion_r374210533 52 53 ### Figuring out if malicious behaviour is immediately slashable 54 55 Let's say H1 was committed from this full node's perspective (see Appendix A). 56 Intersect validator sets of H1 and H2. 57 58 * if there are signers(H2) that are not part of validators(H1), they misbehaved as 59 they are signing protocol messages in heights they are not validators => 60 immediately slashable (#F4). 61 62 * if `H1.Round == H2.Round`, and some signers signed different precommit 63 messages in both commits, then it is an equivocation misbehavior => immediately 64 slashable (#F1). 65 66 * if `H1.Round != H2.Round` we need to run full detection procedure => not 67 immediately slashable. 68 69 * if `ValidatorsHash`, `NextValidatorsHash`, `ConsensusHash`, 70 `AppHash`, and `LastResultsHash` in H2 are different (incorrect application 71 state transition), then it is a lunatic misbehavior => immediately slashable (#F5). 72 73 If evidence is not immediately slashable, fork accountability needs to invoked 74 (ADR does not yet exist). 75 76 It's unclear if we should further break up `ConflictingHeadersEvidence` or 77 gossip and commit it directly. See 78 https://github.com/tendermint/tendermint/issues/4182#issuecomment-590339233 79 80 If we'd go without breaking evidence, all we'll need to do is to strip the 81 committed header from `ConflictingHeadersEvidence` (H1) and leave only the 82 uncommitted header (H2): 83 84 ```go 85 type ConflictingHeaderEvidence struct { 86 H types.SignedHeader 87 } 88 ``` 89 90 If we'd go with breaking evidence, here are the types we'll need: 91 92 ### F1. Equivocation 93 94 Existing `DuplicateVoteEvidence` needs to be created and gossiped. 95 96 ### F4. Phantom validators 97 98 A new type of evidence needs to be created: 99 100 ```go 101 type PhantomValidatorEvidence struct { 102 PubKey crypto.PubKey 103 Vote types.Vote 104 } 105 ``` 106 107 It contains a validator's public key and a vote for a block, where this 108 validator is not part of the validator set. 109 110 ### F5. Lunatic validator 111 112 ```go 113 type LunaticValidatorEvidence struct { 114 Header types.Header 115 Vote types.Vote 116 } 117 ``` 118 119 To punish this attack, we need support for a new Evidence type - 120 `LunaticValidatorEvidence`. This type includes a vote and a header. The header 121 must contain fields that are invalid with respect to the previous block, and a 122 vote for that header by a validator that was in a validator set within the 123 unbonding period. While the attack is only possible if +1/3 of some validator 124 set colludes, the evidence should be verifiable independently for each 125 individual validator. This means the total evidence can be split into one piece 126 of evidence per attacking validator and gossipped to nodes to be verified one 127 piece at a time, reducing the DoS attack surface at the peer layer. 128 129 Note it is not sufficient to simply compare this header with that committed for 130 the corresponding height, as an honest node may vote for a header that is not 131 ultimately committed. Certain fields may also be variable, for instance the 132 `LastCommitHash` and the `Time` may depend on which votes the proposer includes. 133 Thus, the header must be explicitly checked for invalid data. 134 135 For the attack to succeed, VC must sign a header that changes the validator set 136 to consist of something they control. Without doing this, they can not 137 otherwise attack the light client, since the client verifies commits according 138 to validator sets. Thus, it should be sufficient to check only that 139 `ValidatorsHash` and `NextValidatorsHash` are correct with respect to the 140 header that was committed at the corresponding height. 141 142 That said, if the attack is conducted by +2/3 of the validator set, they don't 143 need to make an invalid change to the validator set, since they already control 144 it. Instead they would make invalid changes to the `AppHash`, or possibly other 145 fields. In order to punish them, then, we would have to check all header 146 fields. 147 148 Note some header fields require the block itself to verify, which the light 149 client, by definition, does not possess, so it may not be possible to check 150 these fields. For now, then, `LunaticValidatorEvidence` must be checked against 151 all header fields which are a function of the application at previous blocks. 152 This includes `ValidatorsHash`, `NextValidatorsHash`, `ConsensusHash`, 153 `AppHash`, and `LastResultsHash`. These should all match what's in the header 154 for the block that was actually committed at the corresponding height, and 155 should thus be easy to check. 156 157 ## Status 158 159 Proposed. 160 161 ## Consequences 162 163 ### Positive 164 165 * Tendermint will be able to detect & punish new types of misbehavior 166 * light clients connected to multiple full nodes can help full nodes notice a 167 fork faster 168 169 ### Negative 170 171 * Accepting `ConflictingHeadersEvidence` from light clients opens up a DDOS 172 attack vector (same is fair for any RPC endpoint open to public; remember that 173 RPC is not open by default). 174 175 ### Neutral 176 177 ## References 178 179 * [Fork accountability spec](https://github.com/tendermint/spec/blob/master/spec/consensus/light-client/accountability.md) 180 181 ## Appendix A 182 183 If there is an actual fork (full fork), a full node may follow either one or 184 another branch. So both H1 or H2 can be considered committed depending on which 185 branch the full node is following. It's supposed to halt if it notices an 186 actual fork, but there's a small chance it doesn't.