Skip to content

Commit 1a610b3

Browse files
authored
Cherry-Pick: Added pending enpoints (#16233)
1 parent 768f107 commit 1a610b3

File tree

9 files changed

+379
-14
lines changed

9 files changed

+379
-14
lines changed

cl/beacon/handler/handler.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,9 @@ func (a *ApiHandler) init() {
299299
r.Post("/validator_balances", a.PostEthV1BeaconValidatorsBalances)
300300
r.Get("/validators/{validator_id}", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconStatesValidator))
301301
r.Get("/validator_identities", beaconhttp.HandleEndpointFunc(a.GetEthV1ValidatorIdentities))
302+
r.Get("/pending_consolidations", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconStatesPendingConsolidations))
303+
r.Get("/pending_deposits", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconStatesPendingDeposits))
304+
r.Get("/pending_partial_withdrawals", beaconhttp.HandleEndpointFunc(a.GetEthV1BeaconStatesPendingPartialWithdrawals))
302305
})
303306
})
304307
})

cl/beacon/handler/states.go

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"github.com/erigontech/erigon/cl/cltypes/solid"
3232
"github.com/erigontech/erigon/cl/persistence/beacon_indicies"
3333
state_accessors "github.com/erigontech/erigon/cl/persistence/state"
34+
"github.com/erigontech/erigon/cl/persistence/state/historical_states_reader"
3435
"github.com/erigontech/erigon/cl/utils"
3536
)
3637

@@ -451,3 +452,178 @@ func (a *ApiHandler) getRandao(w http.ResponseWriter, r *http.Request) (*beaconh
451452
WithFinalized(slot <= a.forkchoiceStore.FinalizedSlot()).
452453
WithOptimistic(isOptimistic), nil
453454
}
455+
456+
// Implements /eth/v1/beacon/states/{state_id}/pending_consolidations
457+
func (a *ApiHandler) GetEthV1BeaconStatesPendingConsolidations(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
458+
ctx := r.Context()
459+
460+
tx, err := a.indiciesDB.BeginRo(ctx)
461+
if err != nil {
462+
return nil, err
463+
}
464+
defer tx.Rollback()
465+
466+
blockId, err := beaconhttp.StateIdFromRequest(r)
467+
if err != nil {
468+
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err)
469+
}
470+
471+
blockRoot, httpStatus, err := a.blockRootFromStateId(ctx, tx, blockId)
472+
if err != nil {
473+
return nil, beaconhttp.NewEndpointError(httpStatus, err)
474+
}
475+
476+
isOptimistic := a.forkchoiceStore.IsRootOptimistic(blockRoot)
477+
slot, err := beacon_indicies.ReadBlockSlotByBlockRoot(tx, blockRoot)
478+
if err != nil {
479+
return nil, err
480+
}
481+
if slot == nil {
482+
return nil, beaconhttp.NewEndpointError(http.StatusNotFound, fmt.Errorf("could not read block slot: %x", blockRoot))
483+
}
484+
485+
canonicalRoot, err := beacon_indicies.ReadCanonicalBlockRoot(tx, *slot)
486+
if err != nil {
487+
return nil, err
488+
}
489+
490+
pendingConsolidations := solid.NewPendingConsolidationList(a.beaconChainCfg)
491+
492+
isSlotAvailableInMemory := a.forkchoiceStore.LowestAvailableSlot() < *slot
493+
494+
if isSlotAvailableInMemory {
495+
var ok bool
496+
pendingConsolidations, ok = a.forkchoiceStore.GetPendingConsolidations(blockRoot)
497+
if !ok {
498+
return nil, beaconhttp.NewEndpointError(http.StatusNotFound, fmt.Errorf("no pending consolidations found for block root: %x", blockRoot))
499+
}
500+
// If we have the pending consolidations in memory, we can return them directly.
501+
} else {
502+
stateView := a.caplinStateSnapshots.View()
503+
defer stateView.Close()
504+
505+
if err := historical_states_reader.ReadQueueSSZ(state_accessors.GetValFnTxAndSnapshot(tx, stateView), *slot, kv.PendingConsolidationsDump, kv.PendingConsolidations, pendingConsolidations); err != nil {
506+
return nil, beaconhttp.NewEndpointError(http.StatusInternalServerError, fmt.Errorf("failed to read pending consolidations: %w", err))
507+
}
508+
}
509+
510+
return newBeaconResponse(pendingConsolidations).
511+
WithOptimistic(isOptimistic).
512+
WithFinalized(canonicalRoot == blockRoot && *slot <= a.forkchoiceStore.FinalizedSlot()), nil
513+
}
514+
515+
// Implements /eth/v1/beacon/states/{state_id}/pending_deposits
516+
func (a *ApiHandler) GetEthV1BeaconStatesPendingDeposits(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
517+
ctx := r.Context()
518+
519+
tx, err := a.indiciesDB.BeginRo(ctx)
520+
if err != nil {
521+
return nil, err
522+
}
523+
defer tx.Rollback()
524+
525+
blockId, err := beaconhttp.StateIdFromRequest(r)
526+
if err != nil {
527+
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err)
528+
}
529+
530+
blockRoot, httpStatus, err := a.blockRootFromStateId(ctx, tx, blockId)
531+
if err != nil {
532+
return nil, beaconhttp.NewEndpointError(httpStatus, err)
533+
}
534+
535+
isOptimistic := a.forkchoiceStore.IsRootOptimistic(blockRoot)
536+
slot, err := beacon_indicies.ReadBlockSlotByBlockRoot(tx, blockRoot)
537+
if err != nil {
538+
return nil, err
539+
}
540+
if slot == nil {
541+
return nil, beaconhttp.NewEndpointError(http.StatusNotFound, fmt.Errorf("could not read block slot: %x", blockRoot))
542+
}
543+
544+
canonicalRoot, err := beacon_indicies.ReadCanonicalBlockRoot(tx, *slot)
545+
if err != nil {
546+
return nil, err
547+
}
548+
549+
pendingDeposits := solid.NewPendingDepositList(a.beaconChainCfg)
550+
551+
isSlotAvailableInMemory := a.forkchoiceStore.LowestAvailableSlot() < *slot
552+
553+
if isSlotAvailableInMemory {
554+
var ok bool
555+
pendingDeposits, ok = a.forkchoiceStore.GetPendingDeposits(blockRoot)
556+
if !ok {
557+
return nil, beaconhttp.NewEndpointError(http.StatusNotFound, fmt.Errorf("no pending deposits found for block root: %x", blockRoot))
558+
}
559+
} else {
560+
stateView := a.caplinStateSnapshots.View()
561+
defer stateView.Close()
562+
563+
if err := historical_states_reader.ReadQueueSSZ(state_accessors.GetValFnTxAndSnapshot(tx, stateView), *slot, kv.PendingDepositsDump, kv.PendingDeposits, pendingDeposits); err != nil {
564+
return nil, beaconhttp.NewEndpointError(http.StatusInternalServerError, fmt.Errorf("failed to read pending deposits: %w", err))
565+
}
566+
}
567+
568+
return newBeaconResponse(pendingDeposits).
569+
WithOptimistic(isOptimistic).
570+
WithFinalized(canonicalRoot == blockRoot && *slot <= a.forkchoiceStore.FinalizedSlot()), nil
571+
}
572+
573+
// Implements /eth/v1/beacon/states/{state_id}/pending_partial_withdrawals
574+
func (a *ApiHandler) GetEthV1BeaconStatesPendingPartialWithdrawals(w http.ResponseWriter, r *http.Request) (*beaconhttp.BeaconResponse, error) {
575+
ctx := r.Context()
576+
577+
tx, err := a.indiciesDB.BeginRo(ctx)
578+
if err != nil {
579+
return nil, err
580+
}
581+
defer tx.Rollback()
582+
583+
blockId, err := beaconhttp.StateIdFromRequest(r)
584+
if err != nil {
585+
return nil, beaconhttp.NewEndpointError(http.StatusBadRequest, err)
586+
}
587+
588+
blockRoot, httpStatus, err := a.blockRootFromStateId(ctx, tx, blockId)
589+
if err != nil {
590+
return nil, beaconhttp.NewEndpointError(httpStatus, err)
591+
}
592+
593+
isOptimistic := a.forkchoiceStore.IsRootOptimistic(blockRoot)
594+
slot, err := beacon_indicies.ReadBlockSlotByBlockRoot(tx, blockRoot)
595+
if err != nil {
596+
return nil, err
597+
}
598+
if slot == nil {
599+
return nil, beaconhttp.NewEndpointError(http.StatusNotFound, fmt.Errorf("could not read block slot: %x", blockRoot))
600+
}
601+
602+
canonicalRoot, err := beacon_indicies.ReadCanonicalBlockRoot(tx, *slot)
603+
if err != nil {
604+
return nil, err
605+
}
606+
607+
pendingWithdrawals := solid.NewPendingWithdrawalList(a.beaconChainCfg)
608+
609+
isSlotAvailableInMemory := a.forkchoiceStore.LowestAvailableSlot() < *slot
610+
611+
if isSlotAvailableInMemory {
612+
var ok bool
613+
pendingWithdrawals, ok = a.forkchoiceStore.GetPendingPartialWithdrawals(blockRoot)
614+
if !ok {
615+
return nil, beaconhttp.NewEndpointError(http.StatusNotFound, fmt.Errorf("no pending partial withdrawals found for block root: %x", blockRoot))
616+
}
617+
} else {
618+
stateView := a.caplinStateSnapshots.View()
619+
defer stateView.Close()
620+
621+
if err := historical_states_reader.ReadQueueSSZ(state_accessors.GetValFnTxAndSnapshot(tx, stateView), *slot, kv.PendingPartialWithdrawalsDump, kv.PendingPartialWithdrawals, pendingWithdrawals); err != nil {
622+
return nil, beaconhttp.NewEndpointError(http.StatusInternalServerError, fmt.Errorf("failed to read pending partial withdrawals: %w", err))
623+
}
624+
}
625+
626+
return newBeaconResponse(pendingWithdrawals).
627+
WithOptimistic(isOptimistic).
628+
WithFinalized(canonicalRoot == blockRoot && *slot <= a.forkchoiceStore.FinalizedSlot()), nil
629+
}

cl/cltypes/solid/consolidation.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ func (p *ConsolidationRequest) Static() bool {
5353
}
5454

5555
type PendingConsolidation struct {
56-
SourceIndex uint64 // validator index
57-
TargetIndex uint64 // validator index
56+
SourceIndex uint64 `json:"source_index"` // validator index
57+
TargetIndex uint64 `json:"target_index"` // validator index
5858
}
5959

6060
func (p *PendingConsolidation) EncodingSizeSSZ() int {

cl/cltypes/solid/deposits.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ func (p *DepositRequest) Static() bool {
5555
}
5656

5757
type PendingDeposit struct {
58-
PubKey common.Bytes48 // BLS public key
59-
WithdrawalCredentials common.Hash
60-
Amount uint64 // Gwei
61-
Signature common.Bytes96 // BLS signature
62-
Slot uint64
58+
PubKey common.Bytes48 `json:"pubkey"` // BLS public key
59+
WithdrawalCredentials common.Hash `json:"withdrawal_credentials"`
60+
Amount uint64 `json:"amount"` // Gwei
61+
Signature common.Bytes96 `json:"signature"` // BLS signature
62+
Slot uint64 `json:"slot"`
6363
}
6464

6565
func (p *PendingDeposit) EncodingSizeSSZ() int {

cl/cltypes/solid/withdrawal.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ func (p *WithdrawalRequest) Static() bool {
5353
}
5454

5555
type PendingPartialWithdrawal struct {
56-
Index uint64 // validator index
57-
Amount uint64 // Gwei
58-
WithdrawableEpoch uint64
56+
Index uint64 `json:"index"` // validator index
57+
Amount uint64 `json:"amount"` // Gwei
58+
WithdrawableEpoch uint64 `json:"withdrawable_epoch"` // epoch when the withdrawal can be processed
5959
}
6060

6161
func (p *PendingPartialWithdrawal) EncodingSizeSSZ() int {

cl/persistence/state/historical_states_reader/historical_states_reader.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,15 +308,15 @@ func (r *HistoricalStatesReader) ReadHistoricalState(ctx context.Context, tx kv.
308308
pendingWithdrawals = solid.NewPendingWithdrawalList(r.cfg)
309309
)
310310

311-
if err := readQueueSSZ(kvGetter, slot, kv.PendingConsolidationsDump, kv.PendingConsolidations, pendingConsolidations); err != nil {
311+
if err := ReadQueueSSZ(kvGetter, slot, kv.PendingConsolidationsDump, kv.PendingConsolidations, pendingConsolidations); err != nil {
312312
return nil, fmt.Errorf("failed to read pending consolidations: %w", err)
313313
}
314314

315-
if err := readQueueSSZ(kvGetter, slot, kv.PendingDepositsDump, kv.PendingDeposits, pendingDeposits); err != nil {
315+
if err := ReadQueueSSZ(kvGetter, slot, kv.PendingDepositsDump, kv.PendingDeposits, pendingDeposits); err != nil {
316316
return nil, fmt.Errorf("failed to read pending deposits: %w", err)
317317
}
318318

319-
if err := readQueueSSZ(kvGetter, slot, kv.PendingPartialWithdrawalsDump, kv.PendingPartialWithdrawals, pendingWithdrawals); err != nil {
319+
if err := ReadQueueSSZ(kvGetter, slot, kv.PendingPartialWithdrawalsDump, kv.PendingPartialWithdrawals, pendingWithdrawals); err != nil {
320320
return nil, fmt.Errorf("failed to read pending withdrawals: %w", err)
321321
}
322322

@@ -983,7 +983,7 @@ func (r *HistoricalStatesReader) ReadRandaoMixBySlotAndIndex(tx kv.Tx, kvGetter
983983
return common.BytesToHash(mixBytes), nil
984984
}
985985

986-
func readQueueSSZ[T solid.EncodableHashableSSZ](kvGetter state_accessors.GetValFn, slot uint64, dumpTable, diffsTable string, out *solid.ListSSZ[T]) error {
986+
func ReadQueueSSZ[T solid.EncodableHashableSSZ](kvGetter state_accessors.GetValFn, slot uint64, dumpTable, diffsTable string, out *solid.ListSSZ[T]) error {
987987
remainder := slot % clparams.SlotsPerDump
988988
freshDumpSlot := slot - remainder
989989

0 commit comments

Comments
 (0)