1
- use crate :: { BeaconChain , BeaconChainError , BeaconChainTypes } ;
1
+ use crate :: { BeaconChain , BeaconChainError , BeaconChainTypes , StateSkipConfig } ;
2
+ use attesting_indices_base:: get_attesting_indices;
2
3
use eth2:: lighthouse:: StandardBlockReward ;
3
- use operation_pool:: RewardCache ;
4
4
use safe_arith:: SafeArith ;
5
5
use slog:: error;
6
+ use state_processing:: common:: attesting_indices_base;
6
7
use state_processing:: {
7
- common:: { get_attestation_participation_flag_indices, get_attesting_indices_from_state} ,
8
+ common:: {
9
+ base:: { self , SqrtTotalActiveBalance } ,
10
+ get_attestation_participation_flag_indices, get_attesting_indices_from_state,
11
+ } ,
8
12
epoch_cache:: initialize_epoch_cache,
9
13
per_block_processing:: {
10
14
altair:: sync_committee:: compute_sync_aggregate_rewards, get_slashable_indices,
11
15
} ,
12
16
} ;
17
+ use std:: collections:: HashSet ;
13
18
use store:: {
14
19
consts:: altair:: { PARTICIPATION_FLAG_WEIGHTS , PROPOSER_WEIGHT , WEIGHT_DENOMINATOR } ,
15
20
RelativeEpoch ,
16
21
} ;
17
- use types:: { AbstractExecPayload , BeaconBlockRef , BeaconState , BeaconStateError , Hash256 } ;
22
+ use types:: { AbstractExecPayload , BeaconBlockRef , BeaconState , BeaconStateError , EthSpec } ;
18
23
19
24
type BeaconBlockSubRewardValue = u64 ;
20
25
21
26
impl < T : BeaconChainTypes > BeaconChain < T > {
22
27
pub fn compute_beacon_block_reward < Payload : AbstractExecPayload < T :: EthSpec > > (
23
28
& self ,
24
29
block : BeaconBlockRef < ' _ , T :: EthSpec , Payload > ,
25
- block_root : Hash256 ,
26
30
state : & mut BeaconState < T :: EthSpec > ,
27
31
) -> Result < StandardBlockReward , BeaconChainError > {
28
32
if block. slot ( ) != state. slot ( ) {
@@ -33,15 +37,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
33
37
state. build_committee_cache ( RelativeEpoch :: Current , & self . spec ) ?;
34
38
initialize_epoch_cache ( state, & self . spec ) ?;
35
39
36
- self . compute_beacon_block_reward_with_cache ( block, block_root , state)
40
+ self . compute_beacon_block_reward_with_cache ( block, state)
37
41
}
38
42
39
43
// This should only be called after a committee cache has been built
40
44
// for both the previous and current epoch
41
45
fn compute_beacon_block_reward_with_cache < Payload : AbstractExecPayload < T :: EthSpec > > (
42
46
& self ,
43
47
block : BeaconBlockRef < ' _ , T :: EthSpec , Payload > ,
44
- block_root : Hash256 ,
45
48
state : & BeaconState < T :: EthSpec > ,
46
49
) -> Result < StandardBlockReward , BeaconChainError > {
47
50
let proposer_index = block. proposer_index ( ) ;
@@ -72,7 +75,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
72
75
} ) ?;
73
76
74
77
let block_attestation_reward = if let BeaconState :: Base ( _) = state {
75
- self . compute_beacon_block_attestation_reward_base ( block, block_root , state)
78
+ self . compute_beacon_block_attestation_reward_base ( block, state)
76
79
. map_err ( |e| {
77
80
error ! (
78
81
self . log,
@@ -169,19 +172,85 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
169
172
fn compute_beacon_block_attestation_reward_base < Payload : AbstractExecPayload < T :: EthSpec > > (
170
173
& self ,
171
174
block : BeaconBlockRef < ' _ , T :: EthSpec , Payload > ,
172
- block_root : Hash256 ,
173
175
state : & BeaconState < T :: EthSpec > ,
174
176
) -> Result < BeaconBlockSubRewardValue , BeaconChainError > {
175
- // Call compute_block_reward in the base case
176
- // Since base does not have sync aggregate, we only grab attesation portion of the returned
177
- // value
178
- let mut reward_cache = RewardCache :: default ( ) ;
179
- let block_attestation_reward = self
180
- . compute_block_reward ( block, block_root, state, & mut reward_cache, true ) ?
181
- . attestation_rewards
182
- . total ;
183
-
184
- Ok ( block_attestation_reward)
177
+ // In phase0, rewards for including attestations are awarded at epoch boundaries when the corresponding
178
+ // attestations are contained in state.previous_epoch_attestations. So, if an attestation within this block has
179
+ // target = previous_epoch, it is directly inserted into previous_epoch_attestations and we need the state at
180
+ // the end of this epoch, or the attestation has target = current_epoch and thus we need the state at the end
181
+ // of the next epoch.
182
+ // We fetch these lazily, as only one might be needed depending on the block's content.
183
+ let mut current_epoch_end = None ;
184
+ let mut next_epoch_end = None ;
185
+
186
+ let epoch = block. epoch ( ) ;
187
+ let mut block_reward = 0 ;
188
+
189
+ let mut rewarded_attesters = HashSet :: new ( ) ;
190
+
191
+ for attestation in block. body ( ) . attestations ( ) {
192
+ let processing_epoch_end = if attestation. data ( ) . target . epoch == epoch {
193
+ let next_epoch_end = match & mut next_epoch_end {
194
+ Some ( next_epoch_end) => next_epoch_end,
195
+ None => {
196
+ let state = self . state_at_slot (
197
+ epoch. safe_add ( 1 ) ?. end_slot ( T :: EthSpec :: slots_per_epoch ( ) ) ,
198
+ StateSkipConfig :: WithoutStateRoots ,
199
+ ) ?;
200
+ next_epoch_end. get_or_insert ( state)
201
+ }
202
+ } ;
203
+
204
+ // If the next epoch end is no longer phase0, no proposer rewards are awarded, as Altair epoch boundry
205
+ // processing kicks in. We check this here, as we know that current_epoch_end will always be phase0.
206
+ if !matches ! ( next_epoch_end, BeaconState :: Base ( _) ) {
207
+ continue ;
208
+ }
209
+
210
+ next_epoch_end
211
+ } else if attestation. data ( ) . target . epoch == epoch. safe_sub ( 1 ) ? {
212
+ match & mut current_epoch_end {
213
+ Some ( current_epoch_end) => current_epoch_end,
214
+ None => {
215
+ let state = self . state_at_slot (
216
+ epoch. end_slot ( T :: EthSpec :: slots_per_epoch ( ) ) ,
217
+ StateSkipConfig :: WithoutStateRoots ,
218
+ ) ?;
219
+ current_epoch_end. get_or_insert ( state)
220
+ }
221
+ }
222
+ } else {
223
+ return Err ( BeaconChainError :: BlockRewardAttestationError ) ;
224
+ } ;
225
+
226
+ let inclusion_delay = state. slot ( ) . safe_sub ( attestation. data ( ) . slot ) ?. as_u64 ( ) ;
227
+ let sqrt_total_active_balance =
228
+ SqrtTotalActiveBalance :: new ( processing_epoch_end. get_total_active_balance ( ) ?) ;
229
+ for attester in get_attesting_indices_from_state ( state, attestation) ? {
230
+ let validator = processing_epoch_end. get_validator ( attester as usize ) ?;
231
+ if !validator. slashed
232
+ && !rewarded_attesters. contains ( & attester)
233
+ && !has_earlier_attestation (
234
+ state,
235
+ processing_epoch_end,
236
+ inclusion_delay,
237
+ attester,
238
+ ) ?
239
+ {
240
+ let base_reward = base:: get_base_reward (
241
+ validator. effective_balance ,
242
+ sqrt_total_active_balance,
243
+ & self . spec ,
244
+ ) ?;
245
+ let proposer_reward =
246
+ base_reward. safe_div ( self . spec . proposer_reward_quotient ) ?;
247
+ block_reward. safe_add_assign ( proposer_reward) ?;
248
+ rewarded_attesters. insert ( attester) ;
249
+ }
250
+ }
251
+ }
252
+
253
+ Ok ( block_reward)
185
254
}
186
255
187
256
fn compute_beacon_block_attestation_reward_altair_deneb <
@@ -244,3 +313,25 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
244
313
Ok ( total_proposer_reward)
245
314
}
246
315
}
316
+
317
+ fn has_earlier_attestation < E : EthSpec > (
318
+ state : & BeaconState < E > ,
319
+ processing_epoch_end : & BeaconState < E > ,
320
+ inclusion_delay : u64 ,
321
+ attester : u64 ,
322
+ ) -> Result < bool , BeaconChainError > {
323
+ if inclusion_delay > 1 {
324
+ for epoch_att in processing_epoch_end. previous_epoch_attestations ( ) ? {
325
+ if epoch_att. inclusion_delay < inclusion_delay {
326
+ let committee =
327
+ state. get_beacon_committee ( epoch_att. data . slot , epoch_att. data . index ) ?;
328
+ let earlier_attesters =
329
+ get_attesting_indices :: < E > ( committee. committee , & epoch_att. aggregation_bits ) ?;
330
+ if earlier_attesters. contains ( & attester) {
331
+ return Ok ( true ) ;
332
+ }
333
+ }
334
+ }
335
+ }
336
+ Ok ( false )
337
+ }
0 commit comments