Skip to content

Commit

Permalink
feat(cel-shed/p2p): bootstrapper probe tool (celestiaorg#3780)
Browse files Browse the repository at this point in the history
Signed-off-by: Smuu <[email protected]>
Co-authored-by: Hlib Kanunnikov <[email protected]>
  • Loading branch information
smuu and Wondertan authored Oct 2, 2024
1 parent cf80b08 commit d4e0fc8
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 9 deletions.
15 changes: 9 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM docker.io/golang:1.23-alpine3.20 as builder
FROM --platform=$BUILDPLATFORM docker.io/golang:1.23-alpine3.20 AS builder

ARG TARGETPLATFORM
ARG BUILDPLATFORM
Expand All @@ -21,9 +21,11 @@ COPY go.mod go.sum ./
RUN go mod download
COPY . .

RUN uname -a &&\
CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
make build && make cel-key
RUN uname -a && \
export CGO_ENABLED=${CGO_ENABLED} GOOS=${TARGETOS} GOARCH=${TARGETARCH} && \
make build && \
make cel-key && \
make cel-shed

FROM docker.io/alpine:3.20.2

Expand All @@ -34,8 +36,8 @@ ARG USER_NAME=celestia
ENV CELESTIA_HOME=/home/${USER_NAME}

# Default node type can be overwritten in deployment manifest
ENV NODE_TYPE bridge
ENV P2P_NETWORK mocha
ENV NODE_TYPE=bridge
ENV P2P_NETWORK=mocha

# hadolint ignore=DL3018
RUN uname -a &&\
Expand All @@ -54,6 +56,7 @@ RUN uname -a &&\
# Copy in the binary
COPY --from=builder /src/build/celestia /bin/celestia
COPY --from=builder /src/./cel-key /bin/cel-key
COPY --from=builder /src/./cel-shed /bin/cel-shed

COPY --chown=${USER_NAME}:${USER_NAME} docker/entrypoint.sh /opt/entrypoint.sh

Expand Down
129 changes: 128 additions & 1 deletion cmd/cel-shed/p2p.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
package main

import (
"context"
"crypto/rand"
"encoding/hex"
"fmt"
"os"
"sync"
"sync/atomic"
"time"

"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/spf13/cobra"
"go.uber.org/fx"

"github.com/celestiaorg/celestia-node/nodebuilder"
"github.com/celestiaorg/celestia-node/nodebuilder/fraud"
"github.com/celestiaorg/celestia-node/nodebuilder/node"
"github.com/celestiaorg/celestia-node/nodebuilder/p2p"
)

func init() {
p2pCmd.AddCommand(p2pNewKeyCmd, p2pPeerIDCmd)
p2pCmd.AddCommand(p2pNewKeyCmd, p2pPeerIDCmd, p2pConnectBootstrappersCmd)
}

var p2pCmd = &cobra.Command{
Expand Down Expand Up @@ -75,3 +86,119 @@ var p2pPeerIDCmd = &cobra.Command{
},
Args: cobra.ExactArgs(1),
}

var (
errorOnAnyFailure bool
errorOnAllFailure bool
connectionTimeout time.Duration
)

var p2pConnectBootstrappersCmd = &cobra.Command{
Use: "connect-bootstrappers [network]",
Short: "Connect to bootstrappers of a certain network",
RunE: func(cmd *cobra.Command, args []string) error {
if errorOnAnyFailure && errorOnAllFailure {
return fmt.Errorf("only one of --err-any and --err-all can be specified")
}

ctx, cancel := context.WithTimeout(cmd.Context(), connectionTimeout)
defer cancel()

network := p2p.GetNetwork(args[0])
bootstrappers, err := p2p.BootstrappersFor(network)
if err != nil {
return fmt.Errorf("failed to get bootstrappers: %w", err)
}

store := nodebuilder.NewMemStore()
cfg := p2p.DefaultConfig(node.Light)
modp2p := p2p.ConstructModule(node.Light, &cfg)

var mod p2p.Module
app := fx.New(
fx.NopLogger,
modp2p,
fx.Provide(fraud.Unmarshaler),
fx.Provide(cmd.Context),
fx.Provide(store.Keystore),
fx.Provide(store.Datastore),
fx.Supply(bootstrappers),
fx.Supply(network),
fx.Supply(node.Light),
fx.Invoke(func(modprov p2p.Module) {
mod = modprov
}),
)

if err := app.Start(ctx); err != nil {
return fmt.Errorf("failed to start app: %w", err)
}
defer func() {
if err := app.Stop(ctx); err != nil {
fmt.Printf("failed to stop application: %v\n", err)
}
}()

p2pInfo, err := mod.Info(ctx)
if err != nil {
return fmt.Errorf("failed to get p2p info: %w", err)
}

fmt.Printf("PeerID: %s\n", p2pInfo.ID)
for _, addr := range p2pInfo.Addrs {
fmt.Printf("Listening on: %s\n", addr.String())
}
fmt.Println()

var successfulConnections atomic.Int32
var failedConnections atomic.Int32
var wg sync.WaitGroup

for _, bootstrapper := range bootstrappers {
wg.Add(1)
go func(bootstrapper peer.AddrInfo) {
defer wg.Done()
fmt.Printf("Attempting to connect to bootstrapper: %s\n", bootstrapper)
if err := mod.Connect(ctx, bootstrapper); err != nil {
fmt.Printf("Error: Failed to connect to bootstrapper %s. Reason: %v\n", bootstrapper, err)
failedConnections.Add(1)
return
}
fmt.Printf("Success: Connected to bootstrapper: %s\n", bootstrapper)
successfulConnections.Add(1)
}(bootstrapper)
}

wg.Wait()

if failedConnections.Load() == int32(len(bootstrappers)) && errorOnAllFailure {
fmt.Println()
fmt.Println("failed to connect to all bootstrappers")
os.Exit(1)
return nil
} else if failedConnections.Load() > 0 && errorOnAnyFailure {
fmt.Println()
fmt.Println("failed to connect to some bootstrappers")
os.Exit(1)
return nil
}

return nil
},
Args: cobra.ExactArgs(1),
}

func init() {
p2pConnectBootstrappersCmd.Flags().BoolVar(
&errorOnAnyFailure, "err-any", false,
"Return error if at least one bootstrapper is not reachable",
)
p2pConnectBootstrappersCmd.Flags().BoolVar(
&errorOnAllFailure, "err-all", false,
"Return error if no bootstrapper is reachable",
)
p2pConnectBootstrappersCmd.Flags().DurationVar(
&connectionTimeout, "timeout", 10*time.Second,
"Timeout duration for the entire bootstrapper connection process",
)
}
2 changes: 1 addition & 1 deletion nodebuilder/fraud/constructors.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"github.com/celestiaorg/celestia-node/nodebuilder/p2p"
)

func fraudUnmarshaler() fraud.ProofUnmarshaler[*header.ExtendedHeader] {
func Unmarshaler() fraud.ProofUnmarshaler[*header.ExtendedHeader] {
return defaultProofUnmarshaler
}

Expand Down
2 changes: 1 addition & 1 deletion nodebuilder/fraud/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var log = logging.Logger("module/fraud")

func ConstructModule(tp node.Type) fx.Option {
baseComponent := fx.Options(
fx.Provide(fraudUnmarshaler),
fx.Provide(Unmarshaler),
fx.Provide(func(serv fraud.Service[*header.ExtendedHeader]) fraud.Getter[*header.ExtendedHeader] {
return serv
}),
Expand Down
5 changes: 5 additions & 0 deletions nodebuilder/p2p/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ var networkAliases = map[string]Network{
"private": Private,
}

// GetNetwork returns the Network for the given string representation.
func GetNetwork(networkStr string) Network {
return networkAliases[networkStr]
}

// orderedNetworks is a list of all known networks in order of priority.
var orderedNetworks = []Network{Mainnet, Mocha, Arabica, Private}

Expand Down

0 comments on commit d4e0fc8

Please sign in to comment.