Disconnect peers with low score. (#1747)

* Disconnect peers with low score.

* Change PeerScoreLow value.

* Add spec url for DisconnectionReason.
This commit is contained in:
Eugene Kabanov 2020-09-25 16:43:45 +03:00 committed by GitHub
parent 7ae689d1dd
commit 1bf8d3af33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 24 deletions

View File

@ -662,9 +662,14 @@ proc startSyncManager(node: BeaconNode) =
proc scoreCheck(peer: Peer): bool = proc scoreCheck(peer: Peer): bool =
if peer.score < PeerScoreLowLimit: if peer.score < PeerScoreLowLimit:
try: try:
debug "Peer score is too low, removing it from PeerPool", peer = peer, debug "Peer score is too low, disconnecting", peer = peer,
peer_score = peer.score, score_low_limit = PeerScoreLowLimit, peer_score = peer.score, score_low_limit = PeerScoreLowLimit,
score_high_limit = PeerScoreHighLimit score_high_limit = PeerScoreHighLimit
# We do not care about result of this operation, because even if
# disconnect operation fails, peer will still be added to SeenTable
# and removed from PeerPool. So it will be not reused for syncing for
# `SeenTablePenaltyError` time.
asyncSpawn peer.disconnect(PeerScoreLow)
except: except:
discard discard
false false

View File

@ -163,11 +163,15 @@ type
MounterProc* = proc(network: Eth2Node) {.gcsafe.} MounterProc* = proc(network: Eth2Node) {.gcsafe.}
MessageContentPrinter* = proc(msg: pointer): string {.gcsafe.} MessageContentPrinter* = proc(msg: pointer): string {.gcsafe.}
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/p2p-interface.md#goodbye
DisconnectionReason* = enum DisconnectionReason* = enum
# might see other values on the wire! # might see other values on the wire!
ClientShutDown = 1 ClientShutDown = 1
IrrelevantNetwork = 2 IrrelevantNetwork = 2
FaultOrError = 3 FaultOrError = 3
# Clients MAY use reason codes above 128 to indicate alternative,
# erroneous request-specific responses.
PeerScoreLow = 237 # 79 * 3
PeerDisconnected* = object of CatchableError PeerDisconnected* = object of CatchableError
reason*: DisconnectionReason reason*: DisconnectionReason
@ -230,6 +234,8 @@ const
## Period of time for `ClientShutDown` error reason. ## Period of time for `ClientShutDown` error reason.
SeenTableTimeFaultOrError* = 10.minutes SeenTableTimeFaultOrError* = 10.minutes
## Period of time for `FaultOnError` error reason. ## Period of time for `FaultOnError` error reason.
SeenTablePenaltyError* = 60.minutes
## Period of time for peers which score below or equal to zero.
template neterr(kindParam: Eth2NetworkingErrorKind): auto = template neterr(kindParam: Eth2NetworkingErrorKind): auto =
err(type(result), Eth2NetworkingError(kind: kindParam)) err(type(result), Eth2NetworkingError(kind: kindParam))
@ -303,16 +309,16 @@ proc peerFromStream(network: Eth2Node, conn: Connection): Peer =
return network.getPeer(conn.peerInfo.peerId) return network.getPeer(conn.peerInfo.peerId)
proc getKey*(peer: Peer): PeerID {.inline.} = proc getKey*(peer: Peer): PeerID {.inline.} =
result = peer.info.peerId peer.info.peerId
proc getFuture*(peer: Peer): Future[void] {.inline.} = proc getFuture*(peer: Peer): Future[void] {.inline.} =
if peer.disconnectedFut.isNil: if peer.disconnectedFut.isNil:
peer.disconnectedFut = newFuture[void]() peer.disconnectedFut = newFuture[void]()
result = peer.disconnectedFut peer.disconnectedFut
proc getScore*(a: Peer): int = proc getScore*(a: Peer): int =
## Returns current score value for peer ``peer``. ## Returns current score value for peer ``peer``.
result = a.score a.score
proc updateScore*(peer: Peer, score: int) {.inline.} = proc updateScore*(peer: Peer, score: int) {.inline.} =
## Update peer's ``peer`` score with value ``score``. ## Update peer's ``peer`` score with value ``score``.
@ -363,13 +369,15 @@ proc isSeen*(network: ETh2Node, peerId: PeerID): bool =
## yet expired. ## yet expired.
let currentTime = now(chronos.Moment) let currentTime = now(chronos.Moment)
if peerId notin network.seenTable: if peerId notin network.seenTable:
return false false
let item = network.seenTable[peerId] else:
if currentTime >= item.stamp: let item = network.seenTable[peerId]
# Peer is in SeenTable, but the time period has expired. if currentTime >= item.stamp:
network.seenTable.del(peerId) # Peer is in SeenTable, but the time period has expired.
return false network.seenTable.del(peerId)
return true false
else:
true
proc addSeen*(network: ETh2Node, peerId: PeerID, proc addSeen*(network: ETh2Node, peerId: PeerID,
period: chronos.Duration) = period: chronos.Duration) =
@ -380,19 +388,26 @@ proc addSeen*(network: ETh2Node, peerId: PeerID,
proc disconnect*(peer: Peer, reason: DisconnectionReason, proc disconnect*(peer: Peer, reason: DisconnectionReason,
notifyOtherPeer = false) {.async.} = notifyOtherPeer = false) {.async.} =
# TODO: How should we notify the other peer? # TODO: How should we notify the other peer?
if peer.connectionState notin {Disconnecting, Disconnected}: try:
peer.connectionState = Disconnecting if peer.connectionState notin {Disconnecting, Disconnected}:
await peer.network.switch.disconnect(peer.info.peerId) peer.connectionState = Disconnecting
peer.connectionState = Disconnected # We adding peer in SeenTable before actual disconnect to avoid races.
discard peer.network.peerPool.deletePeer(peer) let seenTime = case reason
let seenTime = case reason of ClientShutDown:
of ClientShutDown: SeenTableTimeClientShutDown
SeenTableTimeClientShutDown of IrrelevantNetwork:
of IrrelevantNetwork: SeenTableTimeIrrelevantNetwork
SeenTableTimeIrrelevantNetwork of FaultOrError:
of FaultOrError: SeenTableTimeFaultOrError
SeenTableTimeFaultOrError of PeerScoreLow:
peer.network.addSeen(peer.info.peerId, seenTime) SeenTablePenaltyError
peer.network.addSeen(peer.info.peerId, seenTime)
await peer.network.switch.disconnect(peer.info.peerId)
peer.connectionState = Disconnected
except CatchableError as exc:
# We do not care about exceptions in disconnection procedure.
trace "Exception while disconnecting peer", peer = peer.info.peerId,
reason = reason
include eth/p2p/p2p_backends_helpers include eth/p2p/p2p_backends_helpers
include eth/p2p/p2p_tracing include eth/p2p/p2p_tracing