@ -60,7 +60,7 @@ include network_shim
module tendermint(abstract_protocol) = {
# the initial value of a node:
parameter init_val(N:node): value
function init_val(N:node): value
# the three type of steps
object step_t = {
@ -129,7 +129,7 @@ module tendermint(abstract_protocol) = {
}
export action start = {
assum e ~_has_started;
requir e ~_has_started;
_has_started := true;
# line 10
call startRound(0);
@ -171,17 +171,15 @@ module tendermint(abstract_protocol) = {
call shim.broadcast(n,m);
}
implement shim.proposal_handler.handle(msg:msg) {
_recved_proposal(msg.m_src, msg.m_round, msg.m_value, msg.m_vround) := true;
}
# line 22-27
export action l_22(v:value) = {
assum e _has_started;
assum e _recved_proposal(proposers.get_proposer(round_p), round_p, v, round.minus_one);
assum e step = step_t.propose;
requir e _has_started;
requir e _recved_proposal(proposers.get_proposer(round_p), round_p, v, round.minus_one);
requir e step = step_t.propose;
if (value.valid(v) & (lockedRound = round.minus_one | lockedValue = v)) {
call broadcast_prevote(round_p, v); # line 24
@ -195,17 +193,15 @@ module tendermint(abstract_protocol) = {
step := step_t.prevote;
}
# line 28-33
export action l_28(r:round, v:value, vr:round, q:nset) = {
assum e _has_started;
assum e r = round_p;
assum e _recved_proposal(proposers.get_proposer(r), r, v, vr);
assum e nset.is_quorum(q);
assum e nset.member(N,q) -> _recved_prevote(N,vr,v);
assum e step = step_t.propose;
assum e vr >= 0 & vr < r;
requir e _has_started;
requir e r = round_p;
requir e _recved_proposal(proposers.get_proposer(r), r, v, vr);
requir e nset.is_quorum(q);
requir e nset.member(N,q) -> _recved_prevote(N,vr,v);
requir e step = step_t.propose;
requir e vr >= 0 & vr < r;
# line 29
if (value.valid(v) & (lockedRound <= vr | lockedValue = v)) {
@ -228,19 +224,17 @@ module tendermint(abstract_protocol) = {
}
implement shim.prevote_handler.handle(msg:msg) {
assume msg.m_vround = round.minus_one;
_recved_prevote(msg.m_src, msg.m_round, msg.m_value) := true;
}
# line 34-35
export action l_34(r:round, q:nset) = {
assum e _has_started;
assum e round_p = r;
assum e nset.is_quorum(q);
assum e exists V . nset.member(N,q) -> _recved_prevote(N,r,V);
assum e step = step_t.prevote;
assum e ~done_l34(r);
requir e _has_started;
requir e round_p = r;
requir e nset.is_quorum(q);
requir e exists V . nset.member(N,q) -> _recved_prevote(N,r,V);
requir e step = step_t.prevote;
requir e ~done_l34(r);
done_l34(r) := true;
prevote_timer_scheduled(r) := true;
@ -249,15 +243,15 @@ module tendermint(abstract_protocol) = {
# line 36-43
export action l_36(r:round, v:value, q:nset) = {
assum e _has_started;
assum e r = round_p;
assume exists VR . _recved_proposal(proposers.get_proposer(r), r, v, VR);
assum e nset.is_quorum(q);
assum e nset.member(N,q) -> _recved_prevote(N,r,v);
assum e value.valid(v);
assum e step = step_t.prevote | step = step_t.precommit;
assum e ~done_l36(r,v);
requir e _has_started;
requir e r = round_p;
require exists VR . round.minus_one <= VR & VR < r & _recved_proposal(proposers.get_proposer(r), r, v, VR);
requir e nset.is_quorum(q);
requir e nset.member(N,q) -> _recved_prevote(N,r,v);
requir e value.valid(v);
requir e step = step_t.prevote | step = step_t.precommit;
requir e ~done_l36(r,v);
done_l36(r, v) := true;
if step = step_t.prevote {
@ -270,17 +264,15 @@ module tendermint(abstract_protocol) = {
validValue := v; # line 42
validRound := r; # line 43
}
# line 44-46
export action l_44(r:round, q:nset) = {
assum e _has_started;
assum e r = round_p;
assum e nset.is_quorum(q);
assum e nset.member(N,q) -> _recved_prevote(N,r,value.nil);
assum e step = step_t.prevote;
requir e _has_started;
requir e r = round_p;
requir e nset.is_quorum(q);
requir e nset.member(N,q) -> _recved_prevote(N,r,value.nil);
requir e step = step_t.prevote;
call broadcast_precommit(r, value.nil); # line 45
step := step_t.precommit; # line 46
@ -294,23 +286,21 @@ module tendermint(abstract_protocol) = {
m.m_src := n;
m.m_round := r;
m.m_value := v;
m.m_vround := round.minus_one;
call shim.broadcast(n,m);
}
implement shim.precommit_handler.handle(msg:msg) {
assume msg.m_vround = round.minus_one;
_recved_precommit(msg.m_src, msg.m_round, msg.m_value) := true;
}
# line 47-48
export action l_47(r:round, q:nset) = {
assum e _has_started;
assum e round_p = r;
assum e nset.is_quorum(q);
assum e nset.member(N,q) -> exists V . _recved_precommit(N,r,V);
assum e ~done_l47(r);
requir e _has_started;
requir e round_p = r;
requir e nset.is_quorum(q);
requir e nset.member(N,q) -> exists V . _recved_precommit(N,r,V);
requir e ~done_l47(r);
done_l47(r) := true;
precommit_timer_scheduled(r) := true;
@ -319,11 +309,11 @@ module tendermint(abstract_protocol) = {
# line 49-54
export action l_49_decide(r:round, v:value, q:nset) = {
assum e _has_started;
assume exists VR . _recved_proposal(proposers.get_proposer(r), r, v, VR);
assum e nset.is_quorum(q);
assum e nset.member(N,q) -> _recved_precommit(N,r,v);
assum e decision = value.nil;
requir e _has_started;
require exists VR . round.minus_one <= VR & VR < r & _recved_proposal(proposers.get_proposer(r), r, v, VR);
requir e nset.is_quorum(q);
requir e nset.member(N,q) -> _recved_precommit(N,r,v);
requir e decision = value.nil;
if value.valid(v) {
decision := v;
@ -334,19 +324,19 @@ module tendermint(abstract_protocol) = {
# line 55-56
export action l_55(r:round, b:nset) = {
assum e _has_started;
assum e nset.is_blocking(b);
assume nset.member(N,b) -> exists V,VR . _recved_proposal(N,r,V,VR) | _recved_prevote(N,r,V) | _recved_precommit(N,r,V);
assum e r > round_p;
requir e _has_started;
requir e nset.is_blocking(b);
require nset.member(N,b) -> exists VR . round.minus_one <= VR & VR < r & exists V . _recved_proposal(N,r,V,VR) | _recved_prevote(N,r,V) | _recved_precommit(N,r,V);
requir e r > round_p;
call startRound(r); # line 56
}
# line 57-60
export action onTimeoutPropose(r:round) = {
assum e _has_started;
assum e propose_timer_scheduled(r);
assum e r = round_p;
assum e step = step_t.propose;
requir e _has_started;
requir e propose_timer_scheduled(r);
requir e r = round_p;
requir e step = step_t.propose;
call broadcast_prevote(r,value.nil);
step := step_t.prevote;
@ -357,10 +347,10 @@ module tendermint(abstract_protocol) = {
# line 61-64
export action onTimeoutPrevote(r:round) = {
assum e _has_started;
assum e prevote_timer_scheduled(r);
assum e r = round_p;
assum e step = step_t.prevote;
requir e _has_started;
requir e prevote_timer_scheduled(r);
requir e r = round_p;
requir e step = step_t.prevote;
call broadcast_precommit(r,value.nil);
step := step_t.precommit;
@ -369,12 +359,11 @@ module tendermint(abstract_protocol) = {
prevote_timer_scheduled(r) := false;
}
# line 65-67
export action onTimeoutPrecommit(r:round) = {
assum e _has_started;
assum e precommit_timer_scheduled(r);
assum e r = round_p;
requir e _has_started;
requir e precommit_timer_scheduled(r);
requir e r = round_p;
call startRound(round.incr(r));
precommit_timer_scheduled(r) := false;
@ -385,13 +374,11 @@ module tendermint(abstract_protocol) = {
# Byzantine nodes can send whatever they want, but they cannot send
# messages on behalf of well-behaved nodes. In practice this is implemented
# using crypr ography (e.g. public-key cryptography).
# using crypt ography (e.g. public-key cryptography).
export action byzantine_send = {
assume ~well_behaved(n);
var m:msg;
var dst:node;
assume ~well_behaved(m.m_src); # cannot forge the identity of well-behaved nodes
export action byzantine_send(m:msg, dst:node) = {
require ~well_behaved(n);
require ~well_behaved(m.m_src); # cannot forge the identity of well-behaved nodes
call shim.send(n,dst,m);
}
@ -407,24 +394,27 @@ module tendermint(abstract_protocol) = {
# preconditions are met, and b) provide a refinement relation.
invariant 0 <= round_p
invariant abstract_protocol.left_round(n,R) <-> R < round_p
specification {
invariant lockedRound ~= round.minus_one -> forall R,V . abstract_protocol.locked(n,R,V) <-> R <= lockedRound & lockedValue = V
invariant lockedRound = round.minus_one -> forall R,V . ~abstract_protocol.locked(n,R,V)
invariant 0 <= round_p
invariant abstract_protocol.left_round(n,R) <-> R < round_p
invariant forall M:msg . well_behaved(M.m_src) & M.m_kind = msg_kind.prevote & shim.sent(M,N) -> abstract_protocol.prevoted(M.m_src,M.m_round,M.m_value)
invariant well_behaved(N) & _recved_prevote(N,R,V) -> abstract_protocol.prevoted(N,R,V)
invariant forall M:msg . well_behaved(M.m_src) & M.m_kind = msg_kind.precommit & shim.sent(M,N) -> abstract_protocol.precommitted(M.m_src,M.m_round,M.m_value)
invariant well_behaved(N) & _recved_precommit(N,R,V) -> abstract_protocol.precommitted(N,R,V)
invariant lockedRound ~= round.minus_one -> forall R,V . abstract_protocol.locked(n,R,V) <-> R <= lockedRound & lockedValue = V
invariant lockedRound = round.minus_one -> forall R,V . ~abstract_protocol.locked(n,R,V)
invariant (step = step_t.prevote | step = step_t.propose) -> ~abstract_protocol.precommitted(n,round_p,V)
invariant step = step_t.propose -> ~abstract_protocol.prevoted(n,round_p,V)
invariant step = step_t.prevote -> exists V . abstract_protocol.prevoted(n,round_p,V)
invariant forall M:msg . well_behaved(M.m_src) & M.m_kind = msg_kind.prevote & shim.sent(M,N) -> abstract_protocol.prevoted(M.m_src,M.m_round,M.m_value)
invariant well_behaved(N) & _recved_prevote(N,R,V) -> abstract_protocol.prevoted(N,R,V)
invariant forall M:msg . well_behaved(M.m_src) & M.m_kind = msg_kind.precommit & shim.sent(M,N) -> abstract_protocol.precommitted(M.m_src,M.m_round,M.m_value)
invariant well_behaved(N) & _recved_precommit(N,R,V) -> abstract_protocol.precommitted(N,R,V)
invariant round_p < R -> ~(abstract_protocol.prevoted(n,R,V) | abstract_protocol.precommitted(n,R,V))
invariant ~_has_started -> step = step_t.propose & ~(abstract_protocol.prevoted(n,R,V) | abstract_protocol.precommitted(n,R,V)) & round_p = 0
invariant (step = step_t.prevote | step = step_t.propose) -> ~abstract_protocol.precommitted(n,round_p,V)
invariant step = step_t.propose -> ~abstract_protocol.prevoted(n,round_p,V)
invariant step = step_t.prevote -> exists V . abstract_protocol.prevoted(n,round_p,V)
invariant decision ~= value.nil -> exists R . abstract_protocol.decided(n,R,decision)
invariant round_p < R -> ~(abstract_protocol.prevoted(n,R,V) | abstract_protocol.precommitted(n,R,V))
invariant ~_has_started -> step = step_t.propose & ~(abstract_protocol.prevoted(n,R,V) | abstract_protocol.precommitted(n,R,V)) & round_p = 0
invariant decision ~= value.nil -> exists R . abstract_protocol.decided(n,R,decision)
}
}
}