Coverage Summary for Class: Stats (org.ethereum.net.server)

Class Method, % Line, %
Stats 0% (0/11) 0% (0/62)
Stats$1 0% (0/1) 0% (0/1)
Total 0% (0/12) 0% (0/63)


1 package org.ethereum.net.server; 2  3 import co.rsk.net.messages.MessageType; 4 import com.google.common.annotations.VisibleForTesting; 5  6 /** 7  * The general idea here is that a score is of the form: 8  * score = type * (a * x + b * y) 9  * where type is a value that depends on the message type, x and y are constants 10  * and a and b are calculated depending on the behaviour of the peer 11  * for a we use time between messages and for b the ratio of imported best vs other imported block messages 12  * 13  * The alternative of updating the score based on the previous score is hard. It becomes really difficult 14  * to predict the behavior of the network and make updates on the algorithms. 15  * 16  * This methodology is simpler. We select easy things to evaluate and put a weight on them, Then we can 17  * improve the system by iterating over the constants or changing how a particular value is calculated 18  * 19  * Some values are estimated using exponential moving average. Basically we say 20  * x_n = x_(n-1) + alpha * (x_(n-1) - x) 21  * where x is the new measure of such value 22  * 23  * Negative scores represent rejected messages 24  */ 25 public class Stats { 26  27  // last message timestamp in ms 28  private long lastMessage; 29  30  // Current minute messages counter 31  private long minute; 32  // Reject messages over this treshold 33  // Is calculated using Exponential moving average 34  private long perMinuteThreshold; 35  36  // events counters 37  // 100% heuristics 38  private long importedBest; 39  private long importedNotBest; 40  41  // vars that get updated with EMA 42  // msg per minutes and "average" time between messages 43  private double mpm; 44  private double avg; //in ms 45  46  // how fast avg and mpm update 47  private double alpha_m; 48  private double alpha_a; 49  50  // scores for blocks and others 51  private double maxBlock; 52  private double maxOther; 53  54  public Stats() { 55  avg = 500; 56  alpha_m = 0.3; 57  alpha_a = 0.03; 58  59  perMinuteThreshold = 1000; 60  61  maxBlock = 200; 62  maxOther = 100; 63  mpm = 1; 64  } 65  66  67  public synchronized double update(long timestamp, MessageType type) { 68  long min = timestamp / 60000; 69  long delta = timestamp - lastMessage; 70  if (delta <= 0) { 71  delta = 1; 72  } 73  74  if (min == lastMessage / 60000) { 75  minute++; 76  } else { 77  // reset to 0 if it passed more than a minute from previous message 78  if ((timestamp - lastMessage) / 60000 > 1) { 79  mpm = 0; 80  } 81  mpm += alpha_m * ((double)minute - mpm); 82  minute = 0; 83  } 84  85  if (minute > perMinuteThreshold) { 86  return -1; 87  } 88  89  90  avg += alpha_a * (delta - avg); 91  92  double res = score(type); 93  lastMessage = timestamp; 94  95  return res; 96  } 97  98  public double score(MessageType type) { 99  double a = avg / 1000; 100  a = (a > 1) ? 1 : a; 101  102  double b = (5 * importedBest) / (double)(importedNotBest + importedBest + 10); 103  b = (b > 1) ? 1 : b; 104  double res = a * maxOther + b * maxBlock; 105  106  res *= priority(type); 107  108  // mpm and avg are kind of redundant here 109  // both somehow count messages and reduce the score based on that 110  double m = 1 + mpm / 90; 111  if (m > 3) { 112  m = 3; 113  } 114  115  res /= m; 116  return res; 117  } 118  119  private double priority(MessageType type) { 120  121  switch (type) { 122  case TRANSACTIONS: 123  return 2; 124  case BLOCK_MESSAGE: 125  return 10; 126  case STATUS_MESSAGE: 127  return 1; 128  case NEW_BLOCK_HASHES: 129  return 3; 130  case GET_BLOCK_MESSAGE: 131  return 1; 132  case BODY_REQUEST_MESSAGE: 133  return 1; 134  case BLOCK_REQUEST_MESSAGE: 135  return 1; 136  case BODY_RESPONSE_MESSAGE: 137  return 1; 138  case BLOCK_RESPONSE_MESSAGE: 139  return 15; 140  case NEW_BLOCK_HASH_MESSAGE: 141  return 3; 142  case SKELETON_REQUEST_MESSAGE: 143  return 1; 144  case SKELETON_RESPONSE_MESSAGE: 145  return 3; 146  case BLOCK_HASH_REQUEST_MESSAGE: 147  return 1; 148  case BLOCK_HASH_RESPONSE_MESSAGE: 149  return 3; 150  case BLOCK_HEADERS_REQUEST_MESSAGE: 151  return 0.5; 152  case BLOCK_HEADERS_RESPONSE_MESSAGE: 153  return 5; 154  } 155  return 0.0; 156  } 157  public synchronized void imported(boolean best) { 158  if (best) { 159  importedBest++; 160  } else { 161  importedNotBest++; 162  } 163  } 164  165  166  @Override 167  public String toString() { 168  return "Stats{" + 169  "lastMessage=" + lastMessage + 170  ", minute=" + minute + 171  ", perMinuteThreshold=" + perMinuteThreshold + 172  ", importedBest=" + importedBest + 173  ", importedNotBest=" + importedNotBest + 174  ", mpm=" + mpm + 175  ", avg=" + avg + 176  ", alpha_m=" + alpha_m + 177  ", alpha_a=" + alpha_a + 178  ", maxBlock=" + maxBlock + 179  ", maxOther=" + maxOther + 180  '}'; 181  } 182  183  @VisibleForTesting 184  public double getMpm() { 185  return mpm; 186  } 187  188  189  @VisibleForTesting 190  public long getMinute() { 191  return minute; 192  } 193  194  @VisibleForTesting 195  public void setAvg(double avg) { 196  this.avg = avg; 197  } 198  199  @VisibleForTesting 200  public void setImportedBest(int importedBest) { 201  this.importedBest = importedBest; 202  } 203  204  @VisibleForTesting 205  public void setImportedNotBest(int importedNotBest) { 206  this.importedNotBest = importedNotBest; 207  } 208  209 }