Withdrawal requests fee analysis
Withdrawal requests fee analysis
Analysis of the following parameters of the Withdrawal request smart contract:
MAX_WITHDRAWAL_REQUESTS_PER_BLOCK = 16
TARGET_WITHDRAWAL_REQUESTS_PER_BLOCK = 2
TL; DR: These parameters have reasonable values.
Consensus layer with TARGET=2, MAX=16
Full withdrawal requests doesn’t create additional data complexity on the CL side as the changes are applied to the list of validators.
Current exit churn size allows to initiate withdrawal for 256 ETH per epoch, if a number of request per epoch is at its level (32 * MAX = 512
requests) then the average withdrawing amount should be no bigger than 0.5 ETH
to fit the churn. It is not unreasonable to assume that most of the time this limit will be satisfied.
Partial withdrawals has a separate list which processing depends on the exit churn. If there is enough churn then pending partial withdrawal request will be processed at least MIN_VALIDATOR_WITHDRAWABILITY_DELAY = 256
epochs after it was queued on the CL. This delay sets a lower boundary on the number of pending withdrawals in the queue in a situation when each block has MAX=16
requests, it is 256 * 32 * 16 = 131,072
, which is 3 MB
of data. In an extreme case scenario when e.g. ~10% of validators are exiting this number can grow up to 192 MB
.
With TARGET=2
requests per each block the above numbers are reduced to 0.375 MB
and 24 MB
respectively. Average amount for a partial withdrawal increases up to 4.0 ETH
.
Attack via prohibitive fee
Full withdrawal requests are a security mechanism and an attacker can potentially benefit from block this functionality by keep the request fee at a prohibitive level. This section explores such attack with more details.
The cost of attack includes two parts. First part is to raise the fee to a certain level (the base cost) and the second part is to keep the fee at that level (per block cost).
The fee is updated at the end of the block processing, so it remains the same regardless of a number of requests submitted within one block. The lowest fee is 1 Wei
which makes the base cost of this attack near to 0
. The cost per block is computed as prohibitive_fee * TARGET
.
There are two ways to increase the cost:
- Raise fee upon each request – affects mostly the base cost, has a slight effect on the cost per block
- Increase
TARGET
– affects the cost per block
The cost of attack with the status quo and above improvements are provided in the table below. The second cost is the cost per hour of such attack, i.e. cost per block times 300
(number of slots per hour).
Fee | TARGET=2 | TARGET=2 + fine-grained fee | TARGET=8 |
---|---|---|---|
0.0001 ETH | 0.06 ETH | 0.07 ETH | 0.25 ETH |
0.01 ETH | 6.25 ETH | 6.61 ETH | 25.00 ETH |
0.1 ETH | 61.98 ETH | 65.56 ETH | 247.92 ETH |
0.5 ETH | 303.39 ETH | 320.93 ETH | 1213.58 ETH |
1 ETH | 614.59 ETH | 650.10 ETH | 2458.37 ETH |
2 ETH | 1244.95 ETH | 1316.90 ETH | 4979.79 ETH |
4 ETH | 2521.76 ETH | 2667.53 ETH | 10087.02 ETH |
To summarize:
- raising fee upon each requests increases the cost of an hour of attack by ~6%, while
TARGET=8
makes the 4 times increase - with the status quo the attack is not sustainable long term
UX
Assuming 1 Gwei
to be a reasonable fee per request, it will take 2.75 hours for the fee to reach this level if someone submits 2,000 requests in one block (the max possible number to fit in 30M gas block).
From the UX standpoint it might seem quite long, but TARGET=2
, comparing to e.g. TARGET=8
, reduces the strain on the protocol by more efficiently rate limiting the growth of the EL and CL queues.