From acf322ea7b93037d233a410086be03ba67a0721d Mon Sep 17 00:00:00 2001 From: mratsim Date: Tue, 11 Sep 2018 14:02:45 +0200 Subject: [PATCH] Fix tables initialization issues --- .../fork_choice_rule/fork_choice_rule.nim | 16 ++++---- .../fork_choice_rule/fork_choice_test.nim | 37 +++++++++++++++++++ .../fork_choice_rule/fork_choice_types.nim | 25 ++++++++++++- beacon_chain/fork_choice_rule/networksim.nim | 9 +++-- 4 files changed, 73 insertions(+), 14 deletions(-) create mode 100644 beacon_chain/fork_choice_rule/fork_choice_test.nim diff --git a/beacon_chain/fork_choice_rule/fork_choice_rule.nim b/beacon_chain/fork_choice_rule/fork_choice_rule.nim index eaac7043f..96e152312 100644 --- a/beacon_chain/fork_choice_rule/fork_choice_rule.nim +++ b/beacon_chain/fork_choice_rule/fork_choice_rule.nim @@ -40,9 +40,7 @@ func add_to_multiset[K, V]( multiset: TableRef[K, seq[V]], k: K, v: V or seq[V]) = - # if k notin multiset: # Unneeded with seq "not nil" changes - # multiset[k] = @[] - multiset[k].add v + multiset.mgetOrPut(k, @[]).add v func change_head(self: Node, chain: var seq[MDigest[256]], new_head: Block) = chain.add newSeq[MDigest[256]](new_head.height + 1 - chain.len) @@ -240,7 +238,9 @@ proc tick*(self: Node) = let slot = int32 seconds(self.timestamp div SLOT_SIZE) if slot > self.last_made_block and (slot mod NOTARIES) == self.id: self.broadcast( - initBlock(self.blocks[self.main_chain[^1]], slot, self.id) + initBlock(self.blocks[ + self.main_chain[^1] + ], slot, self.id) ) self.last_made_block = slot # Make a sig? @@ -248,13 +248,11 @@ proc tick*(self: Node) = var sig_from = self.main_chain.high while sig_from > 0 and self.blocks[self.main_chain[sig_from]].slot >= slot - EPOCH_LENGTH: dec sig_from - let sig = initSig(self.id, self.get_sig_targets(slot), slot, self.timestamp) + let sig = newSig(self.id, self.get_sig_targets(slot), slot, self.timestamp) self.log &"Sig: {self.id} {sig.slot} {sig.targets.mapIt(($it)[0 ..< 4])}" self.broadcast sig self.last_made_sig = slot # process time queue - var first = self.timequeue[0] - while self.timequeue.len > 0 and first.min_timestamp <= self.timestamp: + while self.timequeue.len > 0 and self.timequeue[0].min_timestamp <= self.timestamp: self.timequeue.delete(0) # This is expensive, but we can't use a queue due to random insertions in add_to_timequeue - self.on_receive(first, reprocess = true) - first = self.timequeue[0] + self.on_receive(self.timequeue[0], reprocess = true) diff --git a/beacon_chain/fork_choice_rule/fork_choice_test.nim b/beacon_chain/fork_choice_rule/fork_choice_test.nim new file mode 100644 index 000000000..6af92eaf8 --- /dev/null +++ b/beacon_chain/fork_choice_rule/fork_choice_test.nim @@ -0,0 +1,37 @@ +# beacon_chain +# Copyright (c) 2018 Status Research & Development GmbH +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +# A port of https://github.com/ethereum/research/blob/master/clock_disparity/ghost_node.py +# Specs: https://ethresear.ch/t/beacon-chain-casper-ffg-rpj-mini-spec/2760 +# Part of Casper+Sharding chain v2.1: https://notes.ethereum.org/SCIg8AH5SA-O4C1G1LYZHQ# +# Note that implementation is not updated to the latest v2.1 yet + +import + ./fork_choice_types, ./networksim, ./fork_choice_rule, ./distributions, + sequtils, times, strformat, tables + +let net = newNetworkSimulator(latency = 22) + +for i in 0'i32 ..< NOTARIES: + net.agents.add newNode( + id = i, + network = net, + timestamp = initDuration(seconds = max(normal_distribution(300, 300), 0)) div 10, + sleepy = i mod 4 == 0 + ) + +net.generate_peers() + +for i in 0 ..< 100000: + net.tick() + +for n in net.agents: + echo &"Local timestamp: {n.timestamp:>.1}, timequeue len {n.timequeue.len}" + echo "Main chain head: ", n.blocks[n.main_chain[^1]].height + echo "Total main chain blocks received: ", toSeq(values(n.blocks)).filterIt(it is Block).len + # echo "Notarized main chain blocks received: ", toSeq(values(n.blocks)).filterIt((it is Block) and n.is_notarized(it)).len - 1 + diff --git a/beacon_chain/fork_choice_rule/fork_choice_types.nim b/beacon_chain/fork_choice_rule/fork_choice_types.nim index 1b1a4c987..4ec11e9d4 100644 --- a/beacon_chain/fork_choice_rule/fork_choice_types.nim +++ b/beacon_chain/fork_choice_rule/fork_choice_types.nim @@ -141,7 +141,7 @@ type last_made_block*: int32 last_made_sig*: int32 -proc initSig*( +proc newSig*( proposer: int32, targets: seq[MDigest[256]], slot: int32, @@ -154,6 +154,29 @@ proc initSig*( for val in result.hash.data.mitems: val = rand(0.byte .. 7.byte) +proc newNode*( + id: int32, + network: NetworkSimulator, + sleepy, careless = false, + timestamp = DurationZero + ): Node = + new result + result.id = id + result.network = network + result.timestamp = timestamp + result.sleepy = sleepy + result.careless = careless + result.main_chain = @[Genesis.hash] + result.blocks = {Genesis.hash: Genesis}.newTable + + # Boilerplate empty initialization + result.processed = newTable[BlockOrSigHash, BlockOrSig]() + result.children = newTable[MDigest[256], seq[MDigest[256]]]() + result.parentqueue = newTable[MDigest[256], seq[BlockOrSig]]() + result.scores = newTable[MDigest[256], int]() + result.scores_at_height = newTable[array[36, byte], int]() + result.sigs = newTable[MDigest[384], Sig]() + ########################################################### # Forward declarations diff --git a/beacon_chain/fork_choice_rule/networksim.nim b/beacon_chain/fork_choice_rule/networksim.nim index 0bac77a6a..47142e524 100644 --- a/beacon_chain/fork_choice_rule/networksim.nim +++ b/beacon_chain/fork_choice_rule/networksim.nim @@ -13,7 +13,8 @@ import tables, times, sugar, random, ./fork_choice_types, ./fork_choice_rule, ./distributions -proc initNetworkSimulator*(latency: int): NetworkSimulator = +proc newNetworkSimulator*(latency: int): NetworkSimulator = + new result result.latency_distribution_sample = () => initDuration( seconds = max( 0, @@ -33,11 +34,11 @@ proc generate_peers*(self: NetworkSimulator, num_peers = 5) = p.add self.agents.rand() if p[^1] == a: discard p.pop() - self.peers[a.id].add p + self.peers.mgetOrPut(a.id, @[]).add p for peer in p: - self.peers[peer.id].add a + self.peers.mgetOrPut(peer.id, @[]).add a -proc tick(self: NetworkSimulator) = +proc tick*(self: NetworkSimulator) = if self.time in self.objqueue: for ro in self.objqueue[self.time]: let (recipient, obj) = ro