From 03b1f1a4ba299378daf0e9bcab9e2801794ba99d Mon Sep 17 00:00:00 2001 From: mratsim Date: Mon, 10 Sep 2018 12:35:11 +0200 Subject: [PATCH] Networksim additions + fix agents and normal_distribution types --- .../fork_choice_rule/distributions.nim | 21 ++++++++------ .../fork_choice_rule/fork_choice_types.nim | 2 +- beacon_chain/fork_choice_rule/networksim.nim | 28 +++++++++++++++++-- 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/beacon_chain/fork_choice_rule/distributions.nim b/beacon_chain/fork_choice_rule/distributions.nim index fb885da1a..a3429f090 100644 --- a/beacon_chain/fork_choice_rule/distributions.nim +++ b/beacon_chain/fork_choice_rule/distributions.nim @@ -12,11 +12,14 @@ import math, random -proc normal_distribution*(mean = 0.0, std = 1.0): int = +proc normal_distribution*(mean = 0, std = 1): int = ## Return an integer sampled from a normal distribution (gaussian) ## ⚠ This is not thread-safe # Implementation via the Box-Muller method # See https://en.wikipedia.org/wiki/Box–Muller_transform + let + mean = mean.float + std = std.float var z1 {.global.}: float @@ -46,8 +49,8 @@ when isMainModule: abs(y_true - y)/abs(y_true) let - mu = 1000f - sigma = 12f + mu = 1000 + sigma = 12 a = newSeqWith(10000000, normal_distribution(mean = mu, std = sigma)) var statistics: RunningStat @@ -61,13 +64,13 @@ when isMainModule: echo &"{stat:<20} {value:>9.4f} | Expected: {expected:>9.4f}" echo &"Statistics on {a.len} samples" - report "Mean: ", statistics.mean, mu - report "Standard deviation: ", statistics.standardDeviationS, sigma + report "Mean: ", statistics.mean, mu.float + report "Standard deviation: ", statistics.standardDeviationS, sigma.float # Absolute error - doAssert absolute_error(mu, statistics.mean) < 0.6 - doAssert absolute_error(sigma, statistics.standardDeviationS) < 0.01 + doAssert absolute_error(mu.float, statistics.mean) < 0.6 + doAssert absolute_error(sigma.float, statistics.standardDeviationS) < 0.01 # Relative error - doAssert relative_error(mu, statistics.mean) < 0.01 - doAssert relative_error(sigma, statistics.standardDeviationS) < 0.01 + doAssert relative_error(mu.float, statistics.mean) < 0.01 + doAssert relative_error(sigma.float, statistics.standardDeviationS) < 0.01 diff --git a/beacon_chain/fork_choice_rule/fork_choice_types.nim b/beacon_chain/fork_choice_rule/fork_choice_types.nim index 66ec838f1..19def8a37 100644 --- a/beacon_chain/fork_choice_rule/fork_choice_types.nim +++ b/beacon_chain/fork_choice_rule/fork_choice_types.nim @@ -104,7 +104,7 @@ func hash*(x: Duration): Hash = type NetworkSimulator* = ref object - agents*: seq[int] + agents*: seq[Node] latency_distribution_sample*: proc (): Duration time*: Duration objqueue*: TableRef[Duration, seq[(Node, BlockOrSig)]] diff --git a/beacon_chain/fork_choice_rule/networksim.nim b/beacon_chain/fork_choice_rule/networksim.nim index 4ab86db37..3db580cd4 100644 --- a/beacon_chain/fork_choice_rule/networksim.nim +++ b/beacon_chain/fork_choice_rule/networksim.nim @@ -10,8 +10,32 @@ # Part of Casper+Sharding chain v2.1: https://notes.ethereum.org/SCIg8AH5SA-O4C1G1LYZHQ# import - tables, times, - ./fork_choice_types + tables, times, sugar, random, + ./fork_choice_types, ./distributions + +proc initNetworkSimulator*(latency: int): NetworkSimulator = + result.latency_distribution_sample = () => initDuration( + seconds = max( + 0, + normal_distribution(latency, latency * 2 div 5) + ) + ) + result.reliability = 0.9 + result.objqueue = newTable[Duration, seq[(Node, BlockOrSig)]]() + result.peers = newTable[int, seq[Node]]() + +proc generate_peers*(self: NetworkSimulator, num_peers = 5) = + self.peers.clear() + var p: seq[Node] + for a in self.agents: + p.setLen(0) # reset without involving GC/realloc + while p.len <= num_peers div 2: + p.add self.agents.rand() + if p[^1] == a: + discard p.pop() + self.peers[a.id].add p + for peer in p: + self.peers[peer.id].add a func broadcast*(self: NetworkSimulator, sender: Node, obj: BlockOrSig) = for p in self.peers[sender.id]: