Coverage Summary for Class: PeerScoring (co.rsk.scoring)

Class Method, % Line, %
PeerScoring 0% (0/13) 0% (0/70)
PeerScoring$1 0% (0/1) 0% (0/1)
PeerScoring$Factory
Total 0% (0/14) 0% (0/71)


1 package co.rsk.scoring; 2  3 import com.google.common.annotations.VisibleForTesting; 4  5 import java.util.concurrent.locks.ReadWriteLock; 6 import java.util.concurrent.locks.ReentrantReadWriteLock; 7  8 /** 9  * PeerScoring records the events associated with a peer 10  * identified by node id or IP address (@see PeerScoringManager) 11  * An integer score value is calculated based on recorded events. 12  * Also, a good reputation flag is calculated. 13  * The number of punishment is recorded, as well the initial punishment time and its duration. 14  * When the punishment expires, the good reputation is restored and most counters are reset to zero 15  * <p> 16  * Created by ajlopez on 27/06/2017. 17  */ 18 public class PeerScoring { 19  private final boolean punishmentEnabled; 20  21  private final ReadWriteLock rwlock = new ReentrantReadWriteLock(); 22  private int[] counters = new int[EventType.values().length]; 23  private boolean goodReputation = true; 24  private long timeLostGoodReputation; 25  private long punishmentTime; 26  private int punishmentCounter; 27  private int score; 28  29  public PeerScoring() { 30  this(true); 31  } 32  33  public PeerScoring(boolean punishmentEnabled) { 34  this.punishmentEnabled = punishmentEnabled; 35  } 36  37  /** 38  * Records an event. 39  * Current implementation has a counter by event type. 40  * The score is incremented or decremented, acoording to the kind of the event. 41  * Some negative events alters the score to a negative level, without 42  * taking into account its previous positive value 43  * 44  * @param evt An event type @see EventType 45  */ 46  public void recordEvent(EventType evt) { 47  try { 48  rwlock.writeLock().lock(); 49  50  counters[evt.ordinal()]++; 51  52  switch (evt) { 53  case INVALID_NETWORK: 54  case INVALID_BLOCK: 55  case INVALID_TRANSACTION: 56  case INVALID_MESSAGE: 57  case INVALID_HEADER: 58  // TODO(lsebrie): review how to handle timeouts properly 59  //case TIMEOUT_MESSAGE: 60  if (score > 0) { 61  score = 0; 62  } 63  score--; 64  break; 65  case UNEXPECTED_MESSAGE: 66  case FAILED_HANDSHAKE: 67  case SUCCESSFUL_HANDSHAKE: 68  case REPEATED_MESSAGE: 69  break; 70  71  default: 72  if (score >= 0) { 73  score++; 74  } 75  break; 76  } 77  } finally { 78  rwlock.writeLock().unlock(); 79  } 80  } 81  82  /** 83  * Returns the current computed score. 84  * The score is calculated based on previous event recording. 85  * 86  * @return An integer number, the level of score. Positive value is associated 87  * with a good reputation. Negative values indicates a possible punishment. 88  */ 89  public int getScore() { 90  try { 91  rwlock.readLock().lock(); 92  return score; 93  } finally { 94  rwlock.readLock().unlock(); 95  } 96  } 97  98  /** 99  * Returns the count of events given a event type. 100  * 101  * @param evt Event Type (@see EventType) 102  * 103  * @return The count of events of the specefied type 104  */ 105  public int getEventCounter(EventType evt) { 106  try { 107  rwlock.readLock().lock(); 108  return counters[evt.ordinal()]; 109  } finally { 110  rwlock.readLock().unlock(); 111  } 112  } 113  114  /** 115  * Returns the count of all events 116  * 117  * @return The total count of events 118  */ 119  public int getTotalEventCounter() { 120  try { 121  rwlock.readLock().lock(); 122  int counter = 0; 123  124  for (int i = 0; i < counters.length; i++) { 125  counter += counters[i]; 126  } 127  128  return counter; 129  } finally { 130  rwlock.readLock().unlock(); 131  } 132  } 133  134  /** 135  * Returns <tt>true</tt> if there is no event recorded yet. 136  * 137  * @return <tt>true</tt> if there is no event 138  */ 139  public boolean isEmpty() { 140  try { 141  rwlock.readLock().lock(); 142  return getTotalEventCounter() == 0; 143  } finally { 144  rwlock.readLock().unlock(); 145  } 146  } 147  148  /** 149  * Returns <tt>true</tt> if the peer has good reputation. 150  * Returns <tt>false</tt> if not. 151  * 152  * @return <tt>true</tt> or <tt>false</tt> 153  */ 154  public boolean hasGoodReputation() { 155  try { 156  rwlock.writeLock().lock(); 157  if (this.goodReputation) { 158  return true; 159  } 160  161  if (this.punishmentTime > 0 && this.timeLostGoodReputation > 0 162  && this.punishmentTime + this.timeLostGoodReputation <= System.currentTimeMillis()) { 163  this.endPunishment(); 164  } 165  166  return this.goodReputation; 167  } finally { 168  rwlock.writeLock().unlock(); 169  } 170  } 171  172  /** 173  * Starts the punishment, with specified duration 174  * Changes the reputation to not good 175  * Increments the punishment counter 176  * 177  * @param expirationTime punishment duration in milliseconds 178  */ 179  public void startPunishment(long expirationTime) { 180  if (!punishmentEnabled) { 181  return; 182  } 183  184  try { 185  rwlock.writeLock().lock(); 186  this.goodReputation = false; 187  this.punishmentTime = expirationTime; 188  this.punishmentCounter++; 189  this.timeLostGoodReputation = System.currentTimeMillis(); 190  } finally { 191  rwlock.writeLock().unlock(); 192  } 193  } 194  195  /** 196  * Ends the punishment 197  * Clear the event counters 198  * 199  */ 200  private void endPunishment() { 201  if (!punishmentEnabled) { 202  return; 203  } 204  205  //Check locks before doing this function public 206  for (int i = 0; i < counters.length; i++) { 207  this.counters[i] = 0; 208  } 209  this.goodReputation = true; 210  this.timeLostGoodReputation = 0; 211  this.score = 0; 212  } 213  214  @VisibleForTesting 215  public long getPunishmentTime() { 216  return this.punishmentTime; 217  } 218  219  /** 220  * Returns the number of punishment suffered by this peer. 221  * 222  * @return the counter of punishments 223  */ 224  public int getPunishmentCounter() { 225  return this.punishmentCounter; 226  } 227  228  @VisibleForTesting 229  public long getTimeLostGoodReputation() { 230  return this.timeLostGoodReputation; 231  } 232  233  public interface Factory { 234  PeerScoring newInstance(); 235  } 236 }