diff --git a/mixnet/v2/sim/adversary.py b/mixnet/v2/sim/adversary.py index af7759c..d4af53e 100644 --- a/mixnet/v2/sim/adversary.py +++ b/mixnet/v2/sim/adversary.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import math from collections import defaultdict +from enum import Enum from typing import TYPE_CHECKING import simpy @@ -19,6 +22,8 @@ class Adversary: self.message_sizes = [] self.senders_around_interval = defaultdict(int) self.mixed_msgs_per_window = [] + self.node_states = defaultdict(dict) + self.env.process(self.update_observation_window()) def inspect_message_size(self, msg: SphinxPacket | bytes): @@ -26,11 +31,15 @@ class Adversary: def observe_incoming_message(self, node: "Node"): self.mixed_msgs_per_window[-1][node] += 1 + # TODO: check duplications. Two events at the same time? + self.node_states[self.env.now][node] = NodeState.RECEIVING def observe_outgoing_message(self, node: "Node"): self.mixed_msgs_per_window[-1][node] -= 1 if self.is_around_message_interval(self.env.now): self.senders_around_interval[node] += 1 + # TODO: check duplications. Two events at the same time? + self.node_states[self.env.now][node] = NodeState.SENDING def is_around_message_interval(self, time: SimTime): now_frac, now_int = math.modf(time) @@ -40,3 +49,8 @@ class Adversary: while True: self.mixed_msgs_per_window.append(defaultdict(int)) yield self.env.timeout(self.config.adversary.io_observation_window) + + +class NodeState(Enum): + SENDING = 0 + RECEIVING = 1 diff --git a/mixnet/v2/sim/analysis.py b/mixnet/v2/sim/analysis.py index ba175d8..3efb60b 100644 --- a/mixnet/v2/sim/analysis.py +++ b/mixnet/v2/sim/analysis.py @@ -2,6 +2,7 @@ import pandas as pd import seaborn from matplotlib import pyplot as plt +from adversary import NodeState from simulation import Simulation @@ -13,6 +14,7 @@ class Analysis: self.message_size_distribution() self.messages_emitted_around_interval() self.mixed_messages_per_node_over_time() + self.node_states() def message_size_distribution(self): df = pd.DataFrame(self.sim.p2p.adversary.message_sizes, columns=["message_size"]) @@ -50,3 +52,19 @@ class Analysis: plt.legend(title="Node ID") plt.grid(True) plt.show() + + def node_states(self): + rows = [] + for time, node_states in self.sim.p2p.adversary.node_states.items(): + for node, state in node_states.items(): + rows.append((time, node.id, state)) + df = pd.DataFrame(rows, columns=["time", "node_id", "state"]) + + plt.figure(figsize=(10, 6)) + seaborn.scatterplot(data=df, x="time", y="node_id", hue="state", palette={NodeState.SENDING: "red", NodeState.RECEIVING: "blue"}) + plt.title("Node states over time") + plt.xlabel("Time") + plt.ylabel("Node ID") + plt.legend(title="state") + plt.show() +