peer

package
v0.0.0-...-3fa05c8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 12, 2023 License: BSD-3-Clause Imports: 44 Imported by: 0

Documentation

Overview

Package peer is a generated GoMock package.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func NoPrecondition

func NoPrecondition(Peer) bool

func TLSConfig

func TLSConfig(cert tls.Certificate, keyLogWriter io.Writer) *tls.Config

TLSConfig returns the TLS config that will allow secure connections to other peers.

It is safe, and typically expected, for [keyLogWriter] to be [nil]. [keyLogWriter] should only be enabled for debugging.

Types

type Config

type Config struct {
	// Size, in bytes, of the buffer this peer reads messages into
	ReadBufferSize int
	// Size, in bytes, of the buffer this peer writes messages into
	WriteBufferSize int
	Clock           mockable.Clock
	Metrics         *Metrics
	MessageCreator  message.Creator

	Log                  logging.Logger
	InboundMsgThrottler  throttling.InboundMsgThrottler
	Network              Network
	Router               router.InboundHandler
	VersionCompatibility version.Compatibility
	MySubnets            set.Set[ids.ID]
	Beacons              validators.Set
	NetworkID            uint32
	PingFrequency        time.Duration
	PongTimeout          time.Duration
	MaxClockDifference   time.Duration

	// Unix time of the last message sent and received respectively
	// Must only be accessed atomically
	LastSent, LastReceived int64

	// Tracks CPU/disk usage caused by each peer.
	ResourceTracker tracker.ResourceTracker

	// Calculates uptime of peers
	UptimeCalculator uptime.Calculator

	// Signs my IP so I can send my signed IP address in the Version message
	IPSigner *IPSigner
}

type GossipTracker

type GossipTracker interface {
	// Tracked returns if a peer is being tracked
	// Returns:
	// 	bool: False if [peerID] is not tracked. True otherwise.
	Tracked(peerID ids.NodeID) bool

	// StartTrackingPeer starts tracking a peer
	// Returns:
	// 	bool: False if [peerID] was already tracked. True otherwise.
	StartTrackingPeer(peerID ids.NodeID) bool
	// StopTrackingPeer stops tracking a given peer
	// Returns:
	// 	bool: False if [peerID] was not tracked. True otherwise.
	StopTrackingPeer(peerID ids.NodeID) bool

	// AddValidator adds a validator that can be gossiped about
	// 	bool: False if a validator with the same node ID or txID as [validator]
	// 	is present. True otherwise.
	AddValidator(validator ValidatorID) bool
	// GetNodeID maps a txID into a nodeIDs
	// 	nodeID: The nodeID that was registered by [txID]
	// 	bool: False if [validator] was not present. True otherwise.
	GetNodeID(txID ids.ID) (ids.NodeID, bool)
	// RemoveValidator removes a validator that can be gossiped about
	// 	bool: False if [validator] was already not present. True otherwise.
	RemoveValidator(validatorID ids.NodeID) bool
	// ResetValidator resets known gossip status of [validatorID] to unknown
	// for all peers
	// 	bool: False if [validator] was not present. True otherwise.
	ResetValidator(validatorID ids.NodeID) bool

	// AddKnown adds [knownTxIDs] to the txIDs known by [peerID] and filters
	// [txIDs] for non-validators.
	// Returns:
	// 	txIDs: The txIDs in [txIDs] that are currently validators.
	// 	bool: False if [peerID] is not tracked. True otherwise.
	AddKnown(
		peerID ids.NodeID,
		knownTxIDs []ids.ID,
		txIDs []ids.ID,
	) ([]ids.ID, bool)
	// GetUnknown gets the peers that we haven't sent to this peer
	// Returns:
	// 	[]ValidatorID: a slice of ValidatorIDs that [peerID] doesn't know about.
	// 	bool: False if [peerID] is not tracked. True otherwise.
	GetUnknown(peerID ids.NodeID) ([]ValidatorID, bool)
}

GossipTracker tracks the validators that we're currently aware of, as well as the validators we've told each peers about. This data is stored in a bitset to optimize space, where only N (num validators) bits will be used per peer.

This is done by recording some state information of both what validators this node is aware of, and what validators we've told each peer about. As an example, say we track three peers and three validators (MSB first):

trackedPeers:	{
	p1: [1, 1, 1] // we have already told [p1] about all validators
	p2: [0, 1, 1] // [p2] doesn't know about [v3]
	p3: [0, 0, 1] // [p3] knows only about [v3]
}

GetUnknown computes the validators we haven't sent to a given peer. Ex:

GetUnknown(p1) -  [0, 0, 0]
GetUnknown(p2) -  [1, 0, 0]
GetUnknown(p3) -  [1, 1, 0]

Using the gossipTracker, we can quickly compute the validators each peer doesn't know about using GetUnknown so that in subsequent PeerList gossip messages we only send information that this peer (most likely) doesn't already know about. The only case where we'll send a redundant set of bytes is if another remote peer gossips to the same peer we're trying to gossip to first.

func NewGossipTracker

func NewGossipTracker(
	registerer prometheus.Registerer,
	namespace string,
) (GossipTracker, error)

NewGossipTracker returns an instance of gossipTracker

type GossipTrackerCallback

type GossipTrackerCallback struct {
	Log           logging.Logger
	GossipTracker GossipTracker
}

GossipTrackerCallback synchronizes GossipTracker's validator state with the validator set it's registered to.

func (*GossipTrackerCallback) OnValidatorAdded

func (g *GossipTrackerCallback) OnValidatorAdded(
	nodeID ids.NodeID,
	_ *bls.PublicKey,
	txID ids.ID,
	_ uint64,
)

OnValidatorAdded adds [validatorID] to the set of validators that can be gossiped about

func (*GossipTrackerCallback) OnValidatorRemoved

func (g *GossipTrackerCallback) OnValidatorRemoved(nodeID ids.NodeID, _ uint64)

OnValidatorRemoved removes [validatorID] from the set of validators that can be gossiped about.

func (*GossipTrackerCallback) OnValidatorWeightChanged

func (*GossipTrackerCallback) OnValidatorWeightChanged(ids.NodeID, uint64, uint64)

OnValidatorWeightChanged does nothing because PeerList gossip doesn't care about validator weights.

type IPSigner

type IPSigner struct {
	// contains filtered or unexported fields
}

IPSigner will return a signedIP for the current value of our dynamic IP.

func NewIPSigner

func NewIPSigner(
	ip ips.DynamicIPPort,
	signer crypto.Signer,
) *IPSigner

func (*IPSigner) GetSignedIP

func (s *IPSigner) GetSignedIP() (*SignedIP, error)

GetSignedIP returns the signedIP of the current value of the provided dynamicIP. If the dynamicIP hasn't changed since the prior call to GetSignedIP, then the same SignedIP will be returned.

It's safe for multiple goroutines to concurrently call GetSignedIP.

type Info

type Info struct {
	IP                    string                 `json:"ip"`
	PublicIP              string                 `json:"publicIP,omitempty"`
	ID                    ids.NodeID             `json:"nodeID"`
	Version               string                 `json:"version"`
	LastSent              time.Time              `json:"lastSent"`
	LastReceived          time.Time              `json:"lastReceived"`
	ObservedUptime        json.Uint32            `json:"observedUptime"`
	ObservedSubnetUptimes map[ids.ID]json.Uint32 `json:"observedSubnetUptimes"`
	TrackedSubnets        []ids.ID               `json:"trackedSubnets"`
}

type MessageMetrics

type MessageMetrics struct {
	ReceivedBytes, SentBytes, NumSent, NumFailed, NumReceived prometheus.Counter
	SavedReceivedBytes, SavedSentBytes                        metric.Averager
}

func NewMessageMetrics

func NewMessageMetrics(
	op message.Op,
	namespace string,
	metrics prometheus.Registerer,
	errs *wrappers.Errs,
) *MessageMetrics

type MessageQueue

type MessageQueue interface {
	// Push attempts to add the message to the queue. If the context is
	// canceled, then pushing the message will return `false` and the message
	// will not be added to the queue.
	Push(ctx context.Context, msg message.OutboundMessage) bool

	// Pop blocks until a message is available and then returns the message. If
	// the queue is closed, then `false` is returned.
	Pop() (message.OutboundMessage, bool)

	// PopNow attempts to return a message without blocking. If a message is not
	// available or the queue is closed, then `false` is returned.
	PopNow() (message.OutboundMessage, bool)

	// Close empties the queue and prevents further messages from being pushed
	// onto it. After calling close once, future calls to close will do nothing.
	Close()
}

func NewBlockingMessageQueue

func NewBlockingMessageQueue(
	onFailed SendFailedCallback,
	log logging.Logger,
	bufferSize int,
) MessageQueue

func NewThrottledMessageQueue

func NewThrottledMessageQueue(
	onFailed SendFailedCallback,
	id ids.NodeID,
	log logging.Logger,
	outboundMsgThrottler throttling.OutboundMsgThrottler,
) MessageQueue

type Metrics

type Metrics struct {
	Log            logging.Logger
	FailedToParse  prometheus.Counter
	MessageMetrics map[message.Op]*MessageMetrics
}

func NewMetrics

func NewMetrics(
	log logging.Logger,
	namespace string,
	registerer prometheus.Registerer,
) (*Metrics, error)

func (*Metrics) MultipleSendsFailed

func (m *Metrics) MultipleSendsFailed(op message.Op, count int)

func (*Metrics) Received

func (m *Metrics) Received(msg message.InboundMessage, msgLen uint32)

func (*Metrics) SendFailed

func (m *Metrics) SendFailed(msg message.OutboundMessage)

SendFailed updates the metrics for having failed to send [msg].

func (*Metrics) Sent

func (m *Metrics) Sent(msg message.OutboundMessage)

Sent updates the metrics for having sent [msg].

type MockGossipTracker

type MockGossipTracker struct {
	// contains filtered or unexported fields
}

MockGossipTracker is a mock of GossipTracker interface.

func NewMockGossipTracker

func NewMockGossipTracker(ctrl *gomock.Controller) *MockGossipTracker

NewMockGossipTracker creates a new mock instance.

func (*MockGossipTracker) AddKnown

func (m *MockGossipTracker) AddKnown(arg0 ids.NodeID, arg1, arg2 []ids.ID) ([]ids.ID, bool)

AddKnown mocks base method.

func (*MockGossipTracker) AddValidator

func (m *MockGossipTracker) AddValidator(arg0 ValidatorID) bool

AddValidator mocks base method.

func (*MockGossipTracker) EXPECT

EXPECT returns an object that allows the caller to indicate expected use.

func (*MockGossipTracker) GetNodeID

func (m *MockGossipTracker) GetNodeID(arg0 ids.ID) (ids.NodeID, bool)

GetNodeID mocks base method.

func (*MockGossipTracker) GetUnknown

func (m *MockGossipTracker) GetUnknown(arg0 ids.NodeID) ([]ValidatorID, bool)

GetUnknown mocks base method.

func (*MockGossipTracker) RemoveValidator

func (m *MockGossipTracker) RemoveValidator(arg0 ids.NodeID) bool

RemoveValidator mocks base method.

func (*MockGossipTracker) ResetValidator

func (m *MockGossipTracker) ResetValidator(arg0 ids.NodeID) bool

ResetValidator mocks base method.

func (*MockGossipTracker) StartTrackingPeer

func (m *MockGossipTracker) StartTrackingPeer(arg0 ids.NodeID) bool

StartTrackingPeer mocks base method.

func (*MockGossipTracker) StopTrackingPeer

func (m *MockGossipTracker) StopTrackingPeer(arg0 ids.NodeID) bool

StopTrackingPeer mocks base method.

func (*MockGossipTracker) Tracked

func (m *MockGossipTracker) Tracked(arg0 ids.NodeID) bool

Tracked mocks base method.

type MockGossipTrackerMockRecorder

type MockGossipTrackerMockRecorder struct {
	// contains filtered or unexported fields
}

MockGossipTrackerMockRecorder is the mock recorder for MockGossipTracker.

func (*MockGossipTrackerMockRecorder) AddKnown

func (mr *MockGossipTrackerMockRecorder) AddKnown(arg0, arg1, arg2 interface{}) *gomock.Call

AddKnown indicates an expected call of AddKnown.

func (*MockGossipTrackerMockRecorder) AddValidator

func (mr *MockGossipTrackerMockRecorder) AddValidator(arg0 interface{}) *gomock.Call

AddValidator indicates an expected call of AddValidator.

func (*MockGossipTrackerMockRecorder) GetNodeID

func (mr *MockGossipTrackerMockRecorder) GetNodeID(arg0 interface{}) *gomock.Call

GetNodeID indicates an expected call of GetNodeID.

func (*MockGossipTrackerMockRecorder) GetUnknown

func (mr *MockGossipTrackerMockRecorder) GetUnknown(arg0 interface{}) *gomock.Call

GetUnknown indicates an expected call of GetUnknown.

func (*MockGossipTrackerMockRecorder) RemoveValidator

func (mr *MockGossipTrackerMockRecorder) RemoveValidator(arg0 interface{}) *gomock.Call

RemoveValidator indicates an expected call of RemoveValidator.

func (*MockGossipTrackerMockRecorder) ResetValidator

func (mr *MockGossipTrackerMockRecorder) ResetValidator(arg0 interface{}) *gomock.Call

ResetValidator indicates an expected call of ResetValidator.

func (*MockGossipTrackerMockRecorder) StartTrackingPeer

func (mr *MockGossipTrackerMockRecorder) StartTrackingPeer(arg0 interface{}) *gomock.Call

StartTrackingPeer indicates an expected call of StartTrackingPeer.

func (*MockGossipTrackerMockRecorder) StopTrackingPeer

func (mr *MockGossipTrackerMockRecorder) StopTrackingPeer(arg0 interface{}) *gomock.Call

StopTrackingPeer indicates an expected call of StopTrackingPeer.

func (*MockGossipTrackerMockRecorder) Tracked

func (mr *MockGossipTrackerMockRecorder) Tracked(arg0 interface{}) *gomock.Call

Tracked indicates an expected call of Tracked.

type Network

type Network interface {
	// Connected is called by the peer once the handshake is finished.
	Connected(peerID ids.NodeID)

	// AllowConnection enables the network is signal to the peer that its
	// connection is no longer desired and should be terminated.
	AllowConnection(peerID ids.NodeID) bool

	// Track allows the peer to notify the network of a potential new peer to
	// connect to, given the [ips] of the peers it sent us during the peer
	// handshake.
	//
	// Returns which IPs should not be gossipped to this node again.
	Track(peerID ids.NodeID, ips []*ips.ClaimedIPPort) ([]*p2p.PeerAck, error)

	// MarkTracked stops sending gossip about [ips] to [peerID].
	MarkTracked(peerID ids.NodeID, ips []*p2p.PeerAck) error

	// Disconnected is called when the peer finishes shutting down. It is not
	// guaranteed that [Connected] was called for the provided peer. However, it
	// is guaranteed that [Connected] will not be called after [Disconnected]
	// for a given [Peer] object.
	Disconnected(peerID ids.NodeID)

	// Peers returns peers that [peerID] might not know about.
	Peers(peerID ids.NodeID) ([]ips.ClaimedIPPort, error)
}

Network defines the interface that is used by a peer to help establish a well connected p2p network.

var TestNetwork Network = testNetwork{}

type Peer

type Peer interface {
	// ID returns the nodeID of the remote peer.
	ID() ids.NodeID

	// Cert returns the certificate that the remote peer is using to
	// authenticate their messages.
	Cert() *x509.Certificate

	// LastSent returns the last time a message was sent to the peer.
	LastSent() time.Time

	// LastReceived returns the last time a message was received from the peer.
	LastReceived() time.Time

	// Ready returns true if the peer has finished the p2p handshake and is
	// ready to send and receive messages.
	Ready() bool

	// AwaitReady will block until the peer has finished the p2p handshake. If
	// the context is cancelled or the peer starts closing, then an error will
	// be returned.
	AwaitReady(ctx context.Context) error

	// Info returns a description of the state of this peer. It should only be
	// called after [Ready] returns true.
	Info() Info

	// IP returns the claimed IP and signature provided by this peer during the
	// handshake. It should only be called after [Ready] returns true.
	IP() *SignedIP

	// Version returns the claimed node version this peer is running. It should
	// only be called after [Ready] returns true.
	Version() *version.Application

	// TrackedSubnets returns the subnets this peer is running. It should only
	// be called after [Ready] returns true.
	TrackedSubnets() set.Set[ids.ID]

	// ObservedUptime returns the local node's subnet uptime according to the
	// peer. The value ranges from [0, 100]. It should only be called after
	// [Ready] returns true.
	ObservedUptime(subnetID ids.ID) (uint32, bool)

	// Send attempts to send [msg] to the peer. The peer takes ownership of
	// [msg] for reference counting. This returns false if the message is
	// guaranteed not to be delivered to the peer.
	Send(ctx context.Context, msg message.OutboundMessage) bool

	// StartSendPeerList attempts to send a PeerList message to this peer on
	// this peer's gossip routine. It is not guaranteed that a PeerList will be
	// sent.
	StartSendPeerList()

	// StartClose will begin shutting down the peer. It will not block.
	StartClose()

	// Closed returns true once the peer has been fully shutdown. It is
	// guaranteed that no more messages will be received by this peer once this
	// returns true.
	Closed() bool

	// AwaitClosed will block until the peer has been fully shutdown. If the
	// context is cancelled, then an error will be returned.
	AwaitClosed(ctx context.Context) error
}

Peer encapsulates all of the functionality required to send and receive messages with a remote peer.

func Start

func Start(
	config *Config,
	conn net.Conn,
	cert *x509.Certificate,
	id ids.NodeID,
	messageQueue MessageQueue,
) Peer

Start a new peer instance.

Invariant: There must only be one peer running at a time with a reference to the same [config.InboundMsgThrottler].

func StartTestPeer

func StartTestPeer(
	ctx context.Context,
	ip ips.IPPort,
	networkID uint32,
	router router.InboundHandler,
) (Peer, error)

StartTestPeer provides a simple interface to create a peer that has finished the p2p handshake.

This function will generate a new TLS key to use when connecting to the peer.

The returned peer will not throttle inbound or outbound messages.

  • [ctx] provides a way of canceling the connection request.
  • [ip] is the remote that will be dialed to create the connection.
  • [networkID] will be sent to the peer during the handshake. If the peer is expecting a different [networkID], the handshake will fail and an error will be returned.
  • router will be called with all non-handshake messages received by the peer.
Example
ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, 15*time.Second)
defer cancel()

peerIP := ips.IPPort{
	IP:   net.IPv6loopback,
	Port: 9696,
}
peer, err := StartTestPeer(
	ctx,
	peerIP,
	constants.LocalID,
	router.InboundHandlerFunc(func(_ context.Context, msg message.InboundMessage) {
		fmt.Printf("handling %s\n", msg.Op())
	}),
)
if err != nil {
	panic(err)
}

// Send messages here with [peer.Send].

peer.StartClose()
err = peer.AwaitClosed(ctx)
if err != nil {
	panic(err)
}
Output:

type SendFailedCallback

type SendFailedCallback interface {
	SendFailed(message.OutboundMessage)
}

type SendFailedFunc

type SendFailedFunc func(message.OutboundMessage)

func (SendFailedFunc) SendFailed

func (f SendFailedFunc) SendFailed(msg message.OutboundMessage)

type Set

type Set interface {
	// Add this peer to the set.
	//
	// If a peer with the same [peer.ID] is already in the set, then the new
	// peer instance will replace the old peer instance.
	//
	// Add does not change the [peer.ID] returned from calls to [GetByIndex].
	Add(peer Peer)

	// GetByID attempts to fetch a [peer] whose [peer.ID] is equal to [nodeID].
	// If no such peer exists in the set, then [false] will be returned.
	GetByID(nodeID ids.NodeID) (Peer, bool)

	// GetByIndex attempts to fetch a peer who has been allocated [index]. If
	// [index] < 0 or [index] >= [Len], then false will be returned.
	GetByIndex(index int) (Peer, bool)

	// Remove any [peer] whose [peer.ID] is equal to [nodeID] from the set.
	Remove(nodeID ids.NodeID)

	// Len returns the number of peers currently in this set.
	Len() int

	// Sample attempts to return a random slice of peers with length [n]. The
	// slice will not include any duplicates. Only peers that cause the
	// [precondition] to return true will be returned in the slice.
	Sample(n int, precondition func(Peer) bool) []Peer

	// Returns information about all the peers.
	AllInfo() []Info

	// Info returns information about the requested peers if they are in the
	// set.
	Info(nodeIDs []ids.NodeID) []Info
}

Set contains a group of peers.

func NewSet

func NewSet() Set

NewSet returns a set that does not internally manage synchronization.

Only [Add] and [Remove] require exclusion on the data structure. The remaining methods are safe for concurrent use.

type SignedIP

type SignedIP struct {
	UnsignedIP
	Signature []byte
}

SignedIP is a wrapper of an UnsignedIP with the signature from a signer.

func (*SignedIP) Verify

func (ip *SignedIP) Verify(cert *x509.Certificate) error

type UnsignedIP

type UnsignedIP struct {
	ips.IPPort
	Timestamp uint64
}

UnsignedIP is used for a validator to claim an IP. The [Timestamp] is used to ensure that the most updated IP claim is tracked by peers for a given validator.

func (*UnsignedIP) Sign

func (ip *UnsignedIP) Sign(signer crypto.Signer) (*SignedIP, error)

Sign this IP with the provided signer and return the signed IP.

type Upgrader

type Upgrader interface {
	// Must be thread safe
	Upgrade(net.Conn) (ids.NodeID, net.Conn, *x509.Certificate, error)
}

func NewTLSClientUpgrader

func NewTLSClientUpgrader(config *tls.Config) Upgrader

func NewTLSServerUpgrader

func NewTLSServerUpgrader(config *tls.Config) Upgrader

type ValidatorID

type ValidatorID struct {
	// The validator's ID
	NodeID ids.NodeID
	// The Tx that added this into the validator set
	TxID ids.ID
}

ValidatorID represents a validator that we gossip to other peers

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL