зеркало из https://github.com/microsoft/ivy.git
155 строки
4.9 KiB
XML
155 строки
4.9 KiB
XML
#lang ivy1.6
|
|
|
|
################################################################################
|
|
#
|
|
# Modules that should probably come from a standard library
|
|
#
|
|
################################################################################
|
|
|
|
################################################################################
|
|
#
|
|
# Module for axiomatizing a total order
|
|
#
|
|
################################################################################
|
|
|
|
module total_order(r) = {
|
|
axiom r(X,X) # Reflexivity
|
|
axiom r(X, Y) & r(Y, Z) -> r(X, Z) # Transitivity
|
|
axiom r(X, Y) & r(Y, X) -> X = Y # Anti-symmetry
|
|
axiom r(X, Y) | r(Y, X) # Totality
|
|
}
|
|
|
|
|
|
################################################################################
|
|
#
|
|
# Types, relations and functions describing state of the network
|
|
#
|
|
################################################################################
|
|
|
|
type node
|
|
type value
|
|
type quorum
|
|
type round
|
|
|
|
individual none: round
|
|
relation le(X:round, Y:round)
|
|
instantiate total_order(le)
|
|
|
|
relation member(N:node, Q:quorum)
|
|
axiom forall Q1:quorum, Q2:quorum. exists N:node. member(N, Q1) & member(N, Q2)
|
|
|
|
relation one_a(R:round)
|
|
relation one_b_max_vote(N:node, R1:round, R2:round, V:value)
|
|
relation proposal(R:round, V:value) # 2a
|
|
relation vote(N:node, R:round, V:value) # 2b
|
|
relation decision(N:node, R:round, V:value) # got 2b from a quorum
|
|
|
|
init ~one_a(R)
|
|
init ~one_b_max_vote(N,R1,R2,V)
|
|
init ~proposal(R,V)
|
|
init ~vote(N,R,V)
|
|
init ~decision(N,R,V)
|
|
|
|
action send_1a = {
|
|
# a proposer selects a round and sends a message asking nodes to join the round
|
|
local r:round {
|
|
assume r ~= none;
|
|
one_a(r) := true
|
|
}
|
|
}
|
|
|
|
action join_round = {
|
|
# receive 1a and answer with 1b
|
|
local n:node, r:round {
|
|
assume r ~= none;
|
|
assume one_a(r);
|
|
assume ~(exists R:round,RMAX:round,V:value. one_b_max_vote(n,R,RMAX,V) & ~le(R,r));
|
|
|
|
local maxr:round, v:value {
|
|
# find the maximal vote in a round less than r
|
|
assume ((maxr = none & forall MAXR:round,V:value. ~(~le(r,MAXR) & vote(n,MAXR,V))) |
|
|
(maxr ~= none & ~le(r,maxr) & vote(n,maxr,v) &
|
|
(forall MAXR:round,V:value. (~le(r,MAXR) & vote(n,MAXR,V)) -> le(MAXR,maxr))
|
|
));
|
|
# send the 1b message
|
|
one_b_max_vote(n,r,maxr,v) := true
|
|
}
|
|
}
|
|
}
|
|
|
|
action propose = {
|
|
# receive a quorum of 1b's and send a 2a (proposal)
|
|
local r:round, q:quorum {
|
|
assume r ~= none;
|
|
assume ~proposal(r,V);
|
|
assume forall N:node. member(N, q) -> exists R:round, V:value. one_b_max_vote(N,r,R,V);
|
|
|
|
local maxr:round, v:value {
|
|
# find the maximal max_vote in the quorum
|
|
assume ((maxr = none & forall N:node,MAXR:round,V:value. ~(member(N, q) & one_b_max_vote(N,r,MAXR,V) & MAXR ~= none)) |
|
|
(maxr ~= none &
|
|
(exists N:node. member(N, q) & one_b_max_vote(N,r,maxr,v)) &
|
|
(forall N:node,MAXR:round,V:value. (member(N, q) & one_b_max_vote(N,r,MAXR,V) & MAXR ~= none) -> le(MAXR,maxr))
|
|
));
|
|
# propose value v
|
|
proposal(r, v) := true
|
|
}
|
|
}
|
|
}
|
|
|
|
action cast_vote = {
|
|
# receive a 2a and send 2b
|
|
local n:node, v:value, r:round {
|
|
assume r ~= none;
|
|
assume ~(exists R:round,RMAX:round,V:value. one_b_max_vote(n,R,RMAX,V) & ~le(R,r));
|
|
assume proposal(r, v);
|
|
vote(n, r, v) := true
|
|
}
|
|
}
|
|
|
|
action decide = {
|
|
# get 2b from a quorum
|
|
local n:node, r:round, v:value, q:quorum {
|
|
assume r ~= none;
|
|
assume member(N, q) -> vote(N, r, v);
|
|
decision(n, r, v) := true
|
|
}
|
|
}
|
|
|
|
export send_1a
|
|
export join_round
|
|
export propose
|
|
export cast_vote
|
|
export decide
|
|
|
|
# safety property:
|
|
conjecture (
|
|
decision(N1,R1,V1) &
|
|
decision(N2,R2,V2)
|
|
) -> V1 = V2
|
|
|
|
# proposals are unique per round
|
|
conjecture proposal(R,V1) & proposal(R,V2) -> V1 = V2
|
|
|
|
# only vote for proposed values
|
|
conjecture vote(N,R,V) -> proposal(R,V)
|
|
|
|
# decisions come from quorums of votes:
|
|
conjecture forall R:round, V:value. (exists N:node. decision(N,R,V)) -> exists Q:quorum. forall N:node. member(N, Q) -> vote(N,R,V)
|
|
|
|
# properties of one_b_max_vote
|
|
conjecture one_b_max_vote(N,R2,none,V1) & ~le(R2,R1) -> ~vote(N,R1,V2)
|
|
conjecture one_b_max_vote(N,R,RMAX,V) & RMAX ~= none -> ~le(R,RMAX) & vote(N,RMAX,V)
|
|
conjecture one_b_max_vote(N,R,RMAX,V) & RMAX ~= none & ~le(R,ROTHER) & ~le(ROTHER,RMAX) -> ~vote(N,ROTHER,VOTHER)
|
|
|
|
# properties of none
|
|
conjecture ~vote(N,none,V)
|
|
|
|
# Properties of choosable and proposal
|
|
conjecture forall R1:round, R2:round, V1:value, V2:value, Q:quorum. ~le(R2,R1) & proposal(R2,V2) & V1 ~= V2 ->
|
|
exists N:node, R3:round, RMAX:round, V:value. member(N,Q) & ~le(R3,R1) & one_b_max_vote(N,R3,RMAX,V) & ~vote(N,R1,V1)
|
|
|
|
# restrict size of domain
|
|
#axiom exists V1,V2. forall V:value. V=V1 | V=V2
|
|
#axiom exists R1,R2,R3 . forall R:round. R=R1 | R=R2 | R=R3
|