Chord2s demo
This is a model of the Chord ring maintenance protocol based on Pamela Zave's version. As in Pamela's paper, it handles on successor lists up to length two.
We prove that there is only one cycle and that all active nodes are connected to the cycle.
We assume that there is one permanent node in the ring, which we call "q", the origin.
Theory of partial functions.
module partial_function(f) = {
axiom ~f(X,Y) | ~f(X,Z) | Y = Z
relation dom[f](X)
axiom ~f(X,Y) | dom[f](X)
schema img[f](x) = ~dom[f](x) | f(x,f[x])
update dom[f] from f
params v,w in v.f := w ->
ensures ((~old dom[f](X) | dom[f](X)) & dom[f](v))
params v in v.f := null ->
ensures (~old dom[f](X) | X = v | dom[f](X))
}
relation a(X) # a(x) holds when node x is active
relation s1(X,Y) # s1(x,y) holds when y is the first successor of x
relation s2(X,Y) # s2(x,y) holds when y is the first successor of x
relation p(X,Y) # p(x,y) holds when y is the predessor of p.
instantiate partial_function(s1)
instantiate partial_function(s2)
instantiate partial_function(p)
individual q
Best successor relation. We have bs(x,y) if y is active and either it is the first successor of x or it is the second successor of x and the first successor is inactive. We define bs by Horn clauses, as follows:
relation bs(X,Y)
axiom ~s1(X,Y) | ~a(Y) | bs(X,Y)
axiom ~s1(X,Y) | a(Y) | ~s2(X, Z) | ~a(Z) | bs(X,Z)
Theory of "reaches" predicate. rchy holds if x can reach y by a non-empty sequence of "best successor" arcs. We define rch by a set of horn clauses, as follows.
schema rch(y) =
(~bs(X,y) | rch[y](X)) # base case: reach y in one step
& (~bs(X,Y) | ~rch[y](Y) | rch[y](X)) # inductive case
relation btw(X,Y,Z)
axiom (~btw(W, Y, Z) | ~btw(W, X, Y) | btw(X, Y, Z))
axiom (~btw(W, X, Z) | ~btw(X, Y, Z) | btw(W, X, Y))
axiom (~btw(W, X, Z) | ~btw(X, Y, Z) | btw(W, Y, Z))
axiom (~btw(W, Y, Z) | ~btw(W, X, Y) | btw(W, X, Z))
axiom (W = X | btw(W, X, W))
axiom ~btw(X, X, Y)
axiom ~btw(X, Y, Y)
axiom (btw(X,Y,Z) | Y = Z | btw(X,Z,Y))
axiom (btw(X,Y,Z) | Y = X | btw(Y,X,Z))
derived down(X, Y) = (~btw(X, q, Y) & X ~= q) | X = Y
schema lep(p) =
(p(le[p]) | ~p(X))
& (~btw(le[p],X,q) | ~p(X))
Error condition. A node becomes disconnected if it is active and no longer has a path to the origin via best successors.
relation rch[q](X)
derived err(X) = a(X) & ~rch[q](X)
module witness(f,x) = {
individual f[x]
}
instantiate witness(le,err)
instantiate witness(s1,le[err])
instantiate witness(s2,le[err])
¤
Protocol actions
¤
Temporary variables used in actions
individual x,y,z,qs
init (q ~= qs & a(q) & a(qs) & (~a(V1) | V1 = q | V1 = qs)
& s1(q, qs) & s1(qs, q) & (~s1(X, Y) | X = q | X = qs) & ~s2(X, Y)
& p(q, qs) & p(qs, q) & (~p(X, Y) | X = q | X = qs))
action join = {
x := *;
y := *;
assume ~a(x);
assume a(y);
assume ~btw(x, q, y);
a(x) := true;
x.s1 := y;
x.s2 := false;
x.p := false
}
action stabilize = {
x := *;
y := *;
z := *;
assume a(x);
assume s1(x, y);
assume a(y);
assume p(y, z);
assume a(z);
assume btw(x, z, y);
x.s1 := z;
x.s2 := y
}
action inherit = {
x := *;
y := *;
z := *;
assume a(x);
assume s1(x, y);
assume a(y);
assume s1(y, z);
x.s2 := z
}
action remove = {
x := *;
y := *;
z := *;
assume a(x);
assume s1(x, y);
assume ~a(y);
assume s2(x, z);
x.s1 := z;
x.s2 := false
}
action notify = {
x := *;
y := *;
z := *;
assume a(x);
assume s1(x, y);
assume a(y);
assume p(y, z) | ~p(y, X);
assume btw(z, x, y);
y.p := x
}
action fail = {
x := *;
assume a(x);
assume x ~= q; # assume origin node cannot fail
a(x) := false;
x.p := false;
x.s1 := false;
x.s2 := false;
assume (~s1(X, Y) | a(Y) | dom[s2](X));
assume (~s1(X, Y) | a(Y) | ~s2(X, Z) | a(Z))
}
action error = {
assume err(x); # there is some error
instantiate rch(q);
instantiate lep(err); # find least error node
instantiate img[s1](le[err]);
instantiate img[s2](le[err])
}
concept act(X) = (a(X) + ~a(X))
concept loc(X) = (X = q + ~X = q)
concept node(X) = (loc(X) * act(X))
concept succ(X, Y) = (s1(X, Y) + ~s1(X, Y))
concept pred(X, Y) = (p(X, Y) + ~p(X, Y))
concept spact(X, Y) = (succ(X, Y) * pred(Y, X) * act(X) * act(Y))
concept s2act(X,Y) = (s2(X,Y) * act(X) * act(Y))
concept s1down(X, Y) = (btw(X, q, Y) * s1(X, Y))
concept s2down(X, Z) = (btw(X, q, Z) * s2(X, Z))
concept some_act(X, Y, Z) = (s1(X, Y) * s2(X, Z) * ~a(Y) * ~a(Z))
concept has_s1(X) = (a(X) * ~dom[s1](X))
concept has_s2(X,Y) = (a(X) * s1(X,Y) * ~a(Y) * ~dom[s2](X))