From e51b09da0dfd648a5a45a6b2e9cdd473cae7cbb5 Mon Sep 17 00:00:00 2001
From: mempirate <jonas.bostoen@student.kdg.be>
Date: Thu, 17 Jun 2021 23:55:20 +0200
Subject: [PATCH] Implements net_peerCount RPC call for internal sentries
 (#2172)

* Implement API and protobuf

* Squashed 'interfaces/' content from commit cd3eca28e

git-subtree-dir: interfaces
git-subtree-split: cd3eca28e50367af9de52fca863b1d7528bff774

* Implement net_peerCount RPC call

* Squashed 'interfaces/' content from commit cd3eca28e

git-subtree-dir: interfaces
git-subtree-split: cd3eca28e50367af9de52fca863b1d7528bff774

* Fixing merge conflicts

* Remove p2p.Server from Ethereum backend

* Fix peerCount calculation for internal sentries

* Bump eth backend API version

* Update rpcdaemon README

* Document version change
---
 cmd/rpcdaemon/README.md                   |   2 +-
 cmd/rpcdaemon/commands/net_api.go         |  18 +-
 cmd/rpcdaemon/services/eth_backend.go     |  13 +
 eth/backend.go                            |  23 +-
 ethdb/remote/remotedbserver/ethbackend.go |  12 +-
 gointerfaces/remote/ethbackend.pb.go      | 313 +++++++++++++++-------
 gointerfaces/remote/ethbackend_grpc.pb.go |  36 +++
 interfaces/remote/ethbackend.proto        |   6 +
 8 files changed, 318 insertions(+), 105 deletions(-)

diff --git a/cmd/rpcdaemon/README.md b/cmd/rpcdaemon/README.md
index 7a4894de79..4bf00d0e3e 100644
--- a/cmd/rpcdaemon/README.md
+++ b/cmd/rpcdaemon/README.md
@@ -103,7 +103,7 @@ The following table shows the current implementation status of Erigon's RPC daem
 | web3_sha3                                  | Yes     |                                            |
 |                                            |         |                                            |
 | net_listening                              | HC      | (remote only hard coded returns true)      |
-| net_peerCount                              | HC      | (hard coded 25 - work continues on Sentry) |
+| net_peerCount                              | Limited | internal sentries only                     |
 | net_version                                | Yes     | remote only                                |
 |                                            |         |                                            |
 | eth_blockNumber                            | Yes     |                                            |
diff --git a/cmd/rpcdaemon/commands/net_api.go b/cmd/rpcdaemon/commands/net_api.go
index 9931a7c879..3ccc43ec87 100644
--- a/cmd/rpcdaemon/commands/net_api.go
+++ b/cmd/rpcdaemon/commands/net_api.go
@@ -49,8 +49,18 @@ func (api *NetAPIImpl) Version(ctx context.Context) (string, error) {
 	return strconv.FormatUint(res, 10), nil
 }
 
-// PeerCount implements net_peerCount. Returns number of peers currently connected to the client.
-// TODO: This routine currently returns a hard coded value of '25'
-func (api *NetAPIImpl) PeerCount(_ context.Context) (hexutil.Uint, error) {
-	return hexutil.Uint(25), nil
+// PeerCount implements net_peerCount. Returns number of peers currently
+// connected to the first sentry server.
+func (api *NetAPIImpl) PeerCount(ctx context.Context) (hexutil.Uint, error) {
+	if api.ethBackend == nil {
+		// We're running in --datadir mode or otherwise cannot get the backend
+		return 0, fmt.Errorf(NotAvailableChainData, "net_peerCount")
+	}
+
+	res, err := api.ethBackend.NetPeerCount(ctx)
+	if err != nil {
+		return 0, err
+	}
+
+	return hexutil.Uint(res), nil
 }
diff --git a/cmd/rpcdaemon/services/eth_backend.go b/cmd/rpcdaemon/services/eth_backend.go
index a7f1419140..c0ecffc2e7 100644
--- a/cmd/rpcdaemon/services/eth_backend.go
+++ b/cmd/rpcdaemon/services/eth_backend.go
@@ -22,6 +22,7 @@ import (
 type ApiBackend interface {
 	Etherbase(ctx context.Context) (common.Address, error)
 	NetVersion(ctx context.Context) (uint64, error)
+	NetPeerCount(ctx context.Context) (uint64, error)
 	ProtocolVersion(ctx context.Context) (uint64, error)
 	ClientVersion(ctx context.Context) (string, error)
 	Subscribe(ctx context.Context, cb func(*remote.SubscribeReply)) error
@@ -82,6 +83,18 @@ func (back *RemoteBackend) NetVersion(ctx context.Context) (uint64, error) {
 	return res.Id, nil
 }
 
+func (back *RemoteBackend) NetPeerCount(ctx context.Context) (uint64, error) {
+	res, err := back.remoteEthBackend.NetPeerCount(ctx, &remote.NetPeerCountRequest{})
+	if err != nil {
+		if s, ok := status.FromError(err); ok {
+			return 0, errors.New(s.Message())
+		}
+		return 0, err
+	}
+
+	return res.Id, nil
+}
+
 func (back *RemoteBackend) ProtocolVersion(ctx context.Context) (uint64, error) {
 	res, err := back.remoteEthBackend.ProtocolVersion(ctx, &remote.ProtocolVersionRequest{})
 	if err != nil {
diff --git a/eth/backend.go b/eth/backend.go
index 4e9460f70b..bad1850688 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -88,8 +88,6 @@ type Ethereum struct {
 
 	networkID uint64
 
-	p2pServer *p2p.Server
-
 	torrentClient *snapshotsync.Client
 
 	lock              sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)
@@ -174,7 +172,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
 		chainKV:              chainDb.(ethdb.HasRwKV).RwKV(),
 		networkID:            config.NetworkID,
 		etherbase:            config.Miner.Etherbase,
-		p2pServer:            stack.Server(),
 		torrentClient:        torrentClient,
 		chainConfig:          chainConfig,
 		genesisHash:          genesis.Hash(),
@@ -612,6 +609,26 @@ func (s *Ethereum) IsMining() bool { return s.config.Miner.Enabled }
 func (s *Ethereum) TxPool() *core.TxPool        { return s.txPool }
 func (s *Ethereum) ChainKV() ethdb.RwKV         { return s.chainKV }
 func (s *Ethereum) NetVersion() (uint64, error) { return s.networkID, nil }
+func (s *Ethereum) NetPeerCount() (uint64, error) {
+	// TODO (mempirate): Get peers for all sentries (internal and external)
+	// and return unique count
+	peers := make(map[string]interface{})
+	for _, ss := range s.sentryServers {
+		ss.Peers.Range(func(key, value interface{}) bool {
+			peerID := key.(string)
+			x, _ := ss.Peers.Load(peerID)
+			peerInfo, _ := x.(*download.PeerInfo)
+			if peerInfo == nil {
+				return true
+			}
+			peers[peerID] = peerInfo
+			return true
+		})
+	}
+
+	// TODO (mempirate): Loop over external sentries too
+	return uint64(len(peers)), nil
+}
 
 // Protocols returns all the currently configured
 // network protocols to start.
diff --git a/ethdb/remote/remotedbserver/ethbackend.go b/ethdb/remote/remotedbserver/ethbackend.go
index 3811c5c9f1..268cab1702 100644
--- a/ethdb/remote/remotedbserver/ethbackend.go
+++ b/ethdb/remote/remotedbserver/ethbackend.go
@@ -17,7 +17,8 @@ import (
 
 // EthBackendAPIVersion
 // 2.0.0 - move all mining-related methods to 'txpool/mining' server
-var EthBackendAPIVersion = &types2.VersionReply{Major: 2, Minor: 0, Patch: 0}
+// 2.1.0 - add NetPeerCount function
+var EthBackendAPIVersion = &types2.VersionReply{Major: 2, Minor: 1, Patch: 0}
 
 type EthBackendServer struct {
 	remote.UnimplementedETHBACKENDServer // must be embedded to have forward compatible implementations.
@@ -29,6 +30,7 @@ type EthBackendServer struct {
 type EthBackend interface {
 	Etherbase() (common.Address, error)
 	NetVersion() (uint64, error)
+	NetPeerCount() (uint64, error)
 }
 
 func NewEthBackendServer(eth EthBackend, events *Events) *EthBackendServer {
@@ -59,6 +61,14 @@ func (s *EthBackendServer) NetVersion(_ context.Context, _ *remote.NetVersionReq
 	return &remote.NetVersionReply{Id: id}, nil
 }
 
+func (s *EthBackendServer) NetPeerCount(_ context.Context, _ *remote.NetPeerCountRequest) (*remote.NetPeerCountReply, error) {
+	id, err := s.eth.NetPeerCount()
+	if err != nil {
+		return &remote.NetPeerCountReply{}, err
+	}
+	return &remote.NetPeerCountReply{Id: id}, nil
+}
+
 func (s *EthBackendServer) Subscribe(r *remote.SubscribeRequest, subscribeServer remote.ETHBACKEND_SubscribeServer) error {
 	log.Debug("establishing event subscription channel with the RPC daemon")
 	s.events.AddHeaderSubscription(func(h *types.Header) error {
diff --git a/gointerfaces/remote/ethbackend.pb.go b/gointerfaces/remote/ethbackend.pb.go
index f4b031bcbd..0c5a9c46ea 100644
--- a/gointerfaces/remote/ethbackend.pb.go
+++ b/gointerfaces/remote/ethbackend.pb.go
@@ -241,6 +241,91 @@ func (x *NetVersionReply) GetId() uint64 {
 	return 0
 }
 
+type NetPeerCountRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *NetPeerCountRequest) Reset() {
+	*x = NetPeerCountRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_remote_ethbackend_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *NetPeerCountRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*NetPeerCountRequest) ProtoMessage() {}
+
+func (x *NetPeerCountRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_remote_ethbackend_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use NetPeerCountRequest.ProtoReflect.Descriptor instead.
+func (*NetPeerCountRequest) Descriptor() ([]byte, []int) {
+	return file_remote_ethbackend_proto_rawDescGZIP(), []int{4}
+}
+
+type NetPeerCountReply struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
+}
+
+func (x *NetPeerCountReply) Reset() {
+	*x = NetPeerCountReply{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_remote_ethbackend_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *NetPeerCountReply) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*NetPeerCountReply) ProtoMessage() {}
+
+func (x *NetPeerCountReply) ProtoReflect() protoreflect.Message {
+	mi := &file_remote_ethbackend_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use NetPeerCountReply.ProtoReflect.Descriptor instead.
+func (*NetPeerCountReply) Descriptor() ([]byte, []int) {
+	return file_remote_ethbackend_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *NetPeerCountReply) GetId() uint64 {
+	if x != nil {
+		return x.Id
+	}
+	return 0
+}
+
 type ProtocolVersionRequest struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -250,7 +335,7 @@ type ProtocolVersionRequest struct {
 func (x *ProtocolVersionRequest) Reset() {
 	*x = ProtocolVersionRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_remote_ethbackend_proto_msgTypes[4]
+		mi := &file_remote_ethbackend_proto_msgTypes[6]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -263,7 +348,7 @@ func (x *ProtocolVersionRequest) String() string {
 func (*ProtocolVersionRequest) ProtoMessage() {}
 
 func (x *ProtocolVersionRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_remote_ethbackend_proto_msgTypes[4]
+	mi := &file_remote_ethbackend_proto_msgTypes[6]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -276,7 +361,7 @@ func (x *ProtocolVersionRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ProtocolVersionRequest.ProtoReflect.Descriptor instead.
 func (*ProtocolVersionRequest) Descriptor() ([]byte, []int) {
-	return file_remote_ethbackend_proto_rawDescGZIP(), []int{4}
+	return file_remote_ethbackend_proto_rawDescGZIP(), []int{6}
 }
 
 type ProtocolVersionReply struct {
@@ -290,7 +375,7 @@ type ProtocolVersionReply struct {
 func (x *ProtocolVersionReply) Reset() {
 	*x = ProtocolVersionReply{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_remote_ethbackend_proto_msgTypes[5]
+		mi := &file_remote_ethbackend_proto_msgTypes[7]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -303,7 +388,7 @@ func (x *ProtocolVersionReply) String() string {
 func (*ProtocolVersionReply) ProtoMessage() {}
 
 func (x *ProtocolVersionReply) ProtoReflect() protoreflect.Message {
-	mi := &file_remote_ethbackend_proto_msgTypes[5]
+	mi := &file_remote_ethbackend_proto_msgTypes[7]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -316,7 +401,7 @@ func (x *ProtocolVersionReply) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ProtocolVersionReply.ProtoReflect.Descriptor instead.
 func (*ProtocolVersionReply) Descriptor() ([]byte, []int) {
-	return file_remote_ethbackend_proto_rawDescGZIP(), []int{5}
+	return file_remote_ethbackend_proto_rawDescGZIP(), []int{7}
 }
 
 func (x *ProtocolVersionReply) GetId() uint64 {
@@ -335,7 +420,7 @@ type ClientVersionRequest struct {
 func (x *ClientVersionRequest) Reset() {
 	*x = ClientVersionRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_remote_ethbackend_proto_msgTypes[6]
+		mi := &file_remote_ethbackend_proto_msgTypes[8]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -348,7 +433,7 @@ func (x *ClientVersionRequest) String() string {
 func (*ClientVersionRequest) ProtoMessage() {}
 
 func (x *ClientVersionRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_remote_ethbackend_proto_msgTypes[6]
+	mi := &file_remote_ethbackend_proto_msgTypes[8]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -361,7 +446,7 @@ func (x *ClientVersionRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ClientVersionRequest.ProtoReflect.Descriptor instead.
 func (*ClientVersionRequest) Descriptor() ([]byte, []int) {
-	return file_remote_ethbackend_proto_rawDescGZIP(), []int{6}
+	return file_remote_ethbackend_proto_rawDescGZIP(), []int{8}
 }
 
 type ClientVersionReply struct {
@@ -375,7 +460,7 @@ type ClientVersionReply struct {
 func (x *ClientVersionReply) Reset() {
 	*x = ClientVersionReply{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_remote_ethbackend_proto_msgTypes[7]
+		mi := &file_remote_ethbackend_proto_msgTypes[9]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -388,7 +473,7 @@ func (x *ClientVersionReply) String() string {
 func (*ClientVersionReply) ProtoMessage() {}
 
 func (x *ClientVersionReply) ProtoReflect() protoreflect.Message {
-	mi := &file_remote_ethbackend_proto_msgTypes[7]
+	mi := &file_remote_ethbackend_proto_msgTypes[9]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -401,7 +486,7 @@ func (x *ClientVersionReply) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use ClientVersionReply.ProtoReflect.Descriptor instead.
 func (*ClientVersionReply) Descriptor() ([]byte, []int) {
-	return file_remote_ethbackend_proto_rawDescGZIP(), []int{7}
+	return file_remote_ethbackend_proto_rawDescGZIP(), []int{9}
 }
 
 func (x *ClientVersionReply) GetNodeName() string {
@@ -422,7 +507,7 @@ type SubscribeRequest struct {
 func (x *SubscribeRequest) Reset() {
 	*x = SubscribeRequest{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_remote_ethbackend_proto_msgTypes[8]
+		mi := &file_remote_ethbackend_proto_msgTypes[10]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -435,7 +520,7 @@ func (x *SubscribeRequest) String() string {
 func (*SubscribeRequest) ProtoMessage() {}
 
 func (x *SubscribeRequest) ProtoReflect() protoreflect.Message {
-	mi := &file_remote_ethbackend_proto_msgTypes[8]
+	mi := &file_remote_ethbackend_proto_msgTypes[10]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -448,7 +533,7 @@ func (x *SubscribeRequest) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SubscribeRequest.ProtoReflect.Descriptor instead.
 func (*SubscribeRequest) Descriptor() ([]byte, []int) {
-	return file_remote_ethbackend_proto_rawDescGZIP(), []int{8}
+	return file_remote_ethbackend_proto_rawDescGZIP(), []int{10}
 }
 
 func (x *SubscribeRequest) GetType() Event {
@@ -470,7 +555,7 @@ type SubscribeReply struct {
 func (x *SubscribeReply) Reset() {
 	*x = SubscribeReply{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_remote_ethbackend_proto_msgTypes[9]
+		mi := &file_remote_ethbackend_proto_msgTypes[11]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -483,7 +568,7 @@ func (x *SubscribeReply) String() string {
 func (*SubscribeReply) ProtoMessage() {}
 
 func (x *SubscribeReply) ProtoReflect() protoreflect.Message {
-	mi := &file_remote_ethbackend_proto_msgTypes[9]
+	mi := &file_remote_ethbackend_proto_msgTypes[11]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -496,7 +581,7 @@ func (x *SubscribeReply) ProtoReflect() protoreflect.Message {
 
 // Deprecated: Use SubscribeReply.ProtoReflect.Descriptor instead.
 func (*SubscribeReply) Descriptor() ([]byte, []int) {
-	return file_remote_ethbackend_proto_rawDescGZIP(), []int{9}
+	return file_remote_ethbackend_proto_rawDescGZIP(), []int{11}
 }
 
 func (x *SubscribeReply) GetType() Event {
@@ -529,55 +614,63 @@ var file_remote_ethbackend_proto_rawDesc = []byte{
 	0x0a, 0x11, 0x4e, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
 	0x65, 0x73, 0x74, 0x22, 0x21, 0x0a, 0x0f, 0x4e, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
 	0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x18, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,
-	0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x22, 0x26, 0x0a, 0x14, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73,
-	0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x6c, 0x69, 0x65,
-	0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x22, 0x30, 0x0a, 0x12, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
-	0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61,
-	0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61,
-	0x6d, 0x65, 0x22, 0x35, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x45, 0x76,
-	0x65, 0x6e, 0x74, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x47, 0x0a, 0x0e, 0x53, 0x75, 0x62,
-	0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x21, 0x0a, 0x04, 0x74,
-	0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x72, 0x65, 0x6d, 0x6f,
-	0x74, 0x65, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12,
-	0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61,
-	0x74, 0x61, 0x2a, 0x38, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0a, 0x0a, 0x06, 0x48,
-	0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x45, 0x4e, 0x44, 0x49,
-	0x4e, 0x47, 0x5f, 0x4c, 0x4f, 0x47, 0x53, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x45, 0x4e,
-	0x44, 0x49, 0x4e, 0x47, 0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x02, 0x32, 0xa2, 0x03, 0x0a,
-	0x0a, 0x45, 0x54, 0x48, 0x42, 0x41, 0x43, 0x4b, 0x45, 0x4e, 0x44, 0x12, 0x3d, 0x0a, 0x09, 0x45,
-	0x74, 0x68, 0x65, 0x72, 0x62, 0x61, 0x73, 0x65, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74,
-	0x65, 0x2e, 0x45, 0x74, 0x68, 0x65, 0x72, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
-	0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x45, 0x74, 0x68, 0x65,
-	0x72, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x40, 0x0a, 0x0a, 0x4e, 0x65,
-	0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74,
-	0x65, 0x2e, 0x4e, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
-	0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x4e, 0x65, 0x74,
-	0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x36, 0x0a, 0x07,
-	0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
-	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a,
-	0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52,
-	0x65, 0x70, 0x6c, 0x79, 0x12, 0x4f, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
-	0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
-	0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
-	0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
-	0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x49, 0x0a, 0x0d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56,
-	0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e,
-	0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x43, 0x6c,
-	0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79,
-	0x12, 0x3f, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x12, 0x18, 0x2e,
-	0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65,
-	0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x30,
-	0x01, 0x42, 0x11, 0x5a, 0x0f, 0x2e, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x3b, 0x72, 0x65,
-	0x6d, 0x6f, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x4e, 0x65, 0x74, 0x50, 0x65, 0x65,
+	0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x23, 0x0a,
+	0x11, 0x4e, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70,
+	0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02,
+	0x69, 0x64, 0x22, 0x18, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65,
+	0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x26, 0x0a, 0x14,
+	0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52,
+	0x65, 0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x02, 0x69, 0x64, 0x22, 0x16, 0x0a, 0x14, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65,
+	0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x30, 0x0a, 0x12,
+	0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70,
+	0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x35,
+	0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e,
+	0x32, 0x0d, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52,
+	0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x47, 0x0a, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69,
+	0x62, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x45,
+	0x76, 0x65, 0x6e, 0x74, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61,
+	0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x2a, 0x38,
+	0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x0a, 0x0a, 0x06, 0x48, 0x45, 0x41, 0x44, 0x45,
+	0x52, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x4c,
+	0x4f, 0x47, 0x53, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47,
+	0x5f, 0x42, 0x4c, 0x4f, 0x43, 0x4b, 0x10, 0x02, 0x32, 0xea, 0x03, 0x0a, 0x0a, 0x45, 0x54, 0x48,
+	0x42, 0x41, 0x43, 0x4b, 0x45, 0x4e, 0x44, 0x12, 0x3d, 0x0a, 0x09, 0x45, 0x74, 0x68, 0x65, 0x72,
+	0x62, 0x61, 0x73, 0x65, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x45, 0x74,
+	0x68, 0x65, 0x72, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16,
+	0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x45, 0x74, 0x68, 0x65, 0x72, 0x62, 0x61, 0x73,
+	0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x40, 0x0a, 0x0a, 0x4e, 0x65, 0x74, 0x56, 0x65, 0x72,
+	0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x4e, 0x65,
+	0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x17, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x4e, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73,
+	0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x46, 0x0a, 0x0c, 0x4e, 0x65, 0x74, 0x50,
+	0x65, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1b, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74,
+	0x65, 0x2e, 0x4e, 0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x4e,
+	0x65, 0x74, 0x50, 0x65, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79,
+	0x12, 0x36, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f,
+	0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
+	0x70, 0x74, 0x79, 0x1a, 0x13, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x56, 0x65, 0x72, 0x73,
+	0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x4f, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x74,
+	0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x72, 0x65,
+	0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72,
+	0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x72, 0x65,
+	0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72,
+	0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x49, 0x0a, 0x0d, 0x43, 0x6c, 0x69,
+	0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x2e, 0x72, 0x65, 0x6d,
+	0x6f, 0x74, 0x65, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
+	0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74,
+	0x65, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52,
+	0x65, 0x70, 0x6c, 0x79, 0x12, 0x3f, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62,
+	0x65, 0x12, 0x18, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63,
+	0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x65,
+	0x6d, 0x6f, 0x74, 0x65, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65,
+	0x70, 0x6c, 0x79, 0x30, 0x01, 0x42, 0x11, 0x5a, 0x0f, 0x2e, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x74,
+	0x65, 0x3b, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -593,41 +686,45 @@ func file_remote_ethbackend_proto_rawDescGZIP() []byte {
 }
 
 var file_remote_ethbackend_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
-var file_remote_ethbackend_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
+var file_remote_ethbackend_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
 var file_remote_ethbackend_proto_goTypes = []interface{}{
 	(Event)(0),                     // 0: remote.Event
 	(*EtherbaseRequest)(nil),       // 1: remote.EtherbaseRequest
 	(*EtherbaseReply)(nil),         // 2: remote.EtherbaseReply
 	(*NetVersionRequest)(nil),      // 3: remote.NetVersionRequest
 	(*NetVersionReply)(nil),        // 4: remote.NetVersionReply
-	(*ProtocolVersionRequest)(nil), // 5: remote.ProtocolVersionRequest
-	(*ProtocolVersionReply)(nil),   // 6: remote.ProtocolVersionReply
-	(*ClientVersionRequest)(nil),   // 7: remote.ClientVersionRequest
-	(*ClientVersionReply)(nil),     // 8: remote.ClientVersionReply
-	(*SubscribeRequest)(nil),       // 9: remote.SubscribeRequest
-	(*SubscribeReply)(nil),         // 10: remote.SubscribeReply
-	(*types.H160)(nil),             // 11: types.H160
-	(*emptypb.Empty)(nil),          // 12: google.protobuf.Empty
-	(*types.VersionReply)(nil),     // 13: types.VersionReply
+	(*NetPeerCountRequest)(nil),    // 5: remote.NetPeerCountRequest
+	(*NetPeerCountReply)(nil),      // 6: remote.NetPeerCountReply
+	(*ProtocolVersionRequest)(nil), // 7: remote.ProtocolVersionRequest
+	(*ProtocolVersionReply)(nil),   // 8: remote.ProtocolVersionReply
+	(*ClientVersionRequest)(nil),   // 9: remote.ClientVersionRequest
+	(*ClientVersionReply)(nil),     // 10: remote.ClientVersionReply
+	(*SubscribeRequest)(nil),       // 11: remote.SubscribeRequest
+	(*SubscribeReply)(nil),         // 12: remote.SubscribeReply
+	(*types.H160)(nil),             // 13: types.H160
+	(*emptypb.Empty)(nil),          // 14: google.protobuf.Empty
+	(*types.VersionReply)(nil),     // 15: types.VersionReply
 }
 var file_remote_ethbackend_proto_depIdxs = []int32{
-	11, // 0: remote.EtherbaseReply.address:type_name -> types.H160
+	13, // 0: remote.EtherbaseReply.address:type_name -> types.H160
 	0,  // 1: remote.SubscribeRequest.type:type_name -> remote.Event
 	0,  // 2: remote.SubscribeReply.type:type_name -> remote.Event
 	1,  // 3: remote.ETHBACKEND.Etherbase:input_type -> remote.EtherbaseRequest
 	3,  // 4: remote.ETHBACKEND.NetVersion:input_type -> remote.NetVersionRequest
-	12, // 5: remote.ETHBACKEND.Version:input_type -> google.protobuf.Empty
-	5,  // 6: remote.ETHBACKEND.ProtocolVersion:input_type -> remote.ProtocolVersionRequest
-	7,  // 7: remote.ETHBACKEND.ClientVersion:input_type -> remote.ClientVersionRequest
-	9,  // 8: remote.ETHBACKEND.Subscribe:input_type -> remote.SubscribeRequest
-	2,  // 9: remote.ETHBACKEND.Etherbase:output_type -> remote.EtherbaseReply
-	4,  // 10: remote.ETHBACKEND.NetVersion:output_type -> remote.NetVersionReply
-	13, // 11: remote.ETHBACKEND.Version:output_type -> types.VersionReply
-	6,  // 12: remote.ETHBACKEND.ProtocolVersion:output_type -> remote.ProtocolVersionReply
-	8,  // 13: remote.ETHBACKEND.ClientVersion:output_type -> remote.ClientVersionReply
-	10, // 14: remote.ETHBACKEND.Subscribe:output_type -> remote.SubscribeReply
-	9,  // [9:15] is the sub-list for method output_type
-	3,  // [3:9] is the sub-list for method input_type
+	5,  // 5: remote.ETHBACKEND.NetPeerCount:input_type -> remote.NetPeerCountRequest
+	14, // 6: remote.ETHBACKEND.Version:input_type -> google.protobuf.Empty
+	7,  // 7: remote.ETHBACKEND.ProtocolVersion:input_type -> remote.ProtocolVersionRequest
+	9,  // 8: remote.ETHBACKEND.ClientVersion:input_type -> remote.ClientVersionRequest
+	11, // 9: remote.ETHBACKEND.Subscribe:input_type -> remote.SubscribeRequest
+	2,  // 10: remote.ETHBACKEND.Etherbase:output_type -> remote.EtherbaseReply
+	4,  // 11: remote.ETHBACKEND.NetVersion:output_type -> remote.NetVersionReply
+	6,  // 12: remote.ETHBACKEND.NetPeerCount:output_type -> remote.NetPeerCountReply
+	15, // 13: remote.ETHBACKEND.Version:output_type -> types.VersionReply
+	8,  // 14: remote.ETHBACKEND.ProtocolVersion:output_type -> remote.ProtocolVersionReply
+	10, // 15: remote.ETHBACKEND.ClientVersion:output_type -> remote.ClientVersionReply
+	12, // 16: remote.ETHBACKEND.Subscribe:output_type -> remote.SubscribeReply
+	10, // [10:17] is the sub-list for method output_type
+	3,  // [3:10] is the sub-list for method input_type
 	3,  // [3:3] is the sub-list for extension type_name
 	3,  // [3:3] is the sub-list for extension extendee
 	0,  // [0:3] is the sub-list for field type_name
@@ -688,7 +785,7 @@ func file_remote_ethbackend_proto_init() {
 			}
 		}
 		file_remote_ethbackend_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ProtocolVersionRequest); i {
+			switch v := v.(*NetPeerCountRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -700,7 +797,7 @@ func file_remote_ethbackend_proto_init() {
 			}
 		}
 		file_remote_ethbackend_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ProtocolVersionReply); i {
+			switch v := v.(*NetPeerCountReply); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -712,7 +809,7 @@ func file_remote_ethbackend_proto_init() {
 			}
 		}
 		file_remote_ethbackend_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ClientVersionRequest); i {
+			switch v := v.(*ProtocolVersionRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -724,7 +821,7 @@ func file_remote_ethbackend_proto_init() {
 			}
 		}
 		file_remote_ethbackend_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ClientVersionReply); i {
+			switch v := v.(*ProtocolVersionReply); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -736,7 +833,7 @@ func file_remote_ethbackend_proto_init() {
 			}
 		}
 		file_remote_ethbackend_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*SubscribeRequest); i {
+			switch v := v.(*ClientVersionRequest); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -748,6 +845,30 @@ func file_remote_ethbackend_proto_init() {
 			}
 		}
 		file_remote_ethbackend_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ClientVersionReply); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_remote_ethbackend_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*SubscribeRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_remote_ethbackend_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*SubscribeReply); i {
 			case 0:
 				return &v.state
@@ -766,7 +887,7 @@ func file_remote_ethbackend_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_remote_ethbackend_proto_rawDesc,
 			NumEnums:      1,
-			NumMessages:   10,
+			NumMessages:   12,
 			NumExtensions: 0,
 			NumServices:   1,
 		},
diff --git a/gointerfaces/remote/ethbackend_grpc.pb.go b/gointerfaces/remote/ethbackend_grpc.pb.go
index 05a7cd8bec..8ffd4fcaeb 100644
--- a/gointerfaces/remote/ethbackend_grpc.pb.go
+++ b/gointerfaces/remote/ethbackend_grpc.pb.go
@@ -22,6 +22,7 @@ const _ = grpc.SupportPackageIsVersion7
 type ETHBACKENDClient interface {
 	Etherbase(ctx context.Context, in *EtherbaseRequest, opts ...grpc.CallOption) (*EtherbaseReply, error)
 	NetVersion(ctx context.Context, in *NetVersionRequest, opts ...grpc.CallOption) (*NetVersionReply, error)
+	NetPeerCount(ctx context.Context, in *NetPeerCountRequest, opts ...grpc.CallOption) (*NetPeerCountReply, error)
 	// Version returns the service version number
 	Version(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*types.VersionReply, error)
 	// ProtocolVersion returns the Ethereum protocol version number (e.g. 66 for ETH66).
@@ -57,6 +58,15 @@ func (c *eTHBACKENDClient) NetVersion(ctx context.Context, in *NetVersionRequest
 	return out, nil
 }
 
+func (c *eTHBACKENDClient) NetPeerCount(ctx context.Context, in *NetPeerCountRequest, opts ...grpc.CallOption) (*NetPeerCountReply, error) {
+	out := new(NetPeerCountReply)
+	err := c.cc.Invoke(ctx, "/remote.ETHBACKEND/NetPeerCount", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 func (c *eTHBACKENDClient) Version(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*types.VersionReply, error) {
 	out := new(types.VersionReply)
 	err := c.cc.Invoke(ctx, "/remote.ETHBACKEND/Version", in, out, opts...)
@@ -122,6 +132,7 @@ func (x *eTHBACKENDSubscribeClient) Recv() (*SubscribeReply, error) {
 type ETHBACKENDServer interface {
 	Etherbase(context.Context, *EtherbaseRequest) (*EtherbaseReply, error)
 	NetVersion(context.Context, *NetVersionRequest) (*NetVersionReply, error)
+	NetPeerCount(context.Context, *NetPeerCountRequest) (*NetPeerCountReply, error)
 	// Version returns the service version number
 	Version(context.Context, *emptypb.Empty) (*types.VersionReply, error)
 	// ProtocolVersion returns the Ethereum protocol version number (e.g. 66 for ETH66).
@@ -142,6 +153,9 @@ func (UnimplementedETHBACKENDServer) Etherbase(context.Context, *EtherbaseReques
 func (UnimplementedETHBACKENDServer) NetVersion(context.Context, *NetVersionRequest) (*NetVersionReply, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method NetVersion not implemented")
 }
+func (UnimplementedETHBACKENDServer) NetPeerCount(context.Context, *NetPeerCountRequest) (*NetPeerCountReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method NetPeerCount not implemented")
+}
 func (UnimplementedETHBACKENDServer) Version(context.Context, *emptypb.Empty) (*types.VersionReply, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method Version not implemented")
 }
@@ -203,6 +217,24 @@ func _ETHBACKEND_NetVersion_Handler(srv interface{}, ctx context.Context, dec fu
 	return interceptor(ctx, in, info, handler)
 }
 
+func _ETHBACKEND_NetPeerCount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(NetPeerCountRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(ETHBACKENDServer).NetPeerCount(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/remote.ETHBACKEND/NetPeerCount",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(ETHBACKENDServer).NetPeerCount(ctx, req.(*NetPeerCountRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _ETHBACKEND_Version_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(emptypb.Empty)
 	if err := dec(in); err != nil {
@@ -293,6 +325,10 @@ var ETHBACKEND_ServiceDesc = grpc.ServiceDesc{
 			MethodName: "NetVersion",
 			Handler:    _ETHBACKEND_NetVersion_Handler,
 		},
+		{
+			MethodName: "NetPeerCount",
+			Handler:    _ETHBACKEND_NetPeerCount_Handler,
+		},
 		{
 			MethodName: "Version",
 			Handler:    _ETHBACKEND_Version_Handler,
diff --git a/interfaces/remote/ethbackend.proto b/interfaces/remote/ethbackend.proto
index f5997a5f5d..566cce09f4 100644
--- a/interfaces/remote/ethbackend.proto
+++ b/interfaces/remote/ethbackend.proto
@@ -12,6 +12,8 @@ service ETHBACKEND {
 
   rpc NetVersion(NetVersionRequest) returns (NetVersionReply);
 
+  rpc NetPeerCount(NetPeerCountRequest) returns (NetPeerCountReply);
+
   // Version returns the service version number
   rpc Version(google.protobuf.Empty) returns (types.VersionReply);
 
@@ -38,6 +40,10 @@ message NetVersionRequest {}
 
 message NetVersionReply { uint64 id = 1; }
 
+message NetPeerCountRequest {}
+
+message NetPeerCountReply { uint64 id = 1; }
+
 message ProtocolVersionRequest {}
 
 message ProtocolVersionReply { uint64 id = 1; }
-- 
GitLab