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

feat(cel-shed/p2p): bootstrapper probe tool #3780

Merged
merged 11 commits into from
Oct 2, 2024
9 changes: 5 additions & 4 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 @@ -23,7 +23,7 @@ COPY . .

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

FROM docker.io/alpine:3.20.2

Expand All @@ -34,8 +34,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 +54,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
133 changes: 132 additions & 1 deletion cmd/cel-shed/p2p.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
package main

import (
"context"
"crypto/rand"
"encoding/hex"
"fmt"
"os"
"sync"
"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 +85,124 @@ 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()

successfulConnections := 0
failedConnections := 0
smuu marked this conversation as resolved.
Show resolved Hide resolved
var wg sync.WaitGroup
var mu sync.Mutex

for _, bootstrapper := range bootstrappers {
smuu marked this conversation as resolved.
Show resolved Hide resolved
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)
mu.Lock()
failedConnections++
mu.Unlock()
return
}
fmt.Printf("Success: Connected to bootstrapper: %s\n", bootstrapper)
mu.Lock()
successfulConnections++
mu.Unlock()
}(bootstrapper)
}

wg.Wait()

if failedConnections == len(bootstrappers) && errorOnAllFailure {
fmt.Println()
fmt.Println("failed to connect to all bootstrappers")
os.Exit(1)
return nil
} else if failedConnections > 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
Loading