A version to track scenarios is available at https://hackmd.io/@alainm/Tenderbake-scenarios Mitten scenarios are available in [this branch](https://gitlab.com/nomadic-labs/tezos/-/tree/functori@mitten/src/mitten/scenarios). ### 0. Bake until level L (warming-up) - Tenderbake status: `NOT-A-BUG` :white_check_mark: - Implementation: - [x] Mitten: different formulations: bake_till_level20_loop.ml bake_till_level20_negative.ml bake_till_level20_positive.ml bake_till_level20_round_robin.ml vary_endorsing_power_and_bake_till_10.ml - [x] Mockup: `test_level_5`, tests that the chain reaches level 5 and checks that all rounds are 0. - Description: Just bake until some level without loosing messages or rounds - Checks: - No blocks with round > 0 - There is a block at level 20 ### 1. Slow Consensus - Tenderbake status: `CONFIRMED` MR still open !352 :x: - Implementation: - [x] Mitten: slow_consensus.ml - [ ] Mockup - Description: **This scenario shows a slow consensus situation due do how PCQs are extracted from received blocks (PQCs are not extracted from old blocks)** - we have four nodes and bakers b1, b2, b3, b4 - we have a committee of 6 slots, quorum is fixed to 5 - we have the following distribution for any level (position in the list determines the round): [ n_b1; n_b2; n_b3; n_b4; n_b3; n_b4 ] - all bakers reach level L-1, and got an EQC for proposal of round 0 - level L, round 0: b1 makes a fresh proposal P1, everyone receives it, but only b2 observes a PQC P1. - level L, round 1: b2 proposes a block P1' containing the same payload hash, but only b1 receives it for the moment. No QC is observed on it - level L, round 2: b3 proposes a block P2 without PQC, and b1's and b2's nodes receive it, but they ignore it because it's not better. Even if b4 receives P2, no QC will be reached without b1 and b2. - now, assume b3 and b4 finally receive the proposal P1'. Since it's outdated, these bakers don't extract the PQC of P1' to update theirs, because of a bug in the implementation. (*) - level L, rounds 3,4,5: all proposals of b4 and b3 don't contain a PQC. These proposals are rejected by their own nodes, which switched to proposal P1'. - round6: finally b1 makes a re-proposal with the payload hash of P1' and allows to reach consensus for level L. - Checks: - Ensure that, at level 4, b3, the proposer at round 3, proposes a block with the PQC from P1' that it has just seen (item (*) above) ### 2. Predecessor fork version 1 - Tenderbake status: `FIXED` :white_check_mark: - Implementation: - [x] Mitten: simple_pred_fork_negative.ml simple_pred_fork_positive.ml - [x] Mockup: scenario m7 - Description: **(Some) Bakers switch branch to minimize predecessor round (follow fitness)** - we have four bakers (and nodes) (n_)b1, (n_)b2, (n_)b3, (n_)b4, committee has size 3 - slots distribution around level L is (positions in the lists determine rounds): ``` L-2: [ n_b1; n_b2; n_b3; n_b4; ] L-1: [ n_b2; n_b3; n_b4; n_b1; ] L: [ n_b3; n_b4; n_b1; n_b2; ] L+1: [ n_b4; n_b1; n_b2; n_b3; ] ``` - all bakers reach level L-1 and get a EQC for proposal at round 0 - at level L, round 0: b3 make a proposal P1. All bakers observe a PQC, but only b1 observe a EQC on it - at level L, round 1: b4 make a proposal P1' with the payload of P1. All bakers receive it and get an EQC on it - at level L+1, round 0, b4 bakes Q1 on top of (3,1) (ie. P1'). Everyone receives the proposal, except b1 - at level L+1, round 1, b1 bakes Q2 on top of (3,0) (ie. P1) and propogates its block to b2 and b3. These bakers (and their nodes) switch to this new branch - Now, n_b1 receives the proposal Q1 of b4, but it doesn't switch to it, because it's not better. - Checks: - A baker should make a branch switch with a reorganization of size 2. The predecessor should move from round 1 to round 0. - Extra: grep `switching` in bakers log to observe something like `alpha.baker.transitions: switching branch` ### 3. Predecessor fork version 2 (with PQC) - Tenderbake status: `FIXED` :white_check_mark: - Implementation: - [x] Mitten: simple_pred_fork_negative_with_observed_PQC.ml - [ ] Mockup - Description: **(Some) Bakers DON'T switch branch to minimize predecessor round, because they observed a PQC (they contradict their nodes)** - we have four bakers (and nodes) (n_)b1, (n_)b2, (n_)b3, (n_)b4, committee has size 3 - slots distribution around level L is (positions in the lists determine rounds) ``` L-2: [ n_b1; n_b2; n_b3; n_b4; ] L-1: [ n_b2; n_b3; n_b4; n_b1; ] L: [ n_b3; n_b4; n_b1; n_b2; ] L+1: [ n_b4; n_b1; n_b2; n_b3; ] ``` - all bakers reach level L-1 and get a EQC for proposal at round 0 - at level L, round 0: b3 make a proposal P1. All bakers observe a PQC, but only b1 observe a EQC on it - at level L, round 1: b4 make a proposal P1' with the payload of P1. All bakers receive it and get an EQC on it - at level L+1, round 0, b4 bakes Q1 on top of (3,1) (ie. P1'). Everyone receives the proposal, except b1 - bakers b3, b4 get a PQC for proposal Q1 at (4, 0), but no EQC. b2 observes no QC - at level L+1, round 1, b1 bakes Q2 on top of (3,0) (ie. P1) and propogates its block to other bakers and nodes. - the node (n_)b2 and its baker switch to this branch - the nodes of b3 and b4 switch their heads (branchs), but not their bakers (they prefer keeping the branch for which they observed a PQC) - at level L+1, round 2, a similar situation happens: b2 bakes Q3 on top of (3,0) (ie. P1) and propogates its block to other bakers and nodes. - the node (n_)b1 and its baker switch to this branch - the nodes of b3 and b4 switch their heads, but not their bakers (they prefer keeping the branch for which they observed a PQC) - at level L+1, round 3, b3 proposes a block Q1' having the payload hash of Q1 on top of (3,1). All bakers and nodes switch to it, and an EQC is observed after (pre)-endorsements for this proposal are propagated. - Checks (high level): - A baker should have a branch `(L-1, 0) -- (L, 1)` - The other bakers should be on `(L-1, 1) -- (L, 0)`. - The bakers who have observed a PQC on `(L, 0)` should not switch to the other (seemingly better) branch (with `(L-1, 0)`). - Extra: grep `switching` in bakers log to observe something like `alpha.baker.transitions: switching branch` ### 4. Clock drift - Tenderbake status: `FIXED` :white_check_mark: - Implementation: - [x] Mitten: bake_till_level20_negative_drift.ml - [ ] Mockup - Description: We have four nodes. One of them has a linear drift in the future. Another one has a linear drift in the past. Consensus rounds will be higher and higher when level increases. Drifts are so big that consensus will not be reached at all (delta drifts are bigger than delta durations added to higher rounds). - Checks: - Ensure we can reach level 10 with a max round of 5 (**depend on duration of rounds!!**) ### 4.1. Proposal in the Future with Clock drift - Tenderbake status: `FIXED` :white_check_mark: - Implementation: - [x] Mitten: proposal_in_the_future.ml - [ ] Mockup - Description: In the presence of clock drift, a proposal is made by a baker who has a clock in the future. It is considered in the future by other bakers. They should reconsider this proposal when the time comes otherwise they risk missing information. - Checks: - Ensure all other bakers eventually preendorse the block proposed by the baker who is in advance ### 5. No participation at round R + 1 because of a PQC observed at round R on a different payload - Tenderbake status: `CONFIRMED` MR still open !317 :x: - Implementation: - [x] Mitten: baker_not_participating_round_r_because_pqc_previous_round_diff_playload.ml - [x] Mockup: scenario f1 - Description: One scenario that highlights this problem is: - B3 proposes at (L, 0) with payload hash c1 to B1, B2, B4 - Only B1 sees the PQC on this block (we discard all preendorse messages to B2, B3, B4) - B4 proposes at (L, 1) with payload hash c2 - All messages are forwarded, everybody sees the EQC on c2 except for B1 - B1 should propose at (L+1, 0) - Checks: - Ensure there is a proposal at level L+1, round 0 ### 6. Simple double bake - Tenderbake status: works :white_check_mark: - Implementation: - [x] Mitten: [simple_double_bake.ml](https://gitlab.com/nomadic-labs/tezos/-/tree/functori@mitten/src/mitten/scenarios/simple_double_bake.ml) - [ ] Mockup - Description: - 4 bakers, nodes and slots - delegates selection is the same for all levels: `[ n_b1; n_b2; n_b3; n_b4 ];` - Bake until some level L - at level L, round 0, no EQC is observed, and everyone observed a PQC except b3 - at level L, round 1, b2's proposal with a PQC is delayed - at level L, round 3, b3 proposes a fresh block and its associated preendorsement for everyone. But just after that, it's stopped and its watermarks & local data are reset - Node of b3 finally receives b2's proposal at (L,1) and switches to it (better chain because of included PQC) - Baker b3 re-starts. It doesn't realize it already baked at (L, 3). So it inject a block (with a PQC this time) and its associated preendorsement. - A double-baking operations is emitted. - Checks: - Ensure that there is a double baking denunciation operation in the following block. ### 6.1. Simple double preendorse - Tenderbake status: Bug in accuser `CONFIRMED` MR still open !326 :x: - Implementation: - [x] Mitten: [simple_double_preendorse.ml](https://gitlab.com/nomadic-labs/tezos/-/tree/functori@mitten/src/mitten/scenarios/simple_double_preendorse.ml) - [ ] Mockup - Description: - 4 bakers, nodes and slots - delegates selection is the same for all levels: `[ n_b1; n_b2; n_b3; n_b4 ];` - Bake until some level L - at level L, round 0, no EQC is observed, and everyone observed an EQC except b3 - at level L, round 1, b2's proposal with a PQC is delayed - at level L, round 3, b3 proposes a fresh block and its associated preendorsement for everyone. But just after that, it's stopped and its watermarks & local data are reset - Node of b3 finally receives b2's proposal at (L,1) and switches to it (better chain because of included PQC) - Baker b3 re-starts. It doesn't realize it already baked at (L, 3). So it inject a block (with a PQC this time) and its associated preendorsement. - A double pre-endorsement operation is emitted. - Checks: - Ensure that there is a double preendorsement denunciation operation in the following block. ### 7. Double bake / double preendorse with predecessor fork - Tenderbake status: Bug in accuser `CONFIRMED` MR still open !326 :x: - Implementation: - [x] Mitten: [advanced_fork_with_double_bake_risk.ml](https://gitlab.com/nomadic-labs/tezos/-/tree/functori@mitten/src/mitten/scenarios/advanced_fork_with_double_bake_risk.ml) [advanced_fork_with_double_bake_and_preendorse.ml](https://gitlab.com/nomadic-labs/tezos/-/tree/functori@mitten/src/mitten/scenarios/advanced_fork_with_double_bake_and_preendorse.ml) [advanced_fork_with_double_bake_and_preendorse__5_nodes.ml](https://gitlab.com/nomadic-labs/tezos/-/tree/functori@mitten/src/mitten/scenarios/advanced_fork_with_double_bake_and_preendorse__5_nodes.ml) - [ ] Mockup: - Description: **The description is for advanced_fork_with_double_bake_and_preendorse.ml above** - for nodes, accuser and bakers. Bakers have one slot each - we assume the following delegate selection strategy: ``` [ n_b1; n_b2; n_b3; n_b4; ]; [ n_b1; n_b2; n_b3; n_b4; ]; [ n_b1; n_b2; n_b3; n_b4; ]; [ n_b1; n_b2; n_b3; n_b4; ]; ``` - Rounds durations are important to make the scenario works. - all nodes/bakers reach level L - for proposal PL0 (L, 0) only b1 observes an EQC (others observe a PQC) - b2, b3 and b4 finaly observe an EQC on some proposal PL3 for L at round 3 - b1 being isolated its proposal on top of PL0 at (L+1, 0) haven't been received by other - b2 makes a proposal on top of PL3 at (L+1, 1), b1 doesn't receive it, and b2, b3, b4 observe a PQC on it - b1 makes another proposal on top of PL0 at (L+1, 4) and preendorses it. The proposal is not received by anyone else. Baker b1 then stops are its state and watermarks files are deleted. - b4 proposes at (L+1, 3). The proposal finaly reaches b1's node. The baker of b1 is started. No consensus is reached for this proposal. - now b1, proposes a block (with a PQC extracted from (L+1, 3)) on top of PL3 and preendorses it. - The accuser should denounce it for double baking and double preendorsing. the operations are included in the next block and b1 is slashed. - Checks: - Ensure that there is a double preendorsement/baking denunciation operation in the following block. ### 8. Potential bug in `first_potential_baking_round_at_next_level` - Tenderbake status: - Implementation: - [x] Mitten: first_potential_baking_round_at_next_level.ml - [x] Mockup: scenario f2 - Description: b1 has seen EQC at level L. If b1 proposes at (L+1, 0) but never gets back its proposal from the node, it may be out of sync for level L - Checks: - ~~Ensure b1 proposes at level 4 round 4~~ - TODO: rewrite the scenario with 3 bakers/slot and use the new RPC Proxy between the baker and its node in Mitten to attempt to trigger the bug. ### 9. Simple reproposal - Tenderbake status: works :white_check_mark: - Implementation: - [x] Mitten: reproposal.ml - [x] Mockup: scenario t1 - Description: Node A proposes at the round 0. Both node A and node B preendorse. Node A stops. Node B endorses in the round 0 and locks. No decision is taken at the round 0 because A did not endorse. - Checks: We check that in round 1 (the next slot for B), B proposes the same value as A proposed in the round 0, not a new proposal. ### 10. Baker waits for its round to propose - Tenderbake status: works :white_check_mark: - Implementation: - [x] Mitten: next_round.ml - [x] Mockup: scenario t2 - Description: Node A should propose at the round 0, but it is dead. Node B waits til it has its proposal slot at round 1 and proposes then. - Checks: We check that B proposes at level 1 round 1. ### 11. Locked node refuses to preendorse - Tenderbake status: works :white_check_mark: - Implementation: - [x] Mitten: locked_no_preendrose.ml - [x] Mockup: scenario t3 - Description: With 4 nodes, we let B observe PQC on a proposal and D does not even see the proposal. Since only B has observed PCQ there is no consensus and we move to the next round where D proposes. B refuses to preendorse since it is locked. - Checks: Check that the scenario proceeds as expected. ### 12. Network resumes after a network failure - Tenderbake status: works :white_check_mark: - Implementation: - [x] Mitten: resume_after_network_failure.ml - [x] Mockup: scenario m1 - Description: Four nodes start, each with 1 delegate. As soon as 2nd level is proposed all communication between nodes becomes impossible. The situation continues for 5 seconds. After communication is resumed the bakers must continue making progress. - Checks: level 4 is reached. ### 13. Network is making progress despite missing a delegate with allocated slots - Tenderbake status: works :white_check_mark: - Implementation: - [x] Mitten: bake_till_level10_missing_baker.ml - [x] Mockup: scenario m2 - Description: With 5 nodes, 1 delegate per node, we eliminate a node that has 1 slot at each level. The chain must still make progress, albeit somewhat slower. - Checks: level 5 is reached. ### 14. Chain is blocked because EQC cannot be observed - Tenderbake status: works :white_check_mark: - Implementation: - [x] Mitten: no_eqc_stuck.ml - [x] Mockup: scenario m3 - Description: There are four nodes: A, B, C, and D. A and B propose in turns. Messages from A reach every node, but messages from other nodes only go to A. - Checks: The chain should not make progress. Since we have both A and B in delegate selection they have equal voting power. Therefore it is necessary to have 2 votes for pre-quorums (which is achieved when A is proposing) and 2 votes for quorums (impossible because B has no way to obtain PQC and thus cannot send endorsements). ### 15. Nodes send endorsements despite receiving preendorsements before the proposal - Tenderbake status: works :white_check_mark: - Implementation: - [x] Mitten: preend_before_proposal.ml - [x] Mockup: scenario m4 - Description: There are four bakers: A, B, C, and D. A proposes at level 1 round 0. Its proposal reaches A, B, C, and D, but with a delay of 0.5 seconds. 3 votes are enough for consensus, because voting powers of all delegates are equal. Preendorsements propagate freely, however endorsements from C are blocked. - Checks: Check that at level 1 round 0 quorum is reached (from the point of view of A). This means that D sends an endorsement despite receiving preendorsements before the proposal. ### 16. Nodes send endorsement despite receiving preendorsements and endorsements before the proposal - Tenderbake status: works :white_check_mark: - Implementation: - [x] Mitten : end_before_proposal.ml - [x] Mockup: scenario m5 - Description: There are four bakers: A, B, C, and D. A proposes at level 1 round 0. Its proposal reaches A, B, C, and D, but with a delay of 1 second. There are no problems with propagation of preendorsements and endorsements. At the level 1 all four bakers have proposer slots, however we block possible proposals from B and C at higher rounds. - Checks: Check that D proposes at the level 2 round 0, which means that it has observed QC. ### 17. Advanced fork with subsequent branch switch - Tenderbake status: works :white_check_mark: - Implementation: - [x] Mitten: advanced_fork_with_double_bake_risk.ml advanced_fork_with_double_bake_and_preendorse.ml (although IIUC it has different checks than mockup scenarios) - [x] Mockup: scenario m6, m7, m8 - Description: There are four bakers: A, B, C, and D. A proposes at level 1 round 0. Its proposal reaches all nodes, and they observe PQC. Only A observes a QC. At level 1 round 1 it is B's turn to propose. Since it has observed the PQC, it reproposes A's proposal. A does not see it. B observes PQC and QC for its proposal. The check varies depending on the concrete scenario. - Checks: - In mockup M6: A proposes at 2.0 (only A sees it) and B proposes at 2.1, so A switches to B's branch when it receives 2.1. - In mockup M7: B proposes at 2.0 (A does not see it) and A proposes at 2.1. B switches to A's branch when it receives 2.1. - In mockup M8: B proposes at 2.0 and observes PQC but not QC. C re-proposes at 2.1 and similarly observes PQC but not QC. A proposes at 2.2. B, C, and D do not switch to A's branch; moreover A switches to their branch when it receives the next proposal. This happens because B, C, and D have PQC despite A having a higher round (2 > 1). --- ### X. Template - Tenderbake status: When this scenario covers a bug in Tenderbake, whether it is already fixed or not. - Implementation: - [ ] Mitten: scenario files for mitten - [ ] Mockup: scenario files for mockup - Description: Brief (or long) description of scenario, can include steps - Checks: List of checks that should pass