-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathMempool.tla
257 lines (204 loc) · 7.85 KB
/
Mempool.tla
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
---- MODULE Mempool ----
EXTENDS FiniteSets, Integers, Sequences
CONSTANTS
INIT_PEERS,
INIT_CONNECTIONS,
INIT_PREDECESSOR,
INIT_LIVE_BLOCKS,
INIT_LIVE_OPERATIONS,
MIN_OPS_PER_BLOCK,
MAX_OPS_PER_BLOCK
\* shell peers and messages
VARIABLES
peers, \* set of all known peers
connections, \* set of peer with which the node exchanges messages
greylist, \* set of greylisted peers
outgoing, \* queue of outgoing messages for each peer
incoming, \* queue of incoming messages for each peer
all_operations \* set of all operations which have been generated
\* prevalidator
VARIABLES
predecessor, \* the current head on which a dummy block is baked
live_blocks, \* set of hashes of all blocks in current branch
live_operations, \* set of hashes of all operations in [live_blocks]
branch_delayed, \* set of operations which have this classification
branch_refused, \* set of operations which have this classification
refused, \* set of operations which have this classification
fetching, \* set of operations which are actively being fetched from the db
pending, \* set of operations TODO
in_mempool, \* set of operations which have been pre-applied and added to the mempool
banned, \* set of banned operation hashes
advertisement, \* set of operations to advertise
applied \* set of operations which have been applied to the mempool
\* mempool
VARIABLES
known_valid, \* list of operations which have been successfully pre-applied
mp_pending \* set of pending operations in mempool
vars == <<>>
Nodes == STRING
----
ToSet(seq) == { seq[i] : i \in DOMAIN seq }
----
(* Operations *)
INSTANCE Operations
Mempool == [ known_valid : Seq(Operations), pending : SUBSET Operations ]
Seen_ops == fetching \cup pending \cup banned \cup branch_delayed \cup branch_refused \cup refused \cup known_valid \cup mp_pending
(*
The mempool manages a *validation state* based upon the current head chosen by the validation subsystem
- each time the mempool receives an operation
- it tries to classify it on top of the current validation state
- if the operation is applied successfully
- the validation state is updated
- the operation is classified as `Applied`
- the operation is propagated to peers
- else, the handling of the operation depends on its *classification* which is detailed below
- given an operation, its classification may change if the head changes
- when the validation subsystem switches its head
- it notifies the mempool with the new `live_blocks` and `live_operations`, and
- triggers a `flush` of the mempool
- every classified operation which is *anchored* on a *live* block and which is not in the
`live_operations` is set as `pending`, meaning they are waiting to be classified again
- an exception is made for operations classified as `Branch_refused`
- those operations are reclassified only if the old head is not the predecessor of the new head
*)
----
(* Assumptions *)
\* TODO
----
(* Messages *)
INSTANCE Messages
\* TODO classify operation on top of current validation state
\* do not want to advertise [refused] operations
\* TODO status
\* - fetching: hash known, operation not received
\* - pending: hash and operation known, not classified on top of [predecessor]
\* - classified: hash and operation known, classification has been given
\* - banned: removed from all other fields and ignored when received in any form
(* TODO actions
Handle an operation
- try to classify
- if applied,
Predecessor changes
- how to repressent blocks?
Advertise [advertisement]
- endorsements are propagated if Applied or Branch_delayed
Flush hash
Fetch operation timeout
What else?
*)
ReceiveOperation == \E peer \in connections, op \in Operations :
/\ all_operations' = all_operations \cup {op}
/\ incoming' = [ incoming EXCEPT ![peer] = Append(@, op) ]
/\ UNCHANGED <<>> \* TODO
Applied(peer, op) ==
/\ op.hash \notin live_operations
\* add to applied
\* add to live_operations or fetching/pending?
\* add to known_valid or mp_pending?
/\ {}
/\ UNCHANGED <<>> \* TODO
Branch_delayed(peer, op) ==
/\ op.hash \notin live_operations
\* add to branch_delayed
\* add to live_operations or fetching/pending?
\* add to known_valid or mp_pending?
/\ {}
/\ UNCHANGED <<>> \* TODO
Branch_refused(peer, op) ==
/\ op.hash \notin live_operations
\* add to branch_refused
\* add to live_operations or fetching/pending?
\* add to known_valid or mp_pending?
/\ {}
/\ UNCHANGED <<>> \* TODO
Refused(peer, op) ==
/\ op.hash \notin live_operations
\* add to refused
\* add to banned?
/\ {}
/\ UNCHANGED <<>> \* TODO
Outdated(peer, op) ==
/\ op.hash \in live_operations
/\ incoming' = [ incoming EXCEPT ![peer] = Tail(@) ]
/\ UNCHANGED <<>> \* TODO
Ban(peer, op) ==
\* Why are some operations banned?
\* Affect peer score?
/\ banned' = banned \cup {op}
/\ UNCHANGED <<>> \* TODO
HandleOperation == \E peer \in DOMAIN incoming :
/\ incoming[peer] /= <<>>
/\ LET op == Head(incoming[peer]) IN
\/ Applied(peer, op)
\/ Branch_delayed(peer, op)
\/ Branch_refused(peer, op)
\/ Refused(peer, op)
\/ Outdated(peer, op)
\/ Ban(peer, op)
----
Init ==
/\ peers = INIT_PEERS
/\ connections = INIT_CONNECTIONS
/\ greylist = {}
/\ outgoing = [ x \in connections |-> <<>> ]
/\ incoming = [ x \in connections |-> <<>> ]
/\ all_operations = {}
/\ predecessor = INIT_PREDECESSOR
/\ live_blocks = INIT_LIVE_BLOCKS
/\ live_operations = INIT_LIVE_OPERATIONS
/\ applied = {}
/\ branch_delayed = {}
/\ branch_refused = {}
/\ refused = {}
/\ fetching = {}
/\ pending = {}
/\ in_mempool = {}
/\ banned = {}
/\ advertisement = {}
/\ known_valid = <<>>
/\ mp_pending = {}
Next == {}
\* operation hashes are unique
OperationHashUniqueness ==
[]( { ops \in all_operations \X all_operations :
ops[1].hash = ops[2].hash /\ ops[1] /= ops[2] } = {} )
Spec ==
/\ Init
/\ [][Next]_vars
/\ WF_vars(Next)
/\ OperationHashUniqueness
----
(* Properties *)
TypeOK ==
/\ peers \in SUBSET Nodes
/\ connections \subseteq peers
/\ greylist \in (peers \ connections)
/\ outgoing \in [ connections -> Seq(Messages) ]
/\ incoming \in [ connections -> Seq(Messages) ]
/\ all_operations \in { p \in Int \X SUBSET Operations : p[1] = Cardinality(p[2]) }
/\ predecessor \in Int
/\ live_blocks \subseteq Int
/\ live_operations \subseteq Int
/\ branch_delayed \subseteq Operations
/\ branch_refused \subseteq Operations
/\ refused \subseteq Operations
/\ fetching \subseteq OpHashes
/\ pending \subseteq Operations
/\ in_mempool \subseteq OpHashes
/\ banned \subseteq OpHashes
/\ advertisement \subseteq Operations
/\ applied \subseteq Operations
/\ known_valid \in Seq(Operations)
/\ mp_pending \subseteq Operations
PrevalidatorInvariant ==
\* unclassified
/\ fetching \cap pending \cap applied \cap banned = {}
\* classified
/\ applied \cap branch_delayed \cap branch_refused \cap refused = {}
/\ advertisement \cap refused = {}
\* mempool/prevalidator consistency
/\ mp_pending \cup ToSet(known_valid) = in_mempool
AdvertisingEndorsements ==
LET inter == advertisement \cap branch_delayed IN
{ op \in inter : op.type /= "Endorsement" } = {}
========================