├── .gitignore ├── .gitmodules ├── Dockerfile ├── Jenkinsfile ├── LICENSE.md ├── README.md ├── casper ├── coq │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── _CoqProject │ └── theories │ │ ├── AccountableSafety.v │ │ ├── HashTree.v │ │ ├── Justification.v │ │ ├── NatExt.v │ │ ├── PlausibleLiveness.v │ │ ├── Quorums.v │ │ ├── SetTheoryProps.v │ │ ├── SlashableBound.v │ │ ├── Slashing.v │ │ ├── State.v │ │ ├── StrongInductionLtn.v │ │ ├── Validator.v │ │ └── Weight.v └── report │ ├── .gitignore │ ├── ACM-Reference-Format.bst │ ├── acmart.cls │ ├── bib.bib │ ├── comment.cut │ ├── lstcoq.sty │ ├── report.pdf │ └── report.tex ├── dynamic ├── Makefile ├── dynamic-abstract-beacon-chain-syntax.md ├── dynamic-abstract-beacon-chain.md ├── process-attestation-spec.k ├── process-block-spec.k ├── process-deposit-spec.k ├── process-epoch-spec.k ├── process-justification-finalization-spec.md ├── process-rewards-penalties-spec.k ├── process-slashing-spec.k ├── process-slots-spec.k ├── process-validator-activation-eligibility-spec.k ├── process-validator-activation-spec.k ├── process-validator-ejection-spec.k ├── process-validator-exit-spec.k ├── process-validator-updates-spec.k ├── tests │ ├── concrete │ │ ├── test1.abc │ │ ├── test1.abc.expected │ │ ├── test2.abc │ │ ├── test2.abc.expected │ │ ├── test3.abc │ │ └── test3.abc.expected │ ├── note.txt │ ├── success.out │ └── symbolic │ │ ├── a-spec.k │ │ ├── b-spec.k │ │ ├── c-spec.k │ │ ├── d-spec.k │ │ ├── e-spec.k │ │ ├── f-spec.k │ │ ├── f2-spec.k │ │ ├── finalization-cases.txt │ │ ├── g-spec.k │ │ ├── g2-spec.k │ │ ├── h-spec.k │ │ ├── i-spec.k │ │ ├── j-spec.k │ │ ├── k0-spec.k │ │ ├── k1a-spec.k │ │ ├── k1b-spec.k │ │ ├── k2a-spec.k │ │ ├── k2b-spec.k │ │ ├── kn1-spec.k │ │ ├── kn2-spec.k │ │ ├── l.smt2 │ │ ├── l1-spec.k │ │ ├── l2-spec.k │ │ ├── l3-spec.k │ │ ├── l4-spec.k │ │ ├── l5-spec.k │ │ ├── l6-spec.k │ │ ├── m-spec.k │ │ ├── m2-spec.k │ │ ├── m3-spec.k │ │ ├── n.smt2 │ │ ├── n1-spec.k │ │ ├── n2-spec.k │ │ ├── n3-spec.k │ │ ├── n4-spec.k │ │ ├── n5-spec.k │ │ ├── n6-spec.k │ │ ├── n7-spec.k │ │ ├── n8-spec.k │ │ ├── n9-spec.k │ │ ├── o1-spec.k │ │ ├── o2-spec.k │ │ ├── p1-spec.k │ │ ├── p2-spec.k │ │ ├── process-finalization-spec.k │ │ ├── process-justification-spec.k │ │ ├── process-rewards-penalties-and-validator-updates-spec.k │ │ ├── process-rewards-penalties-spec.k │ │ ├── process-slots-base0-spec.k │ │ ├── process-slots-base1-spec.k │ │ ├── process-slots-inductive-spec.k │ │ ├── q1-spec.k │ │ ├── q2-spec.k │ │ ├── q3-spec.k │ │ ├── q4-spec.k │ │ └── simple-spec.k └── verification.k ├── fork-choice-rule └── preliminary-analysis-fork-choice-rule.pdf ├── resources ├── Notes-on-justification-diagram.png └── pdf-icon.png └── weak-subjectivity ├── Makefile ├── after-n-epoch-balance-top-ups.pdf ├── after-n-epoch.pdf ├── balance-top-ups.pdf ├── discussion.tex ├── header.tex ├── intro.tex ├── llncs.cls ├── paper.tex ├── ref.bib ├── splncs04.bst ├── weak-subjectivity-analysis.pdf └── ws-period.tex /.gitignore: -------------------------------------------------------------------------------- 1 | /*/.build 2 | /dynamic/process-justification-finalization-lemma.k 3 | /dynamic/process-justification-finalization-spec.k 4 | /dynamic/tests/concrete/*.out 5 | /dynamic/*-spec.k.out 6 | .kompile* 7 | .kprove* 8 | .krun* 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/pandoc-tangle"] 2 | path = deps/pandoc-tangle 3 | url = https://github.com/ehildenb/pandoc-tangle 4 | ignore = untracked 5 | [submodule "deps/k"] 6 | path = deps/k 7 | url = https://github.com/kframework/k.git 8 | ignore = untracked 9 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG K_COMMIT 2 | FROM runtimeverificationinc/kframework-k:ubuntu-bionic-${K_COMMIT} 3 | 4 | RUN apt-get update \ 5 | && apt-get upgrade --yes \ 6 | && apt-get install --yes \ 7 | cmake \ 8 | coq \ 9 | pandoc \ 10 | python3 11 | 12 | ARG USER_ID=1000 13 | ARG GROUP_ID=1000 14 | RUN groupadd -g $GROUP_ID user && useradd -m -u $USER_ID -s /bin/sh -g user user 15 | 16 | USER user:user 17 | WORKDIR /home/user 18 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | options { ansiColor('xterm') } 3 | agent { 4 | dockerfile { 5 | label 'docker' 6 | additionalBuildArgs '--build-arg K_COMMIT=$(cd deps/k && git rev-parse --short=7 HEAD) --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g)' 7 | } 8 | } 9 | stages { 10 | stage('Init title') { 11 | when { changeRequest() } 12 | steps { script { currentBuild.displayName = "PR ${env.CHANGE_ID}: ${env.CHANGE_TITLE}" } } 13 | } 14 | stage('Build and Test') { 15 | parallel { 16 | stage('Dynamic - K') { 17 | stages { 18 | stage('Build') { steps { sh 'cd dynamic && make build -j2' } } 19 | stage('Test') { steps { sh 'cd dynamic && make test -j4' } } 20 | } 21 | } 22 | //stage('Static - Coq') { 23 | // steps { 24 | // sh ''' 25 | // cd casper/coq 26 | // make 27 | // ''' 28 | // } 29 | //} 30 | } 31 | } 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Beacon Chain Verification Team. All Rights Reserved. 2 | 3 | Developed by: 4 | 5 | Runtime Verification, Inc. 6 | 7 | University of Illinois/NCSA 8 | Open Source License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of 11 | this software and associated documentation files (the "Software"), to deal with 12 | the Software without restriction, including without limitation the rights to 13 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 14 | of the Software, and to permit persons to whom the Software is furnished to do 15 | so, subject to the following conditions: 16 | 17 | * Redistributions of source code must retain the above copyright notice, 18 | this list of conditions and the following disclaimers. 19 | 20 | * Redistributions in binary form must reproduce the above copyright notice, 21 | this list of conditions and the following disclaimers in the 22 | documentation and/or other materials provided with the distribution. 23 | 24 | * Neither the names of the Beacon Chain Verification Team, 25 | Runtime Verification, Inc., nor the names of 26 | its contributors may be used to endorse or promote products derived from 27 | this Software without specific prior written permission. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE 35 | SOFTWARE. 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Formal Verification of Beacon Chain Specification 2 | 3 | This repository consists of the following developments: 4 | 5 | 1. Mechanized proofs of key properties of finality in [the "Gasper" protocol](https://arxiv.org/abs/2003.03052): 6 | - Model and proofs (in Coq): [`casper/coq/`](casper/coq) 7 | - A technical report describing the model and the proofs: [`casper/report/`](casper/report) 8 | 9 | 2. _(ongoing)_ Mechanized proofs of the refinement soundness of [the state transition (Phase 0)](https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md) w.r.t. the Gasper protocol: 10 | - Model (in K): [`dynamic/dynamic-abstract-beacon-chain.md`](dynamic/dynamic-abstract-beacon-chain.md) 11 | - Proofs (in K): `*-spec.k` files in [`dynamic/`](dynamic) 12 | 13 | 3. Analysis on the weak subjectivity period for Ethereum 2.0: 14 | - Report: [[PDF](weak-subjectivity/weak-subjectivity-analysis.pdf)] [[Source](weak-subjectivity)] 15 | 16 | 4. Preliminary analysis on the fork choice rule for the Beacon chain: 17 | - Report: [[PDF](fork-choice-rule/preliminary-analysis-fork-choice-rule.pdf)] [[Source](https://docs.google.com/document/d/1xiSWfuqssGatVSzYobPhPR-BxgW9Q_5rydyfQvWJW-U/)] 18 | -------------------------------------------------------------------------------- /casper/coq/.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | .*.aux 3 | *.a 4 | *.cma 5 | *.cmi 6 | *.cmo 7 | *.cmx 8 | *.cmxa 9 | *.cmxs 10 | *.glob 11 | *.d 12 | *.native 13 | *.o 14 | *.vio 15 | *.vo 16 | *.vos 17 | *.vok 18 | build/ 19 | .coq-native/ 20 | .csdp.cache 21 | .lia.cache 22 | .nia.cache 23 | .nlia.cache 24 | .nra.cache 25 | csdp.cache 26 | lia.cache 27 | nia.cache 28 | nlia.cache 29 | nra.cache 30 | Makefile.coq 31 | Makefile.coq.conf 32 | **\#* -------------------------------------------------------------------------------- /casper/coq/Makefile: -------------------------------------------------------------------------------- 1 | all: default 2 | 3 | default: Makefile.coq 4 | $(MAKE) -f Makefile.coq 5 | 6 | quick: Makefile.coq 7 | $(MAKE) -f Makefile.coq quick 8 | 9 | clean: Makefile.coq 10 | $(MAKE) -f Makefile.coq cleanall 11 | rm -f Makefile.coq Makefile.coq.conf 12 | 13 | Makefile.coq: _CoqProject 14 | coq_makefile -f _CoqProject -o Makefile.coq 15 | 16 | .PHONY: all default quick clean -------------------------------------------------------------------------------- /casper/coq/README.md: -------------------------------------------------------------------------------- 1 | # Modeling and Verifying Gasper in Coq 2 | 3 | This part of the repository gives a formalization in Coq of finality in Gasper, an abstraction of the Beacon Chain specification described [here](https://arxiv.org/abs/2003.03052). Gasper's finality generalizes [Casper FFG](https://arxiv.org/abs/1710.09437). With this formalization, we mechanize proofs of three main results of Gasper: 4 | 5 | - **Accountable safety:** No two conflicting blocks are finalized without having at least 1/3 of validator deposits slashed. 6 | 7 | - **Plausible liveness:** Assuming that at least 2/3 of validators (by deposit) follow the protocol, it is always possible to continue to finalize new blocks irrespective of what has happened before. 8 | 9 | - **Slashable bound:** Even when the set of active validators is dynamic, a lower bound (given in terms of validator activation and exit policies) on what stake worth of validators is provably slashable can be guaranteed. 10 | 11 | This development is based on previously developed models and proofs of Casper in Coq [here](https://github.com/runtimeverification/casper-proofs). It extends that work in four significant ways: 12 | 13 | - Unifying the two distinct models built sepearately for safey and liveness, and proving both properties in the same unified model. 14 | 15 | - Generalizing the definition of finalization to k-finalization (as defined in the [Gasper protocol](https://arxiv.org/abs/2003.03052)), along with the accountable safety proof. 16 | 17 | - Generalizing the model and proofs to dynamic validator sets, and 18 | 19 | - Modeling validator set weights and proving the slashable bound theorem. 20 | 21 | A more detailed explanation of the models and proofs can be found in the technical report: 22 | 23 | PDF *[Verifying Gasper with Dynamic Validator Sets in Coq](../report/report.pdf)* 24 | 25 | ## Model Layout 26 | 27 | ### Utility files 28 | 29 | - [NatExt.v](theories/NatExt.v): some additional properties of natural numbers 30 | - [SetTheoryProps.v](theories/SetTheoryProps.v): some additional set-theoretic properties 31 | - [StrongInductionLtn.v](theories/StrongInductionLtn.v): some strong induction principles on natural numbers, adapted from work by Tej Chajed 32 | 33 | ### Casper abstract model 34 | 35 | These files define an abstract view of Casper's validators, blocks and votes, and specify its justification and finalization mechanisms. 36 | 37 | - [Validator.v](theories/Validator.v): validators and their stake 38 | - [Weight.v](theories/Weight.v): weights of validator sets and their properties 39 | - [HashTree.v](theories/HashTree.v): the checkpoint block trees and their properties 40 | - [State.v](theories/State.v): the state as a set of votes cast 41 | - [Slashing.v](theories/Slashing.v): the slashing conditions 42 | - [Quorums.v](theories/Quorums.v): Quorum predicates and properties 43 | - [Justification.v](theories/Justification.v): justification and finalization definitions and their properties 44 | 45 | 46 | ### Casper properties 47 | 48 | These files contain the major theorems about Casper. 49 | 50 | - [AccountableSafety.v](theories/AccountableSafety.v): Proof of the Accountable Safety theorem 51 | - [PlausibleLiveness.v](theories/PlausibleLiveness.v): Proof of the Plausible Liveness theorem 52 | - [SlashableBound.v](theories/SlashableBound.v): Proof of the Slashable Bound theorem 53 | 54 | ## Requirements 55 | 56 | * [Coq 8.9 or 8.10](https://coq.inria.fr) 57 | * [Mathematical Components 1.8 or 1.9](http://math-comp.github.io/math-comp/) (`ssreflect`) 58 | * [CoqHammer 1.0.9](https://github.com/lukaszcz/coqhammer) 59 | * [finmap](https://github.com/math-comp/finmap) 60 | 61 | ## Building 62 | 63 | We recommend installing dependencies via [OPAM](http://opam.ocaml.org/doc/Install.html): 64 | 65 | ``` 66 | opam repo add coq-released https://coq.inria.fr/opam/released 67 | opam install coq coq-mathcomp-ssreflect coq-hammer coq-mathcomp-finmap 68 | ``` 69 | 70 | Then, run `make` in the directory of this README to check all definitions and proofs. 71 | 72 | ## Getting Help 73 | 74 | Feel free to report GitHub issues here or to contact us at: [contact@runtimeverification.com](contact@runtimeverification.com). 75 | -------------------------------------------------------------------------------- /casper/coq/_CoqProject: -------------------------------------------------------------------------------- 1 | -Q theories Casper 2 | 3 | theories/NatExt.v 4 | theories/StrongInductionLtn.v 5 | theories/SetTheoryProps.v 6 | theories/Validator.v 7 | theories/Weight.v 8 | theories/HashTree.v 9 | theories/State.v 10 | theories/Slashing.v 11 | theories/Quorums.v 12 | theories/Justification.v 13 | theories/AccountableSafety.v 14 | theories/PlausibleLiveness.v 15 | theories/SlashableBound.v 16 | -------------------------------------------------------------------------------- /casper/coq/theories/HashTree.v: -------------------------------------------------------------------------------- 1 | Set Warnings "-parsing". 2 | From mathcomp.ssreflect 3 | Require Import all_ssreflect. 4 | Set Warnings "parsing". 5 | 6 | Set Implicit Arguments. 7 | Unset Strict Implicit. 8 | Unset Printing Implicit Defensive. 9 | 10 | (******************************************************************************) 11 | (* A representation of block (hash) trees and related properties *) 12 | (* Note: We consider the checkpoint tree of blocks, and so a "block" refers *) 13 | (* to a "checkpoint block" throughout the specs below. *) 14 | (******************************************************************************) 15 | 16 | (* We assume finite hash values (block identifiers) *) 17 | Parameter Hash : finType. 18 | 19 | (* This relation links blocks (b,b'), written b <~ b', if b is the parent *) 20 | (* of b' in the block tree *) 21 | Parameter hash_parent : rel Hash. 22 | 23 | Notation "h1 <~ h2" := (hash_parent h1 h2) (at level 50). 24 | 25 | (* A block cannot be a parent of itself *) 26 | Axiom hash_parent_irreflexive: 27 | forall h1 h2, h1 <~ h2 -> h1 <> h2. 28 | 29 | (* A block cannot have two distinct parent blocks *) 30 | Axiom hash_at_most_one_parent : 31 | forall h1 h2 h3, h2 <~ h1 -> h3 <~ h1 -> h2 = h3. 32 | 33 | (* The ancestor reltion `<~*`: the reflexive-transitive closure of `<~` *) 34 | Definition hash_ancestor h1 h2 := connect hash_parent h1 h2. 35 | 36 | Notation "h1 <~* h2" := (hash_ancestor h1 h2) (at level 50). 37 | 38 | Notation "h1 h1 <~* h2 /\ h1 <> h2. 59 | Proof. 60 | split. 61 | by apply/connect1. 62 | by apply/hash_parent_irreflexive. 63 | Qed. 64 | 65 | (* A parent of an ancestor is an ancestor *) 66 | Lemma hash_ancestor_stepL : 67 | forall h1 h2 h3, 68 | h1 <~ h2 -> h2 <~* h3 -> h1 <~* h3. 69 | Proof. 70 | move => h1 h2 h3. 71 | move/connect1. 72 | by apply/connect_trans. 73 | Qed. 74 | 75 | (* An ancestor of a parent is an ancestor *) 76 | Lemma hash_ancestor_stepR : 77 | forall h1 h2 h3, 78 | h1 <~* h2 -> h2 <~ h3 -> h1 <~* h3. 79 | Proof. 80 | move => h1 h2 h3 H1 H2. 81 | apply: connect_trans; eauto. 82 | by apply/connect1. 83 | Qed. 84 | 85 | (* An ancestor of an ancestor is an ancestor *) 86 | Lemma hash_ancestor_concat : 87 | forall h1 h2 h3, 88 | h1 <~* h2 -> h2 <~* h3 -> h1 <~* h3. 89 | Proof. 90 | move => h1 h2 h3 H2 H1. 91 | by apply: connect_trans; eauto. 92 | Qed. 93 | 94 | (* A block can never conflict with itself *) 95 | Lemma hash_nonancestor_nonequal: 96 | forall h1 h2, 97 | h1 h1 <> h2. 98 | Proof. 99 | intros h1 h2 Hna. 100 | contradict Hna. 101 | replace h1 with h2. 102 | apply hash_self_ancestor. 103 | Qed. 104 | 105 | (* A conflicting block cannot belong to the ancestry of that block *) 106 | Lemma hash_ancestor_conflict: 107 | forall h1 h2 p, 108 | h1 <~* h2 -> p p h1 h2 p H1 H2 Hp. 111 | destruct H2. 112 | move: Hp H1. 113 | by apply/connect_trans. 114 | Qed. 115 | 116 | (* This definition of ancestry makes the exact number of steps explicit *) 117 | Inductive nth_ancestor : nat -> Hash -> Hash -> Prop := 118 | | nth_ancestor_0 : forall h1, nth_ancestor 0 h1 h1 119 | | nth_ancestor_nth : forall n h1 h2 h3, 120 | nth_ancestor n h1 h2 -> h2 <~ h3 -> 121 | nth_ancestor n.+1 h1 h3. 122 | 123 | (* The nth_ancestor is an ancestor *) 124 | Lemma nth_ancestor_ancestor : 125 | forall n s t, 126 | nth_ancestor n s t -> (s <~* t). 127 | Proof. 128 | induction 1. 129 | apply connect0. 130 | apply connect_trans with h2;[|apply connect1];assumption. 131 | Qed. 132 | 133 | (* nth_ancestor_0 must be with oneself *) 134 | Lemma nth_ancestor_0_refl : 135 | forall h1 h2, 136 | nth_ancestor 0 h1 h2 -> 137 | h1 = h2. 138 | Proof. 139 | intros h1 h2 H_an. 140 | inversion H_an; subst. reflexivity. 141 | Qed. 142 | 143 | (* a parent is a first-level ancestor *) 144 | Example parent_ancestor : forall h1 h2, 145 | h1 <~ h2 <-> nth_ancestor 1 h1 h2. 146 | Proof. 147 | move => h1 h2; split; move => Hp. 148 | apply: nth_ancestor_nth; eauto. 149 | exact: nth_ancestor_0. 150 | inversion Hp; subst. 151 | apply nth_ancestor_0_refl in H0. 152 | subst. assumption. 153 | Qed. 154 | -------------------------------------------------------------------------------- /casper/coq/theories/NatExt.v: -------------------------------------------------------------------------------- 1 | Set Warnings "-parsing". 2 | From mathcomp.ssreflect 3 | Require Import all_ssreflect. 4 | Set Warnings "parsing". 5 | 6 | From mathcomp.finmap 7 | Require Import finmap. 8 | 9 | Set Implicit Arguments. 10 | Unset Strict Implicit. 11 | Unset Printing Implicit Defensive. 12 | 13 | (******************************************************************************) 14 | (* Some basic extentions/properties of nats needed in the rest of the specs. *) 15 | (******************************************************************************) 16 | 17 | (* The `highest' value in a finite set of nats *) 18 | Definition highest (A : {fset nat}) : nat := 19 | \max_(i : A) (val i). 20 | 21 | (* The `highest' is the maximum value *) 22 | Lemma highest_ub: 23 | forall (A : {fset nat}) (x:nat), x \in A -> x <= highest A. 24 | Proof. 25 | move => A x Hx. 26 | case (insubP [subType of A] x) => /=; last by move: Hx =>->. 27 | move => k Hk =><-. 28 | exact: leq_bigmax_cond. 29 | Qed. 30 | 31 | (* The successor cannot be smaller *) 32 | Lemma ltSnn n: (n.+1 < n) = false. 33 | Proof. 34 | by apply/negP/negP; rewrite leqNgt; apply/negP; case/negP. 35 | Qed. 36 | 37 | (* Basic fact about nats *) 38 | Lemma leq_one_means_zero_or_one : forall n, 39 | n <= 1 -> n = 0 \/ n = 1. 40 | Proof. 41 | intros n H_leq. 42 | induction n. left; reflexivity. 43 | intuition. destruct IHn. by apply ltnW. 44 | subst. right. easy. subst. inversion H_leq. 45 | Qed. 46 | 47 | (* Basic subtraction fact *) 48 | Lemma sub_eq n : n - n = 0. 49 | Proof. by elim: n => [|n IHn]. Qed. 50 | 51 | (* Conditional associativity of add-sub *) 52 | Lemma addnDAr n m p : 53 | m >= p -> (n + m) - p = n + (m - p). 54 | Proof. 55 | elim: n m => [|n IHn] [|m IHm];trivial. 56 | rewrite leqn0. 57 | by move/eqP => Hp;subst. 58 | apply IHn in IHm as IH. 59 | rewrite [in RHS]addSnnS -[in RHS]addn1 [in RHS]addnA. 60 | rewrite -IH. 61 | rewrite addSn. rewrite [in LHS]subSn. by rewrite [in RHS]addn1. 62 | apply (leq_trans IHm). clear. 63 | elim: m => [|m IHm]. rewrite addn1. apply ltn0Sn. 64 | by rewrite -addn1 addnA leq_add2r. 65 | Qed. 66 | 67 | (* Two uninterpreted functions are introduced to represent quantities that will be *) 68 | (* used in the statement of the slashsable bound theorem. These are not strictly *) 69 | (* necessary, but they enable using statements and proof arguments that are closer *) 70 | (* to the paper. *) 71 | Parameter one_third : nat -> nat. 72 | Parameter two_third : nat -> nat. 73 | 74 | (* Basic axioms assumed to hold for these function symbols *) 75 | Axiom thirds_def : forall n, n - two_third n = one_third n. 76 | Axiom leq_two_thirds : forall n, two_third n <= n. 77 | 78 | (* This property follows from leq_two_thirds above *) 79 | Lemma wt_two_thirds_sum : forall n m, 80 | two_third n + two_third m <= n + m. 81 | Proof. 82 | by move => n m; apply: (leq_add (leq_two_thirds n) (leq_two_thirds m)). 83 | Qed. 84 | 85 | -------------------------------------------------------------------------------- /casper/coq/theories/Quorums.v: -------------------------------------------------------------------------------- 1 | Set Warnings "-parsing". 2 | From mathcomp.ssreflect 3 | Require Import all_ssreflect. 4 | Set Warnings "parsing". 5 | 6 | From mathcomp.finmap 7 | Require Import finmap. 8 | 9 | From Casper 10 | Require Import NatExt. 11 | 12 | From Casper 13 | Require Import Validator Weight HashTree State Slashing. 14 | 15 | Set Implicit Arguments. 16 | Unset Strict Implicit. 17 | Unset Printing Implicit Defensive. 18 | 19 | Open Scope fmap_scope. 20 | Open Scope big_scope. 21 | 22 | (******************************************************************************) 23 | (* Validator sets, quorums and quorum properties *) 24 | (******************************************************************************) 25 | 26 | 27 | (* A finite map vset defining the set of validators for a given block *) 28 | Parameter vset : {fmap Hash -> {set Validator}}. 29 | 30 | (* We assume the map vset is total *) 31 | Axiom vs_fun : forall h : Hash, h \in vset. 32 | 33 | (** Quorum Predicates **) 34 | (* A predicate for an "at least 1/3 weight" set of validators *) 35 | Definition quorum_1 (vs : {set Validator}) (b : Hash) : bool := 36 | (vs \subset vset.[vs_fun b]) && 37 | (wt vs >= one_third (wt vset.[vs_fun b])). 38 | 39 | (* A predicate for an "at least 2/3 weight" set of validators *) 40 | Definition quorum_2 (vs : {set Validator}) (b : Hash) : bool := 41 | (vs \subset vset.[vs_fun b]) && 42 | (wt vs >= two_third (wt vset.[vs_fun b])). 43 | 44 | (* Meaning of a validator set being slashed in the general context of *) 45 | (* dynamic validator sets *) 46 | Definition q_intersection_slashed st := 47 | exists (bL bR: Hash) (vL vR: {set Validator}), 48 | vL \subset vset.[vs_fun bL] /\ 49 | vR \subset vset.[vs_fun bR] /\ 50 | quorum_2 vL bL /\ 51 | quorum_2 vR bR /\ 52 | forall v, v \in vL -> v \in vR -> slashed st v. 53 | 54 | (* The assumption on quorums that a supermajority quorum with respect to a *) 55 | (* block is nonempty (Needed for liveness) *) 56 | Axiom quorum_2_nonempty: 57 | forall (b:Hash) (q :{set Validator}), 58 | quorum_2 q b -> exists v, v \in q. 59 | 60 | (* The property that, with respect to a block b, adding more b-validators *) 61 | (* to a supermajority leaves a supermajority (Needed for liveness) *) 62 | Lemma quorum_2_upclosed: 63 | forall (b:Hash) (q q':{set Validator}), 64 | q \subset q' -> q' \subset vset.[vs_fun b] -> quorum_2 q b -> 65 | quorum_2 q' b. 66 | Proof. 67 | move=> b q q' Hqsubq' Hq'. 68 | rewrite /quorum_2. 69 | move/andP=> [Hq Hqwt]. 70 | apply/andP;split. exact Hq'. 71 | apply wt_inc_leq in Hqsubq'. 72 | by apply (leq_trans Hqwt Hqsubq'). 73 | Qed. 74 | 75 | 76 | -------------------------------------------------------------------------------- /casper/coq/theories/SetTheoryProps.v: -------------------------------------------------------------------------------- 1 | Set Warnings "-parsing". 2 | From mathcomp.ssreflect 3 | Require Import all_ssreflect. 4 | Set Warnings "parsing". 5 | 6 | Set Implicit Arguments. 7 | Unset Strict Implicit. 8 | Unset Printing Implicit Defensive. 9 | 10 | (******************************************************************************) 11 | (* Various set-theoretic properties that are used in the rest of the specs. *) 12 | (******************************************************************************) 13 | 14 | 15 | Lemma setID_disjoint {T : finType} (A B:{set T}): 16 | [disjoint (A :&: B) & (A :\: B)]. 17 | Proof. 18 | rewrite -setI_eq0 eqEsubset. 19 | apply/andP;split;apply/subsetP => x;last by rewrite in_set0. 20 | move/setIP=> [H1 H2]. 21 | move/setIP: H1 => [_ H1]. 22 | move/setDP: H2 => [_ H2]. 23 | move/negP: H2 => H2. 24 | by contradiction. 25 | Qed. 26 | 27 | Lemma setDD_disjoint {T : finType} (A B:{set T}): 28 | [disjoint (A :\: B) & (B :\: A)]. 29 | Proof. 30 | rewrite -setI_eq0 eqEsubset. 31 | apply/andP;split;apply/subsetP => x;last by rewrite in_set0. 32 | move/setIP=> [H1 H2]. 33 | move/setDP: H1 => [H1a H1b]. 34 | move/setDP: H2 => [H2a H2b]. 35 | move/negP: H2b => H2b. 36 | by contradiction. 37 | Qed. 38 | 39 | Lemma setDDI_disjoint {T : finType} (A B:{set T}): 40 | [disjoint A :\: B :|: B :\: A & A :&: B]. 41 | Proof. 42 | rewrite -setI_eq0 eqEsubset. 43 | apply/andP;split;apply/subsetP => x;last by rewrite in_set0. 44 | move/setIP=> [H1 H2]. 45 | move/setIP: H2 => [Hin1 Hin2]. 46 | case/setUP: H1 => H;move/setDP: H => [_ Hnotin2]; 47 | move/negP: Hnotin2 => Hnotin2;contradiction. 48 | Qed. 49 | 50 | Lemma setU_par {T : finType} (A B:{set T}): 51 | A :|: B = (A :\: B) :|: (B :\: A) :|: (A :&: B). 52 | Proof. 53 | apply/eqP. 54 | rewrite eqEsubset. 55 | apply/andP;split;apply/subsetP => x. 56 | case/setUP=> H. 57 | - rewrite -setUA setUC -setUA. 58 | apply/setUP;right. 59 | by rewrite setUC -setDDr setDv setD0. 60 | - rewrite -setUA. 61 | apply/setUP;right. 62 | by rewrite setIC -setDDr setDv setD0. 63 | case/setUP=> H. 64 | - case/setUP: H => H. 65 | * move/setDP: H => [H _]. 66 | by apply/setUP;left. 67 | * move/setDP: H => [H _]. 68 | by apply/setUP;right. 69 | - move/setIP: H => [H _]. 70 | by apply/setUP;left. 71 | Qed. 72 | 73 | Lemma setIs_disjoint {T : finType} (A B C: {set T}): 74 | [disjoint A & B] -> [disjoint A & B :&: C]. 75 | Proof. 76 | move/setDidPl=> <-. 77 | rewrite -setI_eq0 eqEsubset. 78 | apply/andP;split;apply/subsetP => x;last by rewrite in_set0. 79 | move/setIP=> [H1 H2]. 80 | move/setDP: H1 => [_ H1]. 81 | move/setIP: H2 => [H2 _]. 82 | by move/negP: H1 => H1. 83 | Qed. 84 | 85 | Lemma setIID_disjoint {T : finType} (A B C: {set T}): 86 | [disjoint (A :&: B) & (A :&: C :\: B)]. 87 | Proof. 88 | rewrite setDIl. 89 | apply: setIs_disjoint. 90 | apply: setID_disjoint. 91 | Qed. 92 | 93 | Lemma setIIDD_disjoint {T : finType} (A B C D: {set T}): 94 | [disjoint A :&: B :|: A :&: C :\: B & B :&: D :\: A]. 95 | Proof. 96 | rewrite -setI_eq0 eqEsubset. 97 | apply/andP;split;apply/subsetP => x;last by rewrite in_set0. 98 | move/setIP=> [H1 H2]. 99 | move/setUP: H1 => H1. 100 | move/setDP: H2 => [H2a H2b]. 101 | case: H1. 102 | - move/setIP=> [H _]. by move/negP: H2b. 103 | - move/setDP=> [H _]. move/setIP: H => [H _]. by move/negP: H2b. 104 | Qed. 105 | 106 | Lemma setIIDD_subset {T : finType} (A B C D: {set T}): 107 | A \subset C -> 108 | B \subset D -> 109 | A :&: B :|: A :&: D :\: B :|: B :&: C :\: A \subset C :&: D. 110 | Proof. 111 | move=> Ha Hb. 112 | move/subsetP:Ha => Ha. 113 | move/subsetP:Hb => Hb. 114 | apply/subsetP => x. 115 | case/setUP=> H. 116 | apply/setIP. 117 | - case/setUP: H => H. 118 | * move/setIP: H => [Hxa Hxb]. 119 | by (apply Ha in Hxa;apply Hb in Hxb). 120 | * move/setDP: H => [Hxad _]. move/setIP: Hxad => [Hxa Hxd]. 121 | by (apply Ha in Hxa). 122 | - move/setDP: H => [Hxbc _]. move/setIP: Hxbc => [Hxb Hxc]. 123 | apply Hb in Hxb. by apply/setIP. 124 | Qed. 125 | 126 | Lemma setID2_disjoint {T : finType} (A B C:{set T}): 127 | [disjoint (A :&: C) & (B :\: C)]. 128 | Proof. 129 | rewrite -setI_eq0 eqEsubset. 130 | apply/andP;split;apply/subsetP => x;last by rewrite in_set0. 131 | move/setIP=> [H1 H2]. 132 | move/setIP: H1 => [_ H1]. 133 | move/setDP: H2 => [_ H2]. 134 | by move/negP: H2 => H2. 135 | Qed. 136 | 137 | Lemma setID2_subset {T : finType} (A B C:{set T}): 138 | A \subset B -> 139 | A \subset (A :&: C) :|: (B :\: C). 140 | Proof. 141 | move/subsetP => H. 142 | apply/subsetP => x. 143 | move=> Hs0. 144 | apply/setUP. 145 | have : (x \in C) || ~~(x \in C) by apply orbN. 146 | case/orP=> H'. 147 | - left. by apply/setIP. 148 | - right. apply H in Hs0. by apply/setDP. 149 | Qed. 150 | 151 | Lemma set3D_disjoint {T : finType} (A B C:{set T}): 152 | [disjoint C :\: B & A :\: C]. 153 | Proof. 154 | rewrite -setI_eq0 eqEsubset. 155 | apply/andP;split;apply/subsetP => x;last by rewrite in_set0. 156 | move/setIP=> [H1 H2]. 157 | move/setDP: H1 => [H1a H1b]. 158 | move/setDP: H2 => [H2a H2b]. 159 | move/negP: H2b => H2b. 160 | by contradiction. 161 | Qed. 162 | 163 | Lemma set3D_subset {T : finType} (A B C:{set T}): 164 | A :\: B \subset C :\: B :|: A :\: C. 165 | Proof. 166 | apply/subsetP => x. 167 | move/setDP=> [H1 H2]. 168 | apply/setUP. 169 | have : (x \in C) || ~~(x \in C) by apply orbN. 170 | case/orP=> H. 171 | - left. by apply/setDP;split. 172 | - right. by apply/setDP;split. 173 | Qed. 174 | 175 | -------------------------------------------------------------------------------- /casper/coq/theories/Slashing.v: -------------------------------------------------------------------------------- 1 | Set Warnings "-parsing". 2 | From mathcomp.ssreflect 3 | Require Import all_ssreflect. 4 | Set Warnings "parsing". 5 | 6 | From mathcomp.finmap 7 | Require Import finmap. 8 | 9 | From Casper 10 | Require Import Validator HashTree State. 11 | 12 | Set Implicit Arguments. 13 | Unset Strict Implicit. 14 | Unset Printing Implicit Defensive. 15 | 16 | (******************************************************************************) 17 | (* Definitions of the slashing conditions *) 18 | (******************************************************************************) 19 | 20 | (* A validator may not make two votes with different target hashes at the *) 21 | (* same target height (whatever the source blocks) *) 22 | Definition slashed_double_vote st v := 23 | exists t1 t2, t1 <> t2 /\ exists s1 s1_h s2 s2_h t_h, 24 | vote_msg st v s1 t1 s1_h t_h /\ vote_msg st v s2 t2 s2_h t_h. 25 | 26 | (* A validator may not make two votes with the source and target of one *) 27 | (* vote both strictly between the source and target of the other *) 28 | Definition slashed_surround_vote st v := 29 | exists s1 t1 s1_h t1_h, 30 | exists s2 t2 s2_h t2_h, 31 | vote_msg st v s1 t1 s1_h t1_h /\ 32 | vote_msg st v s2 t2 s2_h t2_h /\ 33 | s2_h > s1_h /\ t2_h < t1_h. 34 | 35 | (* A slashed validator is one that has double-voted or surround-voted *) 36 | Definition slashed st v : Prop := 37 | slashed_double_vote st v \/ slashed_surround_vote st v. 38 | -------------------------------------------------------------------------------- /casper/coq/theories/State.v: -------------------------------------------------------------------------------- 1 | Set Warnings "-parsing". 2 | From mathcomp.ssreflect 3 | Require Import all_ssreflect. 4 | Set Warnings "parsing". 5 | 6 | From mathcomp.finmap 7 | Require Import finmap. 8 | 9 | From Casper 10 | Require Import Validator HashTree. 11 | 12 | Set Implicit Arguments. 13 | Unset Strict Implicit. 14 | Unset Printing Implicit Defensive. 15 | 16 | (******************************************************************************) 17 | (* A representation of state as a set of votes cast. *) 18 | (* *) 19 | (* Each vote names source and target nodes by giving hash and height, and is *) 20 | (* signed by a particular validator. This is taken directly from the way *) 21 | (* votes are expressed in the original Casper paper. *) 22 | (******************************************************************************) 23 | 24 | (* A vote is a tuple: *) 25 | (* (attestor, source, target, source height, target height) *) 26 | (* *) 27 | Definition Vote := (Validator * Hash * Hash * nat * nat)%type. 28 | 29 | (* A State is described by the finite set of votes cast. *) 30 | Definition State := {fset Vote}. 31 | 32 | (* A boolean vote_msg predicate that tells us whether a vote belongs to *) 33 | (* the state *) 34 | Definition vote_msg (st:State) v s t (s_h t_h:nat) : bool := 35 | (v,s,t,s_h,t_h) \in st . 36 | 37 | (* Vote projection operations *) 38 | Definition vote_val (v:Vote) : Validator := 39 | match v with 40 | (x,_,_,_,_) => x 41 | end. 42 | 43 | Definition vote_source (v:Vote) : Hash := 44 | match v with 45 | (_,s,_,_,_) => s 46 | end. 47 | 48 | Definition vote_target (v:Vote) : Hash := 49 | match v with 50 | (_,_,t,_,_) => t 51 | end. 52 | 53 | Definition vote_source_height (v:Vote) : nat := 54 | match v with 55 | (_,_,_,s_h,_) => s_h 56 | end. 57 | 58 | Definition vote_target_height (v:Vote) : nat := 59 | match v with 60 | (_,_,_,_,t_h) => t_h 61 | end. 62 | 63 | (* Reconstructing a vote using its projections *) 64 | Lemma vote_unfold (vote:Vote): 65 | vote = ((vote_val vote), 66 | (vote_source vote), 67 | (vote_target vote), 68 | (vote_source_height vote), 69 | (vote_target_height vote)). 70 | Proof. 71 | by move:vote=>[[[[v s] t] s_h] t_h]. 72 | Qed. -------------------------------------------------------------------------------- /casper/coq/theories/StrongInductionLtn.v: -------------------------------------------------------------------------------- 1 | Set Warnings "-parsing". 2 | From mathcomp 3 | Require Import all_ssreflect. 4 | Set Warnings "parsing". 5 | 6 | (******************************************************************************) 7 | (* This utility module proves a few induction principles used in other *) 8 | (* proofs. *) 9 | (******************************************************************************) 10 | 11 | (* Two strong induction principles over natural numbers, 12 | as represented in the MathComp library. 13 | Adapted from work by Tej Chajed. *) 14 | 15 | Section StrongInductionLtn. 16 | 17 | Variable P:nat -> Prop. 18 | 19 | (** The stronger inductive hypothesis given in strong induction. The standard 20 | [nat ] induction principle provides only n = pred m, with [P 0] required 21 | separately. *) 22 | Hypothesis IH : forall m, (forall n, n < m -> P n) -> P m. 23 | 24 | Lemma P0 : P 0. 25 | Proof. 26 | apply IH; intros. 27 | exfalso; inversion H. 28 | Qed. 29 | 30 | Hint Resolve P0 : core. 31 | 32 | Lemma pred_increasing : forall (n m : nat), 33 | n <= m -> 34 | n.-1 <= m.-1. 35 | Proof. by elim => //= n IH'; case. Qed. 36 | 37 | Local Lemma strong_induction_all : forall n, 38 | (forall m, m <= n -> P m). 39 | Proof. 40 | elim => //=; first by case. 41 | move => n IH' m Hm. 42 | apply: IH. 43 | move => n' Hn'. 44 | apply: IH'. 45 | have Hnn: n < n.+1 by apply ltnSn. 46 | move: Hm. 47 | rewrite leq_eqVlt. 48 | move/orP. 49 | case. 50 | - move/eqP => Hm. 51 | by move: Hm Hn' =>->. 52 | - move => Hm. 53 | have Hmn: m <= n by []. 54 | suff Hsuff: n' < n. 55 | rewrite leq_eqVlt. 56 | apply/orP. 57 | by right. 58 | by apply: leq_trans; eauto. 59 | Qed. 60 | 61 | Theorem strong_induction_ltn : forall n, P n. 62 | Proof. 63 | eauto using strong_induction_all. 64 | Qed. 65 | 66 | End StrongInductionLtn. 67 | 68 | Section StrongInductionSub. 69 | 70 | Variable k : nat. 71 | 72 | Variable T : Type. 73 | 74 | Variable P : nat -> T -> Prop. 75 | 76 | Hypothesis IH : forall (v1 : nat) (h1 : T), (forall (v1a : nat) (h1a : T), k < v1a -> v1a - k < v1 - k -> P v1a h1a) -> P v1 h1. 77 | 78 | Theorem strong_induction_sub : forall n t, P n t. 79 | Proof. 80 | elim/strong_induction_ltn. 81 | move => m IH' t. 82 | apply IH. 83 | move => v1a h1a Hlt Hlt'. 84 | apply: IH'. 85 | rewrite ltn_subRL in Hlt'. 86 | rewrite subnKC in Hlt' => //. 87 | rewrite leq_eqVlt. 88 | by apply/orP; right. 89 | Qed. 90 | 91 | End StrongInductionSub. -------------------------------------------------------------------------------- /casper/coq/theories/Validator.v: -------------------------------------------------------------------------------- 1 | Set Warnings "-parsing". 2 | From mathcomp.ssreflect 3 | Require Import all_ssreflect. 4 | Set Warnings "parsing". 5 | 6 | From mathcomp.finmap 7 | Require Import finmap. 8 | 9 | Set Implicit Arguments. 10 | Unset Strict Implicit. 11 | Unset Printing Implicit Defensive. 12 | 13 | Open Scope fmap_scope. 14 | 15 | (******************************************************************************) 16 | (* Validators and validator stake *) 17 | (******************************************************************************) 18 | 19 | (* We assume finite sets of validators *) 20 | Parameter Validator : finType. 21 | 22 | (* A finite map defining the stake (weight) of a validator *) 23 | (* Note: weight is a nat *) 24 | Parameter stake : {fmap Validator -> nat}. 25 | 26 | (* We assume the map stake is total *) 27 | Axiom st_fun : forall v : Validator, v \in stake. 28 | 29 | -------------------------------------------------------------------------------- /casper/coq/theories/Weight.v: -------------------------------------------------------------------------------- 1 | Set Warnings "-parsing". 2 | From mathcomp.ssreflect 3 | Require Import all_ssreflect. 4 | Set Warnings "parsing". 5 | 6 | From mathcomp.finmap 7 | Require Import finmap. 8 | 9 | From Casper 10 | Require Import NatExt SetTheoryProps. 11 | 12 | From Casper 13 | Require Import Validator. 14 | 15 | Set Implicit Arguments. 16 | Unset Strict Implicit. 17 | Unset Printing Implicit Defensive. 18 | 19 | Open Scope fmap_scope. 20 | 21 | (******************************************************************************) 22 | (* Definitions and properties of the function `wt' mapping validator sets to *) 23 | (* values corresponding to their weights. Many of these results follow from *) 24 | (* properties of \sum and set-theoretic properties of set operations. *) 25 | (******************************************************************************) 26 | 27 | (* A finite map defining the weight of a given set of validators as the sum of 28 | * stake values of its validators 29 | *) 30 | Definition wt (s:{set Validator}) : nat := 31 | (\sum_(v in s) stake.[st_fun v]). 32 | 33 | (* wt is always non-negative *) 34 | Lemma wt_nonneg s: wt s >= 0. 35 | Proof. by []. Qed. 36 | 37 | (* wt of the empty set is always 0 *) 38 | Lemma wt_set0 : wt set0 = 0. 39 | Proof. 40 | by rewrite /wt big_set0. 41 | Qed. 42 | 43 | (* set inclusion induces an order on weights *) 44 | Lemma wt_inc_leq (s1 s2:{set Validator}): 45 | s1 \subset s2 -> wt s1 <= wt s2. 46 | Proof. 47 | rewrite /wt. 48 | rewrite [\sum_(v in s2) _](big_setID s1) //=. 49 | move/setIidPr => ->. 50 | apply: leq_addr. 51 | Qed. 52 | 53 | (* equal sets have the same weight *) 54 | Lemma wt_eq (s1 s2:{set Validator}): 55 | s1 = s2 -> wt s1 = wt s2. 56 | Proof. 57 | move=> Heq. 58 | by rewrite /wt Heq. 59 | Qed. 60 | 61 | (* sets commute under wt *) 62 | Lemma wt_meetC (s1 s2:{set Validator}): 63 | wt (s1 :&: s2) = wt (s2 :&: s1). 64 | Proof. 65 | by [rewrite /wt setIC]. 66 | Qed. 67 | 68 | (* the weight of the union of two disjoint sets is exactly the sum of 69 | * their weights 70 | *) 71 | Lemma wt_join_disjoint (s1 s2:{set Validator}): 72 | [disjoint s1 & s2] -> wt (s1 :|: s2) = wt s1 + wt s2. 73 | Proof. 74 | move=> Hdis. 75 | rewrite /wt. 76 | rewrite (eq_bigl [predU s1 & s2]); last by move=> i; rewrite !inE. 77 | rewrite bigU //=. 78 | Qed. 79 | 80 | (* The weight of the difference of two sets *) 81 | Lemma wt_diff (s1 s2:{set Validator}): 82 | wt (s1 :\: s2) = wt s1 - wt (s1 :&: s2). 83 | Proof. 84 | rewrite -{2}(setID s1 s2). 85 | rewrite (wt_join_disjoint). 86 | rewrite addnC -addnBA; last by []. 87 | by rewrite sub_eq addn0. 88 | by apply: setID_disjoint. 89 | Qed. 90 | 91 | (* The weight of the union of two sets as the sum of weights of its partitions *) 92 | Lemma wt_join_partition (s1 s2:{set Validator}): 93 | wt (s1 :|: s2) = wt (s1 :\: s2) + wt (s2 :\: s1) + wt (s1 :&: s2). 94 | Proof. 95 | rewrite -!wt_join_disjoint. 96 | apply: wt_eq. apply: setU_par. 97 | apply: setDDI_disjoint. 98 | apply: setDD_disjoint. 99 | Qed. 100 | 101 | (* The weight of the union of two sets in terms of the weights of the sets *) 102 | Lemma wt_join (s1 s2:{set Validator}): 103 | wt (s1 :|: s2) = wt s1 + wt s2 - wt (s1 :&: s2). 104 | Proof. 105 | rewrite -{2}(setID s1 s2). 106 | rewrite -{4}(setID s2 s1). 107 | rewrite [wt (s1 :&: s2 :|: _)]wt_join_disjoint; last by apply setID_disjoint. 108 | rewrite [wt (s2 :&: s1 :|: _)]wt_join_disjoint; last by apply setID_disjoint. 109 | rewrite [s2 :&: s1]setIC. 110 | rewrite -addnA [_ + wt (s2 :\: s1)]addnC. 111 | rewrite [wt (s1 :\: s2) + (_+_)]addnA. 112 | rewrite -wt_join_partition. 113 | rewrite -addnBAC; last by []. 114 | by rewrite sub_eq add0n. 115 | Qed. 116 | 117 | (* Properties of the weight of the intersection of two sets *) 118 | Lemma wt_meet_leq1 (s1 s2:{set Validator}): 119 | wt (s1 :&: s2) <= wt s1. 120 | Proof. 121 | apply: wt_inc_leq; apply: subsetIl. 122 | Qed. 123 | 124 | Lemma wt_meet_leq2 (s1 s2:{set Validator}): 125 | wt (s1 :&: s2) <= wt s2. 126 | Proof. 127 | apply: wt_inc_leq; apply: subsetIr. 128 | Qed. 129 | 130 | Lemma wt_meet_leq (s1 s2:{set Validator}): 131 | wt (s1 :&: s2) <= wt s1 + wt s2. 132 | Proof. 133 | have H1:= (wt_meet_leq1 s1 s2). 134 | have H2:= (leq_addr (wt s2) (wt s1)). 135 | apply: (leq_trans H1 H2). 136 | Qed. 137 | 138 | -------------------------------------------------------------------------------- /casper/report/.gitignore: -------------------------------------------------------------------------------- 1 | *.aux 2 | *.bbl 3 | *.blg 4 | *.log 5 | *.out 6 | *.synctex.gz 7 | -------------------------------------------------------------------------------- /casper/report/comment.cut: -------------------------------------------------------------------------------- 1 | 2 | We thank Danny Ryan, Carl Beekhuizen, Martin Lundfall, Yan Zhang and Aditya Asgaonkar from the Ethereum Foundation for their valuable feedback and comments. This work was funded by the Ethereum Foundation. 3 | 4 | % %% contents suppressed with 'anonymous' 5 | % %% Commands \grantsponsor{}{}{} and 6 | % %% \grantnum[]{}{} should be used to 7 | % %% acknowledge financial support and will be used by metadata 8 | % %% extraction tools. 9 | % This material is based upon work supported by the 10 | % \grantsponsor{GS100000001}{National Science 11 | % Foundation}{http://dx.doi.org/10.13039/100000001} under Grant 12 | % No.~\grantnum{GS100000001}{nnnnnnn} and Grant 13 | % No.~\grantnum{GS100000001}{mmmmmmm}. Any opinions, findings, and 14 | % conclusions or recommendations expressed in this material are those 15 | % of the author and do not necessarily reflect the views of the 16 | % National Science Foundation. 17 | -------------------------------------------------------------------------------- /casper/report/lstcoq.sty: -------------------------------------------------------------------------------- 1 | % colors 2 | \definecolor{shadecolor}{gray}{1.00} 3 | \definecolor{darkgray}{gray}{0.30} 4 | \definecolor{violet}{rgb}{0.56, 0.0, 1.0} 5 | \definecolor{forestgreen}{rgb}{0.13, 0.55, 0.13} 6 | 7 | % Col language definition 8 | \lstdefinelanguage{Coq} { 9 | mathescape=true, 10 | texcl=false, 11 | morekeywords=[1]{ 12 | Add, 13 | All, 14 | Arguments, 15 | Axiom, 16 | Bind, 17 | Canonical, 18 | Check, 19 | Close, 20 | CoFixpoint, 21 | CoInductive, 22 | Coercion, 23 | Contextual, 24 | Corollary, 25 | Defined, 26 | Definition, 27 | Delimit, 28 | End, 29 | Example, 30 | Export, 31 | Fact, 32 | Fixpoint, 33 | Goal, 34 | Graph, 35 | Hint, 36 | Hypotheses, 37 | Hypothesis, 38 | Implicit, 39 | Implicits, 40 | Import, 41 | Inductive, 42 | Lemma, 43 | Let, 44 | Local, 45 | Locate, 46 | Ltac, 47 | Maximal 48 | Module, 49 | Morphism, 50 | Next, 51 | Notation, 52 | Obligation, 53 | Open, 54 | Parameter, 55 | Parameters, 56 | Prenex, 57 | Print, 58 | Printing, 59 | Program, 60 | Projections, 61 | Proof, 62 | Proposition, 63 | Qed, 64 | Record, 65 | Relation, 66 | Remark, 67 | Require, 68 | Reserved, 69 | Resolve, 70 | Rewrite, 71 | Save, 72 | Scope, 73 | Search, 74 | Section, 75 | Show, 76 | Strict, 77 | Structure, 78 | Tactic, 79 | Theorem, 80 | Unset, 81 | Variable, 82 | Variables, 83 | View, 84 | inside, 85 | outside 86 | }, 87 | morekeywords=[2]{ 88 | as, 89 | cofix, 90 | else, 91 | end, 92 | exists, 93 | exists2, 94 | fix, 95 | for, 96 | forall, 97 | fun, 98 | if, 99 | % in, 100 | is, 101 | let, 102 | match, 103 | nosimpl, 104 | of, 105 | return, 106 | struct, 107 | then, 108 | vfun, 109 | with 110 | }, 111 | morekeywords=[3]{Type, Prop, Set, True, False}, 112 | morekeywords=[4]{ 113 | after, 114 | apply, 115 | assert, 116 | auto, 117 | bool_congr, 118 | case, 119 | change, 120 | clear, 121 | compute, 122 | congr, 123 | cut, 124 | cutrewrite, 125 | destruct, 126 | elim, 127 | field, 128 | fold, 129 | generalize, 130 | have, 131 | heval, 132 | hnf, 133 | induction, 134 | injection, 135 | intro, 136 | intros, 137 | intuition, 138 | inversion, 139 | left, 140 | loss, 141 | move, 142 | nat_congr, 143 | nat_norm, 144 | pattern, 145 | pose, 146 | refine, 147 | rename, 148 | replace, 149 | revert, 150 | rewrite, 151 | right, 152 | ring, 153 | % set, 154 | simpl, 155 | split, 156 | suff, 157 | suffices, 158 | symmetry, 159 | transitivity, 160 | trivial, 161 | unfold, 162 | unlock, 163 | using, 164 | without, 165 | wlog, 166 | autorewrite 167 | }, 168 | morekeywords=[5]{ 169 | assumption, 170 | by, 171 | contradiction, 172 | done, 173 | exact, 174 | lia, 175 | gappa, 176 | omega, 177 | reflexivity, 178 | romega, 179 | solve, 180 | tauto, 181 | discriminate, 182 | unsat 183 | }, 184 | morecomment=[s]{(*}{*)}, 185 | morekeywords=[6]{do, first, try, idtac, repeat}, 186 | showstringspaces=false, 187 | morestring=[b]", 188 | % Size of tabulations 189 | tabsize=3, 190 | % Enables ASCII chars 128 to 255 191 | extendedchars=true, 192 | % Case sensitivity 193 | sensitive=true, 194 | % Automatic breaking of long lines 195 | breaklines=false, 196 | % Default style fors listings 197 | %basicstyle=\scriptsize\ttfamily, 198 | basicstyle=\footnotesize\ttfamily, 199 | % Position of captions is bottom 200 | captionpos=b, 201 | % Full flexible columns 202 | columns=[l]fullflexible, 203 | % Style for (listings') identifiers 204 | identifierstyle={\color{black}}, 205 | % Style for declaration keywords 206 | keywordstyle=[1]{\color{violet}}, 207 | % Style for gallina keywords 208 | keywordstyle=[2]{\color{forestgreen}}, 209 | % Style for sorts keywords 210 | keywordstyle=[3]{\color{forestgreen}}, 211 | % Style for tactics keywords 212 | keywordstyle=[4]{\color{blue}}, 213 | % Style for terminators keywords 214 | keywordstyle=[5]{\color{red}}, 215 | %Style for iterators 216 | keywordstyle=[6]{\color{violet}}, 217 | % Style for strings 218 | stringstyle=, 219 | % Style for comments 220 | commentstyle=\it\ttfamily\color{brown}, 221 | % Style for lines numbering 222 | numberstyle=\tiny, 223 | literate={\\/}{{$\lor~$}}1 224 | {/\\}{{$\land~$}}1 225 | {<>}{{$\neq~$}}1 226 | {<->}{{$\leftrightarrow~$}}1 227 | {:->}{{$\mapsto~$\!}}1 228 | {\\->}{{$\mapsto~$\!}}1 229 | {<--}{{$\asgn~$}}1 230 | {\\in}{{$\in~$}}1 231 | {\\notin}{{$\notin~$}}1 232 | {++}{{$+\!+\!~$}}1 233 | {->}{{$\to~$}}1 234 | {forall}{{$\forall~$}}1 235 | {exists}{{$\exists~$}}1 236 | {=>}{{$\Rightarrow~$}}1 237 | {\\~}{{$\lnot\;$}}1 238 | % {\\+}{{$\!\join\!~$}}1 239 | } 240 | 241 | \lstdefinestyle{Coq}{language=Coq} 242 | \lstset{language=Coq} 243 | -------------------------------------------------------------------------------- /casper/report/report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/beacon-chain-verification/7563b9b338eef019a11edadb8d8e520775a165bf/casper/report/report.pdf -------------------------------------------------------------------------------- /dynamic/Makefile: -------------------------------------------------------------------------------- 1 | # Settings 2 | # -------- 3 | 4 | BUILD_DIR := .build 5 | DEFN_DIR := $(BUILD_DIR)/defn 6 | 7 | DEPS_DIR := ../deps 8 | PANDOC_TANGLE_SUBMODULE := $(DEPS_DIR)/pandoc-tangle 9 | 10 | K_SUBMODULE := $(abspath $(DEPS_DIR)/k) 11 | 12 | ifneq (,$(wildcard $(K_SUBMODULE)/k-distribution/target/release/k/bin/*)) 13 | K_RELEASE ?= $(abspath $(K_SUBMODULE)/k-distribution/target/release/k) 14 | else 15 | K_RELEASE ?= $(dir $(shell which kompile)).. 16 | endif 17 | K_BIN := $(K_RELEASE)/bin 18 | K_LIB := $(K_RELEASE)/lib/kframework 19 | export K_RELEASE 20 | 21 | PATH := $(K_BIN):$(PATH) 22 | export PATH 23 | 24 | PYTHONPATH := $(K_LIB) 25 | export PYTHONPATH 26 | 27 | TANGLER := $(PANDOC_TANGLE_SUBMODULE)/tangle.lua 28 | LUA_PATH := $(PANDOC_TANGLE_SUBMODULE)/?.lua;; 29 | export TANGLER 30 | export LUA_PATH 31 | 32 | .SECONDARY: 33 | 34 | .PHONY: all clean clean-submodules 35 | 36 | all: build 37 | 38 | clean: 39 | rm -rf $(BUILD_DIR) 40 | rm -f process-justification-finalization-spec.k process-justification-finalization-lemma.k 41 | 42 | # Dependencies 43 | # ------------ 44 | 45 | K_JAR := $(K_SUBMODULE)/k-distribution/target/release/k/lib/java/kernel-1.0-SNAPSHOT.jar 46 | 47 | .PHONY: deps deps-k 48 | 49 | deps: deps-k 50 | deps-k: $(K_JAR) 51 | 52 | ifneq ($(RELEASE),) 53 | K_BUILD_TYPE := FastBuild 54 | else 55 | K_BUILD_TYPE := Debug 56 | endif 57 | 58 | $(K_JAR): 59 | cd $(K_SUBMODULE) && mvn package -DskipTests -Dproject.build.type=$(K_BUILD_TYPE) 60 | 61 | # Building 62 | # -------- 63 | 64 | MAIN_MODULE := DYNAMIC-ABSTRACT-BEACON-CHAIN 65 | SYNTAX_MODULE := $(MAIN_MODULE)-SYNTAX 66 | MAIN_DEFN_FILE := dynamic-abstract-beacon-chain 67 | 68 | SOURCE_MD_FILES := dynamic-abstract-beacon-chain \ 69 | dynamic-abstract-beacon-chain-syntax 70 | SOURCE_K_FILES := verification 71 | EXTRA_SOURCE_FILES := 72 | 73 | ALL_FILES := $(patsubst %, %.md, $(SOURCE_MD_FILES)) $(patsubst %, %.k, $(SOURCE_K_FILES)) $(EXTRA_SOURCE_FILES) 74 | 75 | tangle_concrete := k & (concrete | ! symbolic) 76 | tangle_symbolic := k & (symbolic | ! concrete) 77 | 78 | .PHONY: build build-concrete build-symbolic 79 | 80 | build: build-concrete build-symbolic 81 | 82 | KOMPILE_OPTS += --emit-json 83 | 84 | ifneq (,$(RELEASE)) 85 | KOMPILE_OPTS += -O3 86 | endif 87 | 88 | KOMPILE_CONCRETE_OPTS := 89 | 90 | KOMPILE_CONCRETE := kompile --debug --backend java --md-selector "$(tangle_concrete)" \ 91 | $(KOMPILE_OPTS) $(KOMPILE_CONCRETE_OPTS) 92 | 93 | KOMPILE_SYMBOLIC_OPTS := 94 | 95 | KOMPILE_SYMBOLIC := kompile --debug --backend java --md-selector "$(tangle_symbolic)" \ 96 | $(KOMPILE_OPTS) $(KOMPILE_SYMBOLIC_OPTS) 97 | 98 | ### Concrete Backend 99 | 100 | concrete_dir := $(DEFN_DIR)/concrete 101 | concrete_files := $(ALL_FILES) 102 | concrete_main_module := VERIFICATION 103 | concrete_syntax_module := DYNAMIC-ABSTRACT-BEACON-CHAIN-SYNTAX 104 | concrete_main_file := verification.k 105 | concrete_kompiled := $(concrete_dir)/verification-kompiled/timestamp 106 | 107 | build-concrete: $(concrete_kompiled) 108 | 109 | $(concrete_kompiled): $(concrete_files) 110 | $(KOMPILE_CONCRETE) $(concrete_main_file) \ 111 | --main-module $(concrete_main_module) \ 112 | --syntax-module $(concrete_syntax_module) \ 113 | --directory $(concrete_dir) \ 114 | -I $(CURDIR) 115 | 116 | ### Symbolic Backend 117 | 118 | 119 | symbolic_dir := $(DEFN_DIR)/symbolic 120 | symbolic_files := $(ALL_FILES) 121 | symbolic_main_module := VERIFICATION 122 | symbolic_syntax_module := DYNAMIC-ABSTRACT-BEACON-CHAIN-SYNTAX 123 | symbolic_main_file := verification.k 124 | symbolic_kompiled := $(symbolic_dir)/verification-kompiled/timestamp 125 | 126 | build-symbolic: $(symbolic_kompiled) 127 | 128 | $(symbolic_kompiled): $(symbolic_files) 129 | $(KOMPILE_SYMBOLIC) $(symbolic_main_file) \ 130 | --main-module $(symbolic_main_module) \ 131 | --syntax-module $(symbolic_syntax_module) \ 132 | --directory $(symbolic_dir) \ 133 | -I $(CURDIR) 134 | 135 | # Test 136 | # ---- 137 | 138 | CHECK := git --no-pager diff --no-index --ignore-all-space -R 139 | 140 | .PHONY: test test-concrete test-prove 141 | 142 | test: test-concrete test-prove 143 | 144 | concrete_tests := $(wildcard tests/concrete/*.abc) 145 | 146 | tests/concrete/%.abc.run: tests/concrete/%.abc $(concrete_kompiled) 147 | krun -d $(concrete_dir) $< > $<.out 148 | $(CHECK) $<.out $<.expected 149 | rm $<.out 150 | 151 | prove_tests := $(wildcard *-spec.k) 152 | 153 | %-spec.k.prove: %-spec.k $(symbolic_kompiled) process-justification-finalization-spec.k process-justification-finalization-lemma.k 154 | kprove -d $(symbolic_dir) -m VERIFICATION -w none $< > $<.out 155 | $(CHECK) $<.out tests/success.out 156 | rm $<.out 157 | 158 | test-concrete: $(concrete_tests:=.run) 159 | test-prove: $(prove_tests:=.prove) 160 | 161 | process-justification-finalization-spec.k: process-justification-finalization-spec.md $(TANGLER) 162 | pandoc --from markdown --to "$(TANGLER)" --metadata=code:".k:not(.lemma),.proof" $< > $@ 163 | 164 | process-justification-finalization-lemma.k: process-justification-finalization-spec.md $(TANGLER) 165 | pandoc --from markdown --to "$(TANGLER)" --metadata=code:".k:not(.proof),.lemma" $< > $@ 166 | -------------------------------------------------------------------------------- /dynamic/process-attestation-spec.k: -------------------------------------------------------------------------------- 1 | require "verification.k" 2 | 3 | module PROCESS-ATTESTATION-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | processAttestations(As) => .K ... 10 | Slot 11 | 12 | 13 | Slot 14 | v(VM, _) 15 | 16 | ?Epoch -Int 1 |-> (PrevAs1:Attestations => ?PrevAs2) 17 | ?Epoch |-> (CurrAs1:Attestations => ?CurrAs2) 18 | ... 19 | 20 | ... 21 | 22 | 23 | Slot -Int 1 24 | v(ORIG_VM, ORIG_VIDs) 25 | ... 26 | 27 | ... 28 | 29 | LastJustifiedEpoch 30 | BlockMap 31 | ... 32 | 33 | requires true 34 | // types 35 | andBool Slot >=Int 1 36 | // let-bindings 37 | andBool ?Epoch ==Int epochOf(Slot) 38 | // pre-conditions 39 | andBool ?Epoch >=Int 1 40 | andBool isValidAttestationListPartial(As, Slot, LastJustifiedEpoch, BlockMap) 41 | andBool forall(x, getValidatorsA(As), VM.slashed[x]b ==K false) 42 | // invariants 43 | ensures true 44 | // post-conditions 45 | andBool ?PrevAs2 ==K revA(getAttestations(As, ?Epoch -Int 1)) ++A PrevAs1 46 | andBool ?CurrAs2 ==K revA(getAttestations(As, ?Epoch )) ++A CurrAs1 47 | 48 | rule 49 | 50 | processAttestationsAux(L_As, As) => .K ... 51 | Slot 52 | 53 | 54 | Slot 55 | v(VM, _) 56 | 57 | ?Epoch -Int 1 |-> (getAttestations(L_As, ?Epoch -Int 1) ++A PrevAs0:Attestations => ?PrevAs2) 58 | ?Epoch |-> (getAttestations(L_As, ?Epoch ) ++A CurrAs0:Attestations => ?CurrAs2) 59 | ... 60 | 61 | ... 62 | 63 | 64 | Slot -Int 1 65 | v(ORIG_VM, ORIG_VIDs) 66 | ... 67 | 68 | ... 69 | 70 | LastJustifiedEpoch 71 | BlockMap 72 | ... 73 | 74 | requires true 75 | // types 76 | andBool Slot >=Int 1 77 | // let-bindings 78 | andBool ?Epoch ==Int epochOf(Slot) 79 | andBool ?PrevAs1 ==K getAttestations(L_As, ?Epoch -Int 1) ++A PrevAs0 80 | andBool ?CurrAs1 ==K getAttestations(L_As, ?Epoch ) ++A CurrAs0 81 | // pre-conditions 82 | andBool ?Epoch >=Int 1 83 | andBool isValidAttestationListPartial(As, Slot, LastJustifiedEpoch, BlockMap) 84 | andBool forall(x, getValidatorsA(As), VM.slashed[x]b ==K false) 85 | // invariants 86 | ensures true 87 | // post-conditions 88 | andBool ?PrevAs2 ==K revA(getAttestations(As, ?Epoch -Int 1)) ++A ?PrevAs1 89 | andBool ?CurrAs2 ==K revA(getAttestations(As, ?Epoch )) ++A ?CurrAs1 90 | [matching(concatA)] 91 | 92 | endmodule 93 | -------------------------------------------------------------------------------- /dynamic/process-block-spec.k: -------------------------------------------------------------------------------- 1 | require "verification.k" 2 | 3 | require "process-slashing-spec.k" 4 | require "process-attestation-spec.k" 5 | require "process-deposit-spec.k" 6 | require "process-validator-exit-spec.k" 7 | 8 | module PROCESS-BLOCK-SPEC 9 | 10 | imports VERIFICATION 11 | 12 | imports PROCESS-SLASHING-SPEC 13 | imports PROCESS-ATTESTATION-SPEC 14 | imports PROCESS-DEPOSIT-SPEC 15 | imports PROCESS-VALIDATOR-EXIT-SPEC 16 | 17 | rule 18 | 19 | processBlock(#Block((Slot, ID), Parent, Ss, As, Ds, VEs)) => .K ... 20 | Slot 21 | 22 | 23 | Slot 24 | v(m(SM1 => ?SM2, BM1 => ?BM2, EBM1 => ?EBM2, AEM1 => ?AEM2, AM1 => ?AM2, EM1 => ?EM2, WM1 => ?WM2), VIDs1 => ?VIDs2) 25 | 26 | ?Epoch -Int 1 |-> (PrevAs1:Attestations => ?PrevAs2) 27 | ?Epoch |-> (CurrAs1:Attestations => ?CurrAs2) 28 | ... 29 | 30 | _ => ?_ 31 | ... 32 | 33 | 34 | Slot -Int 1 35 | v(m(SM1, BM1, EBM1, AEM1, AM1, EM1, WM1), VIDs1) 36 | ... 37 | 38 | ... 39 | 40 | LastJustifiedEpoch 41 | BlockMap => BlockMap [ Slot <- ID ]i 42 | Bs => Bs [ ID <- #Block((Slot, ID), Parent, Ss, As, Ds, VEs) ]k 43 | ... 44 | 45 | requires true 46 | 47 | // types 48 | andBool Slot >=Int 1 49 | 50 | // let-bindings 51 | //// processVoluntaryExits 52 | andBool ?Epoch ==Int epochOf(Slot) 53 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(VIDs1, EM1), delayedActivationExitEpoch(?Epoch)) 54 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(VIDs1, AM1, EM1, ?Epoch))) 55 | 56 | //////////////////// 57 | // pre-conditions 58 | //////////////////// 59 | 60 | andBool disjoint(getValidatorsA(As), getValidatorsS(Ss)) // no attestation from validators that will be slashed in this block 61 | andBool disjoint(getValidatorsE(VEs), getValidatorsS(Ss)) // no voluntary exits from validators that will be slashed in this block 62 | andBool ?LastExitEpoch +Int sizeS(Ss) +Int sizeE(VEs) +Int MIN_VALIDATOR_WITHDRAWABILITY_DELAY =Int 0) 65 | andBool forall(x, VIDs1, EBM1[x]i >=Int 0) 66 | andBool forall(x, VIDs1, AEM1[x]i >=Int 0) 67 | andBool forall(x, VIDs1, AM1[x]i >=Int 0) 68 | andBool forall(x, VIDs1, EM1[x]i >=Int 0) 69 | andBool forall(x, VIDs1, WM1[x]i >=Int 0) 70 | 71 | //// processSlashings 72 | 73 | andBool forallS(x, Ss, isSlashableAttestation(x.attestation_1, x.attestation_2) andBool x.attestation_1.attester ==Int x.attestation_2.attester) 74 | andBool forall(x, getValidatorsS(Ss), SM1[x]b ==K false) 75 | andBool forall(x, getValidatorsS(Ss), AM1[x]i <=Int ?Epoch) 76 | andBool forall(x, getValidatorsS(Ss), WM1[x]i >Int ?Epoch) 77 | andBool distinct(getValidatorsS(Ss)) 78 | andBool forall(x, getValidatorsS(Ss), x in VIDs1) 79 | 80 | //// processAttestations 81 | 82 | andBool ?Epoch >=Int 1 83 | andBool isValidAttestationListPartial(As, Slot, LastJustifiedEpoch, BlockMap [ Slot <- ID ]i) 84 | andBool forall(x, getValidatorsA(As), SM1[x]b ==K false) 85 | andBool forall(x, getValidatorsA(As), x in VIDs1) 86 | 87 | //// processDeposits 88 | 89 | andBool distinct(VIDs1) 90 | andBool isValidDeposits(Ds) 91 | 92 | //// processVoluntaryExits 93 | 94 | andBool forallE(x, VEs, isValidVoluntaryExit(x, AM1, EM1, ?Epoch)) 95 | andBool distinct(getValidatorsE(VEs)) 96 | andBool forall(x, getValidatorsE(VEs), x in VIDs1) 97 | 98 | ensures true 99 | 100 | //////////////////// 101 | // post-conditions 102 | //////////////////// 103 | 104 | //// processSlashings 105 | 106 | //// processAttestations 107 | 108 | andBool ?PrevAs2 ==K revA(getAttestations(As, ?Epoch -Int 1)) ++A PrevAs1 109 | andBool ?CurrAs2 ==K revA(getAttestations(As, ?Epoch )) ++A CurrAs1 110 | 111 | //// processDeposits 112 | 113 | andBool distinct(?VIDs2) 114 | andBool ?VIDs2 ==K unique(rev(getValidatorsD(Ds)) ++ VIDs1) 115 | 116 | //// processVoluntaryExits 117 | 118 | //// summary 119 | 120 | // existing validators 121 | andBool forall(x, VIDs1, #if x in getValidatorsS(Ss) #then ?SM2[x]b ==K true #else ?SM2[x]b ==K SM1[x]b #fi) 122 | andBool forall(x, VIDs1, #if x in getValidatorsS(Ss) orBool x in getValidatorsD(Ds) #then ?BM2[x]i >=Int 0 #else ?BM2[x]i ==Int BM1[x]i #fi) 123 | andBool forall(x, VIDs1, ?EBM2[x]i ==Int EBM1[x]i) 124 | andBool forall(x, VIDs1, ?AEM2[x]i ==Int AEM1[x]i) 125 | andBool forall(x, VIDs1, ?AM2[x]i ==Int AM1[x]i) 126 | andBool forall(x, VIDs1, #if (x in getValidatorsS(Ss) andBool EM1[x]i ==Int FAR_FUTURE_EPOCH) orBool x in getValidatorsE(VEs) 127 | #then ?EM2[x]i >=Int delayedActivationExitEpoch(?Epoch) andBool ?EM2[x]i =Int ?Epoch +Int EPOCHS_PER_SLASHINGS_VECTOR // TODO: andBool ?WM2[x]i =Int delayedActivationExitEpoch(?Epoch) +Int MIN_VALIDATOR_WITHDRAWABILITY_DELAY andBool ?WM2[x]i =Int 0)) 137 | andBool forall(x, ?VIDs2, implies(notBool x in VIDs1, ?EBM2[x]i >=Int 0 andBool ?EBM2[x]i <=Int MAX_EFFECTIVE_BALANCE)) 138 | andBool forall(x, ?VIDs2, implies(notBool x in VIDs1, ?AEM2[x]i ==Int FAR_FUTURE_EPOCH)) 139 | andBool forall(x, ?VIDs2, implies(notBool x in VIDs1, ?AM2[x]i ==Int FAR_FUTURE_EPOCH)) 140 | andBool forall(x, ?VIDs2, implies(notBool x in VIDs1, ?EM2[x]i ==Int FAR_FUTURE_EPOCH)) 141 | andBool forall(x, ?VIDs2, implies(notBool x in VIDs1, ?WM2[x]i ==Int FAR_FUTURE_EPOCH)) 142 | 143 | // no negative values 144 | andBool forall(x, ?VIDs2, ?BM2[x]i >=Int 0) 145 | andBool forall(x, ?VIDs2, ?EBM2[x]i >=Int 0) 146 | andBool forall(x, ?VIDs2, ?AEM2[x]i >=Int 0) 147 | andBool forall(x, ?VIDs2, ?AM2[x]i >=Int 0) 148 | andBool forall(x, ?VIDs2, ?EM2[x]i >=Int 0) 149 | andBool forall(x, ?VIDs2, ?WM2[x]i >=Int 0) 150 | 151 | /* TODO: 152 | - specify update 153 | - base case: when ?Epoch ==Int 0 154 | */ 155 | 156 | endmodule 157 | -------------------------------------------------------------------------------- /dynamic/process-rewards-penalties-spec.k: -------------------------------------------------------------------------------- 1 | require "verification.k" 2 | 3 | module PROCESS-REWARDS-PENALTIES-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | processRewardsPenaltiesAux(?Epoch) => .K ... 10 | Slot 11 | 12 | 13 | Slot 14 | v(m(SM, BM1 => ?BM2, EBM, AEM, AM, EM, WM), VIDs) 15 | 16 | ?Epoch |-> Attestations:Attestations 17 | ... 18 | 19 | ... 20 | 21 | ... 22 | 23 | ( epochOf(Slot) , LastFinalizedEpoch ) _ 24 | ... 25 | 26 | requires true 27 | // types 28 | andBool Slot >=Int 0 29 | andBool ?Epoch >=Int 0 30 | andBool ?FinalityDelay >=Int 0 31 | // let-bindings 32 | andBool ?Epoch ==Int epochOf(Slot) -Int 2 33 | andBool ?FinalityDelay ==Int ?Epoch -Int LastFinalizedEpoch 34 | andBool ?SourceAttestations ==K filterNotSlashed(SM, Attestations) 35 | andBool ?TotalActiveBalance ==Int lift(totalBalance(EBM, activeValidators(VIDs, AM, EM, ?Epoch))) 36 | // pre-conditions 37 | andBool forall(x, VIDs, BM1[x]i >=Int 0) 38 | andBool forall(x, VIDs, EBM[x]i >=Int 0) 39 | andBool distinct(VIDs) 40 | andBool forall(x, VIDs, implies(x inA ?SourceAttestations, minByInclusionDelay(x, ?SourceAttestations).inclusion_delay >=Int 1)) 41 | andBool forall(x, VIDs, implies(x inA ?SourceAttestations, minByInclusionDelay(x, ?SourceAttestations).proposer in VIDs)) 42 | andBool isValidAttestations(Attestations, VIDs, AM, EM, ?Epoch) 43 | // invariants 44 | ensures true 45 | // post-conditions 46 | andBool forall(x, VIDs, ?BM2[x]i <=Int BM1[x]i +Int (4 *Int getBaseReward(EBM[x]i, ?TotalActiveBalance))) 47 | andBool forall(x, VIDs, ?BM2[x]i >=Int BM1[x]i -Int (7 *Int getBaseReward(EBM[x]i, ?TotalActiveBalance)) -Int getInactivityPenalty(EBM[x]i, ?FinalityDelay)) 48 | andBool forall(x, VIDs, ?BM2[x]i >=Int 0) 49 | 50 | rule 51 | 52 | processRewardsPenaltiesAux3(L_VIDs, R_VIDs, m(SM, BM0, EBM, AEM, AM, EM, WM), ?Epoch, ?FinalityDelay, 53 | ?SourceAttestations, ?TargetAttestations, ?HeadAttestations, 54 | ?SourceAttestingBalance, ?TargetAttestingBalance, ?HeadAttestingBalance, ?TotalActiveBalance) => .K ... 55 | Slot 56 | 57 | 58 | Slot 59 | v(m(SM, BM1 => ?BM2, EBM, AEM, AM, EM, WM), VIDs) 60 | 61 | ?Epoch |-> Attestations:Attestations 62 | ... 63 | 64 | ... 65 | 66 | ... 67 | 68 | BlockMap 69 | ( epochOf(Slot) , LastFinalizedEpoch ) _ 70 | ... 71 | 72 | requires true 73 | // types 74 | andBool Slot >=Int 0 75 | andBool ?Epoch >=Int 0 76 | andBool ?FinalityDelay >=Int 0 77 | // let-bindings 78 | andBool ?Epoch ==Int epochOf(Slot) -Int 2 79 | andBool ?FinalityDelay ==Int ?Epoch -Int LastFinalizedEpoch 80 | andBool ?SourceAttestations ==K filterNotSlashed(SM, Attestations) 81 | andBool ?TargetAttestations ==K filterByTarget(BlockMap[firstSlotOf(?Epoch)]i, ?SourceAttestations) 82 | andBool ?HeadAttestations ==K filterByHead(BlockMap, ?TargetAttestations) 83 | andBool ?SourceAttestingBalance ==Int lift(totalBalance(EBM, getUniqueValidators(?SourceAttestations))) 84 | andBool ?TargetAttestingBalance ==Int lift(totalBalance(EBM, getUniqueValidators(?TargetAttestations))) 85 | andBool ?HeadAttestingBalance ==Int lift(totalBalance(EBM, getUniqueValidators(?HeadAttestations))) 86 | andBool ?TotalActiveBalance ==Int lift(totalBalance(EBM, activeValidators(VIDs, AM, EM, ?Epoch))) 87 | // pre-conditions 88 | andBool forall(x, R_VIDs, BM0[x]i >=Int 0) 89 | andBool forall(x, R_VIDs, EBM[x]i >=Int 0) 90 | andBool distinct(R_VIDs) 91 | andBool forall(x, R_VIDs, implies(x inA ?SourceAttestations, minByInclusionDelay(x, ?SourceAttestations).inclusion_delay >=Int 1)) 92 | andBool forall(x, R_VIDs, implies(x inA ?SourceAttestations, minByInclusionDelay(x, ?SourceAttestations).proposer in VIDs)) 93 | andBool ?SourceAttestingBalance <=Int ?TotalActiveBalance 94 | andBool ?TargetAttestingBalance <=Int ?TotalActiveBalance 95 | andBool ?HeadAttestingBalance <=Int ?TotalActiveBalance 96 | // invariants 97 | andBool disjoint(L_VIDs, R_VIDs) 98 | andBool forall(x, R_VIDs, x in VIDs) 99 | andBool forall(x, R_VIDs, BM1[x]i ==Int BM0[x]i) 100 | andBool forall(x, rev(L_VIDs), BM1[x]i <=Int BM0[x]i +Int (4 *Int getBaseReward(EBM[x]i, ?TotalActiveBalance))) 101 | andBool forall(x, rev(L_VIDs), BM1[x]i >=Int BM0[x]i -Int (7 *Int getBaseReward(EBM[x]i, ?TotalActiveBalance)) -Int getInactivityPenalty(EBM[x]i, ?FinalityDelay)) 102 | andBool forall(x, rev(L_VIDs), BM1[x]i >=Int 0) 103 | ensures true 104 | // post-conditions 105 | andBool forall(x, rev(L_VIDs) ++ R_VIDs, ?BM2[x]i <=Int BM0[x]i +Int (4 *Int getBaseReward(EBM[x]i, ?TotalActiveBalance))) 106 | andBool forall(x, rev(L_VIDs) ++ R_VIDs, ?BM2[x]i >=Int BM0[x]i -Int (7 *Int getBaseReward(EBM[x]i, ?TotalActiveBalance)) -Int getInactivityPenalty(EBM[x]i, ?FinalityDelay)) 107 | andBool forall(x, rev(L_VIDs) ++ R_VIDs, ?BM2[x]i >=Int 0) 108 | 109 | endmodule 110 | -------------------------------------------------------------------------------- /dynamic/process-slots-spec.k: -------------------------------------------------------------------------------- 1 | require "verification.k" 2 | 3 | module PROCESS-SLOTS-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // Slot < TargetSlot - 1 8 | rule 9 | 10 | processSlots(TargetSlot) 11 | Slot => Slot +Int 1 12 | 13 | 14 | Slot 15 | Vs 16 | SB 17 | AttestedMap 18 | JustifiedMap 19 | FinalizedMap 20 | 21 | ( 22 | .Bag 23 | => 24 | 25 | Slot +Int 1 26 | Vs 27 | SB 28 | AttestedMap 29 | JustifiedMap 30 | FinalizedMap 31 | 32 | ) 33 | ... 34 | 35 | B => B [ Slot +Int 1 <- B[Slot]i ]i 36 | ... 37 | 38 | requires true 39 | andBool Slot +Int 1 =Int 0 43 | ensures true 44 | 45 | // Slot == TargetSlot - 1 46 | rule 47 | 48 | processSlots(TargetSlot) => . 49 | Slot => TargetSlot 50 | 51 | 52 | Slot 53 | Vs 54 | SB 55 | AttestedMap 56 | JustifiedMap 57 | FinalizedMap 58 | 59 | ( 60 | .Bag 61 | => 62 | 63 | TargetSlot 64 | Vs 65 | SB 66 | AttestedMap 67 | JustifiedMap 68 | FinalizedMap 69 | 70 | ) 71 | ... 72 | 73 | B => B [ TargetSlot <- B[Slot]i ]i 74 | ... 75 | 76 | requires true 77 | andBool Slot +Int 1 ==Int TargetSlot 78 | andBool isFirstSlotOfEpoch(Slot +Int 1) ==K false 79 | // types 80 | andBool Slot >=Int 0 81 | ensures true 82 | 83 | // Slot == TargetSlot 84 | rule 85 | 86 | processSlots(TargetSlot) => . 87 | Slot 88 | 89 | 90 | Slot 91 | Vs 92 | SB 93 | AttestedMap 94 | JustifiedMap 95 | FinalizedMap 96 | 97 | ... 98 | 99 | ... 100 | 101 | requires true 102 | andBool Slot ==Int TargetSlot 103 | // types 104 | andBool Slot >=Int 0 105 | ensures true 106 | 107 | endmodule 108 | -------------------------------------------------------------------------------- /dynamic/process-validator-activation-eligibility-spec.k: -------------------------------------------------------------------------------- 1 | require "verification.k" 2 | 3 | module PROCESS-VALIDATOR-ACTIVATION-ELIGIBILITY-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | updateActivationEligibilities(VIDs) => .K ... 10 | Slot 11 | 12 | 13 | Slot 14 | v(m(SM, BM, EBM, AEM1 => ?AEM2, AM, EM, WM), VIDs) 15 | ... 16 | 17 | ... 18 | 19 | ( epochOf(Slot) , FinalizedEpoch ) _ 20 | ... 21 | 22 | requires true 23 | // types 24 | andBool Slot >=Int 0 25 | // let-bindings 26 | andBool ?Epoch ==Int epochOf(Slot) 27 | // pre-conditions 28 | andBool distinct(VIDs) 29 | andBool FinalizedEpoch 40 | updateActivationEligibilitiesAux(L_VIDs, R_VIDs, m(SM, BM, EBM, AEM0, AM, EM, WM)) => .K ... 41 | Slot 42 | 43 | 44 | Slot 45 | v(m(SM, BM, EBM, AEM1 => ?AEM2, AM, EM, WM), VIDs) 46 | ... 47 | 48 | ... 49 | 50 | ( epochOf(Slot) , FinalizedEpoch ) _ 51 | ... 52 | 53 | requires true 54 | // types 55 | andBool Slot >=Int 0 56 | // let-bindings 57 | andBool ?Epoch ==Int epochOf(Slot) 58 | // pre-conditions 59 | andBool distinct(R_VIDs) 60 | andBool FinalizedEpoch 9 | processValidatorActivation() => .K ... 10 | Slot 11 | 12 | 13 | Slot 14 | v(m(SM, BM, EBM, AEM, AM1 => ?AM2, EM, WM), VIDs) 15 | ... 16 | 17 | ... 18 | 19 | ( epochOf(Slot) , FinalizedEpoch ) _ 20 | ... 21 | 22 | requires true 23 | // types 24 | andBool Slot >=Int 0 25 | // let-bindings 26 | andBool ?Epoch ==Int epochOf(Slot) -Int 1 27 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(VIDs, AM1, EM, ?Epoch))) 28 | andBool ?ActivationEpoch ==Int delayedActivationExitEpoch(?Epoch) 29 | andBool ?ValidatorsToBeActivated:IntList ==K activationQueueUptoChurnLimit(VIDs, AEM, AM1, EM, FinalizedEpoch, ?Epoch) 30 | // pre-conditions 31 | andBool distinct(VIDs) 32 | andBool ?ActivationEpoch 42 | activateValidators(R_VIDs) => .K ... 43 | Slot 44 | 45 | 46 | Slot 47 | v(m(SM, BM, EBM, AEM, AM1 => ?AM2, EM, WM), VIDs) 48 | ... 49 | 50 | ... 51 | 52 | ( epochOf(Slot) , FinalizedEpoch ) _ 53 | ... 54 | 55 | requires true 56 | // types 57 | andBool Slot >=Int 0 58 | // let-bindings 59 | andBool ?Epoch ==Int epochOf(Slot) -Int 1 60 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(VIDs, AM1, EM, ?Epoch))) 61 | andBool ?ActivationEpoch ==Int delayedActivationExitEpoch(?Epoch) 62 | // pre-conditions 63 | andBool distinct(R_VIDs) 64 | andBool forall(x, R_VIDs, isValidValidatorToActivate(x, AEM, AM1, FinalizedEpoch)) 65 | andBool forall(x, R_VIDs, x in VIDs) 66 | andBool ?ActivationEpoch 76 | activateValidatorsAux(L_VIDs, R_VIDs, m(SM, BM, EBM, AEM, AM0, EM, WM)) => .K ... 77 | Slot 78 | 79 | 80 | Slot 81 | v(m(SM, BM, EBM, AEM, AM1 => ?AM2, EM, WM), VIDs) 82 | ... 83 | 84 | ... 85 | 86 | ( epochOf(Slot) , FinalizedEpoch ) _ 87 | ... 88 | 89 | requires true 90 | // types 91 | andBool Slot >=Int 0 92 | // let-bindings 93 | andBool ?Epoch ==Int epochOf(Slot) -Int 1 94 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(VIDs, AM1, EM, ?Epoch))) 95 | andBool ?ActivationEpoch ==Int delayedActivationExitEpoch(?Epoch) 96 | // pre-conditions 97 | andBool distinct(R_VIDs) 98 | andBool ?ActivationEpoch 9 | processValidatorEjections(VIDs) => .K ... 10 | Slot 11 | 12 | 13 | Slot 14 | v(m(SM, BM, EBM, AEM, AM, EM1 => ?EM2, WM1 => ?WM2), VIDs) 15 | ... 16 | 17 | ... 18 | 19 | ... 20 | 21 | requires true 22 | // types 23 | andBool Slot >=Int 0 24 | // let-bindings 25 | andBool ?Epoch ==Int epochOf(Slot) 26 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(VIDs, EM1), delayedActivationExitEpoch(?Epoch)) 27 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(VIDs, AM, EM1, ?Epoch))) 28 | // pre-conditions 29 | andBool ?LastExitEpoch +Int size(VIDs) +Int MIN_VALIDATOR_WITHDRAWABILITY_DELAY =Int delayedActivationExitEpoch(?Epoch) andBool ?EM2[x]i =Int delayedActivationExitEpoch(?Epoch) +Int MIN_VALIDATOR_WITHDRAWABILITY_DELAY andBool ?WM2[x]i 47 | processValidatorEjectionsAux(L_VIDs, R_VIDs, m(SM, BM, EBM, AEM, AM, EM0, WM0)) => .K ... 48 | Slot 49 | 50 | 51 | Slot 52 | v(m(SM, BM, EBM, AEM, AM, EM1 => ?EM2, WM1 => ?WM2), VIDs) 53 | ... 54 | 55 | ... 56 | 57 | ... 58 | 59 | requires true 60 | // types 61 | andBool Slot >=Int 0 62 | // let-bindings 63 | andBool ?Epoch ==Int epochOf(Slot) 64 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(VIDs, EM1), delayedActivationExitEpoch(?Epoch)) 65 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(VIDs, AM, EM1, ?Epoch))) 66 | // pre-conditions 67 | andBool ?LastExitEpoch +Int size(R_VIDs) +Int MIN_VALIDATOR_WITHDRAWABILITY_DELAY =Int delayedActivationExitEpoch(?Epoch) andBool EM1[x]i =Int delayedActivationExitEpoch(?Epoch) +Int MIN_VALIDATOR_WITHDRAWABILITY_DELAY andBool WM1[x]i =Int delayedActivationExitEpoch(?Epoch) andBool ?EM2[x]i =Int delayedActivationExitEpoch(?Epoch) +Int MIN_VALIDATOR_WITHDRAWABILITY_DELAY andBool ?WM2[x]i 16 | processValidatorUpdates() => .K ... 17 | Slot 18 | 19 | 20 | Slot 21 | v(m(SM, BM, EBM, AEM1 => ?AEM2, AM1 => ?AM2, EM1 => ?EM2, WM1 => ?WM2), VIDs) 22 | ... 23 | 24 | ... 25 | 26 | ( epochOf(Slot) , FinalizedEpoch ) _ 27 | ... 28 | 29 | requires true 30 | // types 31 | andBool Slot >=Int 0 32 | // let-bindings 33 | andBool ?Epoch ==Int epochOf(Slot) 34 | andBool ?ChurnLimitA ==Int churnLimit(size(activeValidators(VIDs, AM1, EM1, ?Epoch))) 35 | andBool ?ChurnLimitB ==Int churnLimit(size(activeValidators(VIDs, AM1, EM1, ?Epoch -Int 1))) 36 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(VIDs, EM1), delayedActivationExitEpoch(?Epoch)) 37 | andBool ?ActivationEpoch ==Int delayedActivationExitEpoch(?Epoch -Int 1) 38 | andBool ?ValidatorsToBeActivated:IntList ==K activationQueueUptoChurnLimit(VIDs, AEM1, AM1, EM1, FinalizedEpoch, ?Epoch -Int 1) 39 | // pre-conditions 40 | andBool distinct(VIDs) 41 | andBool FinalizedEpoch =Int delayedActivationExitEpoch(?Epoch) andBool ?EM2[x]i =Int delayedActivationExitEpoch(?Epoch) +Int MIN_VALIDATOR_WITHDRAWABILITY_DELAY andBool ?WM2[x]i 10 | processJustification(Epoch) => . 11 | Slot 12 | 13 | 14 | Slot 15 | Vs 16 | 17 | Epoch |-> Attestations:Attestations 18 | ... 19 | 20 | 21 | Epoch |-> (false => true) 22 | ... 23 | 24 | _ => Epoch 25 | ... 26 | 27 | 28 | firstSlotOf(Epoch) 29 | Vs 30 | (_, EpochBoundaryBlock) 31 | ... 32 | 33 | ... 34 | 35 | ... 36 | 37 | requires Slot ==Int firstSlotOf(Epoch +Int 1) 38 | andBool Epoch >=Int 1 39 | andBool isJustifiable(Epoch, EpochBoundaryBlock, Attestations, Vs) 40 | 41 | endmodule 42 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/b-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module B-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // once processJustification(e) justifies e, then the subsequent processJustification(e) alters nothing. 8 | rule 9 | 10 | processJustification(Epoch) ~> processJustification(Epoch) => . 11 | Slot 12 | 13 | 14 | Slot 15 | Vs 16 | 17 | Epoch |-> Attestations:Attestations 18 | ... 19 | 20 | 21 | Epoch |-> (false => true) 22 | ... 23 | 24 | _ => Epoch 25 | ... 26 | 27 | 28 | firstSlotOf(Epoch) 29 | Vs 30 | (_, EpochBoundaryBlock) 31 | ... 32 | 33 | ... 34 | 35 | ... 36 | 37 | requires Slot ==Int firstSlotOf(Epoch +Int 1) 38 | andBool Epoch >=Int 1 39 | andBool isJustifiable(Epoch, EpochBoundaryBlock, Attestations, Vs) 40 | 41 | endmodule 42 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/c-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module C-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // if e has not yet been justified, 8 | // processJustification(e) updates the entry according to the justifiability of e. 9 | rule 10 | 11 | processJustification(Epoch) => . 12 | Slot 13 | 14 | 15 | Slot 16 | Vs 17 | 18 | Epoch |-> Attestations 19 | ... 20 | 21 | 22 | Epoch |-> (false => ?EpochJustifiedBlock:Bool) 23 | ... 24 | 25 | LastJustifiedEpoch => ?NewJustifiedEpoch 26 | ... 27 | 28 | 29 | firstSlotOf(Epoch) 30 | Vs 31 | (_, EpochBoundaryBlock) 32 | ... 33 | 34 | ... 35 | 36 | ... 37 | 38 | requires true 39 | andBool Epoch >=Int 1 40 | andBool Epoch ==Int epochOf(Slot) -Int 1 41 | andBool Epoch >Int LastJustifiedEpoch 42 | ensures ( 43 | isJustifiable(Epoch, EpochBoundaryBlock, Attestations, Vs) 44 | andBool ?EpochJustifiedBlock ==K true 45 | andBool ?NewJustifiedEpoch ==Int Epoch 46 | ) orBool ( 47 | notBool isJustifiable(Epoch, EpochBoundaryBlock, Attestations, Vs) 48 | andBool ?EpochJustifiedBlock ==K false 49 | andBool ?NewJustifiedEpoch ==Int LastJustifiedEpoch 50 | ) 51 | 52 | // if e has already been justified, 53 | // processJustification(e) does nothing even if e is justifiable. 54 | rule 55 | 56 | processJustification(Epoch) => . 57 | Slot 58 | 59 | 60 | Slot 61 | Vs 62 | 63 | Epoch |-> Attestations 64 | ... 65 | 66 | 67 | Epoch |-> true 68 | ... 69 | 70 | Epoch 71 | ... 72 | 73 | 74 | firstSlotOf(Epoch) 75 | Vs 76 | (_, EpochBoundaryBlock) 77 | ... 78 | 79 | ... 80 | 81 | ... 82 | 83 | requires true 84 | andBool Epoch >=Int 1 85 | andBool Epoch ==Int epochOf(Slot) -Int 1 86 | andBool isJustifiable(Epoch, EpochBoundaryBlock, Attestations, Vs) 87 | 88 | endmodule 89 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/d-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module D-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // processJustification(e) updates the entry properly according to the justifiability of e, 8 | // even when e has been already justified. 9 | rule 10 | 11 | case(xor2( 12 | LastJustifiedEpoch processJustification(Epoch) => . 17 | Slot 18 | 19 | 20 | Slot 21 | Vs 22 | 23 | Epoch |-> Attestations 24 | ... 25 | 26 | 27 | Epoch |-> (OldEpochJustifiedBlock:Bool => ?NewEpochJustifiedBlock:Bool) 28 | ... 29 | 30 | LastJustifiedEpoch => ?NewJustifiedEpoch 31 | ... 32 | 33 | 34 | firstSlotOf(Epoch) 35 | Vs 36 | (_, EpochBoundaryBlock) 37 | ... 38 | 39 | ... 40 | 41 | ... 42 | 43 | requires true 44 | andBool Epoch >=Int 1 45 | andBool Epoch ==Int epochOf(Slot) -Int 1 46 | // invariant 47 | andBool LastJustifiedEpoch <=Int Epoch 48 | andBool implies(LastJustifiedEpoch entries properly according to the justifiability of e - 2 and e - 1, 9 | // where e is the current epoch. 10 | rule 11 | 12 | case(xor2( 13 | LastJustifiedEpoch processJustification(Epoch2) 18 | ~> processJustification(Epoch1) => . 19 | Slot 20 | 21 | 22 | firstSlotOf(Epoch2) 23 | Vs 24 | (_, Epoch2BoundaryBlock) 25 | ... 26 | 27 | 28 | firstSlotOf(Epoch1) 29 | Vs 30 | (_, Epoch1BoundaryBlock) 31 | ... 32 | 33 | 34 | Slot 35 | Vs 36 | 37 | Epoch2 |-> Attestations2:Attestations 38 | Epoch1 |-> Attestations1:Attestations 39 | ... 40 | 41 | 42 | Epoch2 |-> (OldEpoch2JustifiedBlock:Bool => ?NewEpoch2JustifiedBlock:Bool) 43 | Epoch1 |-> (OldEpoch1JustifiedBlock:Bool => ?NewEpoch1JustifiedBlock:Bool) 44 | ... 45 | 46 | LastJustifiedEpoch => ?NewJustifiedEpoch 47 | ... 48 | 49 | ... 50 | 51 | ... 52 | 53 | requires true 54 | andBool Epoch1 >=Int 1 55 | andBool Epoch1 ==Int epochOf(Slot) -Int 1 56 | andBool Epoch2 ==Int epochOf(Slot) -Int 2 57 | andBool OldEpoch1JustifiedBlock ==K false 58 | // invariant 59 | andBool LastJustifiedEpoch <=Int Epoch2 60 | andBool implies(LastJustifiedEpoch =Int 0 65 | andBool Epoch1 >=Int 0 66 | andBool Epoch2 >=Int 0 67 | andBool LastJustifiedEpoch >=Int 0 68 | ensures ?NewJustifiedEpoch >=Int 0 69 | // ensures 70 | // justification of e - 2 71 | andBool bool(xor2( 72 | isJustifiable(Epoch2, Epoch2BoundaryBlock, Attestations2, Vs) 73 | andBool ?NewEpoch2JustifiedBlock ==K true 74 | , 75 | notBool isJustifiable(Epoch2, Epoch2BoundaryBlock, Attestations2, Vs) 76 | andBool ?NewEpoch2JustifiedBlock ==K false 77 | )) 78 | // justification of e - 1 79 | andBool bool(xor2( 80 | isJustifiable(Epoch1, Epoch1BoundaryBlock, Attestations1, Vs) 81 | andBool ?NewEpoch1JustifiedBlock ==K true 82 | , 83 | notBool isJustifiable(Epoch1, Epoch1BoundaryBlock, Attestations1, Vs) 84 | andBool ?NewEpoch1JustifiedBlock ==K false 85 | )) 86 | // last justified epoch 87 | andBool bool(xor3( 88 | ?NewEpoch2JustifiedBlock ==K false 89 | andBool ?NewEpoch1JustifiedBlock ==K false 90 | andBool ?NewJustifiedEpoch ==Int LastJustifiedEpoch 91 | , 92 | ?NewEpoch2JustifiedBlock ==K true 93 | andBool ?NewEpoch1JustifiedBlock ==K false 94 | andBool ?NewJustifiedEpoch ==Int Epoch2 95 | , 96 | ?NewEpoch1JustifiedBlock ==K true 97 | andBool ?NewJustifiedEpoch ==Int Epoch1 98 | )) 99 | 100 | endmodule 101 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/f-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module F-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // processJustification(e - 2) followed by processJustification(e - 1) 8 | // update the entries properly according to the justifiability of e - 2 and e - 1, 9 | // where e is the current epoch. 10 | rule 11 | 12 | case(xor2( 13 | LastJustifiedEpoch processJustification(Epoch2) 18 | ~> processJustification(Epoch1) => . 19 | firstSlotOf(Epoch) 20 | 21 | 22 | firstSlotOf(Epoch2) 23 | Vs 24 | (_, Epoch2BoundaryBlock) 25 | ... 26 | 27 | 28 | firstSlotOf(Epoch1) 29 | Vs 30 | (_, Epoch1BoundaryBlock) 31 | 32 | Epoch2 |-> PrevAttestations2:Attestations 33 | ... 34 | 35 | 36 | Epoch2 |-> OldEpoch2JustifiedBlock:Bool 37 | ... 38 | 39 | ... 40 | 41 | 42 | firstSlotOf(Epoch) 43 | Vs 44 | 45 | Epoch2 |-> Attestations2:Attestations 46 | Epoch1 |-> Attestations1:Attestations 47 | ... 48 | 49 | 50 | Epoch2 |-> (OldEpoch2JustifiedBlock:Bool => ?NewEpoch2JustifiedBlock:Bool) 51 | Epoch1 |-> (false => ?NewEpoch1JustifiedBlock:Bool) 52 | ... 53 | 54 | LastJustifiedEpoch => ?NewJustifiedEpoch 55 | ... 56 | 57 | ... 58 | 59 | ... 60 | 61 | requires true 62 | andBool Epoch1 ==Int Epoch -Int 1 63 | andBool Epoch2 ==Int Epoch -Int 2 64 | // invariant 65 | andBool LastJustifiedEpoch <=Int Epoch2 66 | andBool implies(LastJustifiedEpoch =Int 0 71 | andBool Epoch1 >=Int 0 72 | andBool Epoch2 >=Int 0 73 | andBool LastJustifiedEpoch >=Int 0 74 | andBool Attestations2 ==K super(PrevAttestations2) 75 | ensures ?NewJustifiedEpoch >=Int 0 76 | // ensures 77 | // justification of e - 2 78 | andBool bool(xor2( 79 | isJustifiable(Epoch2, Epoch2BoundaryBlock, Attestations2, Vs) 80 | andBool ?NewEpoch2JustifiedBlock ==K true 81 | , 82 | notBool isJustifiable(Epoch2, Epoch2BoundaryBlock, Attestations2, Vs) 83 | andBool ?NewEpoch2JustifiedBlock ==K false 84 | )) 85 | // justification of e - 1 86 | andBool bool(xor2( 87 | isJustifiable(Epoch1, Epoch1BoundaryBlock, Attestations1, Vs) 88 | andBool ?NewEpoch1JustifiedBlock ==K true 89 | , 90 | notBool isJustifiable(Epoch1, Epoch1BoundaryBlock, Attestations1, Vs) 91 | andBool ?NewEpoch1JustifiedBlock ==K false 92 | )) 93 | // last justified epoch 94 | andBool bool(xor3( 95 | ?NewEpoch2JustifiedBlock ==K false 96 | andBool ?NewEpoch1JustifiedBlock ==K false 97 | andBool ?NewJustifiedEpoch ==Int LastJustifiedEpoch 98 | , 99 | ?NewEpoch2JustifiedBlock ==K true 100 | andBool ?NewEpoch1JustifiedBlock ==K false 101 | andBool ?NewJustifiedEpoch ==Int Epoch2 102 | , 103 | ?NewEpoch1JustifiedBlock ==K true 104 | andBool ?NewJustifiedEpoch ==Int Epoch1 105 | )) 106 | 107 | endmodule 108 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/f2-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module F2-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // processJustification(e - 2) followed by processJustification(e - 1) 8 | // update the entries properly according to the justifiability of e - 2 and e - 1, 9 | // where e is the current epoch. 10 | rule 11 | 12 | case(xor2( 13 | LastJustifiedEpoch processJustification(Epoch2) 18 | ~> processJustification(Epoch1) => . 19 | firstSlotOf(Epoch) 20 | 21 | 22 | firstSlotOf(Epoch2) 23 | Vs 24 | (_, Epoch2BoundaryBlock) 25 | ... 26 | 27 | 28 | firstSlotOf(Epoch1) 29 | Vs 30 | (_, Epoch1BoundaryBlock) 31 | 32 | Epoch2 |-> PrevAttestations2:Attestations 33 | ... 34 | 35 | 36 | Epoch2 |-> OldEpoch2JustifiedBlock:Bool 37 | ... 38 | 39 | ... 40 | 41 | 42 | firstSlotOf(Epoch) 43 | Vs 44 | 45 | Epoch2 |-> Attestations2:Attestations 46 | Epoch1 |-> Attestations1:Attestations 47 | ... 48 | 49 | 50 | Epoch2 |-> (OldEpoch2JustifiedBlock:Bool => ?NewEpoch2JustifiedBlock:Bool) 51 | Epoch1 |-> (false => ?NewEpoch1JustifiedBlock:Bool) 52 | ... 53 | 54 | LastJustifiedEpoch => ?NewJustifiedEpoch 55 | ... 56 | 57 | ... 58 | 59 | ... 60 | 61 | requires true 62 | andBool Epoch1 ==Int Epoch -Int 1 63 | andBool Epoch2 ==Int Epoch -Int 2 64 | // invariant 65 | andBool LastJustifiedEpoch <=Int Epoch2 66 | andBool implies(LastJustifiedEpoch =Int 0 71 | andBool Epoch1 >=Int 0 72 | andBool Epoch2 >=Int 0 73 | andBool LastJustifiedEpoch >=Int 0 74 | andBool Attestations2 ==K super(PrevAttestations2) 75 | ensures ?NewJustifiedEpoch >=Int 0 76 | // 77 | // ensures 78 | // 79 | // justification of e-2 and e-1 80 | andBool iff(?NewEpoch2JustifiedBlock ==K true, isJustifiable(Epoch2, Epoch2BoundaryBlock, Attestations2, Vs)) 81 | andBool iff(?NewEpoch1JustifiedBlock ==K true, isJustifiable(Epoch1, Epoch1BoundaryBlock, Attestations1, Vs)) 82 | // last justified epoch 83 | andBool implies(?NewJustifiedEpoch e-2 2 | 2. e-1 -> e-3 3 | 3. e-1 -> e-4+ 4 | 5 | a. e-2 -> e-3 6 | b. e-2 -> e-4 7 | c. e-2 -> e-5+ 8 | 9 | 10 | 1a. (e-2 already justified, thus e-3 already finalized) 11 | - e-1 j <=> e-2 f 12 | - e-3 f 13 | - e-4 stay 14 | 15 | 1b. (e-2 already justified) 16 | - e-1 j <=> e-2 f 17 | - e-3 j <=> e-4 f 18 | - e-3 nf 19 | 20 | 1c. (e-2 already justified) 21 | - e-1 j <=> e-2 f 22 | - e-3 nf 23 | - e-4 nf 24 | 25 | 2a. (e-1 doesn't affect) 26 | - e-2 j <=> e-3 f 27 | - e-2 nf 28 | - e-4 stay 29 | 30 | 2b. (e-3 already justified) 31 | - e-2 j <=> e-4 f 32 | - e-1 j and e-2 j <=> e-3 f 33 | - e-2 nf 34 | 35 | 2c. 36 | - e-1 j and e-2 j <=> e-3 f 37 | - e-2 nf 38 | - e-4 nf 39 | 40 | 3a. impossible 41 | 42 | 3b. (e-3 cannot be justified) 43 | - nothing finalized 44 | 45 | 3c. 46 | - nothing finalized 47 | 48 | 49 | 50 | 51 | //// 52 | 53 | 54 | e-1 -> e-2 55 | - e-2 1-f: iff e-1 j 56 | - e-3 2-f: false 57 | 58 | e-1 -> e-3 59 | - e-2 1-f: false 60 | - e-3 2-f: iff e-1 j and e-2 j 61 | 62 | e-1 -> e-4+ 63 | - e-2 1-f: false 64 | - e-3 2-f: false 65 | 66 | 67 | e-2 -> e-3 68 | - e-3 1-f: iff e-2 j 69 | - e-4 2-f: false 70 | 71 | e-2 -> e-4 72 | - e-3 1-f: false 73 | - e-4 2-f: iff e-2 j and e-3 j 74 | 75 | e-2 -> e-5+ 76 | - e-3 1-f: false 77 | - e-4 2-f: false 78 | 79 | 80 | 81 | e-2 f: iff e-2 1-f 82 | e-3 f: iff e-3 1-f or e-3 2-f 83 | e-4 f: iff e-4 2-f 84 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/g-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module G-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // processJustification(e - 2) followed by processJustification(e - 1) 8 | // update the entries properly according to the justifiability of e - 2 and e - 1, 9 | // where e is the current epoch. 10 | rule 11 | 12 | case(xor3( 13 | PrevLastJustifiedEpoch processJustification(Epoch2) 20 | ~> processJustification(Epoch1) => . 21 | firstSlotOf(Epoch) 22 | 23 | 24 | firstSlotOf(Epoch3) 25 | Vs 26 | (_, Epoch3BoundaryBlock) 27 | ... 28 | 29 | 30 | firstSlotOf(Epoch2) 31 | Vs 32 | (_, Epoch2BoundaryBlock) 33 | ... 34 | 35 | 36 | firstSlotOf(Epoch1) 37 | Vs 38 | (_, Epoch1BoundaryBlock) 39 | 40 | Epoch3 |-> PrevAttestations3:Attestations 41 | Epoch2 |-> PrevAttestations2:Attestations 42 | ... 43 | 44 | 45 | Epoch3 |-> PrevEpoch3JustifiedBlock:Bool 46 | Epoch2 |-> PrevEpoch2JustifiedBlock:Bool 47 | ... 48 | 49 | PrevLastJustifiedEpoch 50 | ... 51 | 52 | 53 | firstSlotOf(Epoch) 54 | Vs 55 | 56 | Epoch2 |-> Attestations2:Attestations 57 | Epoch1 |-> Attestations1:Attestations 58 | ... 59 | 60 | 61 | Epoch2 |-> (Epoch2JustifiedBlock:Bool => ?NewEpoch2JustifiedBlock:Bool) 62 | Epoch1 |-> (false => ?NewEpoch1JustifiedBlock:Bool) 63 | ... 64 | 65 | LastJustifiedEpoch => ?NewLastJustifiedEpoch 66 | ... 67 | 68 | ... 69 | 70 | ... 71 | 72 | requires true 73 | andBool Epoch1 ==Int Epoch -Int 1 74 | andBool Epoch2 ==Int Epoch -Int 2 75 | andBool Epoch3 ==Int Epoch -Int 3 76 | // invariant 77 | andBool iff(PrevEpoch3JustifiedBlock ==K true, isJustifiable(Epoch3, Epoch3BoundaryBlock, PrevAttestations3, Vs)) 78 | andBool iff(PrevEpoch2JustifiedBlock ==K true, isJustifiable(Epoch2, Epoch2BoundaryBlock, PrevAttestations2, Vs)) 79 | andBool implies(PrevLastJustifiedEpoch =Int 0 89 | andBool Epoch1 >=Int 0 90 | andBool Epoch2 >=Int 0 91 | andBool Epoch3 >=Int 0 92 | andBool PrevLastJustifiedEpoch >=Int 0 93 | ensures ?NewLastJustifiedEpoch >=Int 0 94 | // 95 | // ensures 96 | // 97 | // justification of e-2 and e-1 98 | andBool iff(?NewEpoch2JustifiedBlock ==K true, isJustifiable(Epoch2, Epoch2BoundaryBlock, Attestations2, Vs)) 99 | andBool iff(?NewEpoch1JustifiedBlock ==K true, isJustifiable(Epoch1, Epoch1BoundaryBlock, Attestations1, Vs)) 100 | // last justified epoch 101 | andBool implies(?NewLastJustifiedEpoch entries properly according to the justifiability of e - 2 and e - 1, 9 | // where e is the current epoch. 10 | rule 11 | 12 | case(xor2( 13 | PrevLastJustifiedEpoch processJustification(Epoch2) 18 | ~> processJustification(Epoch1) => . 19 | firstSlotOf(Epoch) 20 | 21 | 22 | firstSlotOf(Epoch3) 23 | Vs 24 | (_, Epoch3BoundaryBlock) 25 | ... 26 | 27 | 28 | firstSlotOf(Epoch2) 29 | Vs 30 | (_, Epoch2BoundaryBlock) 31 | ... 32 | 33 | 34 | firstSlotOf(Epoch1) 35 | Vs 36 | (_, Epoch1BoundaryBlock) 37 | 38 | Epoch3 |-> PrevAttestations3:Attestations 39 | Epoch2 |-> PrevAttestations2:Attestations 40 | ... 41 | 42 | 43 | Epoch3 |-> PrevEpoch3JustifiedBlock:Bool 44 | Epoch2 |-> PrevEpoch2JustifiedBlock:Bool 45 | ... 46 | 47 | PrevLastJustifiedEpoch 48 | ... 49 | 50 | 51 | firstSlotOf(Epoch) 52 | Vs 53 | 54 | Epoch2 |-> Attestations2:Attestations 55 | Epoch1 |-> Attestations1:Attestations 56 | ... 57 | 58 | 59 | Epoch2 |-> (Epoch2JustifiedBlock:Bool => ?NewEpoch2JustifiedBlock:Bool) 60 | Epoch1 |-> (false => ?NewEpoch1JustifiedBlock:Bool) 61 | ... 62 | 63 | LastJustifiedEpoch => ?NewLastJustifiedEpoch 64 | ... 65 | 66 | ... 67 | 68 | ... 69 | 70 | requires true 71 | andBool Epoch1 ==Int Epoch -Int 1 72 | andBool Epoch2 ==Int Epoch -Int 2 73 | andBool Epoch3 ==Int Epoch -Int 3 74 | // invariant 75 | andBool iff(PrevEpoch3JustifiedBlock ==K true, isJustifiable(Epoch3, Epoch3BoundaryBlock, PrevAttestations3, Vs)) 76 | andBool iff(PrevEpoch2JustifiedBlock ==K true, isJustifiable(Epoch2, Epoch2BoundaryBlock, PrevAttestations2, Vs)) 77 | andBool implies(PrevLastJustifiedEpoch =Int 0 87 | andBool Epoch1 >=Int 0 88 | andBool Epoch2 >=Int 0 89 | andBool Epoch3 >=Int 0 90 | andBool PrevLastJustifiedEpoch >=Int 0 91 | ensures ?NewLastJustifiedEpoch >=Int 0 92 | // 93 | // ensures 94 | // 95 | // justification of e-2 and e-1 96 | andBool iff(?NewEpoch2JustifiedBlock ==K true, isJustifiable(Epoch2, Epoch2BoundaryBlock, Attestations2, Vs)) 97 | andBool iff(?NewEpoch1JustifiedBlock ==K true, isJustifiable(Epoch1, Epoch1BoundaryBlock, Attestations1, Vs)) 98 | // last justified epoch 99 | andBool implies(?NewLastJustifiedEpoch entries properly according to the justifiability of e - 2 and e - 1, 9 | // where e is the current epoch. 10 | rule 11 | 12 | case(xor3( 13 | PrevLastJustifiedEpoch processJustification(Epoch2) 20 | ~> processJustification(Epoch1) => . 21 | firstSlotOf(Epoch) 22 | 23 | 24 | firstSlotOf(Epoch3) 25 | Vs 26 | (_, Epoch3BoundaryBlock) 27 | ... 28 | 29 | 30 | firstSlotOf(Epoch2) 31 | Vs 32 | (_, Epoch2BoundaryBlock) 33 | ... 34 | 35 | 36 | firstSlotOf(Epoch1) 37 | Vs 38 | (_, Epoch1BoundaryBlock) 39 | 40 | Epoch3 |-> PrevAttestations3:Attestations 41 | Epoch2 |-> PrevAttestations2:Attestations 42 | ... 43 | 44 | 45 | Epoch3 |-> PrevEpoch3JustifiedBlock:Bool 46 | Epoch2 |-> PrevEpoch2JustifiedBlock:Bool 47 | ... 48 | 49 | PrevLastJustifiedEpoch 50 | ... 51 | 52 | 53 | firstSlotOf(Epoch) 54 | Vs 55 | 56 | Epoch2 |-> Attestations2:Attestations 57 | Epoch1 |-> Attestations1:Attestations 58 | ... 59 | 60 | 61 | Epoch2 |-> (Epoch2JustifiedBlock:Bool => ?NewEpoch2JustifiedBlock:Bool) 62 | Epoch1 |-> (false => ?NewEpoch1JustifiedBlock:Bool) 63 | ... 64 | 65 | LastJustifiedEpoch => ?NewLastJustifiedEpoch 66 | ... 67 | 68 | ... 69 | 70 | ... 71 | 72 | requires true 73 | andBool Epoch1 ==Int Epoch -Int 1 74 | andBool Epoch2 ==Int Epoch -Int 2 75 | andBool Epoch3 ==Int Epoch -Int 3 76 | // invariant 77 | andBool isGoodState(Epoch3, Epoch3BoundaryBlock, PrevAttestations3, Vs, PrevEpoch3JustifiedBlock, 78 | Epoch2, Epoch2BoundaryBlock, PrevAttestations2, Vs, PrevEpoch2JustifiedBlock, 79 | PrevLastJustifiedEpoch) 80 | // 81 | andBool Epoch2JustifiedBlock ==K PrevEpoch2JustifiedBlock 82 | andBool LastJustifiedEpoch ==Int PrevLastJustifiedEpoch 83 | andBool Attestations2 ==K super(PrevAttestations2) 84 | // ranges 85 | andBool Epoch >=Int 0 86 | andBool Epoch1 >=Int 0 87 | andBool Epoch2 >=Int 0 88 | andBool Epoch3 >=Int 0 89 | andBool PrevLastJustifiedEpoch >=Int 0 90 | ensures ?NewLastJustifiedEpoch >=Int 0 91 | // 92 | // ensures 93 | // 94 | andBool isGoodState(Epoch2, Epoch2BoundaryBlock, Attestations2, Vs, ?NewEpoch2JustifiedBlock, 95 | Epoch1, Epoch1BoundaryBlock, Attestations1, Vs, ?NewEpoch1JustifiedBlock, 96 | ?NewLastJustifiedEpoch) 97 | 98 | endmodule 99 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/k0-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module K0-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // Slot == TargetSlot 8 | rule 9 | 10 | processSlots(TargetSlot) => . 11 | Slot 12 | 13 | 14 | Slot 15 | Vs 16 | SB 17 | AttestedMap 18 | JustifiedMap 19 | FinalizedMap 20 | (LastBlockSlot, LastBlockID) 21 | LastJustifiedEpoch 22 | LastFinalizedEpoch 23 | 24 | ... 25 | 26 | ... 27 | 28 | requires true 29 | andBool TargetSlot ==Int Slot 30 | // types 31 | andBool Slot >=Int 0 32 | andBool LastBlockSlot >=Int 0 33 | andBool LastJustifiedEpoch >=Int 0 34 | andBool LastFinalizedEpoch >=Int 0 35 | ensures true 36 | 37 | endmodule 38 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/k1a-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module K1A-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // Slot + 1 == TargetSlot 8 | // using `...` 9 | rule 10 | 11 | processSlots(TargetSlot) => . 12 | Slot => Slot +Int 1 13 | 14 | 15 | Slot 16 | Vs 17 | SB 18 | AttestedMap 19 | JustifiedMap 20 | FinalizedMap 21 | (LastBlockSlot, LastBlockID) 22 | LastJustifiedEpoch 23 | LastFinalizedEpoch 24 | 25 | ( 26 | .Bag 27 | => 28 | 29 | Slot +Int 1 30 | Vs 31 | SB 32 | AttestedMap 33 | JustifiedMap 34 | FinalizedMap 35 | (LastBlockSlot, LastBlockID) 36 | LastJustifiedEpoch 37 | LastFinalizedEpoch 38 | 39 | ) 40 | ... 41 | 42 | ... 43 | 44 | requires true 45 | andBool TargetSlot ==Int Slot +Int 1 46 | andBool isFirstSlotOfEpoch(TargetSlot) ==K false 47 | // types 48 | andBool Slot >=Int 0 49 | andBool LastBlockSlot >=Int 0 50 | andBool LastJustifiedEpoch >=Int 0 51 | andBool LastFinalizedEpoch >=Int 0 52 | ensures true 53 | 54 | endmodule 55 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/k1b-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module K1B-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // Slot + 1 == TargetSlot 8 | // using `_` 9 | rule 10 | 11 | processSlots(TargetSlot) => . 12 | Slot => Slot +Int 1 13 | 14 | 15 | Slot 16 | Vs 17 | SB 18 | AttestedMap 19 | JustifiedMap 20 | FinalizedMap 21 | (LastBlockSlot, LastBlockID) 22 | LastJustifiedEpoch 23 | LastFinalizedEpoch 24 | 25 | ( 26 | .Bag 27 | => 28 | 29 | Slot +Int 1 30 | Vs 31 | SB 32 | AttestedMap 33 | JustifiedMap 34 | FinalizedMap 35 | (LastBlockSlot, LastBlockID) 36 | LastJustifiedEpoch 37 | LastFinalizedEpoch 38 | 39 | ) 40 | _ // NOTE: `_` instead of `...` 41 | 42 | ... 43 | 44 | requires true 45 | andBool TargetSlot ==Int Slot +Int 1 46 | andBool isFirstSlotOfEpoch(TargetSlot) ==K false 47 | // types 48 | andBool Slot >=Int 0 49 | andBool LastBlockSlot >=Int 0 50 | andBool LastJustifiedEpoch >=Int 0 51 | andBool LastFinalizedEpoch >=Int 0 52 | ensures true 53 | 54 | endmodule 55 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/k2a-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module K2A-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // Slot + 2 == TargetSlot 8 | // explicit 9 | rule 10 | 11 | processSlots(TargetSlot) => . 12 | Slot => TargetSlot 13 | 14 | 15 | Slot 16 | Vs 17 | SB 18 | AttestedMap 19 | JustifiedMap 20 | FinalizedMap 21 | (LastBlockSlot, LastBlockID) 22 | LastJustifiedEpoch 23 | LastFinalizedEpoch 24 | 25 | ( 26 | .Bag 27 | => 28 | 29 | Slot +Int 1 30 | Vs 31 | SB 32 | AttestedMap 33 | JustifiedMap 34 | FinalizedMap 35 | (LastBlockSlot, LastBlockID) 36 | LastJustifiedEpoch 37 | LastFinalizedEpoch 38 | 39 | 40 | TargetSlot 41 | Vs 42 | SB 43 | AttestedMap 44 | JustifiedMap 45 | FinalizedMap 46 | (LastBlockSlot, LastBlockID) 47 | LastJustifiedEpoch 48 | LastFinalizedEpoch 49 | 50 | ) 51 | _ 52 | 53 | ... 54 | 55 | requires true 56 | andBool TargetSlot ==Int Slot +Int 2 57 | andBool isFirstSlotOfEpoch(Slot +Int 1) ==K false 58 | andBool isFirstSlotOfEpoch(TargetSlot) ==K false 59 | // types 60 | andBool Slot >=Int 0 61 | andBool LastBlockSlot >=Int 0 62 | andBool LastJustifiedEpoch >=Int 0 63 | andBool LastFinalizedEpoch >=Int 0 64 | ensures true 65 | 66 | endmodule 67 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/k2b-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module K2B-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // Slot + 2 == TargetSlot 8 | // using `?_` 9 | rule 10 | 11 | processSlots(TargetSlot) => . 12 | Slot => TargetSlot 13 | 14 | 15 | Slot 16 | Vs 17 | SB 18 | AttestedMap 19 | JustifiedMap 20 | FinalizedMap 21 | (LastBlockSlot, LastBlockID) 22 | LastJustifiedEpoch 23 | LastFinalizedEpoch 24 | 25 | ( 26 | .Bag 27 | => 28 | ?_ // NOTE: this captures (zero or more) other 's 29 | 30 | TargetSlot 31 | Vs 32 | SB 33 | AttestedMap 34 | JustifiedMap 35 | FinalizedMap 36 | (LastBlockSlot, LastBlockID) 37 | LastJustifiedEpoch 38 | LastFinalizedEpoch 39 | 40 | ) 41 | _ 42 | 43 | ... 44 | 45 | requires true 46 | andBool TargetSlot ==Int Slot +Int 2 47 | andBool isFirstSlotOfEpoch(Slot +Int 1) ==K false 48 | andBool isFirstSlotOfEpoch(TargetSlot) ==K false 49 | // types 50 | andBool Slot >=Int 0 51 | andBool LastBlockSlot >=Int 0 52 | andBool LastJustifiedEpoch >=Int 0 53 | andBool LastFinalizedEpoch >=Int 0 54 | ensures true 55 | 56 | endmodule 57 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/kn1-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module KN1-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // TODO: when Slot == Target, the additional cell should be idempotent 8 | // when Slot < Target, it needs to know that: lastSlotOf(epochOf(Slot)) == lastSlotOf(epochOf(Slot + 1)) 9 | /* 10 | rule lastSlotOf(epochOf(Slot)) ==K lastSlotOf(epochOf(Slot +Int 1)) => true 11 | requires Slot < lastSlotOf(epochOf(Slot)) 12 | 13 | rule lastSlotOf(epochOf(Slot +Int 1)) ==K lastSlotOf(epochOf(Slot)) => true 14 | requires Slot < lastSlotOf(epochOf(Slot)) 15 | */ 16 | 17 | // Slot + N == TargetSlot 18 | // where 0 <= N <= SLOTS_PER_EPOCH - 1 19 | // loop invariant 20 | // Slot <= TargetSlot 21 | rule 22 | 23 | processSlots(TargetSlot) => . 24 | Slot => TargetSlot 25 | 26 | 27 | Slot 28 | Vs 29 | SB 30 | AttestedMap 31 | JustifiedMap 32 | FinalizedMap 33 | (LastBlockSlot, LastBlockID) 34 | LastJustifiedEpoch 35 | LastFinalizedEpoch 36 | 37 | ( 38 | .Bag 39 | => 40 | ?_ // NOTE: this captures (zero or more) other s 41 | 42 | TargetSlot 43 | Vs 44 | SB 45 | AttestedMap 46 | JustifiedMap 47 | FinalizedMap 48 | (LastBlockSlot, LastBlockID) 49 | LastJustifiedEpoch 50 | LastFinalizedEpoch 51 | 52 | ) 53 | _ 54 | 55 | ... 56 | 57 | requires true 58 | andBool Slot <=Int TargetSlot 59 | andBool TargetSlot ==Int lastSlotOf(epochOf(Slot)) // NOTE: this already implies Slot <=Int TargetSlot 60 | // types 61 | andBool Slot >=Int 0 62 | andBool TargetSlot >=Int 0 63 | andBool LastBlockSlot >=Int 0 64 | andBool LastJustifiedEpoch >=Int 0 65 | andBool LastFinalizedEpoch >=Int 0 66 | ensures true 67 | 68 | endmodule 69 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/kn2-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module KN2-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // TODO: it needs to know that: Slot + N == lastSlotOf(epochOf(Slot)) 8 | /* 9 | rule (Slot +Int N) %Int SLOTS_PER_EPOCH ==K 0 => false // isFirstSlotOfEpoch(Slot +Int N) => false 10 | requires (Slot +Int N) <=Int lastSlotOf(epochOf(Slot)) 11 | */ 12 | /* not needed 13 | rule Slot +Int (SLOTS_PER_EPOCH -Int 1) false 14 | */ 15 | 16 | // Slot + N == TargetSlot 17 | // where 1 <= N <= SLOTS_PER_EPOCH - 1 18 | // loop invariant 19 | // Slot < TargetSlot 20 | rule 21 | 22 | processSlots(TargetSlot) => . 23 | Slot => TargetSlot 24 | 25 | 26 | Slot 27 | Vs 28 | SB 29 | AttestedMap 30 | JustifiedMap 31 | FinalizedMap 32 | (LastBlockSlot, LastBlockID) 33 | LastJustifiedEpoch 34 | LastFinalizedEpoch 35 | 36 | ( 37 | .Bag 38 | => 39 | ?_ // NOTE: this captures (zero or more) other s 40 | 41 | TargetSlot 42 | Vs 43 | SB 44 | AttestedMap 45 | JustifiedMap 46 | FinalizedMap 47 | (LastBlockSlot, LastBlockID) 48 | LastJustifiedEpoch 49 | LastFinalizedEpoch 50 | 51 | ) 52 | _ 53 | 54 | ... 55 | 56 | requires true 57 | andBool Slot =Int 0 61 | andBool TargetSlot >=Int 0 62 | andBool LastBlockSlot >=Int 0 63 | andBool LastJustifiedEpoch >=Int 0 64 | andBool LastFinalizedEpoch >=Int 0 65 | ensures true 66 | 67 | endmodule 68 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/l.smt2: -------------------------------------------------------------------------------- 1 | ; 2 | ; definitions 3 | ; 4 | 5 | (define-fun max ((x Int) (y Int)) Int (ite (> x y) x y)) 6 | 7 | (define-sort M () (Array Int Int)) 8 | 9 | ; return the max value of a map 10 | (declare-fun maxM (M) Int) 11 | ; axiomatization 12 | (assert (forall ((m M) (x Int) (v Int)) 13 | (= (maxM (store m x v)) 14 | (max v (maxM m)) 15 | ) 16 | )) 17 | 18 | ; count the number of the given value 19 | (declare-fun count (M Int) Int) 20 | ; axiomatization 21 | ;TODO: why this is unsat? 22 | ;(assert (forall ((m M) (x Int) (v Int)) 23 | ; (= (count (store m x v) v) 24 | ; (+ (count m v) 1) 25 | ; ) 26 | ;)) 27 | (assert (forall ((m M) (x Int) (v Int) (w Int)) 28 | (and 29 | (=> (not (= (select m x) w)) 30 | (= (count (store m x v) w) 31 | (+ (count m w) (ite (= v w) 1 0)) 32 | ) 33 | ) 34 | (=> (= (select m x) w) 35 | (= (count (store m x v) w) 36 | (+ (count m w) (ite (= v w) 0 -1)) 37 | ) 38 | ) 39 | ) 40 | )) 41 | ; count cannot be negative 42 | (assert (forall ((m M) (v Int)) 43 | (>= (count m v) 0) 44 | )) 45 | 46 | ; count beyond the maximum value is zero 47 | (assert (forall ((m M) (v Int)) 48 | (=> (> v (maxM m)) 49 | (= (count m v) 0) 50 | ) 51 | )) 52 | 53 | ; 54 | ; theorems 55 | ; 56 | 57 | ; validity property 58 | (define-fun isValid ((m M) (l Int)) Bool 59 | (forall ((e Int)) 60 | (=> (and (<= 0 e) (<= e (maxM m))) 61 | (<= (count m e) l) 62 | ) 63 | ) 64 | ) 65 | 66 | ; original map 67 | (declare-const m M) 68 | (declare-const x Int) 69 | 70 | ; e: current epoch 71 | (declare-const e Int) 72 | (assert (>= e 0)) 73 | 74 | ; l = limit >= 4 75 | (declare-const l Int) 76 | (assert (>= l 4)) 77 | 78 | ; v = max (maxM m) (e + 4) 79 | (declare-const v Int) 80 | (assert (= v (max (maxM m) (+ e 4)))) 81 | 82 | ; w = new value 83 | (declare-const w Int) 84 | (assert (= w (ite (= (count m v) l) (+ v 1) v))) 85 | 86 | ; pre-condition: m is valid 87 | (assert (isValid m l)) 88 | ; x is empty 89 | (assert (= (select m x) -1)) 90 | 91 | ; updated map: m2 = m [ x <- w ] 92 | (declare-const m2 M) 93 | (assert (= m2 (store m x w))) 94 | 95 | ; verify post-condition: m2 is still valid 96 | (assert (not 97 | (isValid m2 l) 98 | )) 99 | 100 | (check-sat) 101 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/l1-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module L1-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | initiateValidatorExit(V) => . 10 | Slot 11 | 12 | 13 | Slot 14 | v(VM1 => ?VM2, _) 15 | ... 16 | 17 | ... 18 | 19 | ... 20 | 21 | requires true 22 | andBool V.exit_epoch ==Int FAR_FUTURE_EPOCH 23 | // types 24 | andBool Slot >=Int 0 25 | ensures true 26 | andBool ?VM2[V.id]v.exit_epoch >=Int delayedActivationExitEpoch(epochOf(Slot)) 27 | 28 | endmodule 29 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/l2-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module L2-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | case(xor2( 10 | countValidatorsToExit(v(VM1,VIDs), ?LastExitEpoch) >=Int ?ChurnLimit 11 | , 12 | countValidatorsToExit(v(VM1,VIDs), ?LastExitEpoch) initiateValidatorExit(V) => . 15 | Slot 16 | 17 | 18 | Slot 19 | v(VM1 => ?VM2, VIDs) 20 | ... 21 | 22 | ... 23 | 24 | ... 25 | 26 | requires true 27 | // types 28 | andBool Slot >=Int 0 29 | // let-bindings 30 | andBool ?Epoch ==Int epochOf(Slot) 31 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(v(VM1,VIDs)), delayedActivationExitEpoch(?Epoch)) 32 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(v(VM1,VIDs), ?Epoch))) 33 | // conditions 34 | andBool V.id in VIDs 35 | andBool V.exit_epoch ==Int FAR_FUTURE_EPOCH 36 | andBool VM1[V.id]v ==K V 37 | andBool ?LastExitEpoch +Int 1 =Int delayedActivationExitEpoch(?Epoch) 43 | andBool countValidatorsToExit(v(?VM2,VIDs), ?VM2[V.id]v.exit_epoch) <=Int ?ChurnLimit 44 | /* 45 | andBool activeValidators(v(VM1,VIDs), ?Epoch) ==K activeValidators(v(?VM2,VIDs), ?Epoch) 46 | */ 47 | 48 | endmodule 49 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/l3-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module L3-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | /* case(xor2( 10 | countValidatorsToExit(v(VM1,VIDs), ?LastExitEpoch) >=Int ?ChurnLimit 11 | , 12 | countValidatorsToExit(v(VM1,VIDs), ?LastExitEpoch) */ initiateValidatorExit(V) => .K ... 15 | Slot 16 | 17 | 18 | Slot 19 | v(VM1 => VM1 [ V.id <- ?V2 ]v, VIDs) 20 | ... 21 | 22 | ... 23 | 24 | ... 25 | 26 | requires true 27 | // types 28 | andBool Slot >=Int 0 29 | // let-bindings 30 | andBool ?Epoch ==Int epochOf(Slot) 31 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(v(VM1,VIDs)), delayedActivationExitEpoch(?Epoch)) 32 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(v(VM1,VIDs), ?Epoch))) 33 | // conditions 34 | andBool V.id in VIDs 35 | andBool V.exit_epoch ==Int FAR_FUTURE_EPOCH 36 | andBool VM1[V.id]v ==K V 37 | andBool ?LastExitEpoch +Int 1 =Int delayedActivationExitEpoch(?Epoch) 44 | andBool countValidatorsToExit(v(VM1 [ V.id <- ?V2 ]v, VIDs), ?V2.exit_epoch) <=Int ?ChurnLimit 45 | /* 46 | andBool activeValidators(v(VM1,VIDs), ?Epoch) ==K activeValidators(v(VM1 [ V.id <- ?V2 ]v, VIDs), ?Epoch) 47 | */ 48 | [matching(storeV)] 49 | 50 | endmodule 51 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/l4-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module L4-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | processVoluntaryExits(VEs) => . 10 | Slot 11 | 12 | 13 | Slot 14 | v(VM, VIDs) => ?VS2 15 | ... 16 | 17 | ... 18 | 19 | ... 20 | 21 | requires true 22 | // types 23 | andBool Slot >=Int 0 24 | // let-bindings 25 | andBool ?Epoch ==Int epochOf(Slot) 26 | // conditions 27 | andBool isValidVoluntaryExits(VEs, VM, ?Epoch, VIDs) 28 | ensures true 29 | // ensures 30 | andBool ?VS2 ==K storeValidatorExits(v(VM, VIDs), VEs, ?Epoch) 31 | 32 | endmodule 33 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/l5-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | require "l3-spec.k" 3 | 4 | module L5-SPEC 5 | 6 | imports VERIFICATION 7 | imports L3-SPEC 8 | 9 | rule 10 | 11 | processVoluntaryExits(VEs) => .K ... 12 | Slot 13 | 14 | 15 | Slot 16 | v(VM1 => ?VM2, VIDs) 17 | ... 18 | 19 | ... 20 | 21 | ... 22 | 23 | requires true 24 | // types 25 | andBool Slot >=Int 0 26 | // let-bindings 27 | andBool ?Epoch ==Int epochOf(Slot) 28 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(v(VM1,VIDs)), delayedActivationExitEpoch(?Epoch)) 29 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(v(VM1,VIDs), ?Epoch))) 30 | // conditions 31 | andBool isValidVoluntaryExits(VEs, VM1, ?Epoch, VIDs) 32 | andBool ?LastExitEpoch +Int sizeE(VEs) 9 | processVoluntaryExits(VEs) => .K ... 10 | Slot 11 | 12 | 13 | Slot 14 | v(m(SM, BM, EBM, AEM, AM, EM1 => ?EM2, WM1 => ?WM2), VIDs) 15 | ... 16 | 17 | ... 18 | 19 | ... 20 | 21 | requires true 22 | // types 23 | andBool Slot >=Int 0 24 | // let-bindings 25 | andBool ?Epoch ==Int epochOf(Slot) 26 | andBool ?VM1 ==K m(SM, BM, EBM, AEM, AM, EM1, WM1) 27 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(v(?VM1, VIDs)), delayedActivationExitEpoch(?Epoch)) 28 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(v(?VM1, VIDs), ?Epoch))) 29 | // pre-conditions 30 | andBool ?LastExitEpoch +Int sizeE(VEs) =Int delayedActivationExitEpoch(?Epoch)) 38 | andBool forall(x, getValidatorsE(VEs), ?EM2[x]i 43 | processVoluntaryExitsAux(L_VIDs, R_VEs, m(SM, BM, EBM, AEM, AM, EM0, WM0)) => .K ... 44 | Slot 45 | 46 | 47 | Slot 48 | v(m(SM, BM, EBM, AEM, AM, EM1 => ?EM2, WM1 => ?WM2), VIDs) 49 | ... 50 | 51 | ... 52 | 53 | ... 54 | 55 | requires true 56 | // types 57 | andBool Slot >=Int 0 58 | // let-bindings 59 | andBool ?Epoch ==Int epochOf(Slot) 60 | andBool ?VM0 ==K m(SM, BM, EBM, AEM, AM, EM0, WM0) 61 | andBool ?VM1 ==K m(SM, BM, EBM, AEM, AM, EM1, WM1) 62 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(v(?VM1, VIDs)), delayedActivationExitEpoch(?Epoch)) 63 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(v(?VM1, VIDs), ?Epoch))) 64 | // pre-conditions 65 | andBool ?LastExitEpoch +Int sizeE(R_VEs) =Int delayedActivationExitEpoch(?Epoch)) 74 | andBool forall(x, rev(L_VIDs) , EM1[x]i =Int delayedActivationExitEpoch(?Epoch)) 79 | andBool forall(x, rev(L_VIDs) ++ getValidatorsE(R_VEs), ?EM2[x]i 9 | processValidatorActivation() => activateValidators(?ValidatorsToBeActivated) 10 | Slot 11 | 12 | 13 | Slot 14 | Validators 15 | FinalizedEpoch 16 | ... 17 | 18 | ... 19 | 20 | ... 21 | 22 | requires true 23 | // types 24 | andBool Slot >=Int 0 25 | // let-bindings 26 | andBool ?Epoch ==Int epochOf(Slot) -Int 1 27 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(Validators, ?Epoch))) 28 | ensures true 29 | // ensures 30 | andBool sizeV(?ValidatorsToBeActivated) <=Int ?ChurnLimit 31 | andBool subsetV(?ValidatorsToBeActivated, activationQueue(Validators, FinalizedEpoch)) 32 | 33 | // inductive case 34 | rule 35 | 36 | activateValidators(V Vs => Vs) 37 | Slot 38 | 39 | 40 | Slot 41 | v(VM1 => ?VM2, _) 42 | ... 43 | 44 | ... 45 | 46 | ... 47 | 48 | requires true 49 | // types 50 | andBool Slot >=Int 0 51 | // let-bindings 52 | andBool ?Epoch ==Int epochOf(Slot) -Int 1 53 | ensures true 54 | // ensures 55 | andBool ?VM2[V.id]v.activation_epoch ==Int delayedActivationExitEpoch(?Epoch) 56 | 57 | // base case 58 | rule 59 | 60 | activateValidators(.ValidatorList) => . 61 | ... 62 | 63 | 64 | endmodule 65 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/m2-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module M2-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | processValidatorActivation() => .K ... 10 | Slot 11 | 12 | 13 | Slot 14 | v(VM1 => ?VM2, VIDs) 15 | FinalizedEpoch 16 | ... 17 | 18 | ... 19 | 20 | ... 21 | 22 | requires true 23 | // types 24 | andBool Slot >=Int 0 25 | // let-bindings 26 | andBool ?Epoch ==Int epochOf(Slot) -Int 1 27 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(v(VM1, VIDs), ?Epoch))) 28 | andBool ?ActivationEpoch ==Int delayedActivationExitEpoch(?Epoch) 29 | andBool ?ValidatorsToBeActivated ==K activationQueueUptoChurnLimit(v(VM1, VIDs), FinalizedEpoch, ?Epoch) 30 | // conditions 31 | andBool ?ActivationEpoch 41 | activateValidators(Vs) => .K ... 42 | Slot 43 | 44 | 45 | Slot 46 | v(VM1 => ?VM2, VIDs) 47 | FinalizedEpoch 48 | ... 49 | 50 | ... 51 | 52 | ... 53 | 54 | requires true 55 | // types 56 | andBool Slot >=Int 0 57 | // let-bindings 58 | andBool ?Epoch ==Int epochOf(Slot) -Int 1 59 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(v(VM1, VIDs), ?Epoch))) 60 | andBool ?ActivationEpoch ==Int delayedActivationExitEpoch(?Epoch) 61 | // conditions 62 | andBool ?ActivationEpoch 9 | processValidatorActivation() => .K ... 10 | Slot 11 | 12 | 13 | Slot 14 | v(m(SM, BM, EBM, AEM, AM1 => ?AM2, EM, WM), VIDs) 15 | FinalizedEpoch 16 | ... 17 | 18 | ... 19 | 20 | ... 21 | 22 | requires true 23 | // types 24 | andBool Slot >=Int 0 25 | // let-bindings 26 | andBool ?Epoch ==Int epochOf(Slot) -Int 1 27 | andBool ?VM1 ==K m(SM, BM, EBM, AEM, AM1, EM, WM) 28 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(v(?VM1, VIDs), ?Epoch))) 29 | andBool ?ActivationEpoch ==Int delayedActivationExitEpoch(?Epoch) 30 | andBool ?ValidatorsToBeActivated ==K activationQueueUptoChurnLimit(v(?VM1, VIDs), FinalizedEpoch, ?Epoch) 31 | // pre-conditions 32 | andBool distinct(VIDs) 33 | andBool ?ActivationEpoch 43 | activateValidators(R_VIDs) => .K ... 44 | Slot 45 | 46 | 47 | Slot 48 | v(m(SM, BM, EBM, AEM, AM1 => ?AM2, EM, WM), VIDs) 49 | FinalizedEpoch 50 | ... 51 | 52 | ... 53 | 54 | ... 55 | 56 | requires true 57 | // types 58 | andBool Slot >=Int 0 59 | // let-bindings 60 | andBool ?Epoch ==Int epochOf(Slot) -Int 1 61 | andBool ?VM1 ==K m(SM, BM, EBM, AEM, AM1, EM, WM) 62 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(v(?VM1, VIDs), ?Epoch))) 63 | andBool ?ActivationEpoch ==Int delayedActivationExitEpoch(?Epoch) 64 | // pre-conditions 65 | andBool distinct(R_VIDs) 66 | andBool forall(x, R_VIDs, isValidValidatorToActivate(x, ?VM1, FinalizedEpoch)) 67 | andBool forall(x, R_VIDs, x in VIDs) 68 | andBool ?ActivationEpoch 78 | activateValidatorsAux(L_VIDs, R_VIDs, m(SM, BM, EBM, AEM, AM0, EM, WM)) => .K ... 79 | Slot 80 | 81 | 82 | Slot 83 | v(m(SM, BM, EBM, AEM, AM1 => ?AM2, EM, WM), VIDs) 84 | FinalizedEpoch 85 | ... 86 | 87 | ... 88 | 89 | ... 90 | 91 | requires true 92 | // types 93 | andBool Slot >=Int 0 94 | // let-bindings 95 | andBool ?Epoch ==Int epochOf(Slot) -Int 1 96 | andBool ?VM0 ==K m(SM, BM, EBM, AEM, AM0, EM, WM) 97 | andBool ?VM1 ==K m(SM, BM, EBM, AEM, AM1, EM, WM) 98 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(v(?VM1, VIDs), ?Epoch))) 99 | andBool ?ActivationEpoch ==Int delayedActivationExitEpoch(?Epoch) 100 | // pre-conditions 101 | andBool distinct(R_VIDs) 102 | andBool ?ActivationEpoch = x 0)) 12 | (assert (>= y 0)) 13 | (assert (>= z 0)) 14 | (assert (>= n 0)) 15 | 16 | (assert (>= b 0)) 17 | (assert (>= a 0)) 18 | (assert (>= t 0)) 19 | (assert (>= d 0)) 20 | 21 | ; rule getBaseReward(EffectiveBalance, TotalActiveBalance) 22 | ; => EffectiveBalance *Int BASE_REWARD_FACTOR 23 | ; /Int sqrtInt(TotalActiveBalance) 24 | ; /Int BASE_REWARDS_PER_EPOCH 25 | (define-fun getBaseReward ((b Int) (sqrt_t Int)) Int (div (div (* b 64) sqrt_t) 4)) 26 | 27 | (declare-const sqrt_t Int) 28 | (assert (>= sqrt_t 0)) 29 | 30 | (push) 31 | ; rule getBaseReward(B, T) <=Int B => true requires B >=Int 0 andBool T >=Int 256 32 | (assert (not (=> 33 | (and 34 | (>= (^ sqrt_t 2) 256) 35 | ) 36 | (<= (getBaseReward b sqrt_t) b) 37 | ))) 38 | (check-sat) 39 | (pop) 40 | 41 | (push) 42 | ; rule getBaseReward(B, T) >=Int 0 => true requires B >=Int 0 andBool T >=Int 1 43 | (assert (not (=> 44 | (and 45 | (>= (^ sqrt_t 2) 1) 46 | ) 47 | (>= (getBaseReward b sqrt_t) 0) 48 | ))) 49 | (check-sat) 50 | (pop) 51 | 52 | ; rule getMatchingReward(BaseReward, AttestingBalance, TotalActiveBalance) 53 | ; => BaseReward *Int (AttestingBalance /Int EFFECTIVE_BALANCE_INCREMENT) 54 | ; /Int (TotalActiveBalance /Int EFFECTIVE_BALANCE_INCREMENT) 55 | (define-const c Int (^ 10 9)) 56 | (define-fun getMatchingReward ((b Int) (a Int) (t Int)) Int (div (* b (div a c)) (div t c))) 57 | 58 | (push) 59 | ; rule getMatchingReward(B, A, T) <=Int B => true requires B >=Int 0 andBool A >=Int 0 andBool T >=Int EFFECTIVE_BALANCE_INCREMENT andBool A <=Int T 60 | (assert (not (=> 61 | (and 62 | (>= t c) 63 | (<= a t) 64 | ) 65 | (<= (getMatchingReward b a t) b) 66 | ))) 67 | (check-sat) 68 | (pop) 69 | 70 | (push) 71 | ; rule getMatchingReward(B, A, T) >=Int 0 => true requires B >=Int 0 andBool A >=Int 0 andBool T >=Int EFFECTIVE_BALANCE_INCREMENT 72 | (assert (not (=> 73 | (and 74 | (>= t c) 75 | ) 76 | (>= (getMatchingReward b a t) 0) 77 | ))) 78 | (check-sat) 79 | (pop) 80 | 81 | ; rule getInclusionReward(BaseReward, InclusionDelay) 82 | ; => (BaseReward -Int BaseReward /Int PROPOSER_REWARD_QUOTIENT) /Int InclusionDelay 83 | (define-fun getInclusionReward ((b Int) (d Int)) Int (div (- b (div b 8)) d)) 84 | 85 | (push) 86 | ; rule getInclusionReward(B, D) <=Int B => true requires B >=Int 0 andBool D >=Int 1 87 | (assert (not (=> 88 | (and 89 | (>= d 1) 90 | ) 91 | (<= (getInclusionReward b d) b) 92 | ))) 93 | (check-sat) 94 | (pop) 95 | 96 | (push) 97 | ; rule getInclusionReward(B, D) >=Int 0 => true requires B >=Int 0 andBool D >=Int 1 98 | (assert (not (=> 99 | (and 100 | (>= d 1) 101 | ) 102 | (>= (getInclusionReward b d) 0) 103 | ))) 104 | (check-sat) 105 | (pop) 106 | 107 | ; rule getInactivityPenalty(EffectiveBalance, FinalityDelay) 108 | ; => EffectiveBalance *Int FinalityDelay /Int INACTIVITY_PENALTY_QUOTIENT 109 | (define-fun getInactivityPenalty ((b Int) (d Int)) Int (div (* b d) (^ 2 25))) 110 | 111 | (push) 112 | ; rule getInactivityPenalty(B, D) >=Int 0 => true requires B >=Int 0 andBool D >=Int 0 113 | (assert (not (=> 114 | (and 115 | true 116 | ) 117 | (>= (getInactivityPenalty b d) 0) 118 | ))) 119 | (check-sat) 120 | (pop) 121 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/n1-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module N1-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | processRewardPenalty(V, ?Epoch, ?FinalityDelay, ?BaseReward, 10 | ?SourceAttestations, ?TargetAttestations, ?HeadAttestations, 11 | ?SourceAttestingBalance, ?TargetAttestingBalance, ?HeadAttestingBalance, ?TotalActiveBalance) => . 12 | Slot 13 | 14 | 15 | Slot 16 | v(VM1 => ?VM2, VIDs) 17 | 18 | Epoch |-> Attestations:Attestations 19 | ... 20 | 21 | LastFinalizedEpoch 22 | ... 23 | 24 | 25 | firstSlotOf(Epoch) 26 | (_, EpochBoundaryBlock) 27 | ... 28 | 29 | BM 30 | ... 31 | 32 | ... 33 | 34 | requires true 35 | 36 | andBool ( isActiveValidator(V, ?Epoch) orBool ( V.slashed andBool ?Epoch +Int 1 =Int 1) 43 | 44 | // types 45 | andBool Slot >=Int 0 46 | andBool ?Epoch >=Int 0 47 | andBool ?FinalityDelay >=Int 0 48 | andBool ?BaseReward >=Int 0 49 | andBool ?SourceAttestingBalance >=Int 0 50 | andBool ?TargetAttestingBalance >=Int 0 51 | andBool ?HeadAttestingBalance >=Int 0 52 | andBool ?TotalActiveBalance >=Int 0 53 | // let-bindings 54 | andBool ?Epoch ==Int epochOf(Slot) -Int 2 55 | andBool ?FinalityDelay ==Int ?Epoch -Int LastFinalizedEpoch 56 | andBool ?BaseReward ==Int getBaseReward(V, ?TotalActiveBalance) 57 | andBool ?SourceAttestations ==K filterNotSlashed(VM1, Attestations) 58 | andBool ?TargetAttestations ==K filterByTarget(EpochBoundaryBlock, ?SourceAttestations) 59 | andBool ?HeadAttestations ==K filterByHead(BM, ?TargetAttestations) 60 | andBool ?SourceAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?SourceAttestations))) 61 | andBool ?TargetAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?TargetAttestations))) 62 | andBool ?HeadAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?HeadAttestations))) 63 | andBool ?TotalActiveBalance ==Int lift(totalBalance(VM1, activeValidators(v(VM1,VIDs), ?Epoch))) 64 | // conditions 65 | andBool ?Epoch >=Int 2 66 | // invariants 67 | andBool ?SourceAttestingBalance <=Int ?TotalActiveBalance 68 | andBool ?TargetAttestingBalance <=Int ?TotalActiveBalance 69 | andBool ?HeadAttestingBalance <=Int ?TotalActiveBalance 70 | // consistency conditions 71 | andBool V.id in VIDs andBool VM1[V.id]v ==K V 72 | andBool implies(V.id inA ?SourceAttestations, minByInclusionDelay(V.id, ?SourceAttestations).proposer in VIDs) 73 | ensures true 74 | // ensures 75 | 76 | andBool ?VM2[V.id]v.balance <=Int VM1[V.id]v.balance +Int ?BaseReward +Int ?BaseReward +Int ?BaseReward +Int ?BaseReward 77 | 78 | andBool ?VM2[V.id]v.balance ==Int VM1[V.id]v.balance +Int (?BaseReward *Int (?SourceAttestingBalance /Int EFFECTIVE_BALANCE_INCREMENT) 79 | /Int (?TotalActiveBalance /Int EFFECTIVE_BALANCE_INCREMENT)) 80 | +Int (?BaseReward *Int (?TargetAttestingBalance /Int EFFECTIVE_BALANCE_INCREMENT) 81 | /Int (?TotalActiveBalance /Int EFFECTIVE_BALANCE_INCREMENT)) 82 | +Int (?BaseReward *Int (?HeadAttestingBalance /Int EFFECTIVE_BALANCE_INCREMENT) 83 | /Int (?TotalActiveBalance /Int EFFECTIVE_BALANCE_INCREMENT)) 84 | +Int ((?BaseReward -Int ?BaseReward /Int PROPOSER_REWARD_QUOTIENT) /Int minByInclusionDelay(V.id, ?SourceAttestations).inclusion_delay) 85 | 86 | endmodule 87 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/n2-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module N2-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | processRewardPenalty(V, ?Epoch, ?FinalityDelay, ?BaseReward, 10 | ?SourceAttestations, ?TargetAttestations, ?HeadAttestations, 11 | ?SourceAttestingBalance, ?TargetAttestingBalance, ?HeadAttestingBalance, ?TotalActiveBalance) => . 12 | Slot 13 | 14 | 15 | Slot 16 | v(VM1 => ?VM2, VIDs) 17 | 18 | Epoch |-> Attestations:Attestations 19 | ... 20 | 21 | LastFinalizedEpoch 22 | ... 23 | 24 | 25 | firstSlotOf(Epoch) 26 | (_, EpochBoundaryBlock) 27 | ... 28 | 29 | BM 30 | ... 31 | 32 | ... 33 | 34 | requires true 35 | 36 | andBool ( isActiveValidator(V, ?Epoch) orBool ( V.slashed andBool ?Epoch +Int 1 =Int 1) 43 | 44 | // types 45 | andBool Slot >=Int 0 46 | andBool ?Epoch >=Int 0 47 | andBool ?FinalityDelay >=Int 0 48 | andBool ?BaseReward >=Int 0 49 | andBool ?SourceAttestingBalance >=Int 0 50 | andBool ?TargetAttestingBalance >=Int 0 51 | andBool ?HeadAttestingBalance >=Int 0 52 | andBool ?TotalActiveBalance >=Int 0 53 | // let-bindings 54 | andBool ?Epoch ==Int epochOf(Slot) -Int 2 55 | andBool ?FinalityDelay ==Int ?Epoch -Int LastFinalizedEpoch 56 | andBool ?BaseReward ==Int getBaseReward(V, ?TotalActiveBalance) 57 | andBool ?SourceAttestations ==K filterNotSlashed(VM1, Attestations) 58 | andBool ?TargetAttestations ==K filterByTarget(EpochBoundaryBlock, ?SourceAttestations) 59 | andBool ?HeadAttestations ==K filterByHead(BM, ?TargetAttestations) 60 | andBool ?SourceAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?SourceAttestations))) 61 | andBool ?TargetAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?TargetAttestations))) 62 | andBool ?HeadAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?HeadAttestations))) 63 | andBool ?TotalActiveBalance ==Int lift(totalBalance(VM1, activeValidators(v(VM1,VIDs), ?Epoch))) 64 | // conditions 65 | andBool ?Epoch >=Int 2 66 | // invariants 67 | andBool ?SourceAttestingBalance <=Int ?TotalActiveBalance 68 | andBool ?TargetAttestingBalance <=Int ?TotalActiveBalance 69 | andBool ?HeadAttestingBalance <=Int ?TotalActiveBalance 70 | // consistency conditions 71 | andBool V.id in VIDs andBool VM1[V.id]v ==K V 72 | andBool implies(V.id inA ?SourceAttestations, minByInclusionDelay(V.id, ?SourceAttestations).proposer in VIDs) 73 | ensures true 74 | // ensures 75 | 76 | andBool ?VM2[V.id]v.balance ==Int VM1[V.id]v.balance -Int ?BaseReward *Int 3 77 | 78 | endmodule 79 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/n3-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module N3-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | processRewardPenalty(V, ?Epoch, ?FinalityDelay, ?BaseReward, 10 | ?SourceAttestations, ?TargetAttestations, ?HeadAttestations, 11 | ?SourceAttestingBalance, ?TargetAttestingBalance, ?HeadAttestingBalance, ?TotalActiveBalance) => . 12 | Slot 13 | 14 | 15 | Slot 16 | v(VM1 => ?VM2, VIDs) 17 | 18 | Epoch |-> Attestations:Attestations 19 | ... 20 | 21 | LastFinalizedEpoch 22 | ... 23 | 24 | 25 | firstSlotOf(Epoch) 26 | (_, EpochBoundaryBlock) 27 | ... 28 | 29 | BM 30 | ... 31 | 32 | ... 33 | 34 | requires true 35 | 36 | andBool ( isActiveValidator(V, ?Epoch) orBool ( V.slashed andBool ?Epoch +Int 1 Int MIN_EPOCHS_TO_INACTIVITY_PENALTY 41 | andBool implies(V.id inA ?SourceAttestations, V.id =/=Int minByInclusionDelay(V.id, ?SourceAttestations).proposer) 42 | andBool implies(V.id inA ?SourceAttestations, minByInclusionDelay(V.id, ?SourceAttestations).inclusion_delay >=Int 1) 43 | 44 | // types 45 | andBool Slot >=Int 0 46 | andBool ?Epoch >=Int 0 47 | andBool ?FinalityDelay >=Int 0 48 | andBool ?BaseReward >=Int 0 49 | andBool ?SourceAttestingBalance >=Int 0 50 | andBool ?TargetAttestingBalance >=Int 0 51 | andBool ?HeadAttestingBalance >=Int 0 52 | andBool ?TotalActiveBalance >=Int 0 53 | // let-bindings 54 | andBool ?Epoch ==Int epochOf(Slot) -Int 2 55 | andBool ?FinalityDelay ==Int ?Epoch -Int LastFinalizedEpoch 56 | andBool ?BaseReward ==Int getBaseReward(V, ?TotalActiveBalance) 57 | andBool ?SourceAttestations ==K filterNotSlashed(VM1, Attestations) 58 | andBool ?TargetAttestations ==K filterByTarget(EpochBoundaryBlock, ?SourceAttestations) 59 | andBool ?HeadAttestations ==K filterByHead(BM, ?TargetAttestations) 60 | andBool ?SourceAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?SourceAttestations))) 61 | andBool ?TargetAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?TargetAttestations))) 62 | andBool ?HeadAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?HeadAttestations))) 63 | andBool ?TotalActiveBalance ==Int lift(totalBalance(VM1, activeValidators(v(VM1,VIDs), ?Epoch))) 64 | // conditions 65 | andBool ?Epoch >=Int 2 66 | // invariants 67 | andBool ?SourceAttestingBalance <=Int ?TotalActiveBalance 68 | andBool ?TargetAttestingBalance <=Int ?TotalActiveBalance 69 | andBool ?HeadAttestingBalance <=Int ?TotalActiveBalance 70 | // consistency conditions 71 | andBool V.id in VIDs andBool VM1[V.id]v ==K V 72 | andBool implies(V.id inA ?SourceAttestations, minByInclusionDelay(V.id, ?SourceAttestations).proposer in VIDs) 73 | ensures true 74 | // ensures 75 | 76 | andBool ?VM2[V.id]v.balance <=Int VM1[V.id]v.balance +Int ?BaseReward +Int ?BaseReward +Int ?BaseReward +Int ?BaseReward +Int (0 -Int BASE_REWARDS_PER_EPOCH *Int ?BaseReward) 77 | 78 | andBool ?VM2[V.id]v.balance ==Int VM1[V.id]v.balance +Int (?BaseReward *Int (?SourceAttestingBalance /Int EFFECTIVE_BALANCE_INCREMENT) 79 | /Int (?TotalActiveBalance /Int EFFECTIVE_BALANCE_INCREMENT)) 80 | +Int (?BaseReward *Int (?TargetAttestingBalance /Int EFFECTIVE_BALANCE_INCREMENT) 81 | /Int (?TotalActiveBalance /Int EFFECTIVE_BALANCE_INCREMENT)) 82 | +Int (?BaseReward *Int (?HeadAttestingBalance /Int EFFECTIVE_BALANCE_INCREMENT) 83 | /Int (?TotalActiveBalance /Int EFFECTIVE_BALANCE_INCREMENT)) 84 | +Int ((?BaseReward -Int ?BaseReward /Int PROPOSER_REWARD_QUOTIENT) /Int minByInclusionDelay(V.id, ?SourceAttestations).inclusion_delay) 85 | +Int (0 -Int BASE_REWARDS_PER_EPOCH *Int ?BaseReward) 86 | 87 | endmodule 88 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/n4-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module N4-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | processRewardPenalty(V, ?Epoch, ?FinalityDelay, ?BaseReward, 10 | ?SourceAttestations, ?TargetAttestations, ?HeadAttestations, 11 | ?SourceAttestingBalance, ?TargetAttestingBalance, ?HeadAttestingBalance, ?TotalActiveBalance) => . 12 | Slot 13 | 14 | 15 | Slot 16 | v(VM1 => ?VM2, VIDs) 17 | 18 | Epoch |-> Attestations:Attestations 19 | ... 20 | 21 | LastFinalizedEpoch 22 | ... 23 | 24 | 25 | firstSlotOf(Epoch) 26 | (_, EpochBoundaryBlock) 27 | ... 28 | 29 | BM 30 | ... 31 | 32 | ... 33 | 34 | requires true 35 | 36 | andBool ( isActiveValidator(V, ?Epoch) orBool ( V.slashed andBool ?Epoch +Int 1 Int MIN_EPOCHS_TO_INACTIVITY_PENALTY 41 | andBool implies(V.id inA ?SourceAttestations, V.id =/=Int minByInclusionDelay(V.id, ?SourceAttestations).proposer) 42 | andBool implies(V.id inA ?SourceAttestations, minByInclusionDelay(V.id, ?SourceAttestations).inclusion_delay >=Int 1) 43 | 44 | // types 45 | andBool Slot >=Int 0 46 | andBool ?Epoch >=Int 0 47 | andBool ?FinalityDelay >=Int 0 48 | andBool ?BaseReward >=Int 0 49 | andBool ?SourceAttestingBalance >=Int 0 50 | andBool ?TargetAttestingBalance >=Int 0 51 | andBool ?HeadAttestingBalance >=Int 0 52 | andBool ?TotalActiveBalance >=Int 0 53 | // let-bindings 54 | andBool ?Epoch ==Int epochOf(Slot) -Int 2 55 | andBool ?FinalityDelay ==Int ?Epoch -Int LastFinalizedEpoch 56 | andBool ?BaseReward ==Int getBaseReward(V, ?TotalActiveBalance) 57 | andBool ?SourceAttestations ==K filterNotSlashed(VM1, Attestations) 58 | andBool ?TargetAttestations ==K filterByTarget(EpochBoundaryBlock, ?SourceAttestations) 59 | andBool ?HeadAttestations ==K filterByHead(BM, ?TargetAttestations) 60 | andBool ?SourceAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?SourceAttestations))) 61 | andBool ?TargetAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?TargetAttestations))) 62 | andBool ?HeadAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?HeadAttestations))) 63 | andBool ?TotalActiveBalance ==Int lift(totalBalance(VM1, activeValidators(v(VM1,VIDs), ?Epoch))) 64 | // conditions 65 | andBool ?Epoch >=Int 2 66 | // invariants 67 | andBool ?SourceAttestingBalance <=Int ?TotalActiveBalance 68 | andBool ?TargetAttestingBalance <=Int ?TotalActiveBalance 69 | andBool ?HeadAttestingBalance <=Int ?TotalActiveBalance 70 | // consistency conditions 71 | andBool V.id in VIDs andBool VM1[V.id]v ==K V 72 | andBool implies(V.id inA ?SourceAttestations, minByInclusionDelay(V.id, ?SourceAttestations).proposer in VIDs) 73 | ensures true 74 | // ensures 75 | 76 | andBool ?VM2[V.id]v.balance ==Int VM1[V.id]v.balance -Int ?BaseReward *Int 7 77 | -Int V.effective_balance *Int ?FinalityDelay /Int INACTIVITY_PENALTY_QUOTIENT 78 | 79 | endmodule 80 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/n5-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module N5-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | processRewardPenalty(V, ?Epoch, ?FinalityDelay, ?BaseReward, 10 | ?SourceAttestations, ?TargetAttestations, ?HeadAttestations, 11 | ?SourceAttestingBalance, ?TargetAttestingBalance, ?HeadAttestingBalance, ?TotalActiveBalance) => . 12 | Slot 13 | 14 | 15 | Slot 16 | v(VM1 => ?VM2, VIDs) 17 | 18 | Epoch |-> Attestations:Attestations 19 | ... 20 | 21 | LastFinalizedEpoch 22 | ... 23 | 24 | 25 | firstSlotOf(Epoch) 26 | (_, EpochBoundaryBlock) 27 | ... 28 | 29 | BM 30 | ... 31 | 32 | ... 33 | 34 | requires true 35 | 36 | andBool ( isActiveValidator(V, ?Epoch) orBool ( V.slashed andBool ?Epoch +Int 1 =Int 1) 40 | 41 | // types 42 | andBool Slot >=Int 0 43 | andBool ?Epoch >=Int 0 44 | andBool ?FinalityDelay >=Int 0 45 | andBool ?BaseReward >=Int 0 46 | andBool ?SourceAttestingBalance >=Int 0 47 | andBool ?TargetAttestingBalance >=Int 0 48 | andBool ?HeadAttestingBalance >=Int 0 49 | andBool ?TotalActiveBalance >=Int 0 50 | // let-bindings 51 | andBool ?Epoch ==Int epochOf(Slot) -Int 2 52 | andBool ?FinalityDelay ==Int ?Epoch -Int LastFinalizedEpoch 53 | andBool ?BaseReward ==Int getBaseReward(V, ?TotalActiveBalance) 54 | andBool ?SourceAttestations ==K filterNotSlashed(VM1, Attestations) 55 | andBool ?TargetAttestations ==K filterByTarget(EpochBoundaryBlock, ?SourceAttestations) 56 | andBool ?HeadAttestations ==K filterByHead(BM, ?TargetAttestations) 57 | andBool ?SourceAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?SourceAttestations))) 58 | andBool ?TargetAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?TargetAttestations))) 59 | andBool ?HeadAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?HeadAttestations))) 60 | andBool ?TotalActiveBalance ==Int lift(totalBalance(VM1, activeValidators(v(VM1,VIDs), ?Epoch))) 61 | // conditions 62 | andBool ?Epoch >=Int 2 63 | // invariants 64 | andBool ?SourceAttestingBalance <=Int ?TotalActiveBalance 65 | andBool ?TargetAttestingBalance <=Int ?TotalActiveBalance 66 | andBool ?HeadAttestingBalance <=Int ?TotalActiveBalance 67 | // consistency conditions 68 | andBool V.id in VIDs andBool VM1[V.id]v ==K V 69 | andBool implies(V.id inA ?SourceAttestations, minByInclusionDelay(V.id, ?SourceAttestations).proposer in VIDs) 70 | ensures true 71 | // ensures 72 | 73 | andBool ?VM2[V.id]v.balance <=Int VM1[V.id]v.balance +Int ?BaseReward +Int ?BaseReward +Int ?BaseReward +Int ?BaseReward 74 | andBool ?VM2[V.id]v.balance >=Int VM1[V.id]v.balance +Int (0 -Int ?BaseReward) +Int (0 -Int ?BaseReward) +Int (0 -Int ?BaseReward) 75 | 76 | endmodule 77 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/n6-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module N6-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | processRewardPenalty(V, ?Epoch, ?FinalityDelay, ?BaseReward, 10 | ?SourceAttestations, ?TargetAttestations, ?HeadAttestations, 11 | ?SourceAttestingBalance, ?TargetAttestingBalance, ?HeadAttestingBalance, ?TotalActiveBalance) => . 12 | Slot 13 | 14 | 15 | Slot 16 | v(VM1 => ?VM2, VIDs) 17 | 18 | Epoch |-> Attestations:Attestations 19 | ... 20 | 21 | LastFinalizedEpoch 22 | ... 23 | 24 | 25 | firstSlotOf(Epoch) 26 | (_, EpochBoundaryBlock) 27 | ... 28 | 29 | BM 30 | ... 31 | 32 | ... 33 | 34 | requires true 35 | 36 | andBool ( isActiveValidator(V, ?Epoch) orBool ( V.slashed andBool ?Epoch +Int 1 Int MIN_EPOCHS_TO_INACTIVITY_PENALTY 38 | andBool implies(V.id inA ?SourceAttestations, V.id =/=Int minByInclusionDelay(V.id, ?SourceAttestations).proposer) 39 | andBool implies(V.id inA ?SourceAttestations, minByInclusionDelay(V.id, ?SourceAttestations).inclusion_delay >=Int 1) 40 | 41 | // types 42 | andBool Slot >=Int 0 43 | andBool ?Epoch >=Int 0 44 | andBool ?FinalityDelay >=Int 0 45 | andBool ?BaseReward >=Int 0 46 | andBool ?SourceAttestingBalance >=Int 0 47 | andBool ?TargetAttestingBalance >=Int 0 48 | andBool ?HeadAttestingBalance >=Int 0 49 | andBool ?TotalActiveBalance >=Int 0 50 | // let-bindings 51 | andBool ?Epoch ==Int epochOf(Slot) -Int 2 52 | andBool ?FinalityDelay ==Int ?Epoch -Int LastFinalizedEpoch 53 | andBool ?BaseReward ==Int getBaseReward(V, ?TotalActiveBalance) 54 | andBool ?SourceAttestations ==K filterNotSlashed(VM1, Attestations) 55 | andBool ?TargetAttestations ==K filterByTarget(EpochBoundaryBlock, ?SourceAttestations) 56 | andBool ?HeadAttestations ==K filterByHead(BM, ?TargetAttestations) 57 | andBool ?SourceAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?SourceAttestations))) 58 | andBool ?TargetAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?TargetAttestations))) 59 | andBool ?HeadAttestingBalance ==Int lift(totalBalance(VM1, getValidators(?HeadAttestations))) 60 | andBool ?TotalActiveBalance ==Int lift(totalBalance(VM1, activeValidators(v(VM1,VIDs), ?Epoch))) 61 | // conditions 62 | andBool ?Epoch >=Int 2 63 | // invariants 64 | andBool ?SourceAttestingBalance <=Int ?TotalActiveBalance 65 | andBool ?TargetAttestingBalance <=Int ?TotalActiveBalance 66 | andBool ?HeadAttestingBalance <=Int ?TotalActiveBalance 67 | // consistency conditions 68 | andBool V.id in VIDs andBool VM1[V.id]v ==K V 69 | andBool implies(V.id inA ?SourceAttestations, minByInclusionDelay(V.id, ?SourceAttestations).proposer in VIDs) 70 | ensures true 71 | // ensures 72 | 73 | andBool ?VM2[V.id]v.balance <=Int VM1[V.id]v.balance +Int ?BaseReward +Int ?BaseReward +Int ?BaseReward +Int ?BaseReward 74 | +Int (0 -Int BASE_REWARDS_PER_EPOCH *Int ?BaseReward) 75 | +Int #if V.id inA ?TargetAttestations 76 | #then 0 77 | #else (0 -Int V.effective_balance *Int ?FinalityDelay /Int INACTIVITY_PENALTY_QUOTIENT) 78 | #fi 79 | 80 | andBool ?VM2[V.id]v.balance >=Int VM1[V.id]v.balance +Int (0 -Int ?BaseReward) +Int (0 -Int ?BaseReward) +Int (0 -Int ?BaseReward) 81 | +Int (0 -Int BASE_REWARDS_PER_EPOCH *Int ?BaseReward) 82 | +Int #if V.id inA ?TargetAttestations 83 | #then 0 84 | #else (0 -Int V.effective_balance *Int ?FinalityDelay /Int INACTIVITY_PENALTY_QUOTIENT) 85 | #fi 86 | 87 | endmodule 88 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/n7-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module N7-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | processRewardPenalty(VID, m(SM, BM1, EBM, AEM, AM, EM, WM), ?Epoch, ?FinalityDelay, ?BaseReward, 10 | ?SourceAttestations, ?TargetAttestations, ?HeadAttestations, 11 | ?SourceAttestingBalance, ?TargetAttestingBalance, ?HeadAttestingBalance, ?TotalActiveBalance) => .K ... 12 | Slot 13 | 14 | 15 | Slot 16 | v(m(SM, BM1 => ?BM2, EBM, AEM, AM, EM, WM), VIDs) 17 | 18 | ?Epoch |-> Attestations:Attestations 19 | ... 20 | 21 | LastFinalizedEpoch 22 | ... 23 | 24 | 25 | firstSlotOf(?Epoch) 26 | (_, EpochBoundaryBlock) 27 | ... 28 | 29 | ... 30 | 31 | BM 32 | ... 33 | 34 | requires true 35 | 36 | andBool implies(VID inA ?SourceAttestations, VID =/=Int minByInclusionDelay(VID, ?SourceAttestations).proposer) 37 | 38 | // types 39 | andBool Slot >=Int 0 40 | andBool ?Epoch >=Int 0 41 | andBool ?FinalityDelay >=Int 0 42 | andBool ?BaseReward >=Int 0 43 | andBool ?SourceAttestingBalance >=Int 0 44 | andBool ?TargetAttestingBalance >=Int 0 45 | andBool ?HeadAttestingBalance >=Int 0 46 | andBool ?TotalActiveBalance >=Int 0 47 | // let-bindings 48 | andBool ?Epoch ==Int epochOf(Slot) -Int 2 49 | andBool ?VM1 ==K m(SM, BM1, EBM, AEM, AM, EM, WM) 50 | andBool ?FinalityDelay ==Int ?Epoch -Int LastFinalizedEpoch 51 | andBool ?BaseReward ==Int getBaseReward(EBM[VID]i, ?TotalActiveBalance) 52 | andBool ?SourceAttestations ==K filterNotSlashed(?VM1, Attestations) 53 | andBool ?TargetAttestations ==K filterByTarget(EpochBoundaryBlock, ?SourceAttestations) 54 | andBool ?HeadAttestations ==K filterByHead(BM, ?TargetAttestations) 55 | andBool ?SourceAttestingBalance ==Int lift(totalBalance(?VM1, getValidators(?SourceAttestations))) 56 | andBool ?TargetAttestingBalance ==Int lift(totalBalance(?VM1, getValidators(?TargetAttestations))) 57 | andBool ?HeadAttestingBalance ==Int lift(totalBalance(?VM1, getValidators(?HeadAttestations))) 58 | andBool ?TotalActiveBalance ==Int lift(totalBalance(?VM1, activeValidators(v(?VM1, VIDs), ?Epoch))) 59 | // pre-conditions 60 | andBool ?Epoch >=Int 2 61 | andBool EBM[VID]i >=Int 0 62 | andBool implies(VID inA ?SourceAttestations, minByInclusionDelay(VID, ?SourceAttestations).inclusion_delay >=Int 1) 63 | andBool implies(VID inA ?SourceAttestations, minByInclusionDelay(VID, ?SourceAttestations).proposer in VIDs) 64 | andBool ?SourceAttestingBalance <=Int ?TotalActiveBalance 65 | andBool ?TargetAttestingBalance <=Int ?TotalActiveBalance 66 | andBool ?HeadAttestingBalance <=Int ?TotalActiveBalance 67 | andBool VID in VIDs // andBool VM1[V.id]v ==K V 68 | ensures true 69 | // ensures 70 | 71 | andBool implies( 72 | notBool ( isActiveValidator(VID, ?VM1, ?Epoch) orBool ( SM[VID]b andBool ?Epoch +Int 1 =Int BM1[VID]i -Int (3 *Int ?BaseReward) 89 | ) 90 | andBool 91 | implies( 92 | // inactive case 93 | ?FinalityDelay >Int MIN_EPOCHS_TO_INACTIVITY_PENALTY 94 | , 95 | // max: + 0 96 | ?BM2[VID]i <=Int BM1[VID]i 97 | andBool 98 | // min: - 7 * BaseReward - (EffectiveBalance * FinalityDelay / 33,554,432) 99 | ?BM2[VID]i >=Int BM1[VID]i -Int (7 *Int ?BaseReward) -Int getInactivityPenalty(EBM[VID]i, ?FinalityDelay) 100 | ) 101 | ) 102 | 103 | // max: + 4 * BaseReward 104 | andBool ?BM2[VID]i <=Int BM1[VID]i +Int (4 *Int ?BaseReward) 105 | 106 | // min: - 7 * BaseReward - (EffectiveBalance * FinalityDelay / 33,554,432) 107 | andBool ?BM2[VID]i >=Int BM1[VID]i -Int (7 *Int ?BaseReward) -Int getInactivityPenalty(EBM[VID]i, ?FinalityDelay) 108 | 109 | endmodule 110 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/n8-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module N8-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | processRewardsPenaltiesAux3(L_VIDs, R_VIDs, m(SM, BM0, EBM, AEM, AM, EM, WM), ?Epoch, ?FinalityDelay, 10 | ?SourceAttestations, ?TargetAttestations, ?HeadAttestations, 11 | ?SourceAttestingBalance, ?TargetAttestingBalance, ?HeadAttestingBalance, ?TotalActiveBalance) => .K ... 12 | Slot 13 | 14 | 15 | Slot 16 | v(m(SM, BM1 => ?BM2, EBM, AEM, AM, EM, WM), VIDs) 17 | 18 | ?Epoch |-> Attestations:Attestations 19 | ... 20 | 21 | LastFinalizedEpoch 22 | ... 23 | 24 | 25 | firstSlotOf(?Epoch) 26 | (_, EpochBoundaryBlock) 27 | ... 28 | 29 | ... 30 | 31 | BM 32 | ... 33 | 34 | requires true 35 | // types 36 | andBool Slot >=Int 0 37 | andBool ?Epoch >=Int 0 38 | andBool ?FinalityDelay >=Int 0 39 | andBool ?SourceAttestingBalance >=Int 0 40 | andBool ?TargetAttestingBalance >=Int 0 41 | andBool ?HeadAttestingBalance >=Int 0 42 | andBool ?TotalActiveBalance >=Int 0 43 | // let-bindings 44 | andBool ?Epoch ==Int epochOf(Slot) -Int 2 45 | andBool ?VM0 ==K m(SM, BM0, EBM, AEM, AM, EM, WM) 46 | andBool ?VM1 ==K m(SM, BM1, EBM, AEM, AM, EM, WM) 47 | andBool ?FinalityDelay ==Int ?Epoch -Int LastFinalizedEpoch 48 | andBool ?SourceAttestations ==K filterNotSlashed(?VM0, Attestations) 49 | andBool ?TargetAttestations ==K filterByTarget(EpochBoundaryBlock, ?SourceAttestations) 50 | andBool ?HeadAttestations ==K filterByHead(BM, ?TargetAttestations) 51 | andBool ?SourceAttestingBalance ==Int lift(totalBalance(?VM0, getValidators(?SourceAttestations))) 52 | andBool ?TargetAttestingBalance ==Int lift(totalBalance(?VM0, getValidators(?TargetAttestations))) 53 | andBool ?HeadAttestingBalance ==Int lift(totalBalance(?VM0, getValidators(?HeadAttestations))) 54 | andBool ?TotalActiveBalance ==Int lift(totalBalance(?VM0, activeValidators(v(?VM0, VIDs), ?Epoch))) 55 | // pre-conditions 56 | andBool ?Epoch >=Int 2 57 | andBool forall(x, R_VIDs, EBM[x]i >=Int 0) 58 | andBool distinct(R_VIDs) 59 | andBool forall(x, R_VIDs, implies(x inA ?SourceAttestations, minByInclusionDelay(x, ?SourceAttestations).inclusion_delay >=Int 1)) 60 | andBool forall(x, R_VIDs, implies(x inA ?SourceAttestations, minByInclusionDelay(x, ?SourceAttestations).proposer in VIDs)) 61 | andBool ?SourceAttestingBalance <=Int ?TotalActiveBalance 62 | andBool ?TargetAttestingBalance <=Int ?TotalActiveBalance 63 | andBool ?HeadAttestingBalance <=Int ?TotalActiveBalance 64 | // invariants 65 | andBool disjoint(L_VIDs, R_VIDs) 66 | andBool forall(x, R_VIDs, x in VIDs) 67 | andBool forall(x, R_VIDs, BM1[x]i ==Int BM0[x]i) 68 | andBool forall(x, rev(L_VIDs), BM1[x]i <=Int BM0[x]i +Int (4 *Int getBaseReward(EBM[x]i, ?TotalActiveBalance))) 69 | andBool forall(x, rev(L_VIDs), BM1[x]i >=Int BM0[x]i -Int (7 *Int getBaseReward(EBM[x]i, ?TotalActiveBalance)) -Int getInactivityPenalty(EBM[x]i, ?FinalityDelay)) 70 | ensures true 71 | // post-conditions 72 | andBool forall(x, rev(L_VIDs) ++ R_VIDs, ?BM2[x]i <=Int BM0[x]i +Int (4 *Int getBaseReward(EBM[x]i, ?TotalActiveBalance))) 73 | andBool forall(x, rev(L_VIDs) ++ R_VIDs, ?BM2[x]i >=Int BM0[x]i -Int (7 *Int getBaseReward(EBM[x]i, ?TotalActiveBalance)) -Int getInactivityPenalty(EBM[x]i, ?FinalityDelay)) 74 | 75 | endmodule 76 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/o1-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module O1-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | updateActivationEligibilitiesAux(L_VIDs, R_VIDs, m(SM, BM, EBM, AEM0, AM, EM, WM)) => .K ... 10 | Slot 11 | 12 | 13 | Slot 14 | v(m(SM, BM, EBM, AEM1 => ?AEM2, AM, EM, WM), VIDs) 15 | ... 16 | 17 | ... 18 | 19 | ... 20 | 21 | requires true 22 | // types 23 | andBool Slot >=Int 0 24 | // let-bindings 25 | andBool ?Epoch ==Int epochOf(Slot) 26 | andBool ?VM0 ==K m(SM, BM, EBM, AEM0, AM, EM, WM) 27 | // pre-conditions 28 | andBool distinct(R_VIDs) 29 | // invariants 30 | andBool disjoint(L_VIDs, R_VIDs) 31 | andBool forall(x, R_VIDs, x in VIDs) 32 | andBool forall(x, R_VIDs, AEM1[x]i ==K AEM0[x]i) 33 | andBool forall(x, rev(L_VIDs), AEM1[x]i ==Int #if isActivationEligible(x, ?VM0) #then ?Epoch #else AEM0[x]i #fi) 34 | ensures true 35 | // post-conditions 36 | andBool forall(x, rev(L_VIDs) ++ R_VIDs, ?AEM2[x]i ==Int #if isActivationEligible(x, ?VM0) #then ?Epoch #else AEM0[x]i #fi) 37 | 38 | endmodule 39 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/o2-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | require "o1-spec.k" 3 | 4 | module O2-SPEC 5 | 6 | imports VERIFICATION 7 | imports O1-SPEC 8 | 9 | rule 10 | 11 | updateActivationEligibilities(VIDs) => .K ... 12 | Slot 13 | 14 | 15 | Slot 16 | v(m(SM, BM, EBM, AEM1 => ?AEM2, AM, EM, WM), VIDs) 17 | ... 18 | 19 | ... 20 | 21 | ... 22 | 23 | requires true 24 | // types 25 | andBool Slot >=Int 0 26 | // let-bindings 27 | andBool ?Epoch ==Int epochOf(Slot) 28 | andBool ?VM1 ==K m(SM, BM, EBM, AEM1, AM, EM, WM) 29 | // pre-conditions 30 | andBool distinct(VIDs) 31 | // invariants 32 | ensures true 33 | // post-conditions 34 | andBool forall(x, VIDs, ?AEM2[x]i ==Int #if isActivationEligible(x, ?VM1) #then ?Epoch #else AEM1[x]i #fi) 35 | 36 | endmodule 37 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/p1-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | module P1-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | rule 8 | 9 | processValidatorEjectionsAux(L_VIDs, R_VIDs, m(SM, BM, EBM, AEM, AM, EM0, WM0)) => .K ... 10 | Slot 11 | 12 | 13 | Slot 14 | v(m(SM, BM, EBM, AEM, AM, EM1 => ?EM2, WM1 => ?WM2), VIDs) 15 | ... 16 | 17 | ... 18 | 19 | ... 20 | 21 | requires true 22 | // types 23 | andBool Slot >=Int 0 24 | // let-bindings 25 | andBool ?Epoch ==Int epochOf(Slot) 26 | andBool ?VM0 ==K m(SM, BM, EBM, AEM, AM, EM0, WM0) 27 | andBool ?VM1 ==K m(SM, BM, EBM, AEM, AM, EM1, WM1) 28 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(v(?VM1, VIDs)), delayedActivationExitEpoch(?Epoch)) 29 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(v(?VM1, VIDs), ?Epoch))) 30 | // pre-conditions 31 | andBool ?LastExitEpoch +Int size(R_VIDs) =Int delayedActivationExitEpoch(?Epoch) andBool EM1[x]i =Int delayedActivationExitEpoch(?Epoch) andBool ?EM2[x]i 11 | processValidatorEjections(VIDs) => .K ... 12 | Slot 13 | 14 | 15 | Slot 16 | v(m(SM, BM, EBM, AEM, AM, EM1 => ?EM2, WM1 => ?WM2), VIDs) 17 | ... 18 | 19 | ... 20 | 21 | ... 22 | 23 | requires true 24 | // types 25 | andBool Slot >=Int 0 26 | // let-bindings 27 | andBool ?Epoch ==Int epochOf(Slot) 28 | andBool ?VM1 ==K m(SM, BM, EBM, AEM, AM, EM1, WM1) 29 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(v(?VM1, VIDs)), delayedActivationExitEpoch(?Epoch)) 30 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(v(?VM1, VIDs), ?Epoch))) 31 | // pre-conditions 32 | andBool ?LastExitEpoch +Int size(VIDs) =Int delayedActivationExitEpoch(?Epoch) andBool ?EM2[x]i 14 | begin 15 | ~> processRewardsPenalties(?Epoch -Int 2) 16 | ~> processValidatorUpdates() => .K ... 17 | Slot 18 | 19 | 20 | Slot 21 | v(m(SM, BM1 => ?BM2, EBM, AEM1 => ?AEM2, AM1 => ?AM2, EM1 => ?EM2, WM1 => ?WM2), VIDs) 22 | 23 | ?Epoch -Int 2 |-> Attestations:Attestations 24 | ... 25 | 26 | LastFinalizedEpoch 27 | ... 28 | 29 | 30 | firstSlotOf(?Epoch -Int 2) 31 | ... 32 | 33 | ... 34 | 35 | ... 36 | 37 | requires true 38 | // types 39 | andBool Slot >=Int 0 40 | andBool ?Epoch >=Int 0 41 | andBool ?FinalityDelay >=Int 0 42 | // let-bindings 43 | andBool ?Epoch ==Int epochOf(Slot) 44 | andBool ?FinalityDelay ==Int ?Epoch -Int 2 -Int LastFinalizedEpoch 45 | andBool ?SourceAttestations ==K filterNotSlashed(SM, Attestations) 46 | andBool ?TotalActiveBalance ==Int lift(totalBalance(EBM, activeValidators(VIDs, AM1, EM1, ?Epoch -Int 2))) 47 | // 48 | andBool ?ChurnLimitA ==Int churnLimit(size(activeValidators(VIDs, AM1, EM1, ?Epoch))) 49 | andBool ?ChurnLimitB ==Int churnLimit(size(activeValidators(VIDs, AM1, EM1, ?Epoch -Int 1))) 50 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(VIDs, EM1), delayedActivationExitEpoch(?Epoch)) 51 | andBool ?ActivationEpoch ==Int delayedActivationExitEpoch(?Epoch -Int 1) 52 | andBool ?ValidatorsToBeActivated ==K activationQueueUptoChurnLimit(VIDs, AEM1, AM1, EM1, LastFinalizedEpoch, ?Epoch -Int 1) 53 | // pre-conditions 54 | andBool ?Epoch >=Int 4 55 | andBool forall(x, VIDs, EBM[x]i >=Int 0) 56 | andBool distinct(VIDs) 57 | andBool forall(x, VIDs, implies(x inA ?SourceAttestations, minByInclusionDelay(x, ?SourceAttestations).inclusion_delay >=Int 1)) 58 | andBool forall(x, VIDs, implies(x inA ?SourceAttestations, minByInclusionDelay(x, ?SourceAttestations).proposer in VIDs)) 59 | andBool isValidAttestations(Attestations, VIDs, AM1, EM1, ?Epoch -Int 2) 60 | // 61 | andBool LastFinalizedEpoch =Int BM1[x]i -Int (7 *Int getBaseReward(EBM[x]i, ?TotalActiveBalance)) -Int getInactivityPenalty(EBM[x]i, ?FinalityDelay)) 71 | // 72 | // processValidatorEjections 73 | andBool forall(x, VIDs, #if isActiveValidator(x, AM1, EM1, ?Epoch -Int 1) andBool EBM[x]i <=Int EJECTION_BALANCE andBool EM1[x]i ==Int FAR_FUTURE_EPOCH 74 | #then ?EM2[x]i >=Int delayedActivationExitEpoch(?Epoch) andBool ?EM2[x]i 10 | processSlots(TargetSlot) => . 11 | Slot 12 | 13 | 14 | Slot 15 | Vs 16 | SB 17 | AttestedMap 18 | JustifiedMap 19 | FinalizedMap 20 | 21 | ... 22 | 23 | ... 24 | 25 | requires true 26 | andBool Slot ==Int TargetSlot 27 | // types 28 | andBool Slot >=Int 0 29 | ensures true 30 | 31 | endmodule 32 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/process-slots-base1-spec.k: -------------------------------------------------------------------------------- 1 | require "verification.k" 2 | 3 | module PROCESS-SLOTS-BASE1-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // Slot == TargetSlot - 1 8 | rule 9 | 10 | processSlots(TargetSlot) => . 11 | Slot => TargetSlot 12 | 13 | 14 | Slot 15 | Vs 16 | SB 17 | AttestedMap 18 | JustifiedMap 19 | FinalizedMap 20 | 21 | ( 22 | .Bag 23 | => 24 | 25 | TargetSlot 26 | Vs 27 | SB 28 | AttestedMap 29 | JustifiedMap 30 | FinalizedMap 31 | 32 | ) 33 | ... 34 | 35 | B => B [ TargetSlot <- B[Slot]i ]i 36 | ... 37 | 38 | requires true 39 | andBool Slot +Int 1 ==Int TargetSlot 40 | andBool isFirstSlotOfEpoch(Slot +Int 1) ==K false 41 | // types 42 | andBool Slot >=Int 0 43 | ensures true 44 | 45 | endmodule 46 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/process-slots-inductive-spec.k: -------------------------------------------------------------------------------- 1 | require "verification.k" 2 | 3 | module PROCESS-SLOTS-INDUCTIVE-SPEC 4 | 5 | imports VERIFICATION 6 | 7 | // Slot < TargetSlot - 1 8 | rule 9 | 10 | processSlots(TargetSlot) 11 | Slot => Slot +Int 1 12 | 13 | 14 | Slot 15 | Vs 16 | SB 17 | AttestedMap 18 | JustifiedMap 19 | FinalizedMap 20 | 21 | ( 22 | .Bag 23 | => 24 | 25 | Slot +Int 1 26 | Vs 27 | SB 28 | AttestedMap 29 | JustifiedMap 30 | FinalizedMap 31 | 32 | ) 33 | ... 34 | 35 | B => B [ Slot +Int 1 <- B[Slot]i ]i 36 | ... 37 | 38 | requires true 39 | andBool Slot +Int 1 =Int 0 43 | ensures true 44 | 45 | endmodule 46 | -------------------------------------------------------------------------------- /dynamic/tests/symbolic/q2-spec.k: -------------------------------------------------------------------------------- 1 | require "../../verification.k" 2 | 3 | require "../../process-deposit-spec.k" 4 | require "../../process-validator-exit-spec.k" 5 | 6 | module Q2-SPEC 7 | 8 | imports VERIFICATION 9 | 10 | imports PROCESS-DEPOSIT-SPEC 11 | imports PROCESS-VALIDATOR-EXIT-SPEC 12 | 13 | rule 14 | 15 | begin 16 | ~> processDeposits(Ds) 17 | ~> processVoluntaryExits(VEs) => .K ... 18 | Slot 19 | 20 | 21 | Slot 22 | v(m(SM1 => ?SM2, BM1 => ?BM2, EBM1 => ?EBM2, AEM1 => ?AEM2, AM1 => ?AM2, EM1 => ?EM2, WM1 => ?WM2), VIDs1 => ?VIDs2) 23 | ... 24 | 25 | ... 26 | 27 | ... 28 | 29 | requires true 30 | // types 31 | andBool Slot >=Int 0 32 | // let-bindings 33 | //// processVoluntaryExits 34 | andBool ?Epoch ==Int epochOf(Slot) 35 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(VIDs1, EM1), delayedActivationExitEpoch(?Epoch)) 36 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(VIDs1, AM1, EM1, ?Epoch))) 37 | // pre-conditions 38 | //// processDeposits 39 | andBool distinct(VIDs1) 40 | andBool isValidDeposits(Ds) 41 | //// processVoluntaryExits 42 | andBool ?LastExitEpoch +Int sizeE(VEs) =Int #if x in VIDs1 #then BM1[x]i #else 0 #fi) 54 | andBool forall(x, ?VIDs2, ?EBM2[x]i >=Int #if x in VIDs1 #then EBM1[x]i #else 0 #fi) 55 | andBool forall(x, ?VIDs2, ?EBM2[x]i <=Int #if x in VIDs1 #then EBM1[x]i #else MAX_EFFECTIVE_BALANCE #fi) 56 | andBool forall(x, ?VIDs2, ?AEM2[x]i ==Int #if x in VIDs1 #then AEM1[x]i #else FAR_FUTURE_EPOCH #fi) 57 | andBool forall(x, ?VIDs2, ?AM2[x]i ==Int #if x in VIDs1 #then AM1[x]i #else FAR_FUTURE_EPOCH #fi) 58 | /* 59 | andBool forall(x, ?VIDs2, ?EM2[x]i ==Int #if x in VIDs1 #then EM1[x]i #else FAR_FUTURE_EPOCH #fi) 60 | andBool forall(x, ?VIDs2, ?WM2[x]i ==Int #if x in VIDs1 #then WM1[x]i #else FAR_FUTURE_EPOCH #fi) 61 | */ 62 | //// processVoluntaryExits 63 | andBool forall(x, getValidatorsE(VEs), ?EM2[x]i >=Int delayedActivationExitEpoch(?Epoch)) 64 | andBool forall(x, getValidatorsE(VEs), ?EM2[x]i 70 | processDeposits(Ds) => .K ... 71 | Slot 72 | 73 | 74 | Slot 75 | v(m(SM1 => ?SM2, BM1 => ?BM2, EBM1 => ?EBM2, AEM1 => ?AEM2, AM1 => ?AM2, EM1 => ?EM2, WM1 => ?WM2), VIDs1 => ?VIDs2) 76 | ... 77 | 78 | ... 79 | 80 | ... 81 | 82 | requires true 83 | // types 84 | andBool Slot >=Int 0 85 | // let-bindings 86 | // pre-conditions 87 | andBool distinct(VIDs1) 88 | andBool isValidDeposits(Ds) 89 | // invariants 90 | ensures true 91 | // post-conditions 92 | andBool distinct(?VIDs2) 93 | andBool ?VIDs2 ==K unique(rev(getValidatorsD(Ds)) ++ VIDs1) 94 | andBool forall(x, ?VIDs2, ?SM2[x]b ==K #if x in VIDs1 #then SM1[x]b #else false #fi) 95 | andBool forall(x, ?VIDs2, ?BM2[x]i >=Int #if x in VIDs1 #then BM1[x]i #else 0 #fi) 96 | andBool forall(x, ?VIDs2, ?EBM2[x]i >=Int #if x in VIDs1 #then EBM1[x]i #else 0 #fi) 97 | andBool forall(x, ?VIDs2, ?EBM2[x]i <=Int #if x in VIDs1 #then EBM1[x]i #else MAX_EFFECTIVE_BALANCE #fi) 98 | andBool forall(x, ?VIDs2, ?AEM2[x]i ==Int #if x in VIDs1 #then AEM1[x]i #else FAR_FUTURE_EPOCH #fi) 99 | andBool forall(x, ?VIDs2, ?AM2[x]i ==Int #if x in VIDs1 #then AM1[x]i #else FAR_FUTURE_EPOCH #fi) 100 | andBool forall(x, ?VIDs2, ?EM2[x]i ==Int #if x in VIDs1 #then EM1[x]i #else FAR_FUTURE_EPOCH #fi) 101 | andBool forall(x, ?VIDs2, ?WM2[x]i ==Int #if x in VIDs1 #then WM1[x]i #else FAR_FUTURE_EPOCH #fi) 102 | [trusted] 103 | 104 | rule 105 | 106 | processVoluntaryExits(VEs) => .K ... 107 | Slot 108 | 109 | 110 | Slot 111 | v(m(SM, BM, EBM, AEM, AM, EM1 => ?EM2, WM1 => ?WM2), VIDs) 112 | ... 113 | 114 | ... 115 | 116 | ... 117 | 118 | requires true 119 | // types 120 | andBool Slot >=Int 0 121 | // let-bindings 122 | andBool ?Epoch ==Int epochOf(Slot) 123 | andBool ?LastExitEpoch ==Int maxInt(maxExitEpoch(VIDs, EM1), delayedActivationExitEpoch(?Epoch)) 124 | andBool ?ChurnLimit ==Int churnLimit(size(activeValidators(VIDs, AM, EM1, ?Epoch))) 125 | // pre-conditions 126 | andBool ?LastExitEpoch +Int sizeE(VEs) =Int delayedActivationExitEpoch(?Epoch)) 134 | andBool forall(x, getValidatorsE(VEs), ?EM2[x]i 10 | processSlot() => . 11 | Slot 12 | 13 | ... 14 | 15 | Slot 16 | Vs 17 | Ss 18 | As 19 | Js 20 | Fs 21 | (LastBlockSlot, LastBlockID) 22 | LastJustifiedEpoch 23 | LastFinalizedEpoch 24 | 25 | 26 | ... 27 | 28 | 29 | // processSlots(s) does nothing if s is the current slot. 30 | rule 31 | 32 | processSlots(Slot) => . 33 | Slot 34 | 35 | ... 36 | 37 | Slot 38 | Vs 39 | Ss 40 | As 41 | Js 42 | Fs 43 | (LastBlockSlot, LastBlockID) 44 | LastJustifiedEpoch 45 | LastFinalizedEpoch 46 | 47 | 48 | ... 49 | 50 | 51 | // processJustification(e) does nothing if no validator exist. 52 | rule 53 | 54 | processJustification(Epoch) => . 55 | Slot 56 | 57 | ... 58 | 59 | firstSlotOf(Epoch) 60 | v(m(.BMap, .IMap, .IMap, .IMap, .IMap, .IMap, .IMap), .IntList) 61 | (_, EpochBoundaryBlock) 62 | ... 63 | 64 | 65 | Slot 66 | v(m(.BMap, .IMap, .IMap, .IMap, .IMap, .IMap, .IMap), .IntList) 67 | 68 | Epoch |-> .Attestations 69 | ... 70 | 71 | ... 72 | 73 | 74 | ... 75 | 76 | // TODO: why is this condition not needed? 77 | // requires Slot ==Int firstSlotOf(Epoch +Int 1) 78 | 79 | endmodule 80 | -------------------------------------------------------------------------------- /fork-choice-rule/preliminary-analysis-fork-choice-rule.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/beacon-chain-verification/7563b9b338eef019a11edadb8d8e520775a165bf/fork-choice-rule/preliminary-analysis-fork-choice-rule.pdf -------------------------------------------------------------------------------- /resources/Notes-on-justification-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/beacon-chain-verification/7563b9b338eef019a11edadb8d8e520775a165bf/resources/Notes-on-justification-diagram.png -------------------------------------------------------------------------------- /resources/pdf-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/beacon-chain-verification/7563b9b338eef019a11edadb8d8e520775a165bf/resources/pdf-icon.png -------------------------------------------------------------------------------- /weak-subjectivity/Makefile: -------------------------------------------------------------------------------- 1 | TARGET=paper 2 | 3 | LATEX=pdflatex 4 | BIBTEX=bibtex 5 | TEXFILES = ${wildcard *.tex} ${wildcard tables/*.tex} ${wildcard */*.tex} 6 | BIBFILES = ${wildcard *.bib} ${wildcard bibtex/*.bib} 7 | FIGFILES = $(wildcard figs/*.pdf) 8 | DOTFILES = ${wildcard figs/*.dot} 9 | FIGFILES +=${DOTFILES:%.dot=%.ps} 10 | FIGFILES +=${wildcard figs/*.tex} ${wildcard figs/*.ps} ${wildcard figs/*.eps} 11 | CONFFILES += ${wildcard *.sty} ${wildcard *.cls} 12 | 13 | .PRECIOUS: %.ps %.pdf 14 | 15 | .PHONY: $(TARGET) $(TARGET).pdf clean clean-full 16 | 17 | $(TARGET): $(TARGET).pdf 18 | 19 | $(TARGET).pdf: $(TEXFILES) $(FIGFILES) $(BIBFILES) $(CONFILES) 20 | -rm -f *.aux 21 | $(LATEX) $(TARGET).tex 22 | ifneq ($(shell grep "cite{.*}" $(TEXFILES)),) 23 | $(BIBTEX) $(TARGET) 24 | $(LATEX) $(TARGET).tex 25 | endif 26 | $(LATEX) $(TARGET).tex 27 | @/bin/echo "" 28 | @/bin/echo "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" 29 | @/bin/echo " ++++ ANY UNDEFINED REFERENCES ++++" 30 | -@grep -i undef $(TARGET).log || echo "No undefined references." 31 | @/bin/echo " ++++ ANY EMPTY REFERENCES ++++" 32 | -@egrep -i -n -e 'cite{ *}' -e 'ref{ *}' $(TEXFILES) $(FIGFILES) || echo "No empty references." 33 | @/bin/echo "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" 34 | @/bin/echo "" 35 | 36 | clean: 37 | rm -f *.aux *.bbl *.dvi *.lof *.log *.toc *.lot *.blg *.out *.cut *._paper.pdf 38 | 39 | clean-full: clean 40 | rm -f $(TARGET).pdf 41 | 42 | %.pdf: %.dvi 43 | dvipdfmx -o $@ $< 44 | -------------------------------------------------------------------------------- /weak-subjectivity/after-n-epoch-balance-top-ups.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/beacon-chain-verification/7563b9b338eef019a11edadb8d8e520775a165bf/weak-subjectivity/after-n-epoch-balance-top-ups.pdf -------------------------------------------------------------------------------- /weak-subjectivity/after-n-epoch.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/beacon-chain-verification/7563b9b338eef019a11edadb8d8e520775a165bf/weak-subjectivity/after-n-epoch.pdf -------------------------------------------------------------------------------- /weak-subjectivity/balance-top-ups.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/beacon-chain-verification/7563b9b338eef019a11edadb8d8e520775a165bf/weak-subjectivity/balance-top-ups.pdf -------------------------------------------------------------------------------- /weak-subjectivity/discussion.tex: -------------------------------------------------------------------------------- 1 | \section{Discussion} 2 | 3 | Compared to the limit of the validator activations and exits, the per-epoch limit of balance top-ups is quite high. In the current configuration, while the activation/exit limit is $\max(4, N \cdot 2^{-16})$, the balance top-up limit is 512 regardless of the total number of validators $N$. The high limit of balance top-ups causes the weak subjectivity period to quickly decrease as the average balance decreases. 4 | As shown in Table~\ref{tbl:weak-subjectivity}, the weak subjectivity period becomes too small to be practically maintained even for a reasonably large validator set, if the average balance falls below a certain threshold, say 24 ETH. This shows that the current limit of balance top-ups is too high, and it is recommended to significantly decrease the top-up limit. 5 | Note that it is \emph{not} recommended to merely increase the validator ejection balance (currently 16 ETH). Although it could help to increase the lower bound of the average balance, it is risky because a higher ejection balance could be abused by adversaries to make it easier to forcibly eject honest validators. 6 | 7 | \begin{table}[t] 8 | \caption[Weak Subjectivity Period]{Weak subjectivity period (in number of epochs) for dynamic validator set with balance top-ups,\footnotemark~where the safety decay $D = 10\%$, the maximum effective balance $T = 32$ ETH, the balance top-up limit $\Delta = 512$, and the activation/exit limit $\delta = 4$.} 9 | \label{tbl:weak-subjectivity} 10 | \centering 11 | \begingroup 12 | \newdimen{\colWidth} 13 | \settowidth{\colWidth}{262,144} % column size fit to the given text 14 | \setlength{\tabcolsep}{4pt} 15 | \begin{tabular}{cr|rrrrrrr} 16 | %\hline 17 | & & \multicolumn{7}{c}{Validator Set Size ($N$)} \\ 18 | & & \makebox[\colWidth][r]{262,144} 19 | & \makebox[\colWidth][r]{131,072} 20 | & \makebox[\colWidth][r]{ 65,536} 21 | & \makebox[\colWidth][r]{ 32,768} 22 | & \makebox[\colWidth][r]{ 16,384} 23 | & \makebox[\colWidth][r]{ 8,192} 24 | & \makebox[\colWidth][r]{ 4,096} \\ 25 | \hline 26 | \multirow{9}{*}{\rotatebox{90}{Average Balance ($t$)}} 27 | & 32 & 3,276 & 1,638 & 819 & 409 & 204 & 102 & 51 \\ 28 | & 30 & 2,659 & 1,329 & 664 & 332 & 166 & 83 & 41 \\ 29 | & 28 & 1,985 & 992 & 496 & 248 & 124 & 62 & 31 \\ 30 | & 26 & 1,248 & 624 & 312 & 156 & 78 & 39 & 19 \\ 31 | & 24 & 436 & 218 & 109 & 54 & 27 & 13 & 6 \\ 32 | & 22 & 169 & 84 & 42 & 21 & 11 & 5 & 3 \\ 33 | & 20 & 128 & 64 & 32 & 16 & 8 & 4 & 2 \\ 34 | & 18 & 99 & 49 & 25 & 12 & 6 & 3 & 2 \\ 35 | & 16 & 77 & 38 & 19 & 10 & 5 & 2 & 1 \\ 36 | %\hline 37 | \end{tabular} 38 | \endgroup 39 | \end{table} 40 | \footnotetext{The entries of the first low for $t = 32$ agree with the table presented in~\cite{weak-subjectivity-aditya}. The off-by-one difference is due to the use of the floor function instead of ceiling.} 41 | 42 | On the other hands, as a workaround for the small weak subjectivity period problem, a relaxed notion of weak subjectivity has been proposed by others. The relaxed notion does \emph{not} aim to prevent conflicting finalized blocks from being descendants of the latest weak subjectivity checkpoint, thus does \emph{not} guarantee the unique finalized block to be identified by the fork choice rule. Instead, it relies on the withdrawal delay (currently 256 epochs $\approx$ 27 hours), so that arguably the slashable validators can be indeed slashed. However, the implication of the relaxed notion of weak subjectivity has not been thoroughly analyzed, thus it is not recommended to adopt it until more detailed analysis has been made. 43 | 44 | \paragraph{Limitation.} 45 | 46 | It is not yet known whether the period given in Theorem~\ref{thm:weak-subjectivity-balance-top-ups} is indeed the lower bound (i.e., $\E_2$) or not. 47 | This means that the weak subjectivity period in the setting of dynamic validator set with balance top-ups might need to be much smaller. 48 | However, when $N$ is not large enough, the given weak subjectivity period is already very small, thus does not affect the practical implication. 49 | 50 | On the other hands, if the balance top-up limit $\Delta$ is reduced to close to the activation/exit limit $\delta$, then Theorem~\ref{thm:weak-subjectivity-balance-top-ups} is no longer directly applicable as it assumes $\Delta \gg \delta$. 51 | -------------------------------------------------------------------------------- /weak-subjectivity/header.tex: -------------------------------------------------------------------------------- 1 | % Packages 2 | \usepackage[T1]{fontenc} 3 | \usepackage{hyperref} %\usepackage[hidelinks]{hyperref} 4 | 5 | % break long URLs 6 | \def\UrlBreaks{\do\/\do-} 7 | 8 | %\usepackage[disable]{todonotes} 9 | \usepackage{todonotes} 10 | 11 | \usepackage{amsmath} 12 | \usepackage{amssymb} 13 | \usepackage{xspace} 14 | \usepackage{graphicx} 15 | \usepackage{fancyvrb} 16 | \usepackage[super]{nth} 17 | %\usepackage{enumitem} 18 | %\usepackage{relsize} 19 | %\usepackage{wrapfig} 20 | \usepackage{multirow} 21 | %\usepackage{enumitem} 22 | 23 | % % Theorems 24 | % \usepackage{amsthm} 25 | % \newtheorem{theorem}{Theorem} 26 | % \newtheorem{lemma}{Lemma} 27 | % \newtheorem{corollary}{Corollary} 28 | % \newtheorem{proposition}{Proposition} 29 | % \newtheorem{definition}{Definition} 30 | % \newtheorem{question}{Question} 31 | % \newtheorem{example}{Example} 32 | 33 | % General 34 | \newcommand{\N}{\mathbb{N}} 35 | \newcommand{\Z}{\mathbb{Z}} 36 | \renewcommand{\i}{\item} 37 | \newcommand{\OR}{\;|\;} 38 | \newcommand{\etal}{\textit{et al.}\xspace} 39 | \renewcommand{\th}{\ensuremath{{\m{th}}}} 40 | \newcommand{\w}[1]{\ensuremath{\textit{#1}}} 41 | \renewcommand{\t}[1]{\ensuremath{\texttt{#1}}} 42 | \newcommand{\m}[1]{\ensuremath{\textrm{#1}}} 43 | \newcommand{\s}[1]{\ensuremath{\textsf{#1}}} 44 | \newcommand{\p}[1]{\ensuremath{\left(#1\right)}} 45 | \newcommand{\pl}[1]{\ensuremath{\left\langle#1\right\rangle}} 46 | \newcommand{\finto}{\ensuremath{\stackrel{\mathtt{fin}}{\longrightarrow}}} 47 | \newcommand{\defeq}{\ensuremath{\stackrel{\mathtt{def}}{=}}} 48 | \newcommand{\cond}[1]{\ensuremath{\left\{\begin{array}{ll} #1 \end{array}\right.}} 49 | \newcommand{\lst}[1]{\begin{itemize} {#1} \end{itemize}} 50 | \newcommand{\tlist}[2]{\paragraph{#1} \begin{itemize} {#2} \end{itemize}} 51 | \newcommand{\floor}[1]{\ensuremath{\left\lfloor {#1} \right\rfloor}} 52 | \newcommand{\ceil}[1]{\ensuremath{\left\lceil {#1} \right\rceil}} 53 | \newcommand{\get}{\leftarrow} 54 | \newcommand{\dom}{\ensuremath{\textit{dom}}\xspace} 55 | \newcommand{\sem}[1]{\ensuremath{[\![{#1}]\!]}} 56 | 57 | % Specific 58 | \newcommand{\E}{\ensuremath{\mathsf{E}}} 59 | \newcommand{\twothird}{\ensuremath{\frac{2}{3}}} 60 | \newcommand{\ST}{\ensuremath{\w{SV}}} 61 | \newcommand{\T}{\ensuremath{\mathcal{S}}} 62 | -------------------------------------------------------------------------------- /weak-subjectivity/intro.tex: -------------------------------------------------------------------------------- 1 | \section{Introduction} 2 | 3 | Weak subjectivity~\cite{weak-subjectivity} is a social-consensus-driven approach for solving the fundamental ``nothing-at-stake'' problem of proof-of-stake protocols. In particular, it addresses the problem in the presence of long-range forks, while the slashing mechanism handles the case of short-range forks. Specifically, the current weak subjectivity mechanism deals with the following two types of long-range attacks:\footnote{It is unknown whether this mechanism can deal with other types of long-range attacks, if any, in general.} 4 | \begin{itemize} 5 | \item 6 | \emph{Exploiting retired validators}: Adversaries can create and reveal a new chain branching from a certain block on the canonical chain, after $2/3$ of validators who were active for the block have exited. Note that such validators can still justify and finalize conflicting blocks at earlier slots without being slashed after they have exited. 7 | \item 8 | \emph{Exploiting diverging validator sets}: Adversaries can build a new chain until the validator set for the new chain is sufficiently different from that of the canonical chain. The larger the difference between the two validator sets, the lower the accountable safety tolerance. For example, if the intersection of the two sets is smaller than $2/3$ of each set, then it is possible to have conflicting blocks to be finalized without any validators violating the slashing conditions. 9 | \end{itemize} 10 | The current weak subjectivity mechanism employs a social consensus layer in parallel to maintain sufficiently many checkpoints (called weak subjectivity checkpoints) so that there exist no conflicting finalized blocks that are descendants of the latest weak subjectivity checkpoint. In other words, the purpose of the latest weak subjectivity checkpoints is to \emph{deterministically} identify the unique canonical chain even in the presence of conflicting finalized blocks caused by the long-range attacks. 11 | -------------------------------------------------------------------------------- /weak-subjectivity/paper.tex: -------------------------------------------------------------------------------- 1 | \documentclass[runningheads]{llncs} 2 | %\documentclass{llncs} 3 | 4 | \input{header.tex} 5 | 6 | \begin{document} 7 | 8 | \title{Analysis on Weak Subjectivity in Ethereum 2.0} 9 | %\subtitle{subtitle} 10 | %\titlerunning{Abbreviated paper title} 11 | 12 | \author{Daejun Park\inst{1}%\orcidID{0000-0003-1551-2597} 13 | \and Aditya Asgaonkar\inst{2} 14 | } 15 | %\authorrunning{D. Park et al.} 16 | 17 | \institute{Runtime Verification, Inc. 18 | \\\email{daejun.park@runtimeverification.com} 19 | \and Ethereum Research 20 | \\\email{aditya.asgaonkar@ethereum.org} 21 | } 22 | 23 | \maketitle 24 | 25 | \begin{center} 26 | \vspace{-1\baselineskip} 27 | December 7, 2020 28 | %\today 29 | \end{center} 30 | 31 | %\begin{abstract} 32 | %We present an analysis on the weak subjectivity period in Ethereum 2.0. 33 | %\end{abstract} 34 | 35 | \input{intro.tex} 36 | \input{ws-period.tex} 37 | \input{discussion.tex} 38 | 39 | %\newpage 40 | \bibliographystyle{splncs04} 41 | \bibliography{ref} 42 | 43 | \newpage 44 | \appendix 45 | 46 | \end{document} 47 | -------------------------------------------------------------------------------- /weak-subjectivity/ref.bib: -------------------------------------------------------------------------------- 1 | @misc{beacon-chain-spec, 2 | title = {{Ethereum 2.0 Specifications}}, 3 | author = {{Ethereum Foundation}}, 4 | howpublished = {\url{https://github.com/ethereum/eth2.0-specs}} 5 | } 6 | 7 | @misc{weak-subjectivity, 8 | title = {{Proof of Stake: How I Learned to Love Weak Subjectivity}}, 9 | author = {{Vitalik Buterin}}, 10 | howpublished = {\url{https://blog.ethereum.org/2014/11/25/proof-stake-learned-love-weak-subjectivity/}} 11 | } 12 | 13 | @misc{weak-subjectivity-aditya, 14 | title = {{Weak Subjectivity in Eth2.0}}, 15 | author = {{Aditya Asgaonkar}}, 16 | howpublished = {\url{https://notes.ethereum.org/@adiasg/weak-subjectvity-eth2}} 17 | } 18 | -------------------------------------------------------------------------------- /weak-subjectivity/weak-subjectivity-analysis.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runtimeverification/beacon-chain-verification/7563b9b338eef019a11edadb8d8e520775a165bf/weak-subjectivity/weak-subjectivity-analysis.pdf --------------------------------------------------------------------------------