mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-04 09:11:42 +00:00
Merge remote-tracking branch 'origin/stable' into unstable
This commit is contained in:
44
.github/mergify.yml
vendored
44
.github/mergify.yml
vendored
@@ -1,3 +1,37 @@
|
||||
pull_request_rules:
|
||||
- name: Ask to resolve conflict
|
||||
conditions:
|
||||
- conflict
|
||||
- -author=dependabot[bot]
|
||||
- or:
|
||||
- -draft # Don't report conflicts on regular draft.
|
||||
- and: # Do report conflicts on draft that are scheduled for the next major release.
|
||||
- draft
|
||||
- milestone~=v[0-9]\.[0-9]{2}
|
||||
actions:
|
||||
comment:
|
||||
message: This pull request has merge conflicts. Could you please resolve them
|
||||
@{{author}}? 🙏
|
||||
|
||||
- name: Approve trivial maintainer PRs
|
||||
conditions:
|
||||
- base!=stable
|
||||
- label=trivial
|
||||
- author=@sigp/lighthouse
|
||||
- -conflict
|
||||
actions:
|
||||
review:
|
||||
type: APPROVE
|
||||
|
||||
- name: Add ready-to-merge labeled PRs to merge queue
|
||||
conditions:
|
||||
# All branch protection rules are implicit: https://docs.mergify.com/conditions/#about-branch-protection
|
||||
- base!=stable
|
||||
- label=ready-for-merge
|
||||
- label!=do-not-merge
|
||||
actions:
|
||||
queue:
|
||||
|
||||
queue_rules:
|
||||
- name: default
|
||||
batch_size: 8
|
||||
@@ -6,14 +40,16 @@ queue_rules:
|
||||
merge_method: squash
|
||||
commit_message_template: |
|
||||
{{ title }} (#{{ number }})
|
||||
|
||||
{% for commit in commits %}
|
||||
* {{ commit.commit_message }}
|
||||
{% endfor %}
|
||||
|
||||
{{ body | get_section("## Issue Addressed", "") }}
|
||||
|
||||
|
||||
{{ body | get_section("## Proposed Changes", "") }}
|
||||
queue_conditions:
|
||||
- "#approved-reviews-by >= 1"
|
||||
- "check-success=license/cla"
|
||||
- "check-success=target-branch-check"
|
||||
- "label!=do-not-merge"
|
||||
merge_conditions:
|
||||
- "check-success=test-suite-success"
|
||||
- "check-success=local-testnet-success"
|
||||
|
||||
@@ -135,7 +135,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
state
|
||||
.get_validator(proposer_slashing.proposer_index() as usize)?
|
||||
.effective_balance
|
||||
.safe_div(self.spec.whistleblower_reward_quotient)?,
|
||||
.safe_div(self.spec.whistleblower_reward_quotient_for_state(state))?,
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
state
|
||||
.get_validator(attester_index as usize)?
|
||||
.effective_balance
|
||||
.safe_div(self.spec.whistleblower_reward_quotient)?,
|
||||
.safe_div(self.spec.whistleblower_reward_quotient_for_state(state))?,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,6 +254,35 @@ async fn test_rewards_base_inactivity_leak_justification_epoch() {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_rewards_electra_slashings() {
|
||||
let spec = ForkName::Electra.make_genesis_spec(E::default_spec());
|
||||
let harness = get_electra_harness(spec);
|
||||
let state = harness.get_current_state();
|
||||
|
||||
harness.extend_slots(E::slots_per_epoch() as usize).await;
|
||||
|
||||
let mut initial_balances = harness.get_current_state().balances().to_vec();
|
||||
|
||||
// add an attester slashing and calculate slashing penalties
|
||||
harness.add_attester_slashing(vec![0]).unwrap();
|
||||
let slashed_balance_1 = initial_balances.get_mut(0).unwrap();
|
||||
let validator_1_effective_balance = state.get_effective_balance(0).unwrap();
|
||||
let delta_1 = validator_1_effective_balance
|
||||
/ harness.spec.min_slashing_penalty_quotient_for_state(&state);
|
||||
*slashed_balance_1 -= delta_1;
|
||||
|
||||
// add a proposer slashing and calculating slashing penalties
|
||||
harness.add_proposer_slashing(1).unwrap();
|
||||
let slashed_balance_2 = initial_balances.get_mut(1).unwrap();
|
||||
let validator_2_effective_balance = state.get_effective_balance(1).unwrap();
|
||||
let delta_2 = validator_2_effective_balance
|
||||
/ harness.spec.min_slashing_penalty_quotient_for_state(&state);
|
||||
*slashed_balance_2 -= delta_2;
|
||||
|
||||
check_all_electra_rewards(&harness, initial_balances).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_rewards_base_slashings() {
|
||||
let spec = ForkName::Base.make_genesis_spec(E::default_spec());
|
||||
@@ -693,6 +722,75 @@ async fn test_rewards_base_subset_only() {
|
||||
check_all_base_rewards_for_subset(&harness, initial_balances, validators_subset).await;
|
||||
}
|
||||
|
||||
async fn check_all_electra_rewards(
|
||||
harness: &BeaconChainHarness<EphemeralHarnessType<E>>,
|
||||
mut balances: Vec<u64>,
|
||||
) {
|
||||
let mut proposal_rewards_map = HashMap::new();
|
||||
let mut sync_committee_rewards_map = HashMap::new();
|
||||
for _ in 0..E::slots_per_epoch() {
|
||||
let state = harness.get_current_state();
|
||||
let slot = state.slot() + Slot::new(1);
|
||||
|
||||
// calculate beacon block rewards / penalties
|
||||
let ((signed_block, _maybe_blob_sidecars), mut state) =
|
||||
harness.make_block_return_pre_state(state, slot).await;
|
||||
let beacon_block_reward = harness
|
||||
.chain
|
||||
.compute_beacon_block_reward(signed_block.message(), &mut state)
|
||||
.unwrap();
|
||||
|
||||
let total_proposer_reward = proposal_rewards_map
|
||||
.entry(beacon_block_reward.proposer_index)
|
||||
.or_insert(0);
|
||||
*total_proposer_reward += beacon_block_reward.total as i64;
|
||||
|
||||
// calculate sync committee rewards / penalties
|
||||
let reward_payload = harness
|
||||
.chain
|
||||
.compute_sync_committee_rewards(signed_block.message(), &mut state)
|
||||
.unwrap();
|
||||
|
||||
for reward in reward_payload {
|
||||
let total_sync_reward = sync_committee_rewards_map
|
||||
.entry(reward.validator_index)
|
||||
.or_insert(0);
|
||||
*total_sync_reward += reward.reward;
|
||||
}
|
||||
|
||||
harness.extend_slots(1).await;
|
||||
}
|
||||
|
||||
// compute reward deltas for all validators in epoch 0
|
||||
let StandardAttestationRewards {
|
||||
ideal_rewards,
|
||||
total_rewards,
|
||||
} = harness
|
||||
.chain
|
||||
.compute_attestation_rewards(Epoch::new(0), vec![])
|
||||
.unwrap();
|
||||
|
||||
// assert ideal rewards are greater than 0
|
||||
assert_eq!(
|
||||
ideal_rewards.len() as u64,
|
||||
harness.spec.max_effective_balance_electra / harness.spec.effective_balance_increment
|
||||
);
|
||||
|
||||
assert!(ideal_rewards
|
||||
.iter()
|
||||
.all(|reward| reward.head > 0 && reward.target > 0 && reward.source > 0));
|
||||
|
||||
// apply attestation, proposal, and sync committee rewards and penalties to initial balances
|
||||
apply_attestation_rewards(&mut balances, total_rewards);
|
||||
apply_other_rewards(&mut balances, &proposal_rewards_map);
|
||||
apply_other_rewards(&mut balances, &sync_committee_rewards_map);
|
||||
|
||||
// verify expected balances against actual balances
|
||||
let actual_balances: Vec<u64> = harness.get_current_state().balances().to_vec();
|
||||
|
||||
assert_eq!(balances, actual_balances);
|
||||
}
|
||||
|
||||
async fn check_all_base_rewards(
|
||||
harness: &BeaconChainHarness<EphemeralHarnessType<E>>,
|
||||
balances: Vec<u64>,
|
||||
|
||||
@@ -6363,6 +6363,34 @@ impl ApiTester {
|
||||
|
||||
assert_eq!(result.execution_optimistic, Some(true));
|
||||
}
|
||||
|
||||
async fn test_get_beacon_rewards_blocks_at_head(&self) -> StandardBlockReward {
|
||||
self.client
|
||||
.get_beacon_rewards_blocks(CoreBlockId::Head)
|
||||
.await
|
||||
.unwrap()
|
||||
.data
|
||||
}
|
||||
|
||||
async fn test_beacon_block_rewards_electra(self) -> Self {
|
||||
for _ in 0..E::slots_per_epoch() {
|
||||
let state = self.harness.get_current_state();
|
||||
let slot = state.slot() + Slot::new(1);
|
||||
// calculate beacon block rewards / penalties
|
||||
let ((signed_block, _maybe_blob_sidecars), mut state) =
|
||||
self.harness.make_block_return_pre_state(state, slot).await;
|
||||
|
||||
let beacon_block_reward = self
|
||||
.harness
|
||||
.chain
|
||||
.compute_beacon_block_reward(signed_block.message(), &mut state)
|
||||
.unwrap();
|
||||
self.harness.extend_slots(1).await;
|
||||
let api_beacon_block_reward = self.test_get_beacon_rewards_blocks_at_head().await;
|
||||
assert_eq!(beacon_block_reward, api_beacon_block_reward);
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
async fn poll_events<S: Stream<Item = Result<EventKind<E>, eth2::Error>> + Unpin, E: EthSpec>(
|
||||
@@ -7502,3 +7530,17 @@ async fn expected_withdrawals_valid_capella() {
|
||||
.test_get_expected_withdrawals_capella()
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn get_beacon_rewards_blocks_electra() {
|
||||
let mut config = ApiTesterConfig::default();
|
||||
config.spec.altair_fork_epoch = Some(Epoch::new(0));
|
||||
config.spec.bellatrix_fork_epoch = Some(Epoch::new(0));
|
||||
config.spec.capella_fork_epoch = Some(Epoch::new(0));
|
||||
config.spec.deneb_fork_epoch = Some(Epoch::new(0));
|
||||
config.spec.electra_fork_epoch = Some(Epoch::new(0));
|
||||
ApiTester::new_from_config(config)
|
||||
.await
|
||||
.test_beacon_block_rewards_electra()
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -517,7 +517,7 @@ pub fn get_expected_withdrawals<E: EthSpec>(
|
||||
let epoch = state.current_epoch();
|
||||
let mut withdrawal_index = state.next_withdrawal_index()?;
|
||||
let mut validator_index = state.next_withdrawal_validator_index()?;
|
||||
let mut withdrawals = vec![];
|
||||
let mut withdrawals = Vec::<Withdrawal>::with_capacity(E::max_withdrawals_per_payload());
|
||||
let fork_name = state.fork_name_unchecked();
|
||||
|
||||
// [New in Electra:EIP7251]
|
||||
@@ -532,19 +532,27 @@ pub fn get_expected_withdrawals<E: EthSpec>(
|
||||
break;
|
||||
}
|
||||
|
||||
let withdrawal_balance = state.get_balance(withdrawal.validator_index as usize)?;
|
||||
let validator = state.get_validator(withdrawal.validator_index as usize)?;
|
||||
|
||||
let has_sufficient_effective_balance =
|
||||
validator.effective_balance >= spec.min_activation_balance;
|
||||
let has_excess_balance = withdrawal_balance > spec.min_activation_balance;
|
||||
let total_withdrawn = withdrawals
|
||||
.iter()
|
||||
.filter_map(|w| {
|
||||
(w.validator_index == withdrawal.validator_index).then_some(w.amount)
|
||||
})
|
||||
.safe_sum()?;
|
||||
let balance = state
|
||||
.get_balance(withdrawal.validator_index as usize)?
|
||||
.safe_sub(total_withdrawn)?;
|
||||
let has_excess_balance = balance > spec.min_activation_balance;
|
||||
|
||||
if validator.exit_epoch == spec.far_future_epoch
|
||||
&& has_sufficient_effective_balance
|
||||
&& has_excess_balance
|
||||
{
|
||||
let withdrawable_balance = std::cmp::min(
|
||||
withdrawal_balance.safe_sub(spec.min_activation_balance)?,
|
||||
balance.safe_sub(spec.min_activation_balance)?,
|
||||
withdrawal.amount,
|
||||
);
|
||||
withdrawals.push(Withdrawal {
|
||||
|
||||
Reference in New Issue
Block a user