erigon-pulse/cl/sentinel/handshake/handshake.go
a 436493350e
Sentinel refactor (#8296)
1. changes sentinel to use an http-like interface

2. moves hexutil, crypto/blake2b, metrics packages to erigon-lib
2023-10-22 01:17:18 +02:00

105 lines
2.8 KiB
Go

package handshake
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"sync"
communication2 "github.com/ledgerwatch/erigon/cl/sentinel/communication"
"github.com/ledgerwatch/erigon/cl/sentinel/communication/ssz_snappy"
"github.com/ledgerwatch/erigon/cl/sentinel/httpreqresp"
"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/cltypes"
"github.com/ledgerwatch/erigon/cl/fork"
"github.com/libp2p/go-libp2p/core/peer"
)
// HandShaker is the data type which will handle handshakes and determine if
// The peer is worth connecting to or not.
type HandShaker struct {
ctx context.Context
// Status object to send over.
status *cltypes.Status // Contains status object for handshakes
set bool
handler http.Handler
genesisConfig *clparams.GenesisConfig
beaconConfig *clparams.BeaconChainConfig
mu sync.Mutex
}
func New(ctx context.Context, genesisConfig *clparams.GenesisConfig, beaconConfig *clparams.BeaconChainConfig, handler http.Handler) *HandShaker {
return &HandShaker{
ctx: ctx,
handler: handler,
genesisConfig: genesisConfig,
beaconConfig: beaconConfig,
status: &cltypes.Status{},
}
}
// SetStatus sets the current network status against which we can validate peers.
func (h *HandShaker) SetStatus(status *cltypes.Status) {
h.mu.Lock()
defer h.mu.Unlock()
h.set = true
h.status = status
}
// Status returns the underlying status (only for giving out responses)
func (h *HandShaker) Status() *cltypes.Status {
h.mu.Lock()
defer h.mu.Unlock()
return h.status
}
// Set returns the underlying status (only for giving out responses)
func (h *HandShaker) IsSet() bool {
h.mu.Lock()
defer h.mu.Unlock()
return h.set
}
func (h *HandShaker) ValidatePeer(id peer.ID) (bool, error) {
// Unprotected if it is not set
if !h.IsSet() {
return true, nil
}
status := h.Status()
// Encode our status
buf := new(bytes.Buffer)
if err := ssz_snappy.EncodeAndWrite(buf, status); err != nil {
return false, err
}
req, err := http.NewRequest("GET", "http://service.internal/", buf)
if err != nil {
return false, err
}
req.Header.Set("REQRESP-PEER-ID", id.String())
req.Header.Set("REQRESP-TOPIC", communication2.StatusProtocolV1)
resp, err := httpreqresp.Do(h.handler, req)
if err != nil {
return false, err
}
defer resp.Body.Close()
if resp.Header.Get("REQRESP-RESPONSE-CODE") != "0" {
a, _ := io.ReadAll(resp.Body)
//TODO: proper errors
return false, fmt.Errorf("handshake error: %s", string(a))
}
responseStatus := &cltypes.Status{}
if err := ssz_snappy.DecodeAndReadNoForkDigest(resp.Body, responseStatus, clparams.Phase0Version); err != nil {
return false, nil
}
forkDigest, err := fork.ComputeForkDigest(h.beaconConfig, h.genesisConfig)
if err != nil {
return false, nil
}
return responseStatus.ForkDigest == forkDigest, nil
}