mirror of
https://github.com/luxfi/p2p.git
synced 2026-10-30 15:22:55 +00:00
Update proto definitions to match latest p2p spec. Remove AllChains field from Handshake/GetPeerList messages. Update dependency versions.
142 lines
3.7 KiB
Go
142 lines
3.7 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package p2p
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/log"
|
|
)
|
|
|
|
// Standardized identifiers for application protocol handlers
|
|
const (
|
|
TxGossipHandlerID = iota
|
|
AtomicTxGossipHandlerID
|
|
// SignatureRequestHandlerID is specified in LP-118
|
|
SignatureRequestHandlerID
|
|
)
|
|
|
|
var (
|
|
_ Handler = (*NoOpHandler)(nil)
|
|
_ Handler = (*TestHandler)(nil)
|
|
_ Handler = (*ValidatorHandler)(nil)
|
|
)
|
|
|
|
// Handler is the server-side logic for virtual machine application protocols.
|
|
type Handler interface {
|
|
// Gossip is called when handling a gossip message.
|
|
Gossip(
|
|
ctx context.Context,
|
|
nodeID ids.NodeID,
|
|
gossipBytes []byte,
|
|
)
|
|
// Request is called when handling a request message.
|
|
// Sends a response with the response corresponding to requestBytes or
|
|
// an application-defined error.
|
|
Request(
|
|
ctx context.Context,
|
|
nodeID ids.NodeID,
|
|
deadline time.Time,
|
|
requestBytes []byte,
|
|
) ([]byte, *Error)
|
|
}
|
|
|
|
// NoOpHandler drops all messages
|
|
type NoOpHandler struct{}
|
|
|
|
func (NoOpHandler) Gossip(context.Context, ids.NodeID, []byte) {}
|
|
|
|
func (NoOpHandler) Request(context.Context, ids.NodeID, time.Time, []byte) ([]byte, *Error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func NewValidatorHandler(
|
|
handler Handler,
|
|
validatorSet ValidatorSet,
|
|
log log.Logger,
|
|
) *ValidatorHandler {
|
|
return &ValidatorHandler{
|
|
handler: handler,
|
|
validatorSet: validatorSet,
|
|
log: log,
|
|
}
|
|
}
|
|
|
|
// ValidatorHandler drops messages from non-validators
|
|
type ValidatorHandler struct {
|
|
handler Handler
|
|
validatorSet ValidatorSet
|
|
log log.Logger
|
|
}
|
|
|
|
func (v ValidatorHandler) Gossip(ctx context.Context, nodeID ids.NodeID, gossipBytes []byte) {
|
|
if !v.validatorSet.Has(ctx, nodeID) {
|
|
v.log.Debug("dropping message",
|
|
log.Stringer("nodeID", nodeID),
|
|
log.UserString("reason", "not a validator"),
|
|
)
|
|
return
|
|
}
|
|
|
|
v.handler.Gossip(ctx, nodeID, gossipBytes)
|
|
}
|
|
|
|
func (v ValidatorHandler) Request(ctx context.Context, nodeID ids.NodeID, deadline time.Time, requestBytes []byte) ([]byte, *Error) {
|
|
if !v.validatorSet.Has(ctx, nodeID) {
|
|
return nil, ErrNotValidator
|
|
}
|
|
|
|
return v.handler.Request(ctx, nodeID, deadline, requestBytes)
|
|
}
|
|
|
|
// responder automatically sends the response for a given request
|
|
type responder struct {
|
|
Handler
|
|
handlerID uint64
|
|
log log.Logger
|
|
sender Sender
|
|
}
|
|
|
|
// Request calls the underlying handler and sends back the response to nodeID
|
|
func (r *responder) Request(ctx context.Context, nodeID ids.NodeID, requestID uint32, deadline time.Time, request []byte) error {
|
|
response, err := r.Handler.Request(ctx, nodeID, deadline, request)
|
|
if err != nil {
|
|
r.log.Debug("failed to handle message",
|
|
log.UserString("messageOp", "Request"),
|
|
log.Stringer("nodeID", nodeID),
|
|
log.Uint32("requestID", requestID),
|
|
log.Time("deadline", deadline),
|
|
log.Uint64("handlerID", r.handlerID),
|
|
log.Binary("message", request),
|
|
log.Err(err),
|
|
)
|
|
return r.sender.SendError(ctx, nodeID, requestID, err.Code, err.Message)
|
|
}
|
|
|
|
return r.sender.SendResponse(ctx, nodeID, requestID, response)
|
|
}
|
|
|
|
type TestHandler struct {
|
|
GossipF func(ctx context.Context, nodeID ids.NodeID, gossipBytes []byte)
|
|
RequestF func(ctx context.Context, nodeID ids.NodeID, deadline time.Time, requestBytes []byte) ([]byte, *Error)
|
|
}
|
|
|
|
func (t TestHandler) Gossip(ctx context.Context, nodeID ids.NodeID, gossipBytes []byte) {
|
|
if t.GossipF == nil {
|
|
return
|
|
}
|
|
|
|
t.GossipF(ctx, nodeID, gossipBytes)
|
|
}
|
|
|
|
func (t TestHandler) Request(ctx context.Context, nodeID ids.NodeID, deadline time.Time, requestBytes []byte) ([]byte, *Error) {
|
|
if t.RequestF == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
return t.RequestF(ctx, nodeID, deadline, requestBytes)
|
|
}
|