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 處理的更好
- 同命名空間下方法可能被覆蓋,沒提示