From 55909aac689541c3ae224ae59bfa36d805a75834 Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Mon, 20 Apr 2020 09:08:57 +0200 Subject: [PATCH] docs/architecture: create adr 56: prove amnesia attack ## Description ADR to address the process for proving an amnesia attack (as a form of global evidence) from `PotentialAmnesiaEvidence` detected by light clients ______ For contributor use: - [ ] Wrote tests - [ ] Updated CHANGELOG_PENDING.md - [ ] Linked to Github issue with discussion and accepted design OR link to spec that describes this work. - [ ] Updated relevant documentation (`docs/`) and code comments - [ ] Re-reviewed `Files changed` in the Github PR explorer --- .../adr-056-proving-amnesia-attacks.md | 120 ++++++++++++++++++ docs/imgs/tm-amnesia-attack.png | Bin 0 -> 16912 bytes 2 files changed, 120 insertions(+) create mode 100644 docs/architecture/adr-056-proving-amnesia-attacks.md create mode 100644 docs/imgs/tm-amnesia-attack.png diff --git a/docs/architecture/adr-056-proving-amnesia-attacks.md b/docs/architecture/adr-056-proving-amnesia-attacks.md new file mode 100644 index 000000000..f0200ca7d --- /dev/null +++ b/docs/architecture/adr-056-proving-amnesia-attacks.md @@ -0,0 +1,120 @@ +# ADR 056: Proving amnesia attacks + +## Changelog + +- 02.04.20: Initial Draft +- 06.04.20: Second Draft + +## Context + +Whilst most created evidence of malicious behaviour is self evident such that any individual can verify them independently there are types of evidence, known collectively as global evidence, that require further collaboration from the network in order to accumulate enough information to create evidence that is individually verifiable and can therefore be processed through consensus. [Fork Accountability](https://github.com/tendermint/spec/blob/master/spec/consensus/light-client/accountability.md) has been coined to describe the entire process of detection, proving and punishing of malicious behaviour. This ADR addresses specifically how to prove an amnesia attack but also generally outlines how global evidence can be converted to individual evidence. + +### Amnesia Attack + +The currently only known form of global evidence stems from [flip flopping](https://github.com/tendermint/spec/blob/master/spec/consensus/light-client/accountability.md#flip-flopping) attacks. The schematic below explains one scenario where an amnesia attack, a form of flip flopping, can occur such that two sets of honest nodes, C1 and C2, commit different blocks. + +![](../imgs/tm-amnesia-attack.png) + +1. C1 and F send PREVOTE messages for block A. +2. C1 sends PRECOMMIT for round 1 for block A. +3. A new round is started, C2 and F send PREVOTE messages for a different block B. +4. C2 and F then send PRECOMMIT messages for block B. +5. F breaks the lock and goes back and sends PRECOMMIT messages in round 1 for block A. + + +This creates a fork on the main chain. Back to the past, another form of flip flopping, creates a light fork (capable of fooling those not involved in consensus), in a similar way, with F taking the precommits from C1 and forging a commit from them. + +## Decision + +As the distinction between these two attacks (amnesia and back to the past) can only be distinguished by confirming with all validators (to see if it is a full fork or a light fork), for the purpose of simplicity, these attacks will be treated as the same. + +Currently, the evidence reactor is used to simply broadcast and store evidence. Instead of perhaps creating a new reactor for the specific task of verifying these attacks, the current evidence reactor will be extended. + +The process begins with a light client receiving conflicting headers (in the future this could also be a full node during fast sync), which it sends to a full node to analyse. As part of [evidence handling](https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-047-handling-evidence-from-light-client.md), this could be deduced into potential amnesia evidence + +```golang +type PotentialAmnesiaEvidence struct { + V1 []*types.Vote + V2 []*types.Vote + + timestamp time.Time +} +``` + +*NOTE: Unlike prior evidence types, `PotentialAmnesiaEvidence` and `AmnesiaEvidence` are processed as a batch instead + of individually. This will require changes to much of the API.* + + *NOTE: `PotentialAmnesiaEvidence` could be constructed for when 1/3 or less vote in two different rounds but as it is not currently detected nor can it cause a fork, it will be ignored.* + +The evidence should contain the precommit votes for the intersection of validators that voted for both rounds. The votes should be all valid and the height and time that the infringement was made should be within: + +`MaxEvidenceAge - Amnesia trial period` + +where `Amnesia trial period` is a configurable duration defaulted at 1 day. + +With reference to the honest nodes, C1 and C2, in the schematic, C2 will not PRECOMMIT an earlier round, but it is likely, if a node in C1 were to receive +2/3 PREVOTE's or PRECOMMIT's for a higher round, that it would remove the lock and PREVOTE and PRECOMMIT for the later round. Therefore, unfortunately it is not a case of simply punishing all nodes that have double voted in the `PotentialAmnesiaEvidence`. + +Instead we use the Proof of Lock Change (PoLC) referred to in the [consensus spec](https://github.com/tendermint/spec/blob/master/spec/consensus/consensus.md#terms). When an honest node votes again for a different block in a later round +(which will only occur in very rare cases), it will generate the PoLC and store it in the evidence reactor for a time equal to the `MaxEvidenceAge` + +```golang +type ProofOfLockChange struct { + Votes []*types.Vote +} +``` + +This can be either evidence of +2/3 PREVOTES or PRECOMMITS (either warrants the honest node the right to vote) and is valid, among other checks, so long as the PRECOMMIT vote of the node in V2 came after all the votes in the `ProofOfLockChange` i.e. it received +2/3 votes for a block and then voted for that block thereafter (F is unable to prove this). + +In the event that an honest node receives `PotentialAmnesiaEvidence` it will first `Verify()` it and then will check if it is among the suspected nodes in the evidence. If so, it will retrieve the `ProofOfLockChange` and combine it with `PotentialAmensiaEvidence` to form `AmensiaEvidence`: + +```golang +type AmnesiaEvidence struct { + Evidence *types.PotentialAmnesiaEvidence + Proofs []*types.ProofOfLockChange +} +``` + +If the node is not required to submit any proof than it will simply broadcast the `PotentialAmnesiaEvidence` . + +When a node has successfully validated `PotentialAmnesiaEvidence` it timestamps it and refuses to receive the same form of `PotentialAmnesiaEvidence`. If a node receives `AmnesiaEvidence` it checks it against any current `AmnesiaEvidence` it might have and if so merges the two by adding the proofs, if it doesn't have it yet it run's `Verify()` and stores it. + +There can only be one `AmnesiaEvidence` and one `PotentialAmneisaEvidence` stored for each attack (i.e. for each height). + +When, `time.Now() > PotentialAmnesiaEvidence.timestamp + AmnesiaTrialPeriod`, honest validators of the current validator set can begin proposing the block that contains the `AmnesiaEvidence`. + +*NOTE: Even before the evidence is proposed and committed, the off-chain process of gossiping valid evidence could be + enough for honest nodes to recognize the fork and halt.* + +Other validators will vote if: + +- The Amnesia Evidence is not valid +- The Amensia Evidence is not within the validators trial period i.e. too soon. +- The Amensia Evidence is of the same height but is different to the Amnesia Evidence that they have. i.e. is missing proofs. + (In this case, the validator will try again to gossip the latest Amnesia Evidence that it has) +- Is of an AmnesiaEvidence that has already been committed to the chain. + + +## Status + +Proposed + +## Consequences + +### Positive + +Increasing fork detection makes the system more secure + +### Negative + +Non-responsive but honest nodes that are part of the suspect group that don't produce a proof will be punished + +A delay between the detection of a fork and the punishment of one + +### Neutral + +Evidence package will need to be able to handle batch evidence as well as individual evidence (i.e. extra work) + +## References + +- [Fork accountability algorithm](https://docs.google.com/document/d/11ZhMsCj3y7zIZz4udO9l25xqb0kl7gmWqNpGVRzOeyY/edit) +- [Fork accountability spec](https://github.com/tendermint/spec/blob/master/spec/consensus/light-client/accountability.md) diff --git a/docs/imgs/tm-amnesia-attack.png b/docs/imgs/tm-amnesia-attack.png new file mode 100644 index 0000000000000000000000000000000000000000..7e084b273e97c7b1aa60b273cdfb0bbf811d54ce GIT binary patch literal 16912 zcmd_R2UJwg`YotP&R`%aNkk-elQT3qXPO+F+=M36BuNUAvw(m~Pz1>cND?G8NhFH| z5fCIw5XtZg{dxa)-n@6`tu?b|&3faK?$dRu>QsI8)mOE5?Gvq~p-4hVOL*zhB@$&N zIh{+Fu%O`j9X>AjyhRXged!YJnU}nwmy4gBBhvN~E1&G2D^@74gPW%pE1w)I6l&$} z&W&)iviGoZ@#J>3^#V!YzKa{e(azBp@h1ZJgaMipV;6xVeB71tAe`UT!`SegSR>-^Fuu zt?aBk9RIDFi`LtES=s+-ISj6&sjevN>2AZPqTm1%aFSIQ_|sw^TMti1H`hPeAW&`* zZs9*Sy!_p5|D@Wxx!EJZL!qpE^1yiiSP9hc_>WzbkxDRME(<#ml)SU2j-02BmI~jW zN?ff#Yk%8U3z&ur@~09Z11}vLL1kZgEq;iWtCgaPs+=!ej?bFUS<}ZAffC?DdMjzW z>!>RW$vYUhqCl^}e`jR}WqUm>BvQ%ESC7|S3979p;^pb%4RKYHF?RFh=k@XSa8vOR za8VbuS2nVf6OrYUG18M!@^bZ8=2fy)_teq$S60^364vlHk_W>DGXj+w*gK#ERh$I1 zWbOHt{Zu_2QL;*Io^opPuCne(f`YTE zGE_;^kY7R9N=;jxSKYx`K=7hw7nFmLI-jGqnxV0PCqh=9SIJ6U*;xMK4xh0e8m6J8 zXe;dODJbNkrp0H=C#xwVq@d$#Y@=x-sHLhRg!U8Cas|&(aDW;+fiGcucZ92pv4J5{ zP!O#k%nw%;5!8qA$+@}u+iD^eY#e0$_4(yIb#?t6J?(u2jkSy*B4{HIew3#Y#86Qe zZlq?dWN!^BQq|G370^%xR~p)$ni|Ruh6?J2`Us3h~N0c>3!q*(&+NbgZnD?2t$SK?qt<1!}Da zGRw$o81uVmD{83nE7a{sv}%ojYN2Xqr*J?1+6^L_6S9P5netG zkl<%0Vq+*|?FJWdN4wj3`0&ahRJ38j9##-nsFD`wgO`wykdvIYEX-BTM%`D)O2JJ5 z;cKG=Q}#08a|0E~AyjSU>`+KYFMWiP07Bab?(7a#6oeQkUEKBcb~I2{L0CI@!Vn%V z?zTu5h^me^M9bGeO-YyE&e>2#(?(a8*WX^vP*2238KMma1t#QfZQzB}_T}@0^IkZZ zF`urQs;8R=xP^dw_`_t-Xb(PPO|pp?ZQco(^j68mhv4+9+dJT{KANm(x_$ zQE_#5L5uJk2*PzyI>PFnf`Udmsy6O02TgeaT@jGWPTNLBL0HDgz(~!}2;mA+ltJi$ z3Fzt?SZn+6gG)bodk1eXUX-<;tGbSgoFmFvL&#Z|PgoUd4Mhp)YY6)B>!@4FIg99N zK=kyXLUKAzs&G3{5DbulkGqqIj}Xe%${p>cr(p#17xIwjl|#9sH2Adr<$QGYd_YDW zdmC2`&=>_f5UXI`{$Mb{kBiY#@b*)LTiJsaDY)7}1y!99;7ZdIZsTGgr)Oo0Fm%#a z*VEEa_E6E+(6E78@i}Sn8~XbRyQ#ZsBRt^ta$2?maC?{+(%0J;<%!fbMEm<*jEb5u z%3D^=K*J5Ct^-xk@Y2zNB4q^ptPM3?L+Fg!6m~)zTy)Id<|4@Q zffYmHZ*=}0s=@DnmO4K9u?iIRrAv⋘vdf{LDAZ@VxXp-<~n)T%n*8rO-l?)Tchj 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 O{wd3A$d$n?!~PowBrdxE literal 0 HcmV?d00001