mirror of
https://github.com/logos-blockchain/logos-blockchain-specs.git
synced 2026-01-07 23:53:11 +00:00
analyze nodes who emitted messages around the promised interval
This commit is contained in:
parent
7492be95fb
commit
661f40680c
@ -11,7 +11,7 @@ class Config:
|
||||
num_nodes: int
|
||||
num_mix_layers: int
|
||||
message_interval: int
|
||||
real_message_prob: float
|
||||
real_message_prob: float # TODO: should be proportional to its stake
|
||||
cover_message_prob: float
|
||||
max_message_prep_time: float
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
running_time: 30
|
||||
num_nodes: 5
|
||||
num_nodes: 100
|
||||
num_mix_layers: 3
|
||||
message_interval: 1
|
||||
# (real_message_prob + cover_message_prob) should be <= 1
|
||||
# If the sum is < 1, then the remaining probability is for sending nothing.
|
||||
real_message_prob: 0.1
|
||||
cover_message_prob: 0.4
|
||||
real_message_prob: 0.01
|
||||
cover_message_prob: 0.2
|
||||
max_message_prep_time: 0.3
|
||||
@ -8,7 +8,7 @@ from config import Config
|
||||
from simulation import Simulation
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Run simulation', formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser = argparse.ArgumentParser(description="Run simulation", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument("--config", type=str, required=True, help="Configuration file path")
|
||||
args = parser.parse_args()
|
||||
|
||||
@ -16,12 +16,17 @@ if __name__ == "__main__":
|
||||
sim = Simulation(config)
|
||||
sim.run()
|
||||
|
||||
# Stat the distribution of message sizes
|
||||
df = pd.DataFrame(sim.p2p.message_sizes, columns=["message_size"])
|
||||
print(df.describe())
|
||||
|
||||
# Visualize the nodes emitted messages around the promised interval
|
||||
df = pd.DataFrame([(node.id, cnt) for node, cnt in sim.p2p.nodes_emitted_msg_around_interval.items()], columns=["node", "count"])
|
||||
plt.figure(figsize=(10, 6))
|
||||
seaborn.boxplot(y=df["message_size"])
|
||||
plt.title("Message size distribution")
|
||||
plt.ylabel("Message Size (bytes)")
|
||||
seaborn.barplot(x="node", y="count", data=df)
|
||||
plt.title("Messages emitted around the promised interval")
|
||||
plt.xlabel("Node ID")
|
||||
plt.ylabel("Msg Count")
|
||||
plt.show()
|
||||
|
||||
print("Simulation complete!")
|
||||
@ -40,7 +40,7 @@ class Node:
|
||||
|
||||
self.log("Sending a message to the mixnet")
|
||||
msg = self.create_message(payload)
|
||||
self.env.process(self.p2p.broadcast(msg))
|
||||
self.env.process(self.p2p.broadcast(self, msg))
|
||||
|
||||
def payload_to_send(self) -> bytes | None:
|
||||
rnd = random.random()
|
||||
@ -82,13 +82,13 @@ class Node:
|
||||
final_padded_msg = (msg.payload
|
||||
+ self.PADDING_SEPARATOR
|
||||
+ bytes(len(msg) - len(msg.payload) - len(self.PADDING_SEPARATOR)))
|
||||
self.env.process(self.p2p.broadcast(final_padded_msg))
|
||||
self.env.process(self.p2p.broadcast(self, final_padded_msg))
|
||||
else:
|
||||
self.log("Dropping a cover message: %s" % msg.payload)
|
||||
else:
|
||||
# TODO: use Poisson delay or something else
|
||||
yield self.env.timeout(random.randint(0, 5))
|
||||
self.env.process(self.p2p.broadcast(msg))
|
||||
self.env.process(self.p2p.broadcast(self, msg))
|
||||
else:
|
||||
self.log("Receiving SphinxPacket, but not mine")
|
||||
else:
|
||||
|
||||
@ -1,24 +1,33 @@
|
||||
import math
|
||||
import random
|
||||
from collections import defaultdict
|
||||
|
||||
import simpy
|
||||
|
||||
from config import Config
|
||||
from sphinx import SphinxPacket
|
||||
|
||||
|
||||
class P2p:
|
||||
def __init__(self, env: simpy.Environment):
|
||||
def __init__(self, env: simpy.Environment, config: Config):
|
||||
self.env = env
|
||||
self.config = config
|
||||
self.nodes = []
|
||||
self.message_sizes = []
|
||||
self.nodes_emitted_msg_around_interval = defaultdict(int)
|
||||
|
||||
def add_node(self, nodes):
|
||||
self.nodes.extend(nodes)
|
||||
|
||||
# TODO: This should accept only bytes, but SphinxPacket is also accepted until we implement the Sphinx serde
|
||||
def broadcast(self, msg: SphinxPacket | bytes):
|
||||
def broadcast(self, sender, msg: SphinxPacket | bytes):
|
||||
self.log("Broadcasting a msg: %d bytes" % len(msg))
|
||||
self.message_sizes.append(len(msg))
|
||||
|
||||
now_frac, now_int = math.modf(self.env.now)
|
||||
if now_int % self.config.message_interval == 0 and now_frac <= self.config.max_message_prep_time:
|
||||
self.nodes_emitted_msg_around_interval[sender] += 1
|
||||
|
||||
# Yield 0 to ensure that the broadcast is done in the same time step.
|
||||
# Without this, SimPy complains that the broadcast func is not a generator.
|
||||
yield self.env.timeout(0)
|
||||
|
||||
@ -12,7 +12,7 @@ class Simulation:
|
||||
random.seed()
|
||||
self.config = config
|
||||
self.env = simpy.Environment()
|
||||
self.p2p = P2p(self.env)
|
||||
self.p2p = P2p(self.env, config)
|
||||
self.nodes = [Node(i, self.env, self.p2p, config) for i in range(config.num_nodes)]
|
||||
self.p2p.add_node(self.nodes)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user