2024-07-03 23:29:26 +09:00
|
|
|
import asyncio
|
|
|
|
import random
|
|
|
|
import time
|
|
|
|
|
|
|
|
from mixnet.config import GlobalConfig, MixMembership, NodeInfo
|
|
|
|
from mixnet.node import Node
|
|
|
|
from mixnet.sim.config import Config
|
|
|
|
from mixnet.sim.connection import MeteredRemoteSimplexConnection
|
|
|
|
from mixnet.sim.stats import ConnectionStats
|
|
|
|
|
|
|
|
|
|
|
|
class Simulation:
|
|
|
|
def __init__(self, config: Config):
|
|
|
|
random.seed()
|
|
|
|
self.config = config
|
|
|
|
|
|
|
|
async def run(self):
|
|
|
|
nodes, conn_measurement = self.init_nodes()
|
|
|
|
|
2024-07-04 12:01:51 +09:00
|
|
|
deadline = time.time() + self.config.simulation.scaled_duration()
|
2024-07-03 23:29:26 +09:00
|
|
|
tasks: list[asyncio.Task] = []
|
|
|
|
for node in nodes:
|
|
|
|
tasks.append(asyncio.create_task(self.run_logic(node, deadline)))
|
|
|
|
await asyncio.gather(*tasks)
|
|
|
|
|
|
|
|
conn_measurement.bandwidths()
|
|
|
|
|
|
|
|
def init_nodes(self) -> tuple[list[Node], ConnectionStats]:
|
|
|
|
node_configs = self.config.mixnet.node_configs()
|
|
|
|
global_config = GlobalConfig(
|
|
|
|
MixMembership(
|
|
|
|
[
|
|
|
|
NodeInfo(node_config.private_key.public_key())
|
|
|
|
for node_config in node_configs
|
|
|
|
]
|
|
|
|
),
|
2024-07-04 12:01:51 +09:00
|
|
|
self.config.simulation.scale_rate(
|
|
|
|
self.config.mixnet.transmission_rate_per_sec
|
|
|
|
),
|
2024-07-03 23:29:26 +09:00
|
|
|
self.config.mixnet.max_mix_path_length,
|
|
|
|
)
|
|
|
|
nodes = [Node(node_config, global_config) for node_config in node_configs]
|
|
|
|
|
|
|
|
conn_stats = ConnectionStats()
|
|
|
|
for i, node in enumerate(nodes):
|
|
|
|
inbound_conn, outbound_conn = self.create_conn(), self.create_conn()
|
2024-07-04 12:01:51 +09:00
|
|
|
peer = nodes[(i + 1) % len(nodes)]
|
|
|
|
node.connect(peer, inbound_conn, outbound_conn)
|
2024-07-03 23:29:26 +09:00
|
|
|
conn_stats.register(node, inbound_conn, outbound_conn)
|
2024-07-04 12:01:51 +09:00
|
|
|
conn_stats.register(peer, outbound_conn, inbound_conn)
|
2024-07-03 23:29:26 +09:00
|
|
|
|
|
|
|
return nodes, conn_stats
|
|
|
|
|
|
|
|
def create_conn(self) -> MeteredRemoteSimplexConnection:
|
2024-07-04 12:01:51 +09:00
|
|
|
return MeteredRemoteSimplexConnection(self.config.simulation)
|
2024-07-03 23:29:26 +09:00
|
|
|
|
|
|
|
async def run_logic(self, node: Node, deadline: float):
|
|
|
|
while time.time() < deadline:
|
|
|
|
await asyncio.sleep(
|
2024-07-04 12:01:51 +09:00
|
|
|
self.config.simulation.scale_time(
|
|
|
|
self.config.logic.lottery_interval_sec
|
|
|
|
)
|
2024-07-03 23:29:26 +09:00
|
|
|
)
|
|
|
|
|
|
|
|
if random.random() < self.config.logic.sender_prob:
|
|
|
|
await node.send_message(b"selected block")
|