Ethereum reporting methodology
Methodology deep dive for the Ethereum Reporting API
Coverage
- All network: All stakes (Kiln and non Kiln)
- All time: Since inception of the beacon chain Dec 2020 https://beaconcha.in/slot/1 (before the merge execution layer will be 0)
Methodology
Consensus Layer
- Track all validators balances each day.
- Track all withdrawals (skimmings and exits).
Complexity: Consensus rewards are a combination of the increasing balances of validators on the consensus layer as well as the “skimmings” amounts that are available on the execution layer.
Execution Layer
- Track every block rewards since “The Merge”.
- Track all relays delivered payloads.
Complexity: Rewards are earned through gas fees in every block as well as through custom payouts with the opaque and partially off-chain MEV (Maximal Extractable Value) system.
Skimming slot
Endpoint: https://docs.api.kiln.fi/reference/getethstakes
To compute estimated_next_skimming_slot
for a given validator, we do the following:
- Determine the index of the last validator skimmed (
V
) and the slot at which it happened (S
) - Determine the list of validators that are eligible to skimming (L), it's ordered by validator indexes, to be eligible the validator must:
- A: Have a withdrawal credential starting with 0x01
- B: Have an
effective balance == 32
eth AND abalance > 32
eth (partially withdrawable, skimming) - C: Or, alternatively to B, have a
withdrawable_epoch < current_epoch
AND abalance > 0
(fully withdrawable, exiting)
- Determine the position of
V
inL (N)
- Compute for each validators in
L
their next skimming slot:- We have:
L
the list of validator eligible for skimmingposX
the index inL
of the validator we're estimating for,0 < posX < L
N
the index inL
of the last validator skimmed,0 < N < L
S + 1 + (abs((L/16)*(posX<=N) - abs(N-posX)/16))
- this assumes
false=0
&true=1
S + 1
becauseS
already happened
- this assumes
- We have:
Entry & Exit time estimations
Endpoint: https://docs.api.kiln.fi/reference/getethnetworkstats
To compute estimated_entry_time_seconds
we do the following:
- We take the time for the consensus layer to acknowledge a deposit:
- A: every
2048 blocks * 12 seconds
=24,576 seconds (6.83 hours)
- B: beacons get deposits made from the last
[-13.66, -6.83]
hours - after this, elligible deposits are queued for activation
- As we provide a generic queue time, not based on a specific validator, we don't have a specific deposit timestamp so we take the middle ground of B's range:
10h14m24s (as in A * 1.5)
- A: every
- Then we calculate the time it takes to go through the activation queue (
timeToEmptyActivationQueue
)- Determine how many epochs are needed to empty the queue: nb of validators in
pending_queued state / 8
- 8 is how many validators get activated by epoch
- This value only stands on networks post Dencun hardfork, before that it used to be more approximate.
- Now that we know how many epochs are needed to empty the queue we just need to do:
epochsToEmptyQueue * 12sec * SlotsPerEpoch(=32)
- Determine how many epochs are needed to empty the queue: nb of validators in
- Lastly, we sum
10h14m24s + timeToEmptyActivationQueue
To compute estimated exit_time_seconds we do the following
:
- We take the time to enter the exit queue:
- We can exit at least on the
next epoch + MAX_SEED_LOOKAHEAD (4)
epochs - The next epoch is on average in 0.5 epoch, we use the middle point here as an estimation.
eth.SlotTime(12) * SlotsPerEpoch(32) * (0.5 + MaxSeedLookahead) = 1728sec = 28min48sec
- We can exit at least on the
- Then we calculate the time it takes to go through the exit queue (
timeToEmptyExitQueue
)- Determine how many epochs are needed to empty the queue: number of validators in
active_exiting state / 8
(same 8 as used to compute the entry queue) - Now that we know how many epochs are needed to empty the queue we just need to do:
epochsToEmptyQueue * 12sec * SlotsPerEpoch(=32)
- Determine how many epochs are needed to empty the queue: number of validators in
- Lastly, we sum
28m48s + timeToEmptyExitQueue
To compute the estimated_withdrawal_time_seconds
we do the following:
- Every slots there are 16 withdrawals processed by the consensus layer
(# of active_ongoing validators + # of active_exiting validators) / 16
= number of slot for the next withdraw- Which we then convert to seconds:
# of slot for the next withdraw * 12s (slot time)
Rewards
Endpoint: https://docs.api.kiln.fi/reference/getethrewards
With no scope
filter provided, for the given validators:
stake_balance
: Is the active balance at the end of the dayconsensus_rewards
: Is computed asactive_balance_end_of_day - active_balance_start_of_day + sum_withdrawals_during_day
execution_rewards
: Is computed asSUM(blocks_rewards_of_day) AND/OR SUM(mev_rewards_of_day)
With scope=kiln|network
data is computed in aggregate as such:
stake_balance
:SUM(stake_balance)
consensus_rewards
:SUM(consensus_rewards)
mev_execution_rewards / non_mev_execution_rewards
: execution rewards earned through MEV vs natively.execution_rewards:
mev_execution_rewards+non_mev_execution_rewards
active_validator_count
: Weighted number of active validators during the day. i.e. A validator joining at12:00:00 UTC
counts as 0,5.median_execution_reward
: Median based on every single execution rewards earned during the day for all validators in the scope.
Updated 5 months ago