func (c *Client) GossipHeader(ctx context.Context, headerBytes []byte) error {
	c.logger.Debug("Gossiping block header", "len", len(headerBytes))
	return c.headerGossiper.Publish(ctx, headerBytes)
}
GossipHeader sends the block header to the P2P network.
package p2p
import (
	"context"
	"fmt"
	"strings"
	"time"
	"github.com/libp2p/go-libp2p"
	"github.com/libp2p/go-libp2p-core/crypto"
	cdiscovery "github.com/libp2p/go-libp2p-core/discovery"
	"github.com/libp2p/go-libp2p-core/host"
	"github.com/libp2p/go-libp2p-core/peer"
	discovery "github.com/libp2p/go-libp2p-discovery"
	dht "github.com/libp2p/go-libp2p-kad-dht"
	pubsub "github.com/libp2p/go-libp2p-pubsub"
	routedhost "github.com/libp2p/go-libp2p/p2p/host/routed"
	"github.com/multiformats/go-multiaddr"
	"go.uber.org/multierr"
	"github.com/celestiaorg/optimint/config"
	"github.com/celestiaorg/optimint/log"
)
const (
	reAdvertisePeriod = 1 * time.Hour
	peerLimit = 60
	txTopicSuffix = "-tx"
	headerTopicSuffix = "-header"
)
type Client struct {
	conf    config.P2PConfig
	chainID string
	privKey crypto.PrivKey
	host host.Host
	dht  *dht.IpfsDHT
	disc *discovery.RoutingDiscovery
	txGossiper  *Gossiper
	txValidator GossipValidator
	headerGossiper  *Gossiper
	headerValidator GossipValidator
	headerHandler   GossipHandler
	cancel context.CancelFunc
	logger log.Logger
}
func NewClient(conf config.P2PConfig, privKey crypto.PrivKey, chainID string, logger log.Logger) (*Client, error) {
	if privKey == nil {
		return nil, errNoPrivKey
	}
	if conf.ListenAddress == "" {
		conf.ListenAddress = config.DefaultListenAddress
	}
	return &Client{
		conf:    conf,
		privKey: privKey,
		chainID: chainID,
		logger:  logger,
	}, nil
}
func (c *Client) Start(ctx context.Context) error {
	ctx, c.cancel = context.WithCancel(ctx)
	c.logger.Debug("starting P2P client")
	host, err := c.listen(ctx)
	if err != nil {
		return err
	}
	return c.startWithHost(ctx, host)
}
func (c *Client) startWithHost(ctx context.Context, h host.Host) error {
	c.host = h
	for _, a := range c.host.Addrs() {
		c.logger.Info("listening on", "address", fmt.Sprintf("%s/p2p/%s", a, c.host.ID()))
	}
	c.logger.Debug("setting up gossiping")
	err := c.setupGossiping(ctx)
	if err != nil {
		return err
	}
	c.logger.Debug("setting up DHT")
	err = c.setupDHT(ctx)
	if err != nil {
		return err
	}
	c.logger.Debug("setting up active peer discovery")
	err = c.peerDiscovery(ctx)
	if err != nil {
		return err
	}
	return nil
}
func (c *Client) Close() error {
	c.cancel()
	return multierr.Combine(
		c.txGossiper.Close(),
		c.headerGossiper.Close(),
		c.dht.Close(),
		c.host.Close(),
	)
}
func (c *Client) GossipTx(ctx context.Context, tx []byte) error {
	c.logger.Debug("Gossiping TX", "len", len(tx))
	return c.txGossiper.Publish(ctx, tx)
}
func (c *Client) SetTxHandler(handler GossipHandler) {
	c.txGossiper.handler = handler
}
func (c *Client) SetTxValidator(val GossipValidator) {
	c.txValidator = val
}