Skip to content

Commit 4d7aa09

Browse files
authored
Merge pull request #2196 from mgpai22/peer-ban
Add peer Ban To Config
2 parents bbf6956 + 932edfa commit 4d7aa09

File tree

3 files changed

+99
-73
lines changed

3 files changed

+99
-73
lines changed

ergo-core/src/main/scala/org/ergoplatform/settings/Settings.scala

Lines changed: 64 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -12,67 +12,81 @@ import scala.concurrent.duration._
1212

1313
case class LoggingSettings(level: String)
1414

15-
case class RESTApiSettings(bindAddress: InetSocketAddress,
16-
apiKeyHash: Option[String],
17-
corsAllowedOrigin: Option[String],
18-
timeout: FiniteDuration,
19-
publicUrl: Option[URL])
15+
case class RESTApiSettings(
16+
bindAddress: InetSocketAddress,
17+
apiKeyHash: Option[String],
18+
corsAllowedOrigin: Option[String],
19+
timeout: FiniteDuration,
20+
publicUrl: Option[URL]
21+
)
2022

21-
case class NetworkSettings(nodeName: String,
22-
addedMaxDelay: Option[FiniteDuration],
23-
localOnly: Boolean,
24-
knownPeers: Seq[InetSocketAddress],
25-
bindAddress: InetSocketAddress,
26-
maxConnections: Int,
27-
connectionTimeout: FiniteDuration,
28-
upnpEnabled: Boolean,
29-
upnpGatewayTimeout: Option[FiniteDuration],
30-
upnpDiscoverTimeout: Option[FiniteDuration],
31-
declaredAddress: Option[InetSocketAddress],
32-
handshakeTimeout: FiniteDuration,
33-
deliveryTimeout: FiniteDuration,
34-
maxDeliveryChecks: Int,
35-
appVersion: String,
36-
agentName: String,
37-
desiredInvObjects: Int,
38-
syncInterval: FiniteDuration,
39-
syncStatusRefresh: FiniteDuration,
40-
syncIntervalStable: FiniteDuration,
41-
syncStatusRefreshStable: FiniteDuration,
42-
inactiveConnectionDeadline: FiniteDuration,
43-
syncTimeout: Option[FiniteDuration],
44-
controllerTimeout: Option[FiniteDuration],
45-
maxModifiersCacheSize: Int,
46-
magicBytes: Array[Byte],
47-
getPeersInterval: FiniteDuration,
48-
maxPeerSpecObjects: Int,
49-
temporalBanDuration: FiniteDuration,
50-
penaltySafeInterval: FiniteDuration,
51-
penaltyScoreThreshold: Int,
52-
peerEvictionInterval: FiniteDuration,
53-
peerDiscovery: Boolean)
54-
55-
case class ScorexSettings(dataDir: File,
56-
logDir: File,
57-
logging: LoggingSettings,
58-
network: NetworkSettings,
59-
restApi: RESTApiSettings)
23+
case class NetworkSettings(
24+
nodeName: String,
25+
addedMaxDelay: Option[FiniteDuration],
26+
localOnly: Boolean,
27+
knownPeers: Seq[InetSocketAddress],
28+
bannedPeers: Seq[InetSocketAddress],
29+
bindAddress: InetSocketAddress,
30+
maxConnections: Int,
31+
connectionTimeout: FiniteDuration,
32+
upnpEnabled: Boolean,
33+
upnpGatewayTimeout: Option[FiniteDuration],
34+
upnpDiscoverTimeout: Option[FiniteDuration],
35+
declaredAddress: Option[InetSocketAddress],
36+
handshakeTimeout: FiniteDuration,
37+
deliveryTimeout: FiniteDuration,
38+
maxDeliveryChecks: Int,
39+
appVersion: String,
40+
agentName: String,
41+
desiredInvObjects: Int,
42+
syncInterval: FiniteDuration,
43+
syncStatusRefresh: FiniteDuration,
44+
syncIntervalStable: FiniteDuration,
45+
syncStatusRefreshStable: FiniteDuration,
46+
inactiveConnectionDeadline: FiniteDuration,
47+
syncTimeout: Option[FiniteDuration],
48+
controllerTimeout: Option[FiniteDuration],
49+
maxModifiersCacheSize: Int,
50+
magicBytes: Array[Byte],
51+
getPeersInterval: FiniteDuration,
52+
maxPeerSpecObjects: Int,
53+
temporalBanDuration: FiniteDuration,
54+
penaltySafeInterval: FiniteDuration,
55+
penaltyScoreThreshold: Int,
56+
peerEvictionInterval: FiniteDuration,
57+
peerDiscovery: Boolean
58+
)
6059

60+
case class ScorexSettings(
61+
dataDir: File,
62+
logDir: File,
63+
logging: LoggingSettings,
64+
network: NetworkSettings,
65+
restApi: RESTApiSettings
66+
)
6167

6268
object ScorexSettings extends ScorexLogging with SettingsReaders {
6369

6470
protected val configPath: String = "scorex"
6571

6672
def readConfigFromPath(userConfigPath: Option[String], configPath: String): Config = {
6773

68-
val maybeConfigFile: Option[File] = userConfigPath.map(filename => new File(filename)).filter(_.exists())
69-
.orElse(userConfigPath.flatMap(filename => Option(getClass.getClassLoader.getResource(filename))).
70-
map(r => new File(r.toURI)).filter(_.exists()))
74+
val maybeConfigFile: Option[File] = userConfigPath
75+
.map(filename => new File(filename))
76+
.filter(_.exists())
77+
.orElse(
78+
userConfigPath
79+
.flatMap(filename => Option(getClass.getClassLoader.getResource(filename)))
80+
.map(r => new File(r.toURI))
81+
.filter(_.exists())
82+
)
7183

7284
val config = maybeConfigFile match {
7385
// if no user config is supplied, the library will handle overrides/application/reference automatically
7486
case None =>
75-
log.warn("NO CONFIGURATION FILE WAS PROVIDED. STARTING WITH DEFAULT SETTINGS FOR TESTNET!")
87+
log.warn(
88+
"NO CONFIGURATION FILE WAS PROVIDED. STARTING WITH DEFAULT SETTINGS FOR TESTNET!"
89+
)
7690
ConfigFactory.load()
7791
// application config needs to be resolved wrt both system properties *and* user-supplied config.
7892
case Some(file) =>
@@ -96,7 +110,8 @@ object ScorexSettings extends ScorexLogging with SettingsReaders {
96110
}
97111

98112
def fromConfig(config: Config): ScorexSettings = {
99-
config.as[ScorexSettings](configPath)
113+
config
114+
.as[ScorexSettings](configPath)
100115
.ensuring(_.network.magicBytes.length == MagicLength)
101116
}
102117
}

src/main/resources/application.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,9 @@ scorex {
498498
# A list of `IP:port` pairs of well known nodes.
499499
knownPeers = []
500500

501+
# A list of `IP:port` pairs peers that will be permanently banned
502+
bannedPeers = []
503+
501504
# Interval between GetPeers messages to be send by our node to a random one
502505
getPeersInterval = 2m
503506

src/main/scala/org/ergoplatform/network/peer/PeerDatabase.scala

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package org.ergoplatform.network.peer
22

3-
import org.ergoplatform.nodeView.history.ErgoHistoryUtils._
4-
import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream}
3+
import java.io.{
4+
ByteArrayInputStream,
5+
ByteArrayOutputStream,
6+
ObjectInputStream,
7+
ObjectOutputStream
8+
}
59
import java.net.{InetAddress, InetSocketAddress}
610
import org.ergoplatform.settings.ErgoSettings
711
import scorex.db.LDBFactory
@@ -17,6 +21,13 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging {
1721

1822
private val persistentStore = LDBFactory.createKvDb(s"${settings.directory}/peers")
1923

24+
/**
25+
* banned peer ip -> ban expiration timestamp
26+
*/
27+
private var blacklist = settings.scorexSettings.network.bannedPeers.map { addr =>
28+
addr.getAddress -> Long.MaxValue // Permanent ban
29+
}.toMap
30+
2031
private var peers =
2132
loadPeers match {
2233
case Success(loadedPeers) =>
@@ -26,11 +37,6 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging {
2637
Map.empty[InetSocketAddress, PeerInfo]
2738
}
2839

29-
/**
30-
* banned peer ip -> ban expiration timestamp
31-
*/
32-
private var blacklist = Map.empty[InetAddress, Time]
33-
3440
/**
3541
* penalized peer ip -> (accumulated penalty score, last penalty timestamp)
3642
*/
@@ -41,7 +47,7 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging {
4147
*/
4248
private def serialize(obj: Object): Array[Byte] = {
4349
val stream: ByteArrayOutputStream = new ByteArrayOutputStream()
44-
val oos = new ObjectOutputStream(stream)
50+
val oos = new ObjectOutputStream(stream)
4551
oos.writeObject(obj)
4652
oos.close()
4753
stream.toByteArray
@@ -50,7 +56,7 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging {
5056
/*
5157
* Deserialize object using standard Java serializer
5258
*/
53-
private def deserialize(bytes: Array[Byte]) : Object = {
59+
private def deserialize(bytes: Array[Byte]): Object = {
5460
val ois = new ObjectInputStream(new ByteArrayInputStream(bytes))
5561
ois.readObject()
5662
}
@@ -60,8 +66,8 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging {
6066
*/
6167
private def loadPeers: Try[Map[InetSocketAddress, PeerInfo]] = Try {
6268
var peers = Map.empty[InetSocketAddress, PeerInfo]
63-
for ((addr,peer) <- persistentStore.getAll) {
64-
val address = deserialize(addr).asInstanceOf[InetSocketAddress]
69+
for ((addr, peer) <- persistentStore.getAll) {
70+
val address = deserialize(addr).asInstanceOf[InetSocketAddress]
6571
val peerInfo = PeerInfoSerializer.parseBytes(peer)
6672
peers += address -> peerInfo
6773
}
@@ -84,8 +90,10 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging {
8490
remove(socketAddress)
8591
Option(socketAddress.getAddress).foreach { address =>
8692
penaltyBook -= address
87-
if (!blacklist.keySet.contains(address)){
88-
blacklist += address -> (System.currentTimeMillis() + penaltyDuration(penaltyType))
93+
if (!blacklist.keySet.contains(address)) {
94+
blacklist += address -> (System.currentTimeMillis() + penaltyDuration(
95+
penaltyType
96+
))
8997
} else {
9098
log.warn(s"${address.toString} is already blacklisted")
9199
}
@@ -104,12 +112,12 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging {
104112

105113
def knownPeers: Map[InetSocketAddress, PeerInfo] = peers
106114

107-
def blacklistedPeers: Seq[InetAddress] = blacklist
108-
.map { case (address, bannedTill) =>
109-
checkBanned(address, bannedTill)
110-
address
111-
}
112-
.toSeq
115+
def blacklistedPeers: Seq[InetAddress] =
116+
blacklist.map {
117+
case (address, bannedTill) =>
118+
checkBanned(address, bannedTill)
119+
address
120+
}.toSeq
113121

114122
def isEmpty: Boolean = peers.isEmpty
115123

@@ -126,10 +134,10 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging {
126134
*/
127135
def penalize(socketAddress: InetSocketAddress, penaltyType: PenaltyType): Boolean =
128136
Option(socketAddress.getAddress).exists { address =>
129-
val currentTime = System.currentTimeMillis()
130-
val safeInterval = settings.scorexSettings.network.penaltySafeInterval.toMillis
137+
val currentTime = System.currentTimeMillis()
138+
val safeInterval = settings.scorexSettings.network.penaltySafeInterval.toMillis
131139
val (penaltyScoreAcc, lastPenaltyTs) = penaltyBook.getOrElse(address, (0, 0L))
132-
val applyPenalty = currentTime - lastPenaltyTs - safeInterval > 0 || penaltyType.isPermanent
140+
val applyPenalty = currentTime - lastPenaltyTs - safeInterval > 0 || penaltyType.isPermanent
133141
val newPenaltyScore = if (applyPenalty) {
134142
penaltyScoreAcc + penaltyScore(penaltyType)
135143
} else {
@@ -173,10 +181,10 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging {
173181

174182
private def penaltyDuration(penalty: PenaltyType): Long =
175183
penalty match {
176-
case PenaltyType.NonDeliveryPenalty | PenaltyType.MisbehaviorPenalty | PenaltyType.SpamPenalty =>
184+
case PenaltyType.NonDeliveryPenalty | PenaltyType.MisbehaviorPenalty |
185+
PenaltyType.SpamPenalty =>
177186
settings.scorexSettings.network.temporalBanDuration.toMillis
178187
case PenaltyType.PermanentPenalty =>
179188
(360 * 10).days.toMillis
180189
}
181-
182190
}

0 commit comments

Comments
 (0)