blob: 35ca7d85adb4ea3c312b36c923cd238f7fcc28a9 [file] [log] [blame]
Brian Silverman41cdd3e2019-01-19 19:48:58 -08001= Network Tables Alloy Model
2
3Alloy (http://alloy.mit.edu/alloy/) is a formal logic tool that can analyze
4first-order logic expressions. Under the proposed sequence number -based
5protocol, assuming that all nodes start from the same state, Alloy is unable to
6find a way where two nodes with the same sequence number have different state
7when activity ceases.
8
9The model used is included below. Although Alloy cannot test all cases, since
10such an exhaustive search is intractable, it provides a high level of
11confidence in the proposed protocol.
12
13----
14--- Models a distributed, centralized hash table system called NetworkTables
15--- System state is protected by sequence numbers; the server's value for a certain sequence number always wins
16--- Paul Malmsten, 2012 pmalmsten@gmail.com
17
18open util/ordering[Time] as TO
19open util/natural as natural
20
21sig Time {}
22sig State {}
23
24--- Define nodes and server
25sig Node {
26 state: State -> Time,
27 sequenceNumber: Natural -> Time
28}
29
30--- Only one server
31one sig Server extends Node {
32}
33
34--- Define possible events
35abstract sig Event {
36 pre,post: Time,
37 receiver: one Node
38}
39
40// For all events, event.post is the time directly following event.pre
41fact {
42 all e:Event {
43 e.post = e.pre.next
44 }
45}
46
47// Represents that state has changed on a node
48sig StateChangeEvent extends Event {
49}
50
51// Represents that state has been transferred from one node to another
52sig StateTransferEvent extends Event {
53 sender: one Node
54}
55
56fact {
57 --- Every node must assume at most one state
58 all t:Time, n:Node | #n.state.t = 1
59
60 --- Every node must assume one sequence number
61 all t:Time, n:Node | #n.sequenceNumber.t = 1
62
63 --- Sequence numbers may only increment
64 all t:Time - last, n:Node | let t' = t.next | natural/gte[n.sequenceNumber.t', n.sequenceNumber.t]
65}
66
67
68fact stateChangedImpliesAStateTransfer {
69 all sce:StateChangeEvent {
70 // A StateChange on a client causes a transfer to the Server if its sequence number is greater than the server's
71 sce.receiver in Node - Server and natural/gt[sce.receiver.sequenceNumber.(sce.post), Server.sequenceNumber.(sce.post)]
72 implies
73 some ste:StateTransferEvent {
74 ste.pre = sce.post and ste.sender = sce.receiver and ste.receiver = Server
75 }
76 }
77
78 all sce:StateChangeEvent {
79 // A StateChange on the server causes a transfer to all clients
80 sce.receiver = Server implies
81 all n:Node - Server {
82 some ste:StateTransferEvent {
83 ste.pre = sce.post and ste.sender = Server and ste.receiver = n
84 }
85 }
86 }
87
88 all sce:StateTransferEvent {
89 // A StateTransfer to the server causes a transfer to all clients
90 sce.receiver = Server implies
91 all n:Node - Server {
92 some ste:StateTransferEvent {
93 ste.pre = sce.post and ste.sender = Server and ste.receiver = n
94 }
95 }
96 }
97}
98
99fact stateTransferEventsMoveState {
100 all ste:StateTransferEvent {
101 ste.sender = Server and not ste.receiver = Server or ste.receiver = Server and not ste.sender = Server
102
103 // Nodes can only post to the server if their sequence number is greater than the servers
104 ste.receiver = Server implies natural/gt[ste.sender.sequenceNumber.(ste.pre), ste.receiver.sequenceNumber.(ste.pre)]
105
106 // Server can only post to clients if its sequence number is greater than or equal to the client
107 ste.sender = Server implies natural/gte[ste.sender.sequenceNumber.(ste.pre), ste.receiver.sequenceNumber.(ste.pre)]
108
109 // Actual transfer
110 (ste.receiver.state.(ste.post) = ste.sender.state.(ste.pre) and
111 ste.receiver.sequenceNumber.(ste.post) = ste.sender.sequenceNumber.(ste.pre))
112 }
113}
114
115
116fact noEventsPendingAtEnd {
117 no e:Event {
118 e.pre = last
119 }
120}
121
122fact noDuplicateEvents {
123 all e,e2:Event {
124 // Two different events with the same receiver imply they occurred at different times
125 e.receiver = e2.receiver and e != e2 implies e.pre != e2.pre
126 }
127}
128
129fact noStateTransfersToSelf {
130 all ste:StateTransferEvent {
131 ste.sender != ste.receiver
132 }
133}
134
135fact noDuplicateStateTransferEvents {
136 all ste,ste2:StateTransferEvent {
137 // Two state transfer events with the same nodes imply that they occurred at different times
138 ste.sender = ste2.sender and ste.receiver = ste2.receiver and ste != ste2 implies ste.pre != ste2.pre
139 }
140}
141
142--- Trace (time invariant)
143fact trace {
144 all t:Time - last | let t' = t.next {
145 all n:Node {
146 // A node in (pre.t).receiver means it is being pointed to by some event that will happen over the next time step
147 n in (pre.t).receiver implies n.state.t' != n.state.t and n.sequenceNumber.t' != n.sequenceNumber.t // A node which receives some sort of event at time t causes it to change state
148 else n.state.t' = n.state.t and n.sequenceNumber.t' = n.sequenceNumber.t // Otherwise, it does not change state
149 }
150 }
151}
152
153--- Things we might like to be true, but are not always true
154
155pred atLeastOneEvent {
156 #Event >= 1
157}
158
159pred allNodesStartAtSameStateAndSequenceNumber {
160 all n,n2:Node {
161 n.state.first = n2.state.first and n.sequenceNumber.first = n2.sequenceNumber.first
162 }
163}
164
165pred noStateChangeEventsAtEnd {
166 no e:StateChangeEvent {
167 e.post = last
168 }
169}
170
171--- Demonstration (Alloy will try to satisfy this)
172
173pred show {
174 atLeastOneEvent
175}
176run show
177
178--- Assertions (Alloy will try to break these)
179
180assert allNodesConsistentAtEnd {
181 allNodesStartAtSameStateAndSequenceNumber implies
182 all n,n2:Node {
183 // At the end of a sequence (last) all nodes with the same sequence number have the same state
184 n.sequenceNumber.last = n2.sequenceNumber.last implies n.state.last = n2.state.last
185 }
186}
187check allNodesConsistentAtEnd for 3 Event, 10 Node, 3 State, 5 Time, 5 Natural
188check allNodesConsistentAtEnd for 8 Event, 2 Node, 5 State, 9 Time, 9 Natural
189
190assert serverHasHighestSeqNumAtEnd {
191 allNodesStartAtSameStateAndSequenceNumber implies
192 all n:Node - Server{
193 // At the end of a sequence (last) all nodes with the same sequence number have the same state
194 natural/gte[Server.sequenceNumber.last, n.sequenceNumber.last]
195 }
196}
197check serverHasHighestSeqNumAtEnd for 3 Event, 10 Node, 3 State, 5 Time, 5 Natural
198----