@@ -10,57 +10,151 @@ import scala.jdk.CollectionConverters._
10
10
import scala .jdk .OptionConverters ._
11
11
import scala .jdk .DurationConverters ._
12
12
13
- import Blacklist .BlacklistId
13
+ import Blacklist ._
14
+ import io .iohk .ethereum .network .PeerId
15
+ import io .iohk .ethereum .blockchain .sync .Blacklist .BlacklistReason .BlacklistReasonType .WrongBlockHeadersType
16
+ import io .iohk .ethereum .consensus .validators .std .StdBlockValidator .BlockError
17
+ import io .iohk .ethereum .blockchain .sync .Blacklist .BlacklistReason .BlacklistReasonType
14
18
15
19
trait Blacklist {
16
20
def isBlacklisted (id : BlacklistId ): Boolean
17
- def add (id : BlacklistId , duration : FiniteDuration , reason : String ): Unit
21
+ def add (id : BlacklistId , duration : FiniteDuration , reason : BlacklistReason ): Unit
18
22
def remove (id : BlacklistId ): Unit
19
23
def keys : Set [BlacklistId ]
20
24
}
21
25
22
26
object Blacklist {
27
+ import BlacklistReason ._
28
+ import BlacklistReasonType ._
29
+
23
30
trait BlacklistId {
24
31
def value : String
25
32
}
33
+
34
+ sealed trait BlacklistReason {
35
+ def reasonType : BlacklistReasonType
36
+ def description : String
37
+ }
38
+ object BlacklistReason {
39
+ trait BlacklistReasonType {
40
+ def code : Int
41
+ def name : String
42
+ }
43
+ object BlacklistReasonType {
44
+ case object WrongBlockHeadersType extends BlacklistReasonType {
45
+ val code : Int = 1
46
+ val name : String = " WrongBlockHeadersType"
47
+ }
48
+ case object BlockHeaderValidationFailedType extends BlacklistReasonType {
49
+ val code : Int = 2
50
+ val name : String = " BlockHeaderValidationFailed"
51
+ }
52
+ case object ErrorInBlockHeadersType extends BlacklistReasonType {
53
+ val code : Int = 3
54
+ val name : String = " ErrorInBlockHeaders"
55
+ }
56
+ case object EmptyBlockBodiesType extends BlacklistReasonType {
57
+ val code : Int = 4
58
+ val name : String = " EmptyBlockBodies"
59
+ }
60
+ case object BlockBodiesNotMatchingHeadersType extends BlacklistReasonType {
61
+ val code : Int = 5
62
+ val name : String = " BlockBodiesNotMatchingHeaders"
63
+ }
64
+ case object EmptyReceiptsType extends BlacklistReasonType {
65
+ val code : Int = 6
66
+ val name : String = " EmptyReceipts"
67
+ }
68
+ case object InvalidReceiptsType extends BlacklistReasonType {
69
+ val code : Int = 7
70
+ val name : String = " InvalidReceipts"
71
+ }
72
+ case object RequestFailedType extends BlacklistReasonType {
73
+ val code : Int = 8
74
+ val name : String = " RequestFailed"
75
+ }
76
+ case object PeerActorTerminatedType extends BlacklistReasonType {
77
+ val code : Int = 9
78
+ val name : String = " PeerActorTerminated"
79
+ }
80
+ }
81
+
82
+ case object WrongBlockHeaders extends BlacklistReason {
83
+ val reasonType : BlacklistReasonType = WrongBlockHeadersType
84
+ val description : String = " Wrong blockheaders response (empty or not chain forming)"
85
+ }
86
+ case object BlockHeaderValidationFailed extends BlacklistReason {
87
+ val reasonType : BlacklistReasonType = BlockHeaderValidationFailedType
88
+ val description : String = " Block header validation failed"
89
+ }
90
+ case object ErrorInBlockHeaders extends BlacklistReason {
91
+ val reasonType : BlacklistReasonType = ErrorInBlockHeadersType
92
+ val description : String = " Error in block headers response"
93
+ }
94
+ final case class EmptyBlockBodies (knownHashes : Seq [String ]) extends BlacklistReason {
95
+ val reasonType : BlacklistReasonType = EmptyBlockBodiesType
96
+ val description : String = s " Got empty block bodies response for known hashes: $knownHashes"
97
+ }
98
+ case object BlockBodiesNotMatchingHeaders extends BlacklistReason {
99
+ val reasonType : BlacklistReasonType = BlockBodiesNotMatchingHeadersType
100
+ val description = " Block bodies not matching block headers"
101
+ }
102
+ final case class EmptyReceipts (knownHashes : Seq [String ]) extends BlacklistReason {
103
+ val reasonType : BlacklistReasonType = EmptyReceiptsType
104
+ val description : String = s " Got empty receipts for known hashes: $knownHashes"
105
+ }
106
+ final case class InvalidReceipts (knownHashes : Seq [String ], error : BlockError ) extends BlacklistReason {
107
+ val reasonType : BlacklistReasonType = InvalidReceiptsType
108
+ val description : String = s " Got invalid receipts for known hashes: $knownHashes due to: $error"
109
+ }
110
+ final case class RequestFailed (error : String ) extends BlacklistReason {
111
+ val reasonType : BlacklistReasonType = RequestFailedType
112
+ val description : String = s " Request failed with error: $error"
113
+ }
114
+ case object PeerActorTerminated extends BlacklistReason {
115
+ val reasonType : BlacklistReasonType = PeerActorTerminatedType
116
+ val description : String = " Peer actor terminated"
117
+ }
118
+ }
26
119
}
27
120
28
- final case class CacheBasedBlacklist (cache : Cache [BlacklistId , String ]) extends Blacklist with Logger {
121
+ final case class CacheBasedBlacklist (cache : Cache [BlacklistId , BlacklistReasonType ]) extends Blacklist with Logger {
122
+
123
+ import CacheBasedBlacklist ._
29
124
30
125
override def isBlacklisted (id : BlacklistId ): Boolean = cache.getIfPresent(id).isDefined
31
126
32
- override def add (id : BlacklistId , duration : FiniteDuration , reason : String ): Unit =
33
- cache
34
- .policy()
35
- .expireVariably()
36
- .toScala
37
- .fold {
38
- log.warn(
39
- s " Unexpected error while adding peer [ ${id.value}] to blacklist using custom expiration time. Falling back to default expiration. "
40
- )
41
- cache.put(id, reason)
42
- } { varExpirationPolicy =>
43
- varExpirationPolicy.put(id, reason, duration.toJava)
44
- }
127
+ override def add (id : BlacklistId , duration : FiniteDuration , reason : BlacklistReason ): Unit = {
128
+ log.debug(" Blacklisting peer [{}] for {}. Reason: {}" , id, duration, reason)
129
+ cache.policy().expireVariably().toScala match {
130
+ case Some (varExpiration) => varExpiration.put(id, reason.reasonType, duration.toJava)
131
+ case None =>
132
+ log.warn(customExpirationError(id))
133
+ cache.put(id, reason.reasonType)
134
+ }
135
+ }
45
136
override def remove (id : BlacklistId ): Unit = cache.invalidate(id)
46
137
47
138
override def keys : Set [BlacklistId ] = cache.underlying.asMap().keySet().asScala.toSet
48
139
}
49
140
50
141
object CacheBasedBlacklist {
51
142
143
+ def customExpirationError (id : BlacklistId ): String =
144
+ s " Unexpected error while adding peer [ ${id.value}] to blacklist using custom expiration time. Falling back to default expiration. "
145
+
52
146
def empty (maxSize : Int ): CacheBasedBlacklist = {
53
147
val cache =
54
148
Scaffeine ()
55
- .expireAfter[BlacklistId , String ](
149
+ .expireAfter[BlacklistId , BlacklistReasonType ](
56
150
create = (_, _) => 60 .minutes,
57
151
update = (_, _, _) => 60 .minutes,
58
152
read = (_, _, _) => 60 .minutes
59
153
) // required to enable VarExpiration policy (i.e. set custom expiration time per element)
60
154
.maximumSize(
61
155
maxSize
62
156
) // uses Window TinyLfu eviction policy, see https://github.com/ben-manes/caffeine/wiki/Efficiency
63
- .build[BlacklistId , String ]()
157
+ .build[BlacklistId , BlacklistReasonType ]()
64
158
CacheBasedBlacklist (cache)
65
159
}
66
160
0 commit comments