From 618865fb5cf3d02254b2fa953ec294bcfe8c7aba Mon Sep 17 00:00:00 2001 From: Youngjoon Lee <5462944+youngjoon-lee@users.noreply.github.com> Date: Thu, 23 May 2024 17:52:17 +0900 Subject: [PATCH] gossip --- mixnet/v2/sim/config.py | 5 +++++ mixnet/v2/sim/config.yaml | 4 +++- mixnet/v2/sim/p2p.py | 25 +++++++++++++++++++++++-- mixnet/v2/sim/simulation.py | 6 +++--- 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/mixnet/v2/sim/config.py b/mixnet/v2/sim/config.py index f1314c5..c5b855d 100644 --- a/mixnet/v2/sim/config.py +++ b/mixnet/v2/sim/config.py @@ -98,6 +98,8 @@ class MixnetConfig: class P2PConfig: # Broadcasting type: naive | gossip type: str + # A connection density, only if the type is gossip + connection_density: int # A maximum network latency between nodes directly connected with each other max_network_latency: float @@ -106,11 +108,14 @@ class P2PConfig: def validate(self): assert self.type in [self.TYPE_NAIVE, self.TYPE_GOSSIP] + if self.type == self.TYPE_GOSSIP: + assert self.connection_density > 0 assert self.max_network_latency >= 0 def description(self): return ( f"p2p_type: {self.type}\n" + f"conn_density: {self.connection_density}" f"max_net_latency: {self.max_network_latency:.2f}" ) diff --git a/mixnet/v2/sim/config.yaml b/mixnet/v2/sim/config.yaml index cf444c6..bc3b018 100644 --- a/mixnet/v2/sim/config.yaml +++ b/mixnet/v2/sim/config.yaml @@ -27,7 +27,9 @@ mixnet: p2p: # Broadcasting type: naive | gossip - type: "naive" + type: "gossip" + # A connection density, only if the type is gossip + connection_density: 10 # A maximum network latency between nodes directly connected with each other max_network_latency: 0.5 diff --git a/mixnet/v2/sim/p2p.py b/mixnet/v2/sim/p2p.py index c197284..72fce20 100644 --- a/mixnet/v2/sim/p2p.py +++ b/mixnet/v2/sim/p2p.py @@ -25,8 +25,8 @@ class P2P(ABC): self.measurement = Measurement(env, config) self.adversary = Adversary(env, config) - def add_node(self, nodes: list["Node"]): - self.nodes.extend(nodes) + def set_nodes(self, nodes: list["Node"]): + self.nodes = nodes def get_nodes(self, n: int) -> list["Node"]: return random.sample(self.nodes, n) @@ -57,6 +57,7 @@ class P2P(ABC): class NaiveBroadcastP2P(P2P): def __init__(self, env: simpy.Environment, config: Config): super().__init__(env, config) + self.nodes = [] # This should accept only bytes in practice, # but we accept SphinxPacket as well because we don't implement Sphinx deserialization. @@ -78,6 +79,24 @@ class GossipP2P(P2P): self.topology = defaultdict(set) self.message_cache = defaultdict(set) + def set_nodes(self, nodes: list["Node"]): + super().set_nodes(nodes) + for i, node in enumerate(nodes): + # Each node is chained with the right neighbor, so that no node is not orphaned. + # And then, each node is connected to a random subset of other nodes. + front, back = nodes[:i], nodes[i + 1:] + if len(back) > 0: + neighbor = back[0] + back = back[1:] + else: + neighbor = front[0] + front = front[1:] + others = front + back + n = min(self.config.p2p.connection_density - 1, len(others)) + conns = set(random.sample(others, n)) + conns.add(neighbor) + self.topology[node] = conns + def broadcast(self, sender: "Node", msg: SphinxPacket | bytes): yield from super().broadcast(sender, msg) self.log("Gossiping a msg: %d bytes" % len(msg)) @@ -92,3 +111,5 @@ class GossipP2P(P2P): if msg_hash not in self.message_cache[receiver]: self.message_cache[receiver].add(msg_hash) self.env.process(receiver.receive_message(msg)) + # gossiping + self.env.process(self.broadcast(receiver, msg)) diff --git a/mixnet/v2/sim/simulation.py b/mixnet/v2/sim/simulation.py index 437851d..daad06a 100644 --- a/mixnet/v2/sim/simulation.py +++ b/mixnet/v2/sim/simulation.py @@ -12,9 +12,9 @@ class Simulation: random.seed() self.config = config self.env = simpy.Environment() - self.p2p = NaiveBroadcastP2P(self.env, config) - self.nodes = [Node(i, self.env, self.p2p, config) for i in range(config.mixnet.num_nodes)] - self.p2p.add_node(self.nodes) + self.p2p = Simulation.init_p2p(self.env, config) + nodes = [Node(i, self.env, self.p2p, config) for i in range(config.mixnet.num_nodes)] + self.p2p.set_nodes(nodes) def run(self): self.env.run(until=self.config.simulation.running_time)