mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-28 02:03:32 +00:00
Gloas fork choice redux (#9025)
Co-Authored-By: hopinheimer <knmanas6@gmail.com> Co-Authored-By: Michael Sproul <michael@sigmaprime.io> Co-Authored-By: hopinheimer <48147533+hopinheimer@users.noreply.github.com> Co-Authored-By: Eitan Seri- Levi <eserilev@gmail.com> Co-Authored-By: dapplion <35266934+dapplion@users.noreply.github.com> Co-Authored-By: Michael Sproul <michaelsproul@users.noreply.github.com> Co-Authored-By: Jimmy Chen <jchen.tc@gmail.com> Co-Authored-By: Daniel Knopik <107140945+dknopik@users.noreply.github.com>
This commit is contained in:
@@ -16,6 +16,8 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(0),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a block with a hash of 2.
|
||||
@@ -35,6 +37,8 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that the head is 2
|
||||
@@ -53,6 +57,8 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a block with a hash of 1 that comes off the genesis block (this is a fork compared
|
||||
@@ -73,6 +79,8 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that the head is still 2
|
||||
@@ -91,6 +99,8 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a vote to block 1
|
||||
@@ -101,7 +111,7 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(1),
|
||||
target_epoch: Epoch::new(2),
|
||||
attestation_slot: Slot::new(2),
|
||||
});
|
||||
|
||||
// Ensure that the head is now 1, because 1 has a vote.
|
||||
@@ -120,6 +130,8 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(1),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertWeight {
|
||||
@@ -143,7 +155,7 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(2),
|
||||
target_epoch: Epoch::new(2),
|
||||
attestation_slot: Slot::new(2),
|
||||
});
|
||||
|
||||
// Ensure that the head is 2 since 1 and 2 both have a vote
|
||||
@@ -162,6 +174,8 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertWeight {
|
||||
@@ -196,6 +210,8 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that the head is still 2
|
||||
@@ -216,6 +232,8 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertWeight {
|
||||
@@ -245,7 +263,7 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(3),
|
||||
target_epoch: Epoch::new(3),
|
||||
attestation_slot: Slot::new(3),
|
||||
});
|
||||
|
||||
// Ensure that the head is still 2
|
||||
@@ -266,6 +284,8 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertWeight {
|
||||
@@ -315,6 +335,8 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Invalidation of 3 should have removed upstream weight.
|
||||
@@ -347,7 +369,7 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(1),
|
||||
target_epoch: Epoch::new(3),
|
||||
attestation_slot: Slot::new(3),
|
||||
});
|
||||
|
||||
// Ensure that the head has switched back to 1
|
||||
@@ -368,6 +390,8 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances,
|
||||
expected_head: get_root(1),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertWeight {
|
||||
@@ -399,6 +423,9 @@ pub fn get_execution_status_test_definition_01() -> ForkChoiceTestDefinition {
|
||||
root: get_root(0),
|
||||
},
|
||||
operations: ops,
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
spec: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,6 +445,8 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(0),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a block with a hash of 2.
|
||||
@@ -437,6 +466,8 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that the head is 2
|
||||
@@ -455,6 +486,8 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a block with a hash of 1 that comes off the genesis block (this is a fork compared
|
||||
@@ -475,6 +508,8 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that the head is still 2
|
||||
@@ -493,6 +528,8 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a vote to block 1
|
||||
@@ -503,7 +540,7 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(1),
|
||||
target_epoch: Epoch::new(2),
|
||||
attestation_slot: Slot::new(2),
|
||||
});
|
||||
|
||||
// Ensure that the head is now 1, because 1 has a vote.
|
||||
@@ -522,6 +559,8 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(1),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertWeight {
|
||||
@@ -545,7 +584,7 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(2),
|
||||
target_epoch: Epoch::new(2),
|
||||
attestation_slot: Slot::new(2),
|
||||
});
|
||||
|
||||
// Ensure that the head is 2 since 1 and 2 both have a vote
|
||||
@@ -564,6 +603,8 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertWeight {
|
||||
@@ -598,6 +639,8 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that the head is still 2
|
||||
@@ -618,6 +661,8 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertWeight {
|
||||
@@ -647,7 +692,7 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(3),
|
||||
target_epoch: Epoch::new(3),
|
||||
attestation_slot: Slot::new(3),
|
||||
});
|
||||
|
||||
// Move validator #1 vote from 2 to 3
|
||||
@@ -660,7 +705,7 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(3),
|
||||
target_epoch: Epoch::new(3),
|
||||
attestation_slot: Slot::new(3),
|
||||
});
|
||||
|
||||
// Ensure that the head is now 3.
|
||||
@@ -681,6 +726,8 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(3),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertWeight {
|
||||
@@ -730,6 +777,8 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances,
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Invalidation of 3 should have removed upstream weight.
|
||||
@@ -763,6 +812,9 @@ pub fn get_execution_status_test_definition_02() -> ForkChoiceTestDefinition {
|
||||
root: get_root(0),
|
||||
},
|
||||
operations: ops,
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
spec: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -782,6 +834,8 @@ pub fn get_execution_status_test_definition_03() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(0),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a block with a hash of 2.
|
||||
@@ -801,6 +855,8 @@ pub fn get_execution_status_test_definition_03() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that the head is 2
|
||||
@@ -819,6 +875,8 @@ pub fn get_execution_status_test_definition_03() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a block with a hash of 1 that comes off the genesis block (this is a fork compared
|
||||
@@ -839,6 +897,8 @@ pub fn get_execution_status_test_definition_03() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that the head is still 2
|
||||
@@ -857,6 +917,8 @@ pub fn get_execution_status_test_definition_03() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a vote to block 1
|
||||
@@ -867,7 +929,7 @@ pub fn get_execution_status_test_definition_03() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(1),
|
||||
target_epoch: Epoch::new(2),
|
||||
attestation_slot: Slot::new(2),
|
||||
});
|
||||
|
||||
// Ensure that the head is now 1, because 1 has a vote.
|
||||
@@ -886,6 +948,8 @@ pub fn get_execution_status_test_definition_03() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(1),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertWeight {
|
||||
@@ -909,7 +973,7 @@ pub fn get_execution_status_test_definition_03() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(1),
|
||||
target_epoch: Epoch::new(2),
|
||||
attestation_slot: Slot::new(2),
|
||||
});
|
||||
|
||||
// Ensure that the head is 1.
|
||||
@@ -928,6 +992,8 @@ pub fn get_execution_status_test_definition_03() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(1),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertWeight {
|
||||
@@ -962,6 +1028,8 @@ pub fn get_execution_status_test_definition_03() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that the head is now 3, applying a proposer boost to 3 as well.
|
||||
@@ -985,13 +1053,15 @@ pub fn get_execution_status_test_definition_03() -> ForkChoiceTestDefinition {
|
||||
proposer_boost_root: get_root(3),
|
||||
});
|
||||
|
||||
// Stored weights are pure attestation scores (proposer boost is applied
|
||||
// on-the-fly in the walk's `get_weight`, not baked into `node.weight()`).
|
||||
ops.push(Operation::AssertWeight {
|
||||
block_root: get_root(0),
|
||||
weight: 33_250,
|
||||
weight: 2_000,
|
||||
});
|
||||
ops.push(Operation::AssertWeight {
|
||||
block_root: get_root(1),
|
||||
weight: 33_250,
|
||||
weight: 2_000,
|
||||
});
|
||||
ops.push(Operation::AssertWeight {
|
||||
block_root: get_root(2),
|
||||
@@ -999,8 +1069,7 @@ pub fn get_execution_status_test_definition_03() -> ForkChoiceTestDefinition {
|
||||
});
|
||||
ops.push(Operation::AssertWeight {
|
||||
block_root: get_root(3),
|
||||
// This is a "magic number" generated from `calculate_committee_fraction`.
|
||||
weight: 31_250,
|
||||
weight: 0,
|
||||
});
|
||||
|
||||
// Invalidate the payload of 3.
|
||||
@@ -1065,6 +1134,9 @@ pub fn get_execution_status_test_definition_03() -> ForkChoiceTestDefinition {
|
||||
root: get_root(0),
|
||||
},
|
||||
operations: ops,
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
spec: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ pub fn get_ffg_case_01_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(0),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Build the following tree (stick? lol).
|
||||
@@ -27,6 +29,8 @@ pub fn get_ffg_case_01_test_definition() -> ForkChoiceTestDefinition {
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
@@ -34,6 +38,8 @@ pub fn get_ffg_case_01_test_definition() -> ForkChoiceTestDefinition {
|
||||
parent_root: get_root(1),
|
||||
justified_checkpoint: get_checkpoint(1),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(3),
|
||||
@@ -41,6 +47,8 @@ pub fn get_ffg_case_01_test_definition() -> ForkChoiceTestDefinition {
|
||||
parent_root: get_root(2),
|
||||
justified_checkpoint: get_checkpoint(2),
|
||||
finalized_checkpoint: get_checkpoint(1),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that with justified epoch 0 we find 3
|
||||
@@ -57,6 +65,8 @@ pub fn get_ffg_case_01_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(3),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Ensure that with justified epoch 1 we find 3
|
||||
@@ -77,6 +87,8 @@ pub fn get_ffg_case_01_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(3),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Ensure that with justified epoch 2 we find 3
|
||||
@@ -93,6 +105,8 @@ pub fn get_ffg_case_01_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(1),
|
||||
justified_state_balances: balances,
|
||||
expected_head: get_root(3),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// END OF TESTS
|
||||
@@ -101,6 +115,9 @@ pub fn get_ffg_case_01_test_definition() -> ForkChoiceTestDefinition {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
operations: ops,
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
spec: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +131,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(0),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Build the following tree.
|
||||
@@ -137,6 +156,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
@@ -147,6 +168,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: get_root(1),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(3),
|
||||
@@ -157,6 +180,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: get_root(1),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(4),
|
||||
@@ -167,6 +192,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: get_root(1),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(5),
|
||||
@@ -177,6 +204,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: get_root(3),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Right branch
|
||||
@@ -186,6 +215,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
@@ -193,6 +224,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
parent_root: get_root(2),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(3),
|
||||
@@ -200,6 +233,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
parent_root: get_root(4),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(4),
|
||||
@@ -210,6 +245,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: get_root(2),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(5),
|
||||
@@ -220,6 +257,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: get_root(4),
|
||||
},
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that if we start at 0 we find 10 (just: 0, fin: 0).
|
||||
@@ -240,6 +279,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(10),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
// Same as above, but with justified epoch 2.
|
||||
ops.push(Operation::FindHead {
|
||||
@@ -250,6 +291,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(10),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
// Same as above, but with justified epoch 3.
|
||||
//
|
||||
@@ -264,6 +307,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(10),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a vote to 1.
|
||||
@@ -282,7 +327,7 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(1),
|
||||
target_epoch: Epoch::new(0),
|
||||
attestation_slot: Slot::new(0),
|
||||
});
|
||||
|
||||
// Ensure that if we start at 0 we find 9 (just: 0, fin: 0).
|
||||
@@ -303,6 +348,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(9),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
// Save as above but justified epoch 2.
|
||||
ops.push(Operation::FindHead {
|
||||
@@ -313,6 +360,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(9),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
// Save as above but justified epoch 3.
|
||||
//
|
||||
@@ -327,6 +376,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(9),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a vote to 2.
|
||||
@@ -345,7 +396,7 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(2),
|
||||
target_epoch: Epoch::new(0),
|
||||
attestation_slot: Slot::new(0),
|
||||
});
|
||||
|
||||
// Ensure that if we start at 0 we find 10 (just: 0, fin: 0).
|
||||
@@ -366,6 +417,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(10),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
// Same as above but justified epoch 2.
|
||||
ops.push(Operation::FindHead {
|
||||
@@ -376,6 +429,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(10),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
// Same as above but justified epoch 3.
|
||||
//
|
||||
@@ -390,6 +445,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(10),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Ensure that if we start at 1 we find 9 (just: 0, fin: 0).
|
||||
@@ -413,6 +470,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(9),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
// Same as above but justified epoch 2.
|
||||
ops.push(Operation::FindHead {
|
||||
@@ -423,6 +482,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(9),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
// Same as above but justified epoch 3.
|
||||
//
|
||||
@@ -437,6 +498,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(9),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Ensure that if we start at 2 we find 10 (just: 0, fin: 0).
|
||||
@@ -457,6 +520,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(10),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
// Same as above but justified epoch 2.
|
||||
ops.push(Operation::FindHead {
|
||||
@@ -467,6 +532,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(10),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
// Same as above but justified epoch 3.
|
||||
//
|
||||
@@ -481,6 +548,8 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: balances,
|
||||
expected_head: get_root(10),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// END OF TESTS
|
||||
@@ -489,6 +558,9 @@ pub fn get_ffg_case_02_test_definition() -> ForkChoiceTestDefinition {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
operations: ops,
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
spec: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,893 @@
|
||||
use super::*;
|
||||
|
||||
fn gloas_spec() -> ChainSpec {
|
||||
let mut spec = MainnetEthSpec::default_spec();
|
||||
spec.proposer_score_boost = Some(50);
|
||||
spec.gloas_fork_epoch = Some(Epoch::new(0));
|
||||
spec
|
||||
}
|
||||
|
||||
pub fn get_gloas_chain_following_test_definition() -> ForkChoiceTestDefinition {
|
||||
let mut ops = vec![];
|
||||
|
||||
// Build two branches off genesis where one child extends parent's payload chain (Full)
|
||||
// and the other does not (Empty).
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_root(1),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(0)),
|
||||
execution_payload_block_hash: Some(get_hash(1)),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_root(2),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(99)),
|
||||
execution_payload_block_hash: Some(get_hash(2)),
|
||||
});
|
||||
|
||||
// Extend both branches to verify that head selection follows the selected chain.
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_root(3),
|
||||
parent_root: get_root(1),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(1)),
|
||||
execution_payload_block_hash: Some(get_hash(3)),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_root(4),
|
||||
parent_root: get_root(2),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(100)),
|
||||
execution_payload_block_hash: Some(get_hash(4)),
|
||||
});
|
||||
|
||||
// Mark root_1 as having received its execution payload so that
|
||||
// its FULL virtual node exists in the Gloas fork choice tree.
|
||||
ops.push(Operation::ProcessExecutionPayloadEnvelope {
|
||||
block_root: get_root(1),
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertParentPayloadStatus {
|
||||
block_root: get_root(1),
|
||||
expected_status: PayloadStatus::Full,
|
||||
});
|
||||
ops.push(Operation::AssertParentPayloadStatus {
|
||||
block_root: get_root(2),
|
||||
expected_status: PayloadStatus::Empty,
|
||||
});
|
||||
|
||||
// With equal full/empty parent weights, tiebreak decides which chain to follow.
|
||||
ops.push(Operation::SetPayloadTiebreak {
|
||||
block_root: get_root(0),
|
||||
is_timely: true,
|
||||
is_data_available: true,
|
||||
});
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1],
|
||||
expected_head: get_root(3),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ops.push(Operation::SetPayloadTiebreak {
|
||||
block_root: get_root(0),
|
||||
is_timely: false,
|
||||
is_data_available: false,
|
||||
});
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1],
|
||||
expected_head: get_root(4),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ForkChoiceTestDefinition {
|
||||
finalized_block_slot: Slot::new(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
operations: ops,
|
||||
execution_payload_parent_hash: Some(get_hash(42)),
|
||||
execution_payload_block_hash: Some(get_hash(0)),
|
||||
spec: Some(gloas_spec()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gloas_payload_probe_test_definition() -> ForkChoiceTestDefinition {
|
||||
let mut ops = vec![];
|
||||
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_root(1),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(0)),
|
||||
execution_payload_block_hash: Some(get_hash(1)),
|
||||
});
|
||||
|
||||
// One Full and one Empty vote for the same head block: tie probes via runtime tiebreak,
|
||||
// which defaults to Empty unless timely+data-available evidence is set.
|
||||
ops.push(Operation::ProcessPayloadAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(1),
|
||||
attestation_slot: Slot::new(2),
|
||||
payload_present: true,
|
||||
blob_data_available: false,
|
||||
});
|
||||
ops.push(Operation::ProcessPayloadAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(1),
|
||||
attestation_slot: Slot::new(2),
|
||||
payload_present: false,
|
||||
blob_data_available: false,
|
||||
});
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1, 1],
|
||||
expected_head: get_root(1),
|
||||
current_slot: Slot::new(0),
|
||||
// With MainnetEthSpec PTC_SIZE=512, 1 bit set out of 256 threshold → not timely → Empty.
|
||||
expected_payload_status: Some(PayloadStatus::Empty),
|
||||
});
|
||||
// PTC votes write to bitfields only, not to full/empty weight.
|
||||
// Weight is 0 because no CL attestations target this block.
|
||||
ops.push(Operation::AssertPayloadWeights {
|
||||
block_root: get_root(1),
|
||||
expected_full_weight: 0,
|
||||
expected_empty_weight: 0,
|
||||
});
|
||||
|
||||
// Flip validator 0 to Empty; both bits now clear.
|
||||
ops.push(Operation::ProcessPayloadAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(1),
|
||||
attestation_slot: Slot::new(3),
|
||||
payload_present: false,
|
||||
blob_data_available: false,
|
||||
});
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1, 1],
|
||||
expected_head: get_root(1),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: Some(PayloadStatus::Empty),
|
||||
});
|
||||
ops.push(Operation::AssertPayloadWeights {
|
||||
block_root: get_root(1),
|
||||
expected_full_weight: 0,
|
||||
expected_empty_weight: 0,
|
||||
});
|
||||
|
||||
// Same-slot attestation to a new head candidate should be Pending (no payload bucket change).
|
||||
// Root 5 is an Empty child of root_1 (parent_hash doesn't match root_1's block_hash),
|
||||
// so it's reachable through root_1's Empty direction (root_1 has no payload_received).
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(3),
|
||||
root: get_root(5),
|
||||
parent_root: get_root(1),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(101)),
|
||||
execution_payload_block_hash: Some(get_hash(5)),
|
||||
});
|
||||
ops.push(Operation::ProcessPayloadAttestation {
|
||||
validator_index: 2,
|
||||
block_root: get_root(5),
|
||||
attestation_slot: Slot::new(3),
|
||||
payload_present: true,
|
||||
blob_data_available: false,
|
||||
});
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1, 1, 1],
|
||||
expected_head: get_root(5),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: Some(PayloadStatus::Empty),
|
||||
});
|
||||
ops.push(Operation::AssertPayloadWeights {
|
||||
block_root: get_root(5),
|
||||
expected_full_weight: 0,
|
||||
expected_empty_weight: 0,
|
||||
});
|
||||
|
||||
ForkChoiceTestDefinition {
|
||||
finalized_block_slot: Slot::new(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
operations: ops,
|
||||
execution_payload_parent_hash: Some(get_hash(42)),
|
||||
execution_payload_block_hash: Some(get_hash(0)),
|
||||
spec: Some(gloas_spec()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Test that CL attestation weight can flip the head between Full/Empty branches,
|
||||
/// overriding the tiebreaker.
|
||||
pub fn get_gloas_find_head_vote_transition_test_definition() -> ForkChoiceTestDefinition {
|
||||
let mut ops = vec![];
|
||||
|
||||
// Competing branches with distinct payload ancestry (Full vs Empty from genesis).
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_root(1),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(0)),
|
||||
execution_payload_block_hash: Some(get_hash(1)),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_root(2),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(99)),
|
||||
execution_payload_block_hash: Some(get_hash(2)),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_root(3),
|
||||
parent_root: get_root(1),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(1)),
|
||||
execution_payload_block_hash: Some(get_hash(3)),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_root(4),
|
||||
parent_root: get_root(2),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(100)),
|
||||
execution_payload_block_hash: Some(get_hash(4)),
|
||||
});
|
||||
|
||||
// Mark root_1 as having received its execution payload so that
|
||||
// its FULL virtual node exists in the Gloas fork choice tree.
|
||||
ops.push(Operation::ProcessExecutionPayloadEnvelope {
|
||||
block_root: get_root(1),
|
||||
});
|
||||
|
||||
// Equal branch weights: tiebreak FULL picks branch rooted at 3.
|
||||
ops.push(Operation::SetPayloadTiebreak {
|
||||
block_root: get_root(0),
|
||||
is_timely: true,
|
||||
is_data_available: true,
|
||||
});
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1],
|
||||
expected_head: get_root(3),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// CL attestation to Empty branch (root 4) from validator 0 → head flips to 4.
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(4),
|
||||
attestation_slot: Slot::new(3),
|
||||
});
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1],
|
||||
expected_head: get_root(4),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// CL attestation back to Full branch (root 3) → head returns to 3.
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(3),
|
||||
attestation_slot: Slot::new(4),
|
||||
});
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1],
|
||||
expected_head: get_root(3),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ForkChoiceTestDefinition {
|
||||
finalized_block_slot: Slot::new(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
operations: ops,
|
||||
execution_payload_parent_hash: Some(get_hash(42)),
|
||||
execution_payload_block_hash: Some(get_hash(0)),
|
||||
spec: Some(gloas_spec()),
|
||||
}
|
||||
}
|
||||
|
||||
/// CL attestation weight overrides payload preference tiebreaker.
|
||||
pub fn get_gloas_weight_priority_over_payload_preference_test_definition()
|
||||
-> ForkChoiceTestDefinition {
|
||||
let mut ops = vec![];
|
||||
|
||||
// Build two branches where one child extends payload (Full) and the other doesn't (Empty).
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_root(1),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(0)),
|
||||
execution_payload_block_hash: Some(get_hash(1)),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_root(2),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(99)),
|
||||
execution_payload_block_hash: Some(get_hash(2)),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_root(3),
|
||||
parent_root: get_root(1),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(1)),
|
||||
execution_payload_block_hash: Some(get_hash(3)),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_root(4),
|
||||
parent_root: get_root(2),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(100)),
|
||||
execution_payload_block_hash: Some(get_hash(4)),
|
||||
});
|
||||
|
||||
// Mark root_1 as having received its execution payload so that
|
||||
// its FULL virtual node exists in the Gloas fork choice tree.
|
||||
ops.push(Operation::ProcessExecutionPayloadEnvelope {
|
||||
block_root: get_root(1),
|
||||
});
|
||||
|
||||
// Parent prefers Full on equal branch weights (tiebreaker).
|
||||
ops.push(Operation::SetPayloadTiebreak {
|
||||
block_root: get_root(0),
|
||||
is_timely: true,
|
||||
is_data_available: true,
|
||||
});
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1],
|
||||
expected_head: get_root(3),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Two CL attestations to the Empty branch make it strictly heavier,
|
||||
// overriding the Full tiebreaker.
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(4),
|
||||
attestation_slot: Slot::new(3),
|
||||
});
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(4),
|
||||
attestation_slot: Slot::new(3),
|
||||
});
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1, 1],
|
||||
expected_head: get_root(4),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ForkChoiceTestDefinition {
|
||||
finalized_block_slot: Slot::new(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
operations: ops,
|
||||
execution_payload_parent_hash: Some(get_hash(42)),
|
||||
execution_payload_block_hash: Some(get_hash(0)),
|
||||
spec: Some(gloas_spec()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gloas_parent_empty_when_child_points_to_grandparent_test_definition()
|
||||
-> ForkChoiceTestDefinition {
|
||||
let mut ops = vec![];
|
||||
|
||||
// Build a three-block chain A -> B -> C (CL parent links).
|
||||
// A: EL parent = genesis hash(0), EL hash = hash(1).
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_root(1),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(0)),
|
||||
execution_payload_block_hash: Some(get_hash(1)),
|
||||
});
|
||||
|
||||
// B: EL parent = hash(1), EL hash = hash(2).
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_root(2),
|
||||
parent_root: get_root(1),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(1)),
|
||||
execution_payload_block_hash: Some(get_hash(2)),
|
||||
});
|
||||
|
||||
// C: CL parent is B, but EL parent points to A (hash 1), not B (hash 2).
|
||||
// This models B's payload not arriving in time, so C records parent status as Empty.
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(3),
|
||||
root: get_root(3),
|
||||
parent_root: get_root(2),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(1)),
|
||||
execution_payload_block_hash: Some(get_hash(3)),
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertParentPayloadStatus {
|
||||
block_root: get_root(3),
|
||||
expected_status: PayloadStatus::Empty,
|
||||
});
|
||||
|
||||
ForkChoiceTestDefinition {
|
||||
finalized_block_slot: Slot::new(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
operations: ops,
|
||||
execution_payload_parent_hash: Some(get_hash(42)),
|
||||
execution_payload_block_hash: Some(get_hash(0)),
|
||||
spec: Some(gloas_spec()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Test interleaving of blocks, regular attestations, and tiebreaker.
|
||||
///
|
||||
/// genesis → block 1 (Full) → block 3
|
||||
/// → block 2 (Empty) → block 4
|
||||
///
|
||||
/// With equal CL weight, tiebreaker determines which branch wins.
|
||||
/// An extra CL attestation can override the tiebreaker.
|
||||
pub fn get_gloas_interleaved_attestations_test_definition() -> ForkChoiceTestDefinition {
|
||||
let mut ops = vec![];
|
||||
|
||||
// Step 1: Two competing blocks at slot 1.
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_root(1),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(0)),
|
||||
execution_payload_block_hash: Some(get_hash(1)),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_root(2),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(99)),
|
||||
execution_payload_block_hash: Some(get_hash(2)),
|
||||
});
|
||||
|
||||
// Step 2: Regular attestations arrive, one per branch (equal CL weight).
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(1),
|
||||
attestation_slot: Slot::new(1),
|
||||
});
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(2),
|
||||
attestation_slot: Slot::new(1),
|
||||
});
|
||||
|
||||
// Step 3: Child blocks at slot 2.
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_root(3),
|
||||
parent_root: get_root(1),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(1)),
|
||||
execution_payload_block_hash: Some(get_hash(3)),
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(2),
|
||||
root: get_root(4),
|
||||
parent_root: get_root(2),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(100)),
|
||||
execution_payload_block_hash: Some(get_hash(4)),
|
||||
});
|
||||
|
||||
// Mark root_1 as having received its execution payload so that
|
||||
// its FULL virtual node exists in the Gloas fork choice tree.
|
||||
ops.push(Operation::ProcessExecutionPayloadEnvelope {
|
||||
block_root: get_root(1),
|
||||
});
|
||||
|
||||
// Step 4: Set tiebreaker to Empty on genesis → Empty branch wins.
|
||||
ops.push(Operation::SetPayloadTiebreak {
|
||||
block_root: get_root(0),
|
||||
is_timely: false,
|
||||
is_data_available: false,
|
||||
});
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1, 1],
|
||||
expected_head: get_root(4),
|
||||
current_slot: Slot::new(1),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Step 5: Flip tiebreaker to Full → Full branch wins.
|
||||
ops.push(Operation::SetPayloadTiebreak {
|
||||
block_root: get_root(0),
|
||||
is_timely: true,
|
||||
is_data_available: true,
|
||||
});
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1, 1],
|
||||
expected_head: get_root(3),
|
||||
current_slot: Slot::new(100),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Step 6: Add extra CL weight to Empty branch → overrides Full tiebreaker.
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 2,
|
||||
block_root: get_root(4),
|
||||
attestation_slot: Slot::new(3),
|
||||
});
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1, 1, 1],
|
||||
expected_head: get_root(4),
|
||||
current_slot: Slot::new(100),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ForkChoiceTestDefinition {
|
||||
finalized_block_slot: Slot::new(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
operations: ops,
|
||||
execution_payload_parent_hash: Some(get_hash(42)),
|
||||
execution_payload_block_hash: Some(get_hash(0)),
|
||||
spec: Some(gloas_spec()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Test interleaving of blocks, payload validation, and attestations.
|
||||
///
|
||||
/// Scenario:
|
||||
/// - Genesis block (slot 0)
|
||||
/// - Block 1 (slot 1) extends genesis, Full chain
|
||||
/// - Block 2 (slot 1) extends genesis, Empty chain
|
||||
/// - Before payload arrives: payload_received is false for block 1
|
||||
/// - Process execution payload for block 1 → payload_received becomes true
|
||||
/// - Payload attestations arrive voting block 1's payload as timely + available
|
||||
/// - Head should follow block 1 because the PTC votes now count (payload_received = true)
|
||||
pub fn get_gloas_payload_received_interleaving_test_definition() -> ForkChoiceTestDefinition {
|
||||
let mut ops = vec![];
|
||||
|
||||
// Block 1 at slot 1: extends genesis Full chain.
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_root(1),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(0)),
|
||||
execution_payload_block_hash: Some(get_hash(1)),
|
||||
});
|
||||
|
||||
// Block 2 at slot 1: extends genesis Empty chain (parent_hash doesn't match genesis EL hash).
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(1),
|
||||
root: get_root(2),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(99)),
|
||||
execution_payload_block_hash: Some(get_hash(100)),
|
||||
});
|
||||
|
||||
// Both children have parent_payload_status set correctly.
|
||||
ops.push(Operation::AssertParentPayloadStatus {
|
||||
block_root: get_root(1),
|
||||
expected_status: PayloadStatus::Full,
|
||||
});
|
||||
ops.push(Operation::AssertParentPayloadStatus {
|
||||
block_root: get_root(2),
|
||||
expected_status: PayloadStatus::Empty,
|
||||
});
|
||||
|
||||
// Per spec `get_forkchoice_store`: genesis starts with payload_received=true
|
||||
// (anchor block is in `payload_states`).
|
||||
ops.push(Operation::AssertPayloadReceived {
|
||||
block_root: get_root(0),
|
||||
expected: true,
|
||||
});
|
||||
|
||||
// Give one vote to each child so they have equal weight.
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(1),
|
||||
attestation_slot: Slot::new(1),
|
||||
});
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(2),
|
||||
attestation_slot: Slot::new(1),
|
||||
});
|
||||
|
||||
// Equal weight, payload_received=true on genesis → tiebreaker uses
|
||||
// payload_received (not previous slot, equal payload weights) → prefers Full.
|
||||
// Block 1 (Full) wins because it matches the Full preference.
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1, 1],
|
||||
expected_head: get_root(1),
|
||||
current_slot: Slot::new(100),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// ProcessExecutionPayloadEnvelope on genesis is a no-op (already received at init).
|
||||
ops.push(Operation::ProcessExecutionPayloadEnvelope {
|
||||
block_root: get_root(0),
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertPayloadReceived {
|
||||
block_root: get_root(0),
|
||||
expected: true,
|
||||
});
|
||||
|
||||
// Set PTC votes on genesis as timely + data available (simulates PTC voting).
|
||||
// This doesn't change the preference since genesis is not the previous slot
|
||||
// (slot 0 + 1 != current_slot 100).
|
||||
ops.push(Operation::SetPayloadTiebreak {
|
||||
block_root: get_root(0),
|
||||
is_timely: true,
|
||||
is_data_available: true,
|
||||
});
|
||||
|
||||
// Still prefers Full via payload_received tiebreaker → Block 1 (Full) wins.
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1, 1],
|
||||
expected_head: get_root(1),
|
||||
current_slot: Slot::new(100),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ForkChoiceTestDefinition {
|
||||
finalized_block_slot: Slot::new(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
operations: ops,
|
||||
execution_payload_parent_hash: Some(get_hash(42)),
|
||||
execution_payload_block_hash: Some(get_hash(0)),
|
||||
spec: Some(gloas_spec()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn gloas_fork_boundary_spec() -> ChainSpec {
|
||||
let mut spec = MainnetEthSpec::default_spec();
|
||||
spec.proposer_score_boost = Some(50);
|
||||
spec.gloas_fork_epoch = Some(Epoch::new(1));
|
||||
spec
|
||||
}
|
||||
|
||||
/// Gloas fork boundary: a chain starting pre-Gloas (V17 nodes) that crosses into
|
||||
/// Gloas (V29 nodes). The head should advance through the fork boundary.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - `skip_first_gloas_slot`: if true, there is no block at the first Gloas slot (slot 32);
|
||||
/// the first V29 block appears at slot 33.
|
||||
/// - `first_gloas_block_full`: if true, the first V29 block extends the parent V17 node's
|
||||
/// EL chain (Full parent payload status). If false, it doesn't (Empty).
|
||||
fn get_gloas_fork_boundary_test_definition(
|
||||
skip_first_gloas_slot: bool,
|
||||
first_gloas_block_full: bool,
|
||||
) -> ForkChoiceTestDefinition {
|
||||
let mut ops = vec![];
|
||||
|
||||
// Block at slot 31 — last pre-Gloas slot. Created as a V17 node because
|
||||
// gloas_fork_epoch = 1 → Gloas starts at slot 32.
|
||||
//
|
||||
// The test harness sets execution_status = Optimistic(ExecutionBlockHash::from_root(root)),
|
||||
// so this V17 node's EL block hash = ExecutionBlockHash::from_root(get_root(1)).
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(31),
|
||||
root: get_root(1),
|
||||
parent_root: get_root(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// First Gloas block (V29 node).
|
||||
let gloas_slot = if skip_first_gloas_slot { 33 } else { 32 };
|
||||
|
||||
// The first Gloas block should always have the pre-Gloas block as its execution parent,
|
||||
// although this is currently not checked anywhere (the spec doesn't mention this).
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(gloas_slot),
|
||||
root: get_root(2),
|
||||
parent_root: get_root(1),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: Some(get_hash(1)),
|
||||
execution_payload_block_hash: Some(get_hash(2)),
|
||||
});
|
||||
|
||||
// Parent payload status of fork boundary block should always be Empty.
|
||||
let expected_parent_status = PayloadStatus::Empty;
|
||||
ops.push(Operation::AssertParentPayloadStatus {
|
||||
block_root: get_root(2),
|
||||
expected_status: expected_parent_status,
|
||||
});
|
||||
|
||||
// Mark root 2's execution payload as received so the Full virtual child exists.
|
||||
if first_gloas_block_full {
|
||||
ops.push(Operation::ProcessExecutionPayloadEnvelope {
|
||||
block_root: get_root(2),
|
||||
});
|
||||
}
|
||||
|
||||
// Extend the chain with another V29 block (Full child of root 2).
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(gloas_slot + 1),
|
||||
root: get_root(3),
|
||||
parent_root: get_root(2),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
execution_payload_parent_hash: if first_gloas_block_full {
|
||||
Some(get_hash(2))
|
||||
} else {
|
||||
Some(get_hash(1))
|
||||
},
|
||||
execution_payload_block_hash: Some(get_hash(3)),
|
||||
});
|
||||
|
||||
// Head should advance to the tip of the chain through the fork boundary.
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
justified_state_balances: vec![1],
|
||||
expected_head: get_root(3),
|
||||
current_slot: Slot::new(gloas_slot + 1),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ops.push(Operation::AssertParentPayloadStatus {
|
||||
block_root: get_root(3),
|
||||
expected_status: if first_gloas_block_full {
|
||||
PayloadStatus::Full
|
||||
} else {
|
||||
PayloadStatus::Empty
|
||||
},
|
||||
});
|
||||
|
||||
ForkChoiceTestDefinition {
|
||||
finalized_block_slot: Slot::new(0),
|
||||
justified_checkpoint: get_checkpoint(0),
|
||||
finalized_checkpoint: get_checkpoint(0),
|
||||
operations: ops,
|
||||
// Genesis is V17 (slot 0 < Gloas fork slot 32), these are unused for V17.
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
spec: Some(gloas_fork_boundary_spec()),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fork_boundary_no_skip_full() {
|
||||
get_gloas_fork_boundary_test_definition(false, true).run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fork_boundary_no_skip_empty() {
|
||||
get_gloas_fork_boundary_test_definition(false, false).run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fork_boundary_skip_first_gloas_slot_full() {
|
||||
get_gloas_fork_boundary_test_definition(true, true).run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fork_boundary_skip_first_gloas_slot_empty() {
|
||||
get_gloas_fork_boundary_test_definition(true, false).run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chain_following() {
|
||||
let test = get_gloas_chain_following_test_definition();
|
||||
test.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn payload_probe() {
|
||||
let test = get_gloas_payload_probe_test_definition();
|
||||
test.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn find_head_vote_transition() {
|
||||
let test = get_gloas_find_head_vote_transition_test_definition();
|
||||
test.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn weight_priority_over_payload_preference() {
|
||||
let test = get_gloas_weight_priority_over_payload_preference_test_definition();
|
||||
test.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parent_empty_when_child_points_to_grandparent() {
|
||||
let test = get_gloas_parent_empty_when_child_points_to_grandparent_test_definition();
|
||||
test.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interleaved_attestations() {
|
||||
let test = get_gloas_interleaved_attestations_test_definition();
|
||||
test.run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn payload_received_interleaving() {
|
||||
let test = get_gloas_payload_received_interleaving_test_definition();
|
||||
test.run();
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: Hash256::zero(),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
},
|
||||
// Add block 2
|
||||
//
|
||||
@@ -36,6 +38,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
},
|
||||
// Ensure the head is 2
|
||||
//
|
||||
@@ -53,6 +57,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
},
|
||||
// Add block 1
|
||||
//
|
||||
@@ -71,6 +77,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
},
|
||||
// Ensure the head is still 2
|
||||
//
|
||||
@@ -88,6 +96,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
},
|
||||
// Add block 3
|
||||
//
|
||||
@@ -108,6 +118,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
},
|
||||
// Ensure 2 is still the head
|
||||
//
|
||||
@@ -127,6 +139,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
},
|
||||
// Add block 4
|
||||
//
|
||||
@@ -147,6 +161,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
},
|
||||
// Ensure the head is 4.
|
||||
//
|
||||
@@ -166,6 +182,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(4),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
},
|
||||
// Add block 5 with a justified epoch of 2
|
||||
//
|
||||
@@ -185,6 +203,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
},
|
||||
// Ensure the head is now 5 whilst the justified epoch is 0.
|
||||
//
|
||||
@@ -206,6 +226,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(5),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
},
|
||||
// Ensure there is no error when starting from a block that has the
|
||||
// wrong justified epoch.
|
||||
@@ -232,6 +254,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(5),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
},
|
||||
// Set the justified epoch to 2 and the start block to 5 and ensure 5 is the head.
|
||||
//
|
||||
@@ -250,6 +274,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(5),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
},
|
||||
// Add block 6
|
||||
//
|
||||
@@ -271,6 +297,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
},
|
||||
// Ensure 6 is the head
|
||||
//
|
||||
@@ -291,6 +319,8 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances,
|
||||
expected_head: get_root(6),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -305,6 +335,9 @@ pub fn get_no_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: Hash256::zero(),
|
||||
},
|
||||
operations,
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
spec: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(0),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a block with a hash of 2.
|
||||
@@ -35,6 +37,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that the head is 2
|
||||
@@ -53,6 +57,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a block with a hash of 1 that comes off the genesis block (this is a fork compared
|
||||
@@ -73,6 +79,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that the head is still 2
|
||||
@@ -91,6 +99,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a vote to block 1
|
||||
@@ -101,7 +111,7 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(1),
|
||||
target_epoch: Epoch::new(2),
|
||||
attestation_slot: Slot::new(2),
|
||||
});
|
||||
|
||||
// Ensure that the head is now 1, because 1 has a vote.
|
||||
@@ -120,6 +130,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(1),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add a vote to block 2
|
||||
@@ -130,7 +142,7 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(2),
|
||||
target_epoch: Epoch::new(2),
|
||||
attestation_slot: Slot::new(2),
|
||||
});
|
||||
|
||||
// Ensure that the head is 2 since 1 and 2 both have a vote
|
||||
@@ -149,6 +161,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add block 3.
|
||||
@@ -170,6 +184,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that the head is still 2
|
||||
@@ -190,6 +206,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Move validator #0 vote from 1 to 3
|
||||
@@ -202,7 +220,7 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(3),
|
||||
target_epoch: Epoch::new(3),
|
||||
attestation_slot: Slot::new(3),
|
||||
});
|
||||
|
||||
// Ensure that the head is still 2
|
||||
@@ -223,6 +241,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Move validator #1 vote from 2 to 1 (this is an equivocation, but fork choice doesn't
|
||||
@@ -236,7 +256,7 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(1),
|
||||
target_epoch: Epoch::new(3),
|
||||
attestation_slot: Slot::new(3),
|
||||
});
|
||||
|
||||
// Ensure that the head is now 3
|
||||
@@ -257,6 +277,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(3),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add block 4.
|
||||
@@ -280,6 +302,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that the head is now 4
|
||||
@@ -302,6 +326,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(4),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add block 5, which has a justified epoch of 2.
|
||||
@@ -327,19 +353,22 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_root(1),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that 5 is filtered out and the head stays at 4.
|
||||
// Block 5 has incompatible finalized checkpoint, so `get_filtered_block_tree`
|
||||
// excludes the entire 1->3->4->5 branch (no viable leaf). Head moves to 2.
|
||||
//
|
||||
// 0
|
||||
// / \
|
||||
// 2 1
|
||||
// head-> 2 1
|
||||
// |
|
||||
// 3
|
||||
// |
|
||||
// 4 <- head
|
||||
// 4
|
||||
// /
|
||||
// 5
|
||||
// 5 <- incompatible finalized checkpoint
|
||||
ops.push(Operation::FindHead {
|
||||
justified_checkpoint: Checkpoint {
|
||||
epoch: Epoch::new(1),
|
||||
@@ -350,7 +379,9 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: get_root(0),
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(4),
|
||||
expected_head: get_root(2),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add block 6, which has a justified epoch of 0.
|
||||
@@ -376,6 +407,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(1),
|
||||
root: get_root(0),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Move both votes to 5.
|
||||
@@ -392,12 +425,12 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(5),
|
||||
target_epoch: Epoch::new(4),
|
||||
attestation_slot: Slot::new(4),
|
||||
});
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(5),
|
||||
target_epoch: Epoch::new(4),
|
||||
attestation_slot: Slot::new(4),
|
||||
});
|
||||
|
||||
// Add blocks 7, 8 and 9. Adding these blocks helps test the `best_descendant`
|
||||
@@ -430,6 +463,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_root(5),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(0),
|
||||
@@ -443,6 +478,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_root(5),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
ops.push(Operation::ProcessBlock {
|
||||
slot: Slot::new(0),
|
||||
@@ -456,6 +493,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_root(5),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure that 6 is the head, even though 5 has all the votes. This is testing to ensure
|
||||
@@ -487,6 +526,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(6),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Change fork-choice justified epoch to 1, and the start block to 5 and ensure that 9 is
|
||||
@@ -520,6 +561,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(9),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Change fork-choice justified epoch to 1, and the start block to 5 and ensure that 9 is
|
||||
@@ -545,12 +588,12 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 0,
|
||||
block_root: get_root(9),
|
||||
target_epoch: Epoch::new(5),
|
||||
attestation_slot: Slot::new(5),
|
||||
});
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 1,
|
||||
block_root: get_root(9),
|
||||
target_epoch: Epoch::new(5),
|
||||
attestation_slot: Slot::new(5),
|
||||
});
|
||||
|
||||
// Add block 10
|
||||
@@ -582,6 +625,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_root(5),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Double-check the head is still 9 (no diagram this time)
|
||||
@@ -596,6 +641,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(9),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Introduce 2 more validators into the system
|
||||
@@ -621,12 +668,12 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 2,
|
||||
block_root: get_root(10),
|
||||
target_epoch: Epoch::new(5),
|
||||
attestation_slot: Slot::new(5),
|
||||
});
|
||||
ops.push(Operation::ProcessAttestation {
|
||||
validator_index: 3,
|
||||
block_root: get_root(10),
|
||||
target_epoch: Epoch::new(5),
|
||||
attestation_slot: Slot::new(5),
|
||||
});
|
||||
|
||||
// Check the head is now 10.
|
||||
@@ -657,6 +704,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(10),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Set the balances of the last two validators to zero
|
||||
@@ -682,6 +731,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(9),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Set the balances of the last two validators back to 1
|
||||
@@ -707,6 +758,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(10),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Remove the last two validators
|
||||
@@ -733,6 +786,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(9),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Ensure that pruning below the prune threshold does not prune.
|
||||
@@ -754,6 +809,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(9),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Ensure that pruning above the prune threshold does prune.
|
||||
@@ -792,6 +849,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances.clone(),
|
||||
expected_head: get_root(9),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// Add block 11
|
||||
@@ -817,6 +876,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
epoch: Epoch::new(2),
|
||||
root: get_root(5),
|
||||
},
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
});
|
||||
|
||||
// Ensure the head is now 11
|
||||
@@ -841,6 +902,8 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
},
|
||||
justified_state_balances: balances,
|
||||
expected_head: get_root(11),
|
||||
current_slot: Slot::new(0),
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
ForkChoiceTestDefinition {
|
||||
@@ -854,6 +917,9 @@ pub fn get_votes_test_definition() -> ForkChoiceTestDefinition {
|
||||
root: get_root(0),
|
||||
},
|
||||
operations: ops,
|
||||
execution_payload_parent_hash: None,
|
||||
execution_payload_block_hash: None,
|
||||
spec: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user