1. Service
Service 抽象两类功能的集合:
Protocol
:p2p 节点间交互协议
API
:为客户端提供的 RPC 接口
service 接口定义 service.go
// Service is an individual protocol that can be registered into a node.
//
// Notes:
//
// • Service life-cycle management is delegated to the node. The service is allowed to
// initialize itself upon creation, but no goroutines should be spun up outside of the
// Start method.
//
// • Restart logic is not required as the node will create a fresh instance
// every time a service is started.
type Service interface {
// Protocols retrieves the P2P protocols the service wishes to start.
Protocols() []p2p.Protocol
// APIs retrieves the list of RPC descriptors the service provides
APIs() []rpc.API
// Start is called after all services have been constructed and the networking
// layer was also initialized to spawn any goroutines required by the service.
Start(server *p2p.Server) error
// Stop terminates all goroutines belonging to the service, blocking until they
// are all terminated.
Stop() error
}
1.1 Protocol
Protocol 表示P2P子协议实现,当有其他 Peer 连接过来的时候会匹配双方的 Protocols
随后调用 Protocol 中定义的 Run
函数。
Protocol 结构体定义 protocol.go
// Protocol represents a P2P subprotocol implementation.
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.
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 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
}
1.2 API
API描述了对外的 RPC 接口,通过 reflect
机制将 Service
字段指定的具体实现的 Exported Method
集合到同一 Namespace
下,之后客户端通过 Namespace
+ Method Name
调用 API。
API 的 Service 对外提供的方法需要遵循一定的格式:
PubSub
:第一个参数为 context.Context
,返回值定义为 (rpc.Subscription, error)
其他 :方法返回值不能超过两个,并且最后一个必须是 error
从代码逻辑理解,同 Namespace 下,方法有覆盖风险,API 注册见 rpc/service.go
API 结构体定义 types.go
// API describes the set of methods offered over the RPC interface
type API struct {
Namespace string // namespace under which the rpc methods of Service are exposed
Version string // api version for DApp's
Service interface{
} // receiver instance which holds the methods
Public bool // indication if the methods must be considered safe for public use
}
2. Node
Node 示例代表一个 Ethereum
节点,geth
启动过程中向 Node
注册 Service ,在 Node Start 阶段:
- 按注册顺序调用 Service 构造函数
- 通过
Protocols()
收集服务支持的 p2p 子协议,由 p2p.Server 管理 Protocols - 调用 Service 的 Start 方法
- 调用 Node 的 startRPC 方法
3. 存在问题
- 没有完善的 Service 间依赖关系管理,类似功能 containerd 处理的更好
- 同命名空间下方法可能被覆盖,没提示