-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
EIP-7002:Execution layer triggerable withdrawals #14031
Changes from 14 commits
519b579
b8f41d3
61974ee
e5e295f
656e861
15d7b48
2460106
e9e08d0
100979a
ef062b8
d39885c
fe64b57
6b2923c
8e7be27
2abb60f
09a66f7
b89212f
a333aed
98f2188
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,21 @@ | ||
package electra | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
|
||
"github.com/pkg/errors" | ||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers" | ||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/validators" | ||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state" | ||
"github.com/prysmaticlabs/prysm/v5/config/params" | ||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" | ||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" | ||
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" | ||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" | ||
"github.com/prysmaticlabs/prysm/v5/time/slots" | ||
log "github.com/sirupsen/logrus" | ||
"go.opencensus.io/trace" | ||
) | ||
|
||
// ProcessExecutionLayerWithdrawRequests processes the validator withdrawals from the provided execution payload | ||
|
@@ -75,6 +86,107 @@ import ( | |
// withdrawable_epoch=withdrawable_epoch, | ||
// )) | ||
func ProcessExecutionLayerWithdrawRequests(ctx context.Context, st state.BeaconState, wrs []*enginev1.ExecutionLayerWithdrawalRequest) (state.BeaconState, error) { | ||
//TODO: replace with real implementation | ||
ctx, span := trace.StartSpan(ctx, "electra.ProcessExecutionLayerWithdrawRequests") | ||
defer span.End() | ||
currentEpoch := slots.ToEpoch(st.Slot()) | ||
for _, wr := range wrs { | ||
if wr == nil { | ||
return nil, errors.New("nil execution layer withdrawal request") | ||
} | ||
amount := wr.Amount | ||
isFullExitRequest := amount == params.BeaconConfig().FullExitRequestAmount | ||
// If partial withdrawal queue is full, only full exits are processed | ||
if n, err := st.NumPendingPartialWithdrawals(); err != nil { | ||
return nil, err | ||
} else if n == params.BeaconConfig().PendingPartialWithdrawalsLimit && !isFullExitRequest { | ||
// if the PendingPartialWithdrawalsLimit is met, the user would have paid for a partial withdrawal that's not included | ||
log.Debugln("Skipping execution layer withdrawal request, PendingPartialWithdrawalsLimit reached") | ||
continue | ||
} | ||
|
||
vIdx, exists := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(wr.ValidatorPubkey)) | ||
if !exists { | ||
log.Debugln("Skipping execution layer withdrawal request, validator index not found") | ||
james-prysm marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the difference between There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm not sure i used debugln since i know it adds a new line not sure if debug also does |
||
continue | ||
james-prysm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
validator, err := st.ValidatorAtIndex(vIdx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// Verify withdrawal credentials | ||
hasCorrectCredential := helpers.HasExecutionWithdrawalCredentials(validator) | ||
isCorrectSourceAddress := bytes.Equal(validator.WithdrawalCredentials[12:], wr.SourceAddress) | ||
if !hasCorrectCredential || !isCorrectSourceAddress { | ||
log.Debugln("Skipping execution layer withdrawal request, wrong withdrawal credentials") | ||
continue | ||
} | ||
|
||
// Verify the validator is active. | ||
if !helpers.IsActiveValidator(validator, currentEpoch) { | ||
log.Debugln("Skipping execution layer withdrawal request, validator not active") | ||
continue | ||
} | ||
// Verify the validator has not yet submitted an exit. | ||
if validator.ExitEpoch != params.BeaconConfig().FarFutureEpoch { | ||
log.Debugln("Skipping execution layer withdrawal request, validator has submitted an exit already") | ||
continue | ||
} | ||
// Verify the validator has been active long enough. | ||
if currentEpoch < validator.ActivationEpoch.AddEpoch(params.BeaconConfig().ShardCommitteePeriod) { | ||
log.Debugln("Skipping execution layer withdrawal request, validator has not been active long enough") | ||
continue | ||
} | ||
|
||
pendingBalanceToWithdraw, err := st.PendingBalanceToWithdraw(vIdx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if isFullExitRequest { | ||
// Only exit validator if it has no pending withdrawals in the queue | ||
if pendingBalanceToWithdraw == 0 { | ||
maxExitEpoch, churn := validators.MaxExitEpochAndChurn(st) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could be defined outside of the for loop There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so, if there are multiple values the loop updates the state I think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah. Good point |
||
var err error | ||
st, _, err = validators.InitiateValidatorExit(ctx, st, vIdx, maxExitEpoch, churn) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
continue | ||
} | ||
|
||
hasSufficientEffectiveBalance := validator.EffectiveBalance >= params.BeaconConfig().MinActivationBalance | ||
vBal, err := st.BalanceAtIndex(vIdx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
hasExcessBalance := vBal > params.BeaconConfig().MinActivationBalance+pendingBalanceToWithdraw | ||
|
||
// Only allow partial withdrawals with compounding withdrawal credentials | ||
if helpers.HasCompoundingWithdrawalCredential(validator) && hasSufficientEffectiveBalance && hasExcessBalance { | ||
//to_withdraw = min( | ||
// state.balances[index] - MIN_ACTIVATION_BALANCE - pending_balance_to_withdraw, | ||
// amount | ||
//) | ||
james-prysm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// note: you can safely subtract these values because haxExcessBalance is checked | ||
toWithdraw := min(vBal-params.BeaconConfig().MinActivationBalance-pendingBalanceToWithdraw, amount) | ||
exitQueueEpoch, err := st.ExitEpochAndUpdateChurn(primitives.Gwei(toWithdraw)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// safe add the uint64 to avoid overflow | ||
withdrawableEpoch, err := exitQueueEpoch.SafeAddEpoch(params.BeaconConfig().MinValidatorWithdrawabilityDelay) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "failed to add withdrawablility delay to exit queue") | ||
james-prysm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
if err := st.AppendPendingPartialWithdrawal(ðpb.PendingPartialWithdrawal{ | ||
Index: vIdx, | ||
Amount: toWithdraw, | ||
WithdrawableEpoch: withdrawableEpoch, | ||
}); err != nil { | ||
return nil, err | ||
} | ||
} | ||
} | ||
return st, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the spec the function is called
process_execution_layer_withdrawal_request
(Withdraw
-->Withdrawal
). The parameter also hasWithdrawal
in the name,