@@ -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+ }
0 commit comments