github.com/vipernet-xyz/tm@v0.34.24/spec/ivy-proofs/domain_model.ivy (about)

     1  #lang ivy1.7
     2  
     3  include order # this is a file from the standard library (`ivy/ivy/include/1.7/order.ivy`)
     4  
     5  isolate round = {
     6      type this
     7      individual minus_one:this
     8      relation succ(R1:round, R2:round)
     9      action incr(i:this) returns (j:this)
    10      specification {
    11  # to simplify verification, we treat rounds as an abstract totally ordered set with a successor relation.
    12          instantiate totally_ordered(this)
    13          property minus_one < 0
    14          property succ(X,Z) -> (X < Z & ~(X < Y & Y < Z))
    15          after incr {
    16              ensure succ(i,j)
    17          }
    18      }
    19      implementation {
    20  # here we prove that the abstraction is sound.
    21          interpret this -> int # rounds are integers in the Tendermint specification.
    22          definition minus_one = 0-1
    23          definition succ(R1,R2) = R2 = R1 + 1
    24          implement incr {
    25              j := i+1;
    26          }
    27      }
    28  }
    29  
    30  instance node : iterable # nodes are a set with an order, that can be iterated over (see order.ivy in the standard library)
    31  
    32  relation well_behaved(N:node) # whether a node is well-behaved or not. NOTE: Used only in the proof and the Byzantine model; Nodes do know know who is well-behaved and who is not.
    33  
    34  isolate proposers = {
    35      # each round has a unique proposer in Tendermint. In order to avoid a
    36      # function from round to node (which makes verification more difficult), we
    37      # abstract over this function using a relation.
    38      relation is_proposer(N:node, R:round)
    39      export action get_proposer(r:round) returns (n:node)
    40      specification {
    41          property is_proposer(N1,R) & is_proposer(N2,R) -> N1 = N2
    42          after get_proposer {
    43              ensure is_proposer(n,r);
    44          }
    45      }
    46      implementation {
    47          function f(R:round):node
    48          definition f(r:round) = <<<r % `node.size`>>>
    49          definition is_proposer(N,R) = N = f(R)
    50          implement get_proposer {
    51              n := f(r);
    52          }
    53      }
    54  }
    55  
    56  isolate value = { # the type of values
    57      type this
    58      relation valid(V:value)
    59      individual nil:value
    60      specification {
    61          property ~valid(nil)
    62      }
    63      implementation {
    64          interpret value -> bv[2]
    65          definition nil = <<< -1 >>> # let's say nil is -1
    66          definition valid(V) = V ~= nil
    67      }
    68  }
    69  
    70  object nset = { # the type of node sets
    71      type this # a set of N=3f+i nodes for 0<i<=3
    72      relation member(N:node, S:nset) # set-membership relation
    73      relation is_quorum(S:nset) # intent: sets of cardinality at least 2f+i+1
    74      relation is_blocking(S:nset) # intent: at least f+1 nodes
    75      export action insert(s:nset, n:node) returns (t:nset)
    76      export action empty returns (s:nset)
    77      implementation {
    78          # NOTE: this is not checked at all by Ivy; it is however useful to generate C++ code and run it for debugging purposes
    79          <<< header
    80              #include <set>
    81              #include <exception>
    82              namespace hash_space {
    83                  template <typename T>
    84                      class hash<std::set<T> > {
    85                  public:
    86                      size_t operator()(const std::set<T> &s) const {
    87                          hash<T> h;
    88                          size_t res = 0;
    89                          for (const T &e : s)
    90                              res += h(e);
    91                          return res;
    92                      }
    93                  };
    94          }
    95          >>>
    96          interpret nset -> <<< std::set<`node`> >>>
    97          definition member(n:node, s:nset) = <<< `s`.find(`n`) != `s`.end() >>>
    98          definition is_quorum(s:nset) = <<< 3*`s`.size() > 2*`node.size` >>>
    99          definition is_blocking(s:nset) = <<< 3*`s`.size() > `node.size` >>>
   100          implement empty {
   101              <<<
   102              >>>
   103          }
   104          implement insert {
   105              <<<
   106                  `t` = `s`;
   107                  `t`.insert(`n`);
   108              >>>
   109          }
   110      <<< encode `nset`
   111  
   112          std::ostream &operator <<(std::ostream &s, const `nset` &a) {
   113              s << "{";
   114              for (auto iter = a.begin(); iter != a.end(); iter++) {
   115                  if (iter != a.begin()) s << ", ";
   116                  s << *iter;
   117              }
   118              s << "}";
   119              return s;
   120          }
   121  
   122          template <>
   123          `nset` _arg<`nset`>(std::vector<ivy_value> &args, unsigned idx, long long bound) {
   124              throw std::invalid_argument("Not implemented"); // no syntax for nset values in the REPL
   125          }
   126  
   127      >>>
   128      }
   129  }
   130  
   131  object classic_bft = {
   132      relation quorum_intersection
   133      private {
   134          definition [quorum_intersection_def] quorum_intersection = forall Q1,Q2. exists N. well_behaved(N) & nset.member(N, Q1) & nset.member(N, Q2) # every two quorums have a well-behaved node in common
   135      }
   136  }
   137  
   138  trusted isolate accountable_bft = {
   139      # this is our baseline assumption about quorums:
   140      private {
   141          property [max_2f_byzantine] exists N . well_behaved(N) & nset.member(N,Q) # every quorum has a well-behaved member
   142      }
   143  }