nomos-specs/mixnet/v2/sim/p2p.py

54 lines
1.6 KiB
Python
Raw Normal View History

from __future__ import annotations
2024-05-09 10:37:39 +00:00
import random
from typing import TYPE_CHECKING
2024-05-09 10:37:39 +00:00
import simpy
2024-05-09 05:29:10 +00:00
2024-05-17 04:29:20 +00:00
from adversary import Adversary
from config import Config
2024-05-12 23:49:09 +00:00
from sphinx import SphinxPacket
if TYPE_CHECKING:
from node import Node
2024-05-09 05:29:10 +00:00
class P2p:
def __init__(self, env: simpy.Environment, config: Config):
2024-05-09 10:37:39 +00:00
self.env = env
self.config = config
2024-05-09 10:37:39 +00:00
self.nodes = []
2024-05-17 04:29:20 +00:00
self.adversary = Adversary(env, config)
2024-05-09 10:37:39 +00:00
def add_node(self, nodes: list["Node"]):
2024-05-09 10:37:39 +00:00
self.nodes.extend(nodes)
2024-05-09 05:29:10 +00:00
def get_nodes(self, n: int) -> list["Node"]:
return random.sample(self.nodes, n)
2024-05-16 08:13:43 +00:00
# This should accept only bytes in practice,
# but we accept SphinxPacket as well because we don't implement Sphinx deserialization.
def broadcast(self, sender, msg: SphinxPacket | bytes):
2024-05-13 03:53:14 +00:00
self.log("Broadcasting a msg: %d bytes" % len(msg))
# Adversary
2024-05-17 04:29:20 +00:00
self.adversary.inspect_message_size(msg)
self.adversary.observe_outgoing_message(sender)
2024-05-15 08:21:31 +00:00
# Yield 0 to ensure that the broadcast is done in the same time step.
2024-05-16 07:02:34 +00:00
# Without any yield, SimPy complains that the broadcast func is not a generator.
2024-05-15 08:21:31 +00:00
yield self.env.timeout(0)
2024-05-09 05:29:10 +00:00
# TODO: gossipsub or something similar
for node in self.nodes:
self.env.process(self.send(msg, node))
2024-05-09 10:37:39 +00:00
def send(self, msg: SphinxPacket | bytes, node):
# simulate network latency
2024-05-17 05:54:23 +00:00
yield self.env.timeout(random.uniform(0, self.config.p2p.max_network_latency))
2024-05-16 08:13:43 +00:00
2024-05-17 04:29:20 +00:00
self.adversary.observe_incoming_message(node)
self.env.process(node.receive_message(msg))
def log(self, msg):
print("P2P at %g: %s" % (self.env.now, msg))