Files
prysm/proto/engine/v1/electra.go
kasey d12da8cbe0 remove usages of params from proto packages (#15403)
* remove usages of params from proto packages

* make it harder to mess up the order of request limit args

* remove errant edit (Terence review)

* fix missed updates after sig change

---------

Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
2025-06-11 21:15:10 +00:00

191 lines
6.4 KiB
Go

package enginev1
import (
"fmt"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
)
var (
drExample = &DepositRequest{}
drSize = drExample.SizeSSZ()
wrExample = &WithdrawalRequest{}
wrSize = wrExample.SizeSSZ()
crExample = &ConsolidationRequest{}
crSize = crExample.SizeSSZ()
)
const (
DepositRequestType = iota
WithdrawalRequestType
ConsolidationRequestType
)
// ExecutionRequestConfig ensures that we don't mix up the execution request params
type ExecutionRequestLimits struct {
Deposits uint64
Withdrawals uint64
Consolidations uint64
}
func (ebe *ExecutionBundleElectra) GetDecodedExecutionRequests(limits ExecutionRequestLimits) (*ExecutionRequests, error) {
requests := &ExecutionRequests{}
var prevTypeNum *uint8
for i := range ebe.ExecutionRequests {
requestType, requestListInSSZBytes, err := decodeExecutionRequest(ebe.ExecutionRequests[i])
if err != nil {
return nil, err
}
if prevTypeNum != nil && *prevTypeNum >= requestType {
return nil, errors.New("invalid execution request type order or duplicate requests, requests should be in sorted order and unique")
}
prevTypeNum = &requestType
switch requestType {
case DepositRequestType:
drs, err := unmarshalDeposits(requestListInSSZBytes, limits.Deposits)
if err != nil {
return nil, err
}
requests.Deposits = drs
case WithdrawalRequestType:
wrs, err := unmarshalWithdrawals(requestListInSSZBytes, limits.Withdrawals)
if err != nil {
return nil, err
}
requests.Withdrawals = wrs
case ConsolidationRequestType:
crs, err := unmarshalConsolidations(requestListInSSZBytes, limits.Consolidations)
if err != nil {
return nil, err
}
requests.Consolidations = crs
default:
return nil, errors.Errorf("unsupported request type %d", requestType)
}
}
return requests, nil
}
func unmarshalDeposits(requestListInSSZBytes []byte, maxDepositRequests uint64) ([]*DepositRequest, error) {
if len(requestListInSSZBytes) < drSize {
return nil, fmt.Errorf("invalid deposit requests SSZ size, got %d expected at least %d", len(requestListInSSZBytes), drSize)
}
maxSSZsize := uint64(drSize) * maxDepositRequests
if uint64(len(requestListInSSZBytes)) > maxSSZsize {
return nil, fmt.Errorf("invalid deposit requests SSZ size, requests should not be more than the max per payload, got %d max %d", len(requestListInSSZBytes), maxSSZsize)
}
return unmarshalItems(requestListInSSZBytes, drSize, func() *DepositRequest { return &DepositRequest{} })
}
func unmarshalWithdrawals(requestListInSSZBytes []byte, maxWithdrawals uint64) ([]*WithdrawalRequest, error) {
if len(requestListInSSZBytes) < wrSize {
return nil, fmt.Errorf("invalid withdrawal requests SSZ size, got %d expected at least %d", len(requestListInSSZBytes), wrSize)
}
maxSSZsize := uint64(wrSize) * maxWithdrawals
if uint64(len(requestListInSSZBytes)) > maxSSZsize {
return nil, fmt.Errorf("invalid withdrawal requests SSZ size, requests should not be more than the max per payload, got %d max %d", len(requestListInSSZBytes), maxSSZsize)
}
return unmarshalItems(requestListInSSZBytes, wrSize, func() *WithdrawalRequest { return &WithdrawalRequest{} })
}
func unmarshalConsolidations(requestListInSSZBytes []byte, maxConsolidations uint64) ([]*ConsolidationRequest, error) {
if len(requestListInSSZBytes) < crSize {
return nil, fmt.Errorf("invalid consolidation requests SSZ size, got %d expected at least %d", len(requestListInSSZBytes), crSize)
}
maxSSZsize := uint64(crSize) * maxConsolidations
if uint64(len(requestListInSSZBytes)) > maxSSZsize {
return nil, fmt.Errorf("invalid consolidation requests SSZ size, requests should not be more than the max per payload, got %d max %d", len(requestListInSSZBytes), maxSSZsize)
}
return unmarshalItems(requestListInSSZBytes, crSize, func() *ConsolidationRequest { return &ConsolidationRequest{} })
}
func decodeExecutionRequest(req []byte) (typ uint8, data []byte, err error) {
if len(req) < 1 {
return 0, nil, errors.New("invalid execution request, length less than 1")
}
return req[0], req[1:], nil
}
func EncodeExecutionRequests(requests *ExecutionRequests) ([]hexutil.Bytes, error) {
if requests == nil {
return nil, errors.New("invalid execution requests")
}
requestsData := make([]hexutil.Bytes, 0)
// request types MUST be in sorted order starting from 0
if len(requests.Deposits) > 0 {
drBytes, err := marshalItems(requests.Deposits)
if err != nil {
return nil, errors.Wrap(err, "failed to marshal deposit requests")
}
requestData := []byte{DepositRequestType}
requestData = append(requestData, drBytes...)
requestsData = append(requestsData, requestData)
}
if len(requests.Withdrawals) > 0 {
wrBytes, err := marshalItems(requests.Withdrawals)
if err != nil {
return nil, errors.Wrap(err, "failed to marshal withdrawal requests")
}
requestData := []byte{WithdrawalRequestType}
requestData = append(requestData, wrBytes...)
requestsData = append(requestsData, requestData)
}
if len(requests.Consolidations) > 0 {
crBytes, err := marshalItems(requests.Consolidations)
if err != nil {
return nil, errors.Wrap(err, "failed to marshal consolidation requests")
}
requestData := []byte{ConsolidationRequestType}
requestData = append(requestData, crBytes...)
requestsData = append(requestsData, requestData)
}
return requestsData, nil
}
type sszUnmarshaler interface {
UnmarshalSSZ([]byte) error
}
type sszMarshaler interface {
MarshalSSZTo(buf []byte) ([]byte, error)
SizeSSZ() int
}
func marshalItems[T sszMarshaler](items []T) ([]byte, error) {
if len(items) == 0 {
return []byte{}, nil
}
size := items[0].SizeSSZ()
buf := make([]byte, 0, size*len(items))
var err error
for i, item := range items {
buf, err = item.MarshalSSZTo(buf)
if err != nil {
return nil, fmt.Errorf("failed to marshal item at index %d: %w", i, err)
}
}
return buf, nil
}
// Generic function to unmarshal items
func unmarshalItems[T sszUnmarshaler](data []byte, itemSize int, newItem func() T) ([]T, error) {
if len(data)%itemSize != 0 {
return nil, fmt.Errorf("invalid data length: data size (%d) is not a multiple of item size (%d)", len(data), itemSize)
}
numItems := len(data) / itemSize
items := make([]T, numItems)
for i := range items {
itemBytes := data[i*itemSize : (i+1)*itemSize]
item := newItem()
if err := item.UnmarshalSSZ(itemBytes); err != nil {
return nil, fmt.Errorf("failed to unmarshal item at index %d: %w", i, err)
}
items[i] = item
}
return items, nil
}