-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathschedule.py
138 lines (114 loc) · 4.06 KB
/
schedule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
from queue import PriorityQueue
from random import choice
from numpy.random import exponential, lognormal
from event import Event
from params import ProtocolParams, PaymentFlowParams
import logging
logger = logging.getLogger(__name__)
class GenericSchedule:
'''
A schedule of Events (to-be payments) to be executed by a Simulator.
'''
def __init__(self, duration=0):
self.end_time = duration
self.schedule = PriorityQueue()
def get_num_events(self):
return self.schedule.qsize()
def get_event(self):
# return event time and the event itself
if self.schedule.empty():
return None, None
time, event = self.schedule.get_nowait()
return time, event
def get_all_events(self):
# Only used for debugging. Note: this clears the queue!
timed_events = []
while not self.schedule.empty():
time, event = self.schedule.get_nowait()
timed_events.append((time, event))
return timed_events
def no_more_events(self):
return self.schedule.empty()
def put_event(self, event_time, event, current_time=-1):
# prohibit inserting events into the past or after end time
assert current_time < event_time <= self.end_time
self.schedule.put_nowait((event_time, event))
def __repr__(self): # pragma: no cover
s = "\nSchedule:\n"
s += "\n".join([str(str(time) + " " + str(event)) for (time, event) in self.get_all_events()])
return s
class HonestSchedule(GenericSchedule):
def __init__(
self,
duration,
senders,
receivers,
amount_function=lambda: lognormal(mean=PaymentFlowParams["AMOUNT_MU"], sigma=PaymentFlowParams["AMOUNT_SIGMA"]),
desired_result_function=lambda: True,
payment_processing_delay_function=lambda: PaymentFlowParams["MIN_DELAY"] + exponential(PaymentFlowParams["EXPECTED_EXTRA_DELAY"]),
payment_generation_delay_function=lambda: exponential(PaymentFlowParams["HONEST_PAYMENTS_PER_SECOND"]),
must_route_via_nodes=[]):
'''
- duration
The schedule end time.
- senders
A list of possible senders.
- receivers
A list of possible receivers.
- amount_function
Generate the payment amount.
- desired_result_function
Generate the desired result (True for honest payments, False for jams).
- payment_processing_delay_function
Generate the processing delay (encoded within the payment).
- payment_generation_delay_function
Generate the delay until the next Event in the Schedule.
- must_route_via_nodes
A tuple of (consecutive) nodes that the payment must be routed through.
'''
GenericSchedule.__init__(self, duration)
t = 0
while t <= self.end_time:
sender = choice(senders)
receiver = choice(receivers)
amount = amount_function()
if sender != receiver:
# whether to exclude last-hop upfront fee from amount or not,
# is decided on Payment construction stage later
processing_delay = payment_processing_delay_function()
desired_result = desired_result_function()
event = Event(sender, receiver, amount, processing_delay, desired_result, must_route_via_nodes)
self.put_event(t, event)
t += payment_generation_delay_function()
class JammingSchedule(GenericSchedule):
def __init__(
self,
duration,
jam_sender="JammerSender",
jam_receiver="JammerReceiver",
hop_to_jam_with_own_batch=[]):
GenericSchedule.__init__(self, duration)
jam_amount = ProtocolParams["DUST_LIMIT"]
jam_delay = PaymentFlowParams["JAM_DELAY"]
if hop_to_jam_with_own_batch:
# if provided, an extra jam batch will be sent through this specific hop
for hop in hop_to_jam_with_own_batch:
initial_jam = Event(
sender=jam_sender,
receiver=jam_receiver,
amount=jam_amount,
processing_delay=jam_delay,
desired_result=False,
must_route_via_nodes=hop)
self.put_event(0, initial_jam)
else:
# insert one (initial) jam into the schedule for time 0
# it will be sent until all target channels are jammed
# then, the next jam will be pushed into the schedule
initial_jam = Event(
sender=jam_sender,
receiver=jam_receiver,
amount=jam_amount,
processing_delay=jam_delay,
desired_result=False)
self.put_event(0, initial_jam)