Skip to content
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

chore(node-endpoint): Implement node syncing #2100

Draft
wants to merge 9 commits into
base: blob-sidecars
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions mod/consensus/pkg/cometbft/service/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"github.com/berachain/beacon-kit/mod/primitives/pkg/encoding/json"
math "github.com/berachain/beacon-kit/mod/primitives/pkg/math"
cmtabci "github.com/cometbft/cometbft/abci/types"
"github.com/cometbft/cometbft/node"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
sdkversion "github.com/cosmos/cosmos-sdk/version"
Expand Down Expand Up @@ -615,3 +616,8 @@ func (s *Service[_]) GetBlockRetentionHeight(commitHeight int64) int64 {
func (s *Service[_]) GetBeaconVersion() (string, error) {
return sdkversion.Version, nil
}

// GetCometNode returns the concrete CometBFT node.
func (s *Service[_]) GetCometNode() *node.Node {
return s.node
}
8 changes: 8 additions & 0 deletions mod/node-api/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (

"github.com/berachain/beacon-kit/mod/primitives/pkg/common"
"github.com/berachain/beacon-kit/mod/primitives/pkg/math"
"github.com/cometbft/cometbft/node"
)

// Backend is the db access layer for the beacon node-api.
Expand Down Expand Up @@ -237,3 +238,10 @@ func (b *Backend[
}
return appVersion, nil
}

// GetNode returns the comet node from the backend.
func (b *Backend[
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,
]) GetNode() *node.Node {
return b.node.GetCometNode()
}
3 changes: 3 additions & 0 deletions mod/node-api/backend/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/berachain/beacon-kit/mod/primitives/pkg/math"
"github.com/berachain/beacon-kit/mod/primitives/pkg/transition"
"github.com/berachain/beacon-kit/mod/state-transition/pkg/core"
"github.com/cometbft/cometbft/node"
)

// The AvailabilityStore interface is responsible for validating and storing
Expand Down Expand Up @@ -112,6 +113,8 @@ type Node[ContextT any] interface {
CreateQueryContext(height int64, prove bool) (ContextT, error)
// GetBeaconVersion returns the version of the beacon node.
GetBeaconVersion() (string, error)
// GetCometNode returns the comet node.
GetCometNode() *node.Node
}

type StateProcessor[BeaconStateT any] interface {
Expand Down
3 changes: 3 additions & 0 deletions mod/node-api/handlers/node/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

package node

import "github.com/cometbft/cometbft/node"

type Backend interface {
GetNodeVersion() (string, error)
GetNode() *node.Node
}
53 changes: 34 additions & 19 deletions mod/node-api/handlers/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,47 @@
package node

import (
"github.com/berachain/beacon-kit/mod/errors"
nodetypes "github.com/berachain/beacon-kit/mod/node-api/handlers/node/types"
"github.com/berachain/beacon-kit/mod/node-api/handlers/types"
)

// Syncing is a placeholder so that beacon API clients don't break.
//
// TODO: Implement with real data.
func (h *Handler[ContextT]) Syncing(ContextT) (any, error) {
type SyncingResponse struct {
Data struct {
HeadSlot string `json:"head_slot"`
SyncDistance string `json:"sync_distance"`
IsSyncing bool `json:"is_syncing"`
IsOptimistic bool `json:"is_optimistic"`
ELOffline bool `json:"el_offline"`
} `json:"data"`
var (
errNilBlockStore = errors.New("block store is nil")
errNilNode = errors.New("node is nil")
)

// Syncing returns the syncing status of the beacon node.
func (h *Handler[ContextT]) Syncing(_ ContextT) (any, error) {
node := h.backend.GetNode()
if node == nil {
return nil, errNilNode
}

// Get blockStore for heights
blockStore := node.BlockStore()
if blockStore == nil {
return nil, errNilBlockStore
}

response := SyncingResponse{}
response.Data.HeadSlot = "0"
response.Data.SyncDistance = "1"
response.Data.IsSyncing = false
response.Data.IsOptimistic = true
response.Data.ELOffline = false
latestHeight := blockStore.Height()
baseHeight := blockStore.Base()

response := nodetypes.SyncingData{
HeadSlot: latestHeight,
IsOptimistic: true,
ELOffline: false,
}

// Calculate sync distance using block heights
response.SyncDistance = latestHeight - baseHeight
// If SyncDistance is greater than 0,
// we consider the node to be syncing
if response.SyncDistance > 0 {
response.IsSyncing = true
}

return response, nil
return types.Wrap(&response), nil
}

// Version returns the version of the beacon node.
Expand Down
31 changes: 31 additions & 0 deletions mod/node-api/handlers/node/types/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,37 @@

package types

import (
"encoding/json"
"strconv"
)

type VersionData struct {
Version string `json:"version"`
}

type SyncingData struct {
HeadSlot int64 `json:"head_slot"`
SyncDistance int64 `json:"sync_distance"`
IsSyncing bool `json:"is_syncing"`
IsOptimistic bool `json:"is_optimistic"`
ELOffline bool `json:"el_offline"`
}

type syncingJSON struct {
HeadSlot string `json:"head_slot"`
SyncDistance string `json:"sync_distance"`
IsSyncing bool `json:"is_syncing"`
IsOptimistic bool `json:"is_optimistic"`
ELOffline bool `json:"el_offline"`
}

func (s *SyncingData) MarshalJSON() ([]byte, error) {
return json.Marshal(syncingJSON{
HeadSlot: strconv.FormatInt(s.HeadSlot, 10),
SyncDistance: strconv.FormatInt(s.SyncDistance, 10),
IsSyncing: s.IsSyncing,
IsOptimistic: s.IsOptimistic,
ELOffline: s.ELOffline,
})
}
2 changes: 2 additions & 0 deletions mod/node-core/pkg/components/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/berachain/beacon-kit/mod/node-api/handlers"
"github.com/berachain/beacon-kit/mod/node-api/server"
"github.com/berachain/beacon-kit/mod/primitives/pkg/common"
"github.com/cometbft/cometbft/node"
sdk "github.com/cosmos/cosmos-sdk/types"
)

Expand Down Expand Up @@ -78,6 +79,7 @@ func ProvideNodeAPIBackend[
NodeT interface {
CreateQueryContext(height int64, prove bool) (sdk.Context, error)
GetBeaconVersion() (string, error)
GetCometNode() *node.Node
},
StorageBackendT StorageBackend[
AvailabilityStoreT, BeaconStateT, BeaconBlockStoreT, DepositStoreT,
Expand Down
2 changes: 2 additions & 0 deletions mod/node-core/pkg/components/api_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
eventsapi "github.com/berachain/beacon-kit/mod/node-api/handlers/events"
nodeapi "github.com/berachain/beacon-kit/mod/node-api/handlers/node"
proofapi "github.com/berachain/beacon-kit/mod/node-api/handlers/proof"
"github.com/cometbft/cometbft/node"
)

type NodeAPIHandlersInput[
Expand Down Expand Up @@ -146,6 +147,7 @@ func ProvideNodeAPIEventsHandler[

type Backend interface {
GetNodeVersion() (string, error)
GetNode() *node.Node
}

func ProvideNodeAPINodeHandler[
Expand Down
20 changes: 20 additions & 0 deletions testing/e2e/e2e_node_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package e2e_test

import (
beaconapi "github.com/attestantio/go-eth2-client/api"
"github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/berachain/beacon-kit/testing/e2e/config"
"github.com/berachain/beacon-kit/testing/e2e/suite/types"
)
Expand Down Expand Up @@ -52,3 +53,22 @@ func (s *BeaconKitE2ESuite) TestNodeVersion() {
versionStr := version.Data
s.Require().NotEmpty(versionStr)
}

// TestNodeSyncing tests the node api for syncing status of the node.
func (s *BeaconKitE2ESuite) TestNodeSyncing() {
client := s.initNodeTest()

syncing, err := client.NodeSyncing(s.Ctx(),
&beaconapi.NodeSyncingOpts{})
s.Require().NoError(err)
s.Require().NotNil(syncing)
syncData := syncing.Data
s.Require().NotEmpty(syncData.HeadSlot)
s.Require().Greater(syncData.HeadSlot, phase0.Slot(0))
s.Require().NotNil(syncData.SyncDistance)

s.Require().NotNil(syncData.IsSyncing)
s.Require().True(syncData.IsOptimistic)

// TODO: Add more assertions.
}
10 changes: 10 additions & 0 deletions testing/e2e/suite/types/consensus_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,5 +258,15 @@ func (cc ConsensusClient) Spec(
return cc.beaconClient.Spec(ctx, opts)
}

func (cc ConsensusClient) NodeSyncing(
ctx context.Context,
opts *beaconapi.NodeSyncingOpts,
) (*beaconapi.Response[*apiv1.SyncState], error) {
if cc.beaconClient == nil {
return nil, errors.New("beacon client is not initialized")
}
return cc.beaconClient.NodeSyncing(ctx, opts)
}

// TODO: Add helpers for the beacon node-api client (converting from
// go-eth2-client types to beacon-kit consensus types).
Loading