p2p

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: May 9, 2022 License: GPL-3.0 Imports: 31 Imported by: 0

Documentation

Overview

Package p2p implements the Ethereum p2p network protocols.

Index

Examples

Constants

View Source
const (

	// HandleHistName is the prefix of the per-packet serving time histograms.
	HandleHistName = "p2p/handle"
)

Variables

View Source
var ErrPipeClosed = errors.New("p2p: read or write on closed message pipe")

ErrPipeClosed is returned from pipe operations after the pipe has been closed.

View Source
var (
	ErrShuttingDown = errors.New("shutting down")
)

Functions

func ExpectMsg

func ExpectMsg(r MsgReader, code uint64, content interface{}) error

ExpectMsg reads a message from r and verifies that its code and encoded RLP content match the provided values. If content is nil, the payload is discarded and not verified. 从r中读取一条消息判断是否与输入的code和content匹配

func MsgPipe

func MsgPipe() (*MsgPipeRW, *MsgPipeRW)

MsgPipe creates a message pipe. Reads on one end are matched with writes on the other. The pipe is full-duplex, both ends implement MsgReadWriter. 创建一对MsgPipeRW对象,他们实现了MsgReadWriter接口

Example
rw1, rw2 := MsgPipe()
go func() {
	Send(rw1, 8, [][]byte{{0, 0}})
	Send(rw1, 5, [][]byte{{1, 1}})
	rw1.Close()
}()

for {
	msg, err := rw2.ReadMsg()
	if err != nil {
		break
	}
	var data [][]byte
	msg.Decode(&data)
	fmt.Printf("msg: %d, %x\n", msg.Code, data[0])
}
Output:

msg: 8, 0000
msg: 5, 0101

func Send

func Send(w MsgWriter, msgcode uint64, data interface{}) error

Send writes an RLP-encoded message with the given code. data should encode as an RLP list. 将消息msgcode和data通过w发送出去 首先将data转化成rlp编码,保存到io.Reader里后构造Msg对象 然后调用w.WriteMsg发送Msg对象

func SendItems

func SendItems(w MsgWriter, msgcode uint64, elems ...interface{}) error

SendItems writes an RLP with the given code and data elements. For a call such as:

SendItems(w, code, e1, e2, e3)

the message payload will be an RLP list containing the items:

[e1, e2, e3]

发送好几个数据,例如调用SendItems(w, code, e1, e2, e3) 会将e1,e2,e3编码成一个数组[e1,e2,e3]

Types

type Cap

type Cap struct {
	Name    string
	Version uint
}

Cap is the structure of a peer capability. Cap代表一个远程节点协议的能力 通过协议名称和协议版本来描述能力

func (Cap) String

func (cap Cap) String() string

Cap的打印格式 name/version 例如 protocol/1

type Config

type Config struct {
	// This field must be set to a valid secp256k1 private key.
	// 必选值,本地节点的私钥
	PrivateKey *ecdsa.PrivateKey `toml:"-"`

	// MaxPeers is the maximum number of peers that can be
	// connected. It must be greater than zero.
	// 必选值,最多可以同时连接的节点个数
	// MaxPeers必须指定,而且必须指定一个大于零的数
	MaxPeers int

	// MaxPendingPeers is the maximum number of peers that can be pending in the
	// handshake phase, counted separately for inbound and outbound connections.
	// Zero defaults to preset values.
	// 可选值,默认为50
	// 指正在进行握手阶段的连接个数,inbound和outbound分别进行计数
	MaxPendingPeers int `toml:",omitempty"`

	// DialRatio controls the ratio of inbound to dialed connections.
	// Example: a DialRatio of 2 allows 1/2 of connections to be dialed.
	// Setting DialRatio to zero defaults it to 3.
	// 可选值,默认值3
	// 代表本地主动拨号的节点上限个数所占MaxPeers的比例
	// 默认是最多1/3的节点由本地主动拨号,剩下2/3由远程节点连接本地
	DialRatio int `toml:",omitempty"`

	// NoDiscovery can be used to disable the peer discovery mechanism.
	// Disabling is useful for protocol debugging (manual topology).
	// 可选值,默认为false
	// 默认启用节点发现
	NoDiscovery bool

	// DiscoveryV5 specifies whether the new topic-discovery based V5 discovery
	// protocol should be started or not.
	// 可选值,默认为false
	// 默认不启用v5版本的节点发现
	DiscoveryV5 bool `toml:",omitempty"`

	// Name sets the node name of this server.
	// Use common.MakeName to create a name that follows existing conventions.
	// 可选值,本地节点的名称
	// 通常使用common.MakeName方法来创建本地的名称
	Name string `toml:"-"`

	// BootstrapNodes are used to establish connectivity
	// with the rest of the network.
	// 可选值,代表节点发现过程的初始节点
	BootstrapNodes []*enode.Node

	// BootstrapNodesV5 are used to establish connectivity
	// with the rest of the network using the V5 discovery
	// protocol.
	BootstrapNodesV5 []*enode.Node `toml:",omitempty"`

	// Static nodes are used as pre-configured connections which are always
	// maintained and re-connected on disconnects.
	// 本地会始终尝试与静态节点建立连接,除非达到连接上限
	StaticNodes []*enode.Node

	// Trusted nodes are used as pre-configured connections which are always
	// allowed to connect, even above the peer limit.
	// 在TrustedNodes中的节点不受到连接节点个数的限制
	TrustedNodes []*enode.Node

	// Connectivity can be restricted to certain IP networks.
	// If this option is set to a non-nil value, only hosts which match one of the
	// IP networks contained in the list are considered.
	// 如果此字段不为nil,则本地指定的网段的ip的建立连接
	NetRestrict *netutil.Netlist `toml:",omitempty"`

	// NodeDatabase is the path to the database containing the previously seen
	// live nodes in the network.
	// 保存了之前节点发现结果的数据库的路径
	// 可选值,代表节点数据库的路径
	// 默认值为空,代表使用内存数据库
	NodeDatabase string `toml:",omitempty"`

	// Protocols should contain the protocols supported
	// by the server. Matching protocols are launched for
	// each peer.
	// 可选项,代表本地可以运行的子协议
	Protocols []Protocol `toml:"-"`

	// If ListenAddr is set to a non-nil address, the server
	// will listen for incoming connections.
	//
	// If the port is zero, the operating system will pick a port. The
	// ListenAddr field will be updated with the actual address when
	// the server is started.
	// 可选值,默认是空字符串,代表不启动监听
	// 如果设置端口为0,代表随机监听一个端口,服务器启动后会更新为真正监听的端口
	ListenAddr string

	// If set to a non-nil value, the given NAT port mapper
	// is used to make the listening port available to the
	// Internet.
	// 不是nil,也不是nat.ExtIP的情况下
	// 例如设置为nat.Any(),Server.Start会阻塞一会,探测节点的ip
	// nat.ExtIP是固定了本地的ip为指定的值,不需要再运行upnp或者pmp协议了
	NAT nat.Interface `toml:",omitempty"`

	// If Dialer is set to a non-nil value, the given Dialer
	// is used to dial outbound peer connections.
	// 创建Server的时候可以指定自定义的拨号器
	// 可选值,默认值nil,代表建立实际的tcp连接来拨号
	// 如果是nil,将使用net.Dialer.DialContext进行拨号,也就是自定义的tcpDialer对象
	Dialer NodeDialer `toml:"-"`

	// If NoDial is true, the server will not dial any peers.
	// 如果为true本地不会主动向外进行拨号
	NoDial bool `toml:",omitempty"`

	// If EnableMsgEvents is set then the server will emit PeerEvents
	// whenever a message is sent to or received from a peer
	// 用来控制订阅的管道是否收到节点发送和接收消息的通知
	EnableMsgEvents bool

	// Logger is a custom logger to use with the p2p.Server.
	Logger log.Logger `toml:",omitempty"`
	// contains filtered or unexported fields
}

Config holds Server options. 必须指定的字段 PrivateKey MaxPeers 必须指定大于零的整数 不指定ListenAddr将不会监听tcp连接

type DiscReason

type DiscReason uint

断开连接的原因 Disconnect Reason

const (
	DiscRequested DiscReason = iota
	DiscNetworkError
	DiscProtocolError
	DiscUselessPeer
	DiscTooManyPeers
	DiscAlreadyConnected
	DiscIncompatibleVersion
	DiscInvalidIdentity
	DiscQuitting
	DiscUnexpectedIdentity
	DiscSelf
	DiscReadTimeout
	DiscSubprotocolError = 0x10
)

func (DiscReason) Error

func (d DiscReason) Error() string

实现error接口

func (DiscReason) String

func (d DiscReason) String() string

type Msg

type Msg struct {
	Code uint64
	// 代表Payload中rlp编码的总长度
	Size    uint32 // Size of the raw payload
	Payload io.Reader
	// 消息接收到的时间
	// 在Peer.readLoop函数中设置
	ReceivedAt time.Time
	// contains filtered or unexported fields
}

Msg defines the structure of a p2p message.

Note that a Msg can only be sent once since the Payload reader is consumed during sending. It is not possible to create a Msg and send it any number of times. If you want to reuse an encoded structure, encode the payload into a byte array and create a separate Msg with a bytes.Reader as Payload for each send. p2p网络中传递的消息对象 每个Msg对象只能发送一次,因为发送一次中后内部的Payload是io.Reader类型已经被读取完了

func (Msg) Decode

func (msg Msg) Decode(val interface{}) error

Decode parses the RLP content of a message into the given value, which must be a pointer.

For the decoding rules, please see package rlp. 将Msg.Payload里保存的rlp编码解码成输入的类型 输入的变量必须是指针

func (Msg) Discard

func (msg Msg) Discard() error

Discard reads any remaining payload data into a black hole. 清空Msg.Payload中保存的数据

func (Msg) String

func (msg Msg) String() string

输出消息码和消息的长度

func (Msg) Time

func (msg Msg) Time() time.Time

获得消息接收的时间

type MsgPipeRW

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

MsgPipeRW is an endpoint of a MsgReadWriter pipe. 实现了MsgReadWriter接口 内部保存了两个管道分别用来发送和接收数据

func (*MsgPipeRW) Close

func (p *MsgPipeRW) Close() error

Close unblocks any pending ReadMsg and WriteMsg calls on both ends of the pipe. They will return ErrPipeClosed. Close also interrupts any reads from a message payload. Close函数的目的是关闭closing管道 使用额外变量closed来标记是否关闭过

func (*MsgPipeRW) ReadMsg

func (p *MsgPipeRW) ReadMsg() (Msg, error)

ReadMsg returns a message sent on the other end of the pipe. 接收MsgPipe另一端发送的消息

func (*MsgPipeRW) WriteMsg

func (p *MsgPipeRW) WriteMsg(msg Msg) error

WriteMsg sends a message on the pipe. It blocks until the receiver has consumed the message payload. 向MsgPipe创建的另一头发送消息,这个函数会阻塞直到对方将Msg.Payload中的数据全部读取

type MsgReadWriter

type MsgReadWriter interface {
	MsgReader
	MsgWriter
}

MsgReadWriter provides reading and writing of encoded messages. Implementations should ensure that ReadMsg and WriteMsg can be called simultaneously from multiple goroutines. 对消息可读可写 ReadMsg,WriteMsg

type MsgReader

type MsgReader interface {
	ReadMsg() (Msg, error)
}

读取消息,ReadMsg

type MsgWriter

type MsgWriter interface {
	// WriteMsg sends a message. It will block until the message's
	// Payload has been consumed by the other end.
	//
	// Note that messages can be sent only once because their
	// payload reader is drained.
	WriteMsg(Msg) error
}

写入消息,WriteMsg

type NodeDialer

type NodeDialer interface {
	Dial(context.Context, *enode.Node) (net.Conn, error)
}

NodeDialer is used to connect to nodes in the network, typically by using an underlying net.Dialer but also using net.Pipe in tests. 用来创建与另一个节点的连接 这个接口被tcpDialer和SimAdapter实现,tcpDialer是真正的网络连接,SimAdapter是使用内存管道 这个Dial方法传入的参数是Context和enode.Node 是对下面这个函数的封装,network一般直接指定为tcp,address由enode.Node解析出来 func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error) {

type NodeInfo

type NodeInfo struct {
	ID    string `json:"id"`    // Unique node identifier (also the encryption key)
	Name  string `json:"name"`  // Name of the node, including client type, version, OS, custom data
	Enode string `json:"enode"` // Enode URL for adding this peer from remote peers
	ENR   string `json:"enr"`   // Ethereum Node Record
	IP    string `json:"ip"`    // IP address of the node
	// 本地占用的两个端口
	Ports struct {
		// UDP用于节点发现的端口
		Discovery int `json:"discovery"` // UDP listening port for discovery protocol
		// TCP运行RLPx协议进行数据传输的端口
		Listener int `json:"listener"` // TCP listening port for RLPx
	} `json:"ports"`
	ListenAddr string                 `json:"listenAddr"`
	Protocols  map[string]interface{} `json:"protocols"`
}

NodeInfo represents a short summary of the information known about the host. NodeInfo用来表示本地节点的各种信息 对应的是PeerInfo用来表示本地连接的其他节点的信息

type Peer

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

Peer represents a connected remote node. Peer代表一个本地已经连接的远程节点

func NewPeer

func NewPeer(id enode.ID, name string, caps []Cap) *Peer

NewPeer returns a peer for testing purposes. 只用在测试中

func NewPeerPipe

func NewPeerPipe(id enode.ID, name string, caps []Cap, pipe *MsgPipeRW) *Peer

NewPeerPipe creates a peer for testing purposes. The message pipe given as the last parameter is closed when Disconnect is called on the peer.

func (*Peer) Caps

func (p *Peer) Caps() []Cap

Caps returns the capabilities (supported subprotocols) of the remote peer.

func (*Peer) Disconnect

func (p *Peer) Disconnect(reason DiscReason)

Disconnect terminates the peer connection with the given reason. It returns immediately and does not wait until the connection is closed.

func (*Peer) Fullname

func (p *Peer) Fullname() string

Fullname returns the node name that the remote node advertised. Fullname 就是在Server里定义的Name

func (*Peer) ID

func (p *Peer) ID() enode.ID

ID returns the node's public key.

func (*Peer) Inbound

func (p *Peer) Inbound() bool

Inbound returns true if the peer is an inbound connection Inbound为true代表这个peer主动连接的本地 为false代表本地主动连接的这个peer

func (*Peer) Info

func (p *Peer) Info() *PeerInfo

Info gathers and returns a collection of metadata known about a peer.

func (*Peer) LocalAddr

func (p *Peer) LocalAddr() net.Addr

LocalAddr returns the local address of the network connection.

func (*Peer) Log

func (p *Peer) Log() log.Logger

func (*Peer) Name

func (p *Peer) Name() string

Name returns an abbreviated form of the name Name如果是对Fullname的省略,小于20字节时Name和Fullname一致 Fullname超过20个字节后面使用省略号缩写

func (*Peer) Node

func (p *Peer) Node() *enode.Node

Node returns the peer's node descriptor.

func (*Peer) RemoteAddr

func (p *Peer) RemoteAddr() net.Addr

RemoteAddr returns the remote address of the network connection.

func (*Peer) RunningCap

func (p *Peer) RunningCap(protocol string, versions []uint) bool

RunningCap returns true if the peer is actively connected using any of the enumerated versions of a specific protocol, meaning that at least one of the versions is supported by both this node and the peer p. 判断这个对等节点是否支持运行输入的协议

func (*Peer) String

func (p *Peer) String() string

String implements fmt.Stringer.

type PeerEvent

type PeerEvent struct {
	Type PeerEventType `json:"type"`
	// 事件发生的节点,也就是接收到或发送消息的本地节点的id
	Peer          enode.ID `json:"peer"`
	Error         string   `json:"error,omitempty"`
	Protocol      string   `json:"protocol,omitempty"`
	MsgCode       *uint64  `json:"msg_code,omitempty"`
	MsgSize       *uint32  `json:"msg_size,omitempty"`
	LocalAddress  string   `json:"local,omitempty"`
	RemoteAddress string   `json:"remote,omitempty"`
}

PeerEvent is an event emitted when peers are either added or dropped from a p2p.Server or when a message is sent or received on a peer connection PeerEvent总共有四种,分别是增加或者移除节点,以及接收或发送消息 PeerEventTypeAdd,PeerEventTypeDrop,PeerEventTypeMsgSend,PeerEventTypeMsgRecv

type PeerEventType

type PeerEventType string

PeerEventType is the type of peer events emitted by a p2p.Server

const (
	// PeerEventTypeAdd is the type of event emitted when a peer is added
	// to a p2p.Server
	PeerEventTypeAdd PeerEventType = "add"

	// PeerEventTypeDrop is the type of event emitted when a peer is
	// dropped from a p2p.Server
	PeerEventTypeDrop PeerEventType = "drop"

	// PeerEventTypeMsgSend is the type of event emitted when a
	// message is successfully sent to a peer
	PeerEventTypeMsgSend PeerEventType = "msgsend"

	// PeerEventTypeMsgRecv is the type of event emitted when a
	// message is received from a peer
	PeerEventTypeMsgRecv PeerEventType = "msgrecv"
)

type PeerInfo

type PeerInfo struct {
	ENR     string   `json:"enr,omitempty"` // Ethereum Node Record
	Enode   string   `json:"enode"`         // Node URL
	ID      string   `json:"id"`            // Unique node identifier
	Name    string   `json:"name"`          // Name of the node, including client type, version, OS, custom data
	Caps    []string `json:"caps"`          // Protocols advertised by this peer
	Network struct {
		LocalAddress  string `json:"localAddress"`  // Local endpoint of the TCP data connection
		RemoteAddress string `json:"remoteAddress"` // Remote endpoint of the TCP data connection
		Inbound       bool   `json:"inbound"`
		Trusted       bool   `json:"trusted"`
		Static        bool   `json:"static"`
	} `json:"network"`
	Protocols map[string]interface{} `json:"protocols"` // Sub-protocol specific metadata fields
}

PeerInfo represents a short summary of the information known about a connected peer. Sub-protocol independent fields are contained and initialized here, with protocol specifics delegated to all connected sub-protocols.

type Protocol

type Protocol struct {
	// Name should contain the official protocol name,
	// often a three-letter word.
	// 官方的协议名称,一般是一个三个字母的单词
	Name string

	// Version should contain the version number of the protocol.
	Version uint

	// Length should contain the number of message codes used
	// by the protocol.
	// 代表不同messsage code的个数,也就是消息的类型总数
	// 由于message code从0开始,所以所有的message code都必须小于Length
	Length uint64

	// Run is called in a new goroutine when the protocol has been
	// negotiated with a peer. It should read and write messages from
	// rw. The Payload for each message must be fully consumed.
	//
	// The peer connection is closed when Start returns. It should return
	// any protocol-level error (such as an I/O error) that is
	// encountered.
	// Run 在与一个节点握手成功后调用,在单独协程中执行.
	// 可以通过rw来接收和发送消息,所有接收的消息的Payload必须被全部读取
	Run func(peer *Peer, rw MsgReadWriter) error

	// NodeInfo is an optional helper method to retrieve protocol specific metadata
	// about the host node.
	NodeInfo func() interface{}

	// PeerInfo is an optional helper method to retrieve protocol specific metadata
	// about a certain peer in the network. If an info retrieval function is set,
	// but returns nil, it is assumed that the protocol handshake is still running.
	PeerInfo func(id enode.ID) interface{}

	// DialCandidates, if non-nil, is a way to tell Server about protocol-specific nodes
	// that should be dialed. The server continuously reads nodes from the iterator and
	// attempts to create connections to them.
	// 用于为不同的协议指定不同的节点
	DialCandidates enode.Iterator

	// Attributes contains protocol specific information for the node record.
	// 节点记录中增加的额外信息
	Attributes []enr.Entry
}

Protocol represents a P2P subprotocol implementation. 由外部定义的子协议对象

type Server

type Server struct {
	// Config fields may not be modified while the server is running.
	Config

	DiscV5 *discover.UDPv5
	// contains filtered or unexported fields
}

Server manages all peer connections.

func (*Server) AddPeer

func (srv *Server) AddPeer(node *enode.Node)

AddPeer adds the given node to the static node set. When there is room in the peer set, the server will connect to the node. If the connection fails for any reason, the server will attempt to reconnect the peer. 添加静态节点

func (*Server) AddTrustedPeer

func (srv *Server) AddTrustedPeer(node *enode.Node)

AddTrustedPeer adds the given node to a reserved trusted list which allows the node to always connect, even if the slot are full.

func (*Server) LocalNode

func (srv *Server) LocalNode() *enode.LocalNode

LocalNode returns the local node record.

func (*Server) NodeInfo

func (srv *Server) NodeInfo() *NodeInfo

NodeInfo gathers and returns a collection of metadata known about the host. 获取本地节点的相关信息

func (*Server) PeerCount

func (srv *Server) PeerCount() int

PeerCount returns the number of connected peers. 获取当前连接的节点个数

func (*Server) Peers

func (srv *Server) Peers() []*Peer

Peers returns all connected peers. 获取所有的对等节点

func (*Server) PeersInfo

func (srv *Server) PeersInfo() []*PeerInfo

PeersInfo returns an array of metadata objects describing connected peers. 获取本地连接的所有节点的信息 返回的所有信息根据节点的ID从小到大排序

func (*Server) RemovePeer

func (srv *Server) RemovePeer(node *enode.Node)

RemovePeer removes a node from the static node set. It also disconnects from the given node if it is currently connected as a peer.

This method blocks until all protocols have exited and the peer is removed. Do not use RemovePeer in protocol implementations, call Disconnect on the Peer instead. 从静态节点中删除指定的节点,然后断开与该节点的连接

func (*Server) RemoveTrustedPeer

func (srv *Server) RemoveTrustedPeer(node *enode.Node)

RemoveTrustedPeer removes the given node from the trusted peer set.

func (*Server) Self

func (srv *Server) Self() *enode.Node

Self returns the local node's endpoint information. 获取Server对应的enode.Node对象 在Server调用Start前获取到v4版本 在Server调用Start后获取到enr记录

func (*Server) SetupConn

func (srv *Server) SetupConn(fd net.Conn, flags connFlag, dialDest *enode.Node) error

SetupConn runs the handshakes and attempts to add the connection as a peer. It returns when the connection has been added as a peer or the handshakes have failed. Server必须已经调用了Start方法,在运行过程中 SetupConn在传入的net.Conn连接上执行握手过程,生成的所有net.Conn对象都会进入这里处理 如果握手成功将新增一个对等节点,否则返回错误 调用的时机有两个分别是

在listenLoop中本地监听到了来自远程发起的连接
本地对外部节点拨号成功获得了net.Conn对象,在dialTask.dial中调用

这是一个公开方法,外部如果建立了网络连接,也可以通过这个方法在该连接上执行握手过程,如果成功将添加一个Peer

func (*Server) Start

func (srv *Server) Start() (err error)

Start starts running the server. Servers can not be re-used after stopping.

func (*Server) Stop

func (srv *Server) Stop()

Stop terminates the server and all active peer connections. It blocks until all active connections have been closed.

func (*Server) SubscribeEvents

func (srv *Server) SubscribeEvents(ch chan *PeerEvent) event.Subscription

SubscribeEvents subscribes the given channel to peer events 订阅节点事件,每当有新节点添加或者删除的时候输入的管道会接收到通知

Directories

Path Synopsis
v4wire
Package v4wire implements the Discovery v4 Wire Protocol.
Package v4wire implements the Discovery v4 Wire Protocol.
Package dnsdisc implements node discovery via DNS (EIP-1459).
Package dnsdisc implements node discovery via DNS (EIP-1459).
Package enr implements Ethereum Node Records as defined in EIP-778.
Package enr implements Ethereum Node Records as defined in EIP-778.
Package msgrate allows estimating the throughput of peers for more balanced syncs.
Package msgrate allows estimating the throughput of peers for more balanced syncs.
Package nat provides access to common network port mapping protocols.
Package nat provides access to common network port mapping protocols.
Package netutil contains extensions to the net package.
Package netutil contains extensions to the net package.
Package rlpx implements the RLPx transport protocol.
Package rlpx implements the RLPx transport protocol.
Package simulations simulates p2p networks.
Package simulations simulates p2p networks.

Jump to

Keyboard shortcuts

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