From 9c26cd4ab34e6f3c51d9a32a98d6432b23237f5a Mon Sep 17 00:00:00 2001 From: Zack Balbin Date: Sat, 3 Aug 2024 22:17:14 -0500 Subject: [PATCH 1/6] add lastMemPoolUpdateTime to info route, create new transaction mempool routes --- out/production/avldb/scorex/ByteUtils.class | Bin 0 -> 1826 bytes src/main/resources/api/openapi.yaml | 52 ++++++++++++++++++ .../ergoplatform/http/api/InfoApiRoute.scala | 11 +++- .../http/api/TransactionsApiRoute.scala | 27 ++++++++- .../local/ErgoStatsCollector.scala | 5 ++ .../nodeView/mempool/ErgoMemPool.scala | 1 + .../nodeView/mempool/ErgoMemPoolReader.scala | 1 - 7 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 out/production/avldb/scorex/ByteUtils.class diff --git a/out/production/avldb/scorex/ByteUtils.class b/out/production/avldb/scorex/ByteUtils.class new file mode 100644 index 0000000000000000000000000000000000000000..ae92bd161ef8f178c318ed52f20fad559bb66236 GIT binary patch literal 1826 zcmbVM%}yIv6#lM%u`yuWm;eS!2qCtiF@ct(VBFenQk>c$0vah|kzU&qJi*LZ_Bg6H zts;?i-=LM)bdxTsE}CY+rn{;y&`0PSRFzu#-SG%ai?ZlgzW1Cn=jS_r^UL3_j{&UX zK@cvu{qTg~g-;;-R6dibx-|Auo8_lk#S-wPbwjr@0`7R?VGw-?_z?`DA0dIkGxd_R zYScN<4FPYwP)HQqU*GEdN9bD1>(Pu{FjXQ-$f+Wq!HS!?dda-EV$ z(X7b&L)p|7?+86sO=m`t;=i+`Cs+BVfG8+piG)tVq{OwGQxrw+y2cs~Y+JIjUy=>S z<#3sm$~K#_vmslxE*dZEl%OY3=AY)CsG>N7v={6P^u| z;D+k*pj?%+ElXN@Wp+`ZFI}lSy$)`h?Pf*0tE&_TPn&c@b%4#wnWojUnzB*SteRPE z4f&7>;sbo>M>d2U@&YqwqoEtm%zZ6YwByl2K9Lo6t|QQY(98WA?{>f*KgXyWU_%=xFc}AH>2)C z^?Gz9i302Qv09Lg5N;zHRtpj;7>3r&*JZ1vwfrawT>DQ&FDi~7_XVcjtjdY#RuWej z)Wt0m7*iX>dy(>&E{3h4$2IrI#!k_)Icr$ib5 zOou++tI6Z}<5%#nyEBs$M~EjUmxpok#foR%A-qvf)cXwr>Z-mxbc=6Kep5Epm$Y_c zn&%8ZK)?XcK@9OXim;tT91+~0>|MrHXfljAiV@7>8a$K?V2+d*K_qdVl$$!Mh$F#U zQAtwV04!miZ(UfRv>)!j5ESC-pEL~M9R}zo^p%s)oF|g|I6RdKK0Hr2kRLRb~6 z*H5s=kMFc!zSDlaZ_l8bvMcnbp1^C?5kFu|jj8B?6l8^0DRW^BY2IpJ*D3o5cTvDS NN`jPpf)X|{_76H1dM*F} literal 0 HcmV?d00001 diff --git a/src/main/resources/api/openapi.yaml b/src/main/resources/api/openapi.yaml index 3de95cc170..e783558efe 100644 --- a/src/main/resources/api/openapi.yaml +++ b/src/main/resources/api/openapi.yaml @@ -3252,6 +3252,58 @@ paths: schema: $ref: '#/components/schemas/ApiError' + /transactions/unconfirmed/transactionIds: + get: + summary: Get list of unconfirmed transactions ids + operationId: getUnconfirmedTxIds + tags: + - transactions + responses: + '200': + description: List of unconfirmed transaction ids + content: + application/json: + schema: + type: array + items: + type: string + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schema/ApiError' + + /transactions/unconfirmed/byTransactionIds: + post: + summary: Get list of unconfirmed transactions by their ids + operationId: getUnconfirmedTxsByIds + tags: + - transactions + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + type: string + responses: + '200': + description: List of unconfirmed transaction ids + content: + application/json: + schema: + type: array + items: + type: string + default: + description: Error + content: + application/json: + schema: + $ref: '#/components/schemas/ApiError' + /transactions/unconfirmed/byErgoTree: parameters: - in: query diff --git a/src/main/scala/org/ergoplatform/http/api/InfoApiRoute.scala b/src/main/scala/org/ergoplatform/http/api/InfoApiRoute.scala index b78f974e61..701e9f2dfb 100644 --- a/src/main/scala/org/ergoplatform/http/api/InfoApiRoute.scala +++ b/src/main/scala/org/ergoplatform/http/api/InfoApiRoute.scala @@ -5,6 +5,7 @@ import akka.http.scaladsl.model.ContentTypes import akka.http.scaladsl.server.Route import akka.pattern.ask import io.circe.syntax._ +import io.circe.Json import org.ergoplatform.local.ErgoStatsCollector.{GetNodeInfo, NodeInfo} import org.ergoplatform.settings.RESTApiSettings import scorex.core.api.http.ApiResponse @@ -19,8 +20,14 @@ case class InfoApiRoute(statsCollector: ActorRef, override val route: Route = { (path("info") & get) { - val timeJson = Map("currentTime" -> System.currentTimeMillis().asJson).asJson - ApiResponse((statsCollector ? GetNodeInfo).mapTo[NodeInfo].map(_.asJson.deepMerge(timeJson))) + val timeJson = Map( + "currentTime" -> System.currentTimeMillis().asJson + ).asJson + ApiResponse((statsCollector ? GetNodeInfo).mapTo[NodeInfo].map { nodeInfo => + nodeInfo.asJson.deepMerge(timeJson).deepMerge(Json.obj( + "lastMemPoolUpdateTime" -> nodeInfo.lastMemPoolUpdateTime.asJson + )) + }) } ~ (path(".well-known" / "ai-plugin.json") & get) { getFromResource(".well-known/ai-plugin.json", ContentTypes.`application/json`) diff --git a/src/main/scala/org/ergoplatform/http/api/TransactionsApiRoute.scala b/src/main/scala/org/ergoplatform/http/api/TransactionsApiRoute.scala index 0cc95f24a3..d5ef26ed57 100644 --- a/src/main/scala/org/ergoplatform/http/api/TransactionsApiRoute.scala +++ b/src/main/scala/org/ergoplatform/http/api/TransactionsApiRoute.scala @@ -64,7 +64,9 @@ case class TransactionsApiRoute(readersHolder: ActorRef, getUnconfirmedOutputByBoxIdR ~ getUnconfirmedInputByBoxIdR ~ getUnconfirmedTxsByErgoTreeR ~ + getUnconfirmedTxIdsR ~ getUnconfirmedTxByIdR ~ + getUnconfirmedTxsByIdsR ~ getUnconfirmedTransactionsR ~ unconfirmedContainsR ~ sendTransactionR ~ @@ -167,6 +169,29 @@ case class TransactionsApiRoute(readersHolder: ActorRef, ApiResponse(getMemPool.map(_.modifierById(modifierId))) } + /** Get list of unconfirmed transaction ids */ + def getUnconfirmedTxIdsR: Route = + (pathPrefix("unconfirmed" / "transactionIds") & get) { + ApiResponse(getMemPool.map(_.getAll.map(_.id))) + } + + /** Post list of unconfirmed transaction ids and check if they are in the mempool */ + def getUnconfirmedTxsByIdsR: Route = + (pathPrefix("unconfirmed" / "transactionIds") & post & entity(as[Json])) { txIds => + txIds.as[List[String]] match { + case Left(ex) => + ApiError(StatusCodes.BadRequest, ex.getMessage()) + case Right(ids) => + ApiResponse( + getMemPool.map { pool => + pool.getAll + .filter(tx => ids.contains(tx.id)) + .map(_.id) + } + ) + } + } + /** Collect all transactions which inputs or outputs contain given ErgoTree hex */ def getUnconfirmedTxsByErgoTreeR: Route = (pathPrefix("unconfirmed" / "byErgoTree") & post & entity(as[Json]) & txPaging) { case (body, offset, limit) => @@ -268,4 +293,4 @@ case class TransactionsApiRoute(readersHolder: ActorRef, } } -} +} \ No newline at end of file diff --git a/src/main/scala/org/ergoplatform/local/ErgoStatsCollector.scala b/src/main/scala/org/ergoplatform/local/ErgoStatsCollector.scala index 39091b904a..064c2c242d 100644 --- a/src/main/scala/org/ergoplatform/local/ErgoStatsCollector.scala +++ b/src/main/scala/org/ergoplatform/local/ErgoStatsCollector.scala @@ -62,6 +62,7 @@ class ErgoStatsCollector(readersHolder: ActorRef, None, launchTime = System.currentTimeMillis(), lastIncomingMessageTime = System.currentTimeMillis(), + lastMemPoolUpdateTime = System.currentTimeMillis(), None, LaunchParameters, eip27Supported = true, @@ -100,6 +101,7 @@ class ErgoStatsCollector(readersHolder: ActorRef, private def onMempoolChanged: Receive = { case ChangedMempool(p) => + nodeInfo = nodeInfo.copy(lastMemPoolUpdateTime = System.currentTimeMillis()) nodeInfo = nodeInfo.copy(unconfirmedCount = p.size) } @@ -171,6 +173,7 @@ object ErgoStatsCollector { * @param maxPeerHeight - maximum block height of connected peers * @param launchTime - when the node was launched (in Java time format, basically, UNIX time * 1000) * @param lastIncomingMessageTime - when the node received last p2p message (in Java time) + * @param lastMemPoolUpdateTime - when the mempool was last updated (in Java time) * @param genesisBlockIdOpt - header id of genesis block * @param parameters - array with network parameters at the moment * @param eip27Supported - whether EIP-27 locked in @@ -193,6 +196,7 @@ object ErgoStatsCollector { maxPeerHeight : Option[Int], launchTime: Long, lastIncomingMessageTime: Long, + lastMemPoolUpdateTime: Long, genesisBlockIdOpt: Option[String], parameters: Parameters, eip27Supported: Boolean, @@ -227,6 +231,7 @@ object ErgoStatsCollector { "peersCount" -> ni.peersCount.asJson, "launchTime" -> ni.launchTime.asJson, "lastSeenMessageTime" -> ni.lastIncomingMessageTime.asJson, + "lastMemPoolUpdateTime" -> ni.lastMemPoolUpdateTime.asJson, "genesisBlockId" -> ni.genesisBlockIdOpt.asJson, "parameters" -> ni.parameters.asJson, "eip27Supported" -> ni.eip27Supported.asJson, diff --git a/src/main/scala/org/ergoplatform/nodeView/mempool/ErgoMemPool.scala b/src/main/scala/org/ergoplatform/nodeView/mempool/ErgoMemPool.scala index df08cd4858..37040d8439 100644 --- a/src/main/scala/org/ergoplatform/nodeView/mempool/ErgoMemPool.scala +++ b/src/main/scala/org/ergoplatform/nodeView/mempool/ErgoMemPool.scala @@ -97,6 +97,7 @@ class ErgoMemPool private[mempool](private[mempool] val pool: OrderedTxPool, def put(txs: TraversableOnce[UnconfirmedTransaction]): ErgoMemPool = { txs.foldLeft(this) { case (acc, tx) => acc.put(tx) } + this } private def updateStatsOnRemoval(tx: ErgoTransaction): MemPoolStatistics = { diff --git a/src/main/scala/org/ergoplatform/nodeView/mempool/ErgoMemPoolReader.scala b/src/main/scala/org/ergoplatform/nodeView/mempool/ErgoMemPoolReader.scala index a3f31a1c61..eda71c1f56 100644 --- a/src/main/scala/org/ergoplatform/nodeView/mempool/ErgoMemPoolReader.scala +++ b/src/main/scala/org/ergoplatform/nodeView/mempool/ErgoMemPoolReader.scala @@ -68,5 +68,4 @@ trait ErgoMemPoolReader extends NodeViewComponent with ContainsModifiers[ErgoTra * @return recommended fee value for transaction to be proceeded in specified time */ def getRecommendedFee(expectedWaitTimeMinutes: Int, txSize: Int) : Long - } From 5214736d22a18d9f34b99dbcad2ba7e59490fea3 Mon Sep 17 00:00:00 2001 From: Zack Balbin Date: Mon, 19 Aug 2024 23:53:52 -0500 Subject: [PATCH 2/6] remove mempool rewrite line --- .../scala/org/ergoplatform/nodeView/mempool/ErgoMemPool.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/scala/org/ergoplatform/nodeView/mempool/ErgoMemPool.scala b/src/main/scala/org/ergoplatform/nodeView/mempool/ErgoMemPool.scala index 37040d8439..df08cd4858 100644 --- a/src/main/scala/org/ergoplatform/nodeView/mempool/ErgoMemPool.scala +++ b/src/main/scala/org/ergoplatform/nodeView/mempool/ErgoMemPool.scala @@ -97,7 +97,6 @@ class ErgoMemPool private[mempool](private[mempool] val pool: OrderedTxPool, def put(txs: TraversableOnce[UnconfirmedTransaction]): ErgoMemPool = { txs.foldLeft(this) { case (acc, tx) => acc.put(tx) } - this } private def updateStatsOnRemoval(tx: ErgoTransaction): MemPoolStatistics = { From 097eeec0a7715a753534944aec400e3b5f48a5e4 Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Fri, 11 Oct 2024 22:38:59 +0300 Subject: [PATCH 3/6] version 5.0.25 set --- src/main/resources/api/openapi-ai.yaml | 2 +- src/main/resources/api/openapi.yaml | 2 +- src/main/resources/application.conf | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/api/openapi-ai.yaml b/src/main/resources/api/openapi-ai.yaml index 84d7cd411d..2c71bc677a 100644 --- a/src/main/resources/api/openapi-ai.yaml +++ b/src/main/resources/api/openapi-ai.yaml @@ -1,7 +1,7 @@ openapi: "3.0.2" info: - version: "5.0.22" + version: "5.0.25" title: Ergo Node API description: Specification of Ergo Node API for ChatGPT plugin. The following endpoints supported diff --git a/src/main/resources/api/openapi.yaml b/src/main/resources/api/openapi.yaml index 2f6f15a0a5..e570717127 100644 --- a/src/main/resources/api/openapi.yaml +++ b/src/main/resources/api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.2" info: - version: "5.0.22" + version: "5.0.25" title: Ergo Node API description: API docs for Ergo Node. Models are shared between all Ergo products contact: diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index cbc5dd4382..da063d53d0 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -436,7 +436,7 @@ scorex { nodeName = "ergo-node" # Network protocol version to be sent in handshakes - appVersion = 5.0.22 + appVersion = 5.0.25 # Network agent name. May contain information about client code # stack, starting from core code-base up to the end graphical interface. From debdf9e8dee5191aa191e7b7ce4dd4bdd4b3571a Mon Sep 17 00:00:00 2001 From: Alexander Chepurnoy Date: Tue, 19 Nov 2024 15:21:33 +0300 Subject: [PATCH 4/6] after merge fixes for #2177 --- .gitignore | 1 + out/production/avldb/scorex/ByteUtils.class | Bin 1826 -> 0 bytes .../http/api/TransactionsApiRoute.scala | 4 ++-- 3 files changed, 3 insertions(+), 2 deletions(-) delete mode 100644 out/production/avldb/scorex/ByteUtils.class diff --git a/.gitignore b/.gitignore index 626004c1c7..313a6221d1 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,7 @@ local.conf .vscode/ project/metals.sbt null/ +out/ # scala worksheets *.worksheet.sc \ No newline at end of file diff --git a/out/production/avldb/scorex/ByteUtils.class b/out/production/avldb/scorex/ByteUtils.class deleted file mode 100644 index ae92bd161ef8f178c318ed52f20fad559bb66236..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1826 zcmbVM%}yIv6#lM%u`yuWm;eS!2qCtiF@ct(VBFenQk>c$0vah|kzU&qJi*LZ_Bg6H zts;?i-=LM)bdxTsE}CY+rn{;y&`0PSRFzu#-SG%ai?ZlgzW1Cn=jS_r^UL3_j{&UX zK@cvu{qTg~g-;;-R6dibx-|Auo8_lk#S-wPbwjr@0`7R?VGw-?_z?`DA0dIkGxd_R zYScN<4FPYwP)HQqU*GEdN9bD1>(Pu{FjXQ-$f+Wq!HS!?dda-EV$ z(X7b&L)p|7?+86sO=m`t;=i+`Cs+BVfG8+piG)tVq{OwGQxrw+y2cs~Y+JIjUy=>S z<#3sm$~K#_vmslxE*dZEl%OY3=AY)CsG>N7v={6P^u| z;D+k*pj?%+ElXN@Wp+`ZFI}lSy$)`h?Pf*0tE&_TPn&c@b%4#wnWojUnzB*SteRPE z4f&7>;sbo>M>d2U@&YqwqoEtm%zZ6YwByl2K9Lo6t|QQY(98WA?{>f*KgXyWU_%=xFc}AH>2)C z^?Gz9i302Qv09Lg5N;zHRtpj;7>3r&*JZ1vwfrawT>DQ&FDi~7_XVcjtjdY#RuWej z)Wt0m7*iX>dy(>&E{3h4$2IrI#!k_)Icr$ib5 zOou++tI6Z}<5%#nyEBs$M~EjUmxpok#foR%A-qvf)cXwr>Z-mxbc=6Kep5Epm$Y_c zn&%8ZK)?XcK@9OXim;tT91+~0>|MrHXfljAiV@7>8a$K?V2+d*K_qdVl$$!Mh$F#U zQAtwV04!miZ(UfRv>)!j5ESC-pEL~M9R}zo^p%s)oF|g|I6RdKK0Hr2kRLRb~6 z*H5s=kMFc!zSDlaZ_l8bvMcnbp1^C?5kFu|jj8B?6l8^0DRW^BY2IpJ*D3o5cTvDS NN`jPpf)X|{_76H1dM*F} diff --git a/src/main/scala/org/ergoplatform/http/api/TransactionsApiRoute.scala b/src/main/scala/org/ergoplatform/http/api/TransactionsApiRoute.scala index 74b8609d17..fd7d920502 100644 --- a/src/main/scala/org/ergoplatform/http/api/TransactionsApiRoute.scala +++ b/src/main/scala/org/ergoplatform/http/api/TransactionsApiRoute.scala @@ -177,7 +177,7 @@ case class TransactionsApiRoute(readersHolder: ActorRef, /** Post list of unconfirmed transaction ids and check if they are in the mempool */ def getUnconfirmedTxsByIdsR: Route = - (pathPrefix("unconfirmed" / "transactionIds") & post & entity(as[Json])) { txIds => + (pathPrefix("unconfirmed" / "byTransactionIds") & post & entity(as[Json])) { txIds => txIds.as[List[String]] match { case Left(ex) => ApiError(StatusCodes.BadRequest, ex.getMessage()) @@ -293,4 +293,4 @@ case class TransactionsApiRoute(readersHolder: ActorRef, } } -} \ No newline at end of file +} From 1507c3e72bce129b10e162074b3aef87347051e8 Mon Sep 17 00:00:00 2001 From: mgpai <64056966+mgpai22@users.noreply.github.com> Date: Tue, 19 Nov 2024 15:51:38 -0500 Subject: [PATCH 5/6] add peer ban to config --- .../org/ergoplatform/settings/Settings.scala | 113 ++++++++++-------- src/main/resources/application.conf | 3 + .../network/peer/PeerDatabase.scala | 55 +++++---- 3 files changed, 99 insertions(+), 72 deletions(-) diff --git a/ergo-core/src/main/scala/org/ergoplatform/settings/Settings.scala b/ergo-core/src/main/scala/org/ergoplatform/settings/Settings.scala index 34f7701bba..b75afbcec2 100644 --- a/ergo-core/src/main/scala/org/ergoplatform/settings/Settings.scala +++ b/ergo-core/src/main/scala/org/ergoplatform/settings/Settings.scala @@ -12,52 +12,58 @@ import scala.concurrent.duration._ case class LoggingSettings(level: String) -case class RESTApiSettings(bindAddress: InetSocketAddress, - apiKeyHash: Option[String], - corsAllowedOrigin: Option[String], - timeout: FiniteDuration, - publicUrl: Option[URL]) +case class RESTApiSettings( + bindAddress: InetSocketAddress, + apiKeyHash: Option[String], + corsAllowedOrigin: Option[String], + timeout: FiniteDuration, + publicUrl: Option[URL] +) -case class NetworkSettings(nodeName: String, - addedMaxDelay: Option[FiniteDuration], - localOnly: Boolean, - knownPeers: Seq[InetSocketAddress], - bindAddress: InetSocketAddress, - maxConnections: Int, - connectionTimeout: FiniteDuration, - upnpEnabled: Boolean, - upnpGatewayTimeout: Option[FiniteDuration], - upnpDiscoverTimeout: Option[FiniteDuration], - declaredAddress: Option[InetSocketAddress], - handshakeTimeout: FiniteDuration, - deliveryTimeout: FiniteDuration, - maxDeliveryChecks: Int, - appVersion: String, - agentName: String, - desiredInvObjects: Int, - syncInterval: FiniteDuration, - syncStatusRefresh: FiniteDuration, - syncIntervalStable: FiniteDuration, - syncStatusRefreshStable: FiniteDuration, - inactiveConnectionDeadline: FiniteDuration, - syncTimeout: Option[FiniteDuration], - controllerTimeout: Option[FiniteDuration], - maxModifiersCacheSize: Int, - magicBytes: Array[Byte], - getPeersInterval: FiniteDuration, - maxPeerSpecObjects: Int, - temporalBanDuration: FiniteDuration, - penaltySafeInterval: FiniteDuration, - penaltyScoreThreshold: Int, - peerEvictionInterval: FiniteDuration, - peerDiscovery: Boolean) - -case class ScorexSettings(dataDir: File, - logDir: File, - logging: LoggingSettings, - network: NetworkSettings, - restApi: RESTApiSettings) +case class NetworkSettings( + nodeName: String, + addedMaxDelay: Option[FiniteDuration], + localOnly: Boolean, + knownPeers: Seq[InetSocketAddress], + bannedPeers: Seq[InetSocketAddress], + bindAddress: InetSocketAddress, + maxConnections: Int, + connectionTimeout: FiniteDuration, + upnpEnabled: Boolean, + upnpGatewayTimeout: Option[FiniteDuration], + upnpDiscoverTimeout: Option[FiniteDuration], + declaredAddress: Option[InetSocketAddress], + handshakeTimeout: FiniteDuration, + deliveryTimeout: FiniteDuration, + maxDeliveryChecks: Int, + appVersion: String, + agentName: String, + desiredInvObjects: Int, + syncInterval: FiniteDuration, + syncStatusRefresh: FiniteDuration, + syncIntervalStable: FiniteDuration, + syncStatusRefreshStable: FiniteDuration, + inactiveConnectionDeadline: FiniteDuration, + syncTimeout: Option[FiniteDuration], + controllerTimeout: Option[FiniteDuration], + maxModifiersCacheSize: Int, + magicBytes: Array[Byte], + getPeersInterval: FiniteDuration, + maxPeerSpecObjects: Int, + temporalBanDuration: FiniteDuration, + penaltySafeInterval: FiniteDuration, + penaltyScoreThreshold: Int, + peerEvictionInterval: FiniteDuration, + peerDiscovery: Boolean +) +case class ScorexSettings( + dataDir: File, + logDir: File, + logging: LoggingSettings, + network: NetworkSettings, + restApi: RESTApiSettings +) object ScorexSettings extends ScorexLogging with SettingsReaders { @@ -65,14 +71,22 @@ object ScorexSettings extends ScorexLogging with SettingsReaders { def readConfigFromPath(userConfigPath: Option[String], configPath: String): Config = { - val maybeConfigFile: Option[File] = userConfigPath.map(filename => new File(filename)).filter(_.exists()) - .orElse(userConfigPath.flatMap(filename => Option(getClass.getClassLoader.getResource(filename))). - map(r => new File(r.toURI)).filter(_.exists())) + val maybeConfigFile: Option[File] = userConfigPath + .map(filename => new File(filename)) + .filter(_.exists()) + .orElse( + userConfigPath + .flatMap(filename => Option(getClass.getClassLoader.getResource(filename))) + .map(r => new File(r.toURI)) + .filter(_.exists()) + ) val config = maybeConfigFile match { // if no user config is supplied, the library will handle overrides/application/reference automatically case None => - log.warn("NO CONFIGURATION FILE WAS PROVIDED. STARTING WITH DEFAULT SETTINGS FOR TESTNET!") + log.warn( + "NO CONFIGURATION FILE WAS PROVIDED. STARTING WITH DEFAULT SETTINGS FOR TESTNET!" + ) ConfigFactory.load() // application config needs to be resolved wrt both system properties *and* user-supplied config. case Some(file) => @@ -96,7 +110,8 @@ object ScorexSettings extends ScorexLogging with SettingsReaders { } def fromConfig(config: Config): ScorexSettings = { - config.as[ScorexSettings](configPath) + config + .as[ScorexSettings](configPath) .ensuring(_.network.magicBytes.length == MagicLength) } } diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 7d30c0ea97..900f80addd 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -498,6 +498,9 @@ scorex { # A list of `IP:port` pairs of well known nodes. knownPeers = [] + # A list of `IP:port` pairs peers that will be permanently banned + bannedPeers = [] + # Interval between GetPeers messages to be send by our node to a random one getPeersInterval = 2m diff --git a/src/main/scala/org/ergoplatform/network/peer/PeerDatabase.scala b/src/main/scala/org/ergoplatform/network/peer/PeerDatabase.scala index 5040fbe561..8f40f1740d 100644 --- a/src/main/scala/org/ergoplatform/network/peer/PeerDatabase.scala +++ b/src/main/scala/org/ergoplatform/network/peer/PeerDatabase.scala @@ -1,7 +1,12 @@ package org.ergoplatform.network.peer import org.ergoplatform.nodeView.history.ErgoHistoryUtils._ -import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream} +import java.io.{ + ByteArrayInputStream, + ByteArrayOutputStream, + ObjectInputStream, + ObjectOutputStream +} import java.net.{InetAddress, InetSocketAddress} import org.ergoplatform.settings.ErgoSettings import scorex.db.LDBFactory @@ -17,6 +22,13 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging { private val persistentStore = LDBFactory.createKvDb(s"${settings.directory}/peers") + /** + * banned peer ip -> ban expiration timestamp + */ + private var blacklist = settings.scorexSettings.network.bannedPeers.map { addr => + addr.getAddress -> Long.MaxValue // Permanent ban + }.toMap + private var peers = loadPeers match { case Success(loadedPeers) => @@ -26,11 +38,6 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging { Map.empty[InetSocketAddress, PeerInfo] } - /** - * banned peer ip -> ban expiration timestamp - */ - private var blacklist = Map.empty[InetAddress, Time] - /** * penalized peer ip -> (accumulated penalty score, last penalty timestamp) */ @@ -41,7 +48,7 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging { */ private def serialize(obj: Object): Array[Byte] = { val stream: ByteArrayOutputStream = new ByteArrayOutputStream() - val oos = new ObjectOutputStream(stream) + val oos = new ObjectOutputStream(stream) oos.writeObject(obj) oos.close() stream.toByteArray @@ -50,7 +57,7 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging { /* * Deserialize object using standard Java serializer */ - private def deserialize(bytes: Array[Byte]) : Object = { + private def deserialize(bytes: Array[Byte]): Object = { val ois = new ObjectInputStream(new ByteArrayInputStream(bytes)) ois.readObject() } @@ -60,8 +67,8 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging { */ private def loadPeers: Try[Map[InetSocketAddress, PeerInfo]] = Try { var peers = Map.empty[InetSocketAddress, PeerInfo] - for ((addr,peer) <- persistentStore.getAll) { - val address = deserialize(addr).asInstanceOf[InetSocketAddress] + for ((addr, peer) <- persistentStore.getAll) { + val address = deserialize(addr).asInstanceOf[InetSocketAddress] val peerInfo = PeerInfoSerializer.parseBytes(peer) peers += address -> peerInfo } @@ -84,8 +91,10 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging { remove(socketAddress) Option(socketAddress.getAddress).foreach { address => penaltyBook -= address - if (!blacklist.keySet.contains(address)){ - blacklist += address -> (System.currentTimeMillis() + penaltyDuration(penaltyType)) + if (!blacklist.keySet.contains(address)) { + blacklist += address -> (System.currentTimeMillis() + penaltyDuration( + penaltyType + )) } else { log.warn(s"${address.toString} is already blacklisted") } @@ -104,12 +113,12 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging { def knownPeers: Map[InetSocketAddress, PeerInfo] = peers - def blacklistedPeers: Seq[InetAddress] = blacklist - .map { case (address, bannedTill) => - checkBanned(address, bannedTill) - address - } - .toSeq + def blacklistedPeers: Seq[InetAddress] = + blacklist.map { + case (address, bannedTill) => + checkBanned(address, bannedTill) + address + }.toSeq def isEmpty: Boolean = peers.isEmpty @@ -126,10 +135,10 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging { */ def penalize(socketAddress: InetSocketAddress, penaltyType: PenaltyType): Boolean = Option(socketAddress.getAddress).exists { address => - val currentTime = System.currentTimeMillis() - val safeInterval = settings.scorexSettings.network.penaltySafeInterval.toMillis + val currentTime = System.currentTimeMillis() + val safeInterval = settings.scorexSettings.network.penaltySafeInterval.toMillis val (penaltyScoreAcc, lastPenaltyTs) = penaltyBook.getOrElse(address, (0, 0L)) - val applyPenalty = currentTime - lastPenaltyTs - safeInterval > 0 || penaltyType.isPermanent + val applyPenalty = currentTime - lastPenaltyTs - safeInterval > 0 || penaltyType.isPermanent val newPenaltyScore = if (applyPenalty) { penaltyScoreAcc + penaltyScore(penaltyType) } else { @@ -173,10 +182,10 @@ final class PeerDatabase(settings: ErgoSettings) extends ScorexLogging { private def penaltyDuration(penalty: PenaltyType): Long = penalty match { - case PenaltyType.NonDeliveryPenalty | PenaltyType.MisbehaviorPenalty | PenaltyType.SpamPenalty => + case PenaltyType.NonDeliveryPenalty | PenaltyType.MisbehaviorPenalty | + PenaltyType.SpamPenalty => settings.scorexSettings.network.temporalBanDuration.toMillis case PenaltyType.PermanentPenalty => (360 * 10).days.toMillis } - } From 932edfa86c56291bc5ee1f85240b6682517d9d06 Mon Sep 17 00:00:00 2001 From: mgpai <64056966+mgpai22@users.noreply.github.com> Date: Tue, 19 Nov 2024 16:22:29 -0500 Subject: [PATCH 6/6] remove unused import --- src/main/scala/org/ergoplatform/network/peer/PeerDatabase.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/scala/org/ergoplatform/network/peer/PeerDatabase.scala b/src/main/scala/org/ergoplatform/network/peer/PeerDatabase.scala index 8f40f1740d..8a3c624791 100644 --- a/src/main/scala/org/ergoplatform/network/peer/PeerDatabase.scala +++ b/src/main/scala/org/ergoplatform/network/peer/PeerDatabase.scala @@ -1,6 +1,5 @@ package org.ergoplatform.network.peer -import org.ergoplatform.nodeView.history.ErgoHistoryUtils._ import java.io.{ ByteArrayInputStream, ByteArrayOutputStream,