This repository has been archived by the owner on Jan 27, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 82
/
Copy pathraft_logs.ivy
139 lines (93 loc) · 3.21 KB
/
raft_logs.ivy
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
#lang ivy1.5
include theory
# This is a very abstraft model of Raft that considers only
# operations on logs and not leader election.
type log
# this is the prefix order on logs
relation (X:log < Y:log)
instantiate prefix_strict_order(log,<)
# a measure function on logs, totally ordered
type weight
relation (X:log < Y:log)
instantiate total_strict_order(weight,<)
individual meas(X:log) : weight
axiom (X:log < Y:log) -> (meas(X) < meas(Y))
axiom meas(X) = meas(Y) -> X = Y
# protocol nodes and sets of nodes
type node
type node_set
relation mem(N:node,S:node_set)
# is a set a majority?
relation maj(S:node_set)
# two majorities must have a node in common
axiom maj(S1) & maj(S2) -> exists N. mem(N,S1) & mem(N,S2)
# term numbers
type term
relation (X:term < Y:term)
instantiate total_strict_order_with_zero(term,<,0)
# abstract operations on logs
type elem
object logs = {
individual get_term(l:log) : term
action extend(l:log,e:elem,t:term) returns(lp:log) = {
assert l < lp & get_term(lp) = term
}
}
object proto = {
individual node_logs(X:node) : log
individual node_terms(X:node) : term
relation leader(T:term,X:node)
init ~leader(T,X)
init node_terms(X) = 0
action extend(n:node, e:elem) = {
assume leader(node_terms(n),n);
node_logs(n) := logs.extend(node_logs(n),e,node_terms(n))
}
action send_log(leader:node, dominated:node_set) = {
assume maj(dominated);
assume mem(X,dominated) -> (meas(node_logs(X)) < meas(node_logs(leader))
| meas(node_logs(X)) = meas(node_logs(leader)));
call abs_net.send_log(leader,node_logs(leader))
}
action receive_log(dst:node, leader:node, l:log) = {
if meas(node_logs(dst)) < meas(l) {
node_logs(dst) := l;
call abs_net.send_ack(dst,l)
}
}
# This means log L has been committed by majority S
relation committed(L:log,S:node_set)
init ~committed(L,S)
# to commit a log, we mus have a majority of nodes
# that agree with the leader
action commit(leader:node, dominated:node_set) = {
assume maj(dominated);
assume mem(X,dominated) -> node_logs(X) = node_logs(leader);
committed(node_logs(leader),dominated) := true
}
conjecture committed(L,S) -> maj(S)
conjecture committed(L,S) & mem(N,S) -> (L < node_logs(N) | L = node_logs(N))
conjecture committed(L:log,S:node_set) & mem(N:node,S) & ~(L < node_logs(M:node) | L = node_logs(M:node)) -> meas(node_logs(M:node)) < meas(node_logs(N:node))
conjecture ~(meas(node_logs(NO0)) < meas(LO1) & abs_net.sent(NO0,LO1))
conjecture committed(L:log,S:node_set) & mem(N:node,S) & abs_net.sent(M,L2) & ~(L < L2 | L = L2) -> meas(L2) < meas(node_logs(N:node))
}
object abs_net = {
# this says leader N has sent log L
relation sent(N:node,L:log)
init ~(sent(N,L))
action send_log(leader:node, l:log) = {
sent(leader,l) := true
}
action send_ack(n:node, l:log) = {
# TODO: fill this in
}
action receive_log(dst:node, leader:node, l:log) = {
assert sent(leader,l)
}
execute receive_log before proto.receive_log
}
export proto.extend
export proto.send_log
export proto.receive_log
export proto.commit
isolate iso_p = proto with abs_net,logs