|
|
- #lang ivy1.7
-
- include tendermint
- include abstract_tendermint
-
- isolate ghost_ = {
- instantiate abstract_tendermint
- }
-
- isolate protocol = {
- instantiate tendermint(ghost_) # here we instantiate the parameter of the tendermint module with `ghost_`; however note that we don't extract any code for `ghost_` (it's not in the list of object in the extract, and it's thus sliced away).
- implementation {
- definition init_val(n:node) = <<< `n`%2 >>>
- }
- # attribute test = impl
- } with ghost_, shim, value, round, proposers
-
- # Here we run a simple scenario that exhibits an execution in which nodes make
- # a decision. We do this to rule out trivial modeling errors.
-
- # One option to check that this scenario is valid is to run it in Ivy's REPL.
- # For this, first compile the scenario:
- #```ivyc target=repl isolate=code trace=true tendermint_test.ivy
- # Then, run the produced binary (e.g. for 4 nodes):
- #``` ./tendermint_test 4
- # Finally, call the action:
- #``` scenarios.scenario_1
- # Note that Ivy will check at runtime that all action preconditions are
- # satisfied. For example, runing the scenario twice will cause a violation of
- # the precondition of the `start` action, because a node cannot start twice
- # (see `require ~_has_started` in action `start`).
-
- # Another possibility would be to run `ivy_check` on the scenario, but that
- # does not seem to work at the moment.
-
- isolate scenarios = {
- individual all:nset # will be used as parameter to actions requiring a quorum
-
- after init {
- var iter := node.iter.create(0);
- while ~iter.is_end
- {
- all := all.insert(iter.val);
- iter := iter.next;
- };
- assert nset.is_quorum(all); # we can also use asserts to make sure we are getting what we expect
- }
-
- export action scenario_1 = {
- # all nodes start:
- var iter := node.iter.create(0);
- while ~iter.is_end
- {
- call protocol.server.start(iter.val);
- iter := iter.next;
- };
- # all nodes receive the leader's proposal:
- var m:msg;
- m.m_kind := msg_kind.proposal;
- m.m_src := 0;
- m.m_round := 0;
- m.m_value := 0;
- m.m_vround := round.minus_one;
- iter := node.iter.create(0);
- while ~iter.is_end
- {
- call net.recv(iter.val,m);
- iter := iter.next;
- };
- # all nodes prevote:
- iter := node.iter.create(0);
- while ~iter.is_end
- {
- call protocol.server.l_22(iter.val,0);
- iter := iter.next;
- };
- # all nodes receive each other's prevote messages;
- m.m_kind := msg_kind.prevote;
- m.m_vround := 0;
- iter := node.iter.create(0);
- while ~iter.is_end
- {
- var iter2 := node.iter.create(0); # the sender
- while ~iter2.is_end
- {
- m.m_src := iter2.val;
- call net.recv(iter.val,m);
- iter2 := iter2.next;
- };
- iter := iter.next;
- };
- # all nodes precommit:
- iter := node.iter.create(0);
- while ~iter.is_end
- {
- call protocol.server.l_36(iter.val,0,0,all);
- iter := iter.next;
- };
- # all nodes receive each other's pre-commits
- m.m_kind := msg_kind.precommit;
- iter := node.iter.create(0);
- while ~iter.is_end
- {
- var iter2 := node.iter.create(0); # the sender
- while ~iter2.is_end
- {
- m.m_src := iter2.val;
- call net.recv(iter.val,m);
- iter2 := iter2.next;
- };
- iter := iter.next;
- };
- # now all nodes can decide:
- iter := node.iter.create(0);
- while ~iter.is_end
- {
- call protocol.server.l_49_decide(iter.val,0,0,all);
- iter := iter.next;
- };
- }
-
- # TODO: add more scenarios
-
- } with round, node, proposers, value, nset, protocol, shim, net
-
- # extract code = protocol, shim, round, node
- extract code = round, node, proposers, value, nset, protocol, shim, net, scenarios
|