[
  {
    "path": ".gitignore",
    "content": "**/.DS_Store\n**/tla/*.toolbox/model\n**/tla/*.toolbox/*aux\n**/tla/*.toolbox/*.log\n**/tla/*.toolbox/*.pdf\n**/tla/*.toolbox/*.tex\n**/tla/*.toolbox/*___model_SnapShot*.launch\n**/tla/*.toolbox/**/*.tla\n**/tla/*.toolbox/**/*.out\n**/tla/*.toolbox/**/MC.cfg\n**/tla/*.pdf\n**/tla/*.old\n**/*~\ncluster/isabelle/output\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# Formal models of core Elasticsearch algorithms\n\nThis repository contains formal models of core [Elasticsearch](https://github.com/elastic/elasticsearch) algorithms and is directly related to implementation efforts around [data replication](https://github.com/elastic/elasticsearch/issues/10708) and [cluster coordination](https://github.com/elastic/elasticsearch/issues/32006). The models in this repository might represent past, current and future designs of Elasticsearch and can differ to their implementations in substantial ways. The formal models mainly serve to illustrate some of the high-level concepts and help to validate resiliency-related aspects.\n\n## Models\n\n### Cluster coordination model\n\nThe cluster coordination TLA+ model ensures the consistency of cluster state updates and represents the core [cluster coordination](https://github.com/elastic/elasticsearch/issues/32006) and metadata replication algorithm implemented in Elasticsearch 7.0. It consists of two files:\n\n- [TLA+ specification](ZenWithTerms/tla/ZenWithTerms.tla) which has a [direct one-to-one implementation in Elasticsearch](https://github.com/elastic/elasticsearch/blob/master/server/src/main/java/org/elasticsearch/cluster/coordination/CoordinationState.java)\n- [TLC model checking configuration](ZenWithTerms/tla/ZenWithTerms.toolbox/ZenWithTerms___model.launch)\n\n### Data replication model\n\nThe data replication TLA+ model describes the Elasticsearch [sequence number](https://github.com/elastic/elasticsearch/issues/10708) based data replication approach, implemented since Elasticsearch 6.0, which consists of two files:\n\n- [TLA+ specification](data/tla/replication.tla)\n- [TLC model checking configuration](data/tla/replication.toolbox/replication___model.launch)\n\n### Replica engine\n\nA TLA+ model of how the\n[engine](https://github.com/elastic/elasticsearch/blob/00fd73acc4a2991f96438f8c1948016c5b9eefb2/server/src/main/java/org/elasticsearch/index/engine/InternalEngine.java)\nhandles replication requests.\n\n- [TLA+ specification](ReplicaEngine/tla/ReplicaEngine.tla)\n- [TLC model checking configuration](ReplicaEngine/tla/ReplicaEngine.toolbox/ReplicaEngine___model.launch)\n\n### Alternative cluster coordination model\n\nThe alternative cluster coordination TLA+ model consists of two files:\n\n- [TLA+ specification](cluster/tla/consensus.tla)\n- [TLC model checking configuration](cluster/tla/consensus.toolbox/consensus___model.launch)\n\nThe alternative cluster consensus Isabelle model consists of the following theories:\n\n- [Basic definitions](cluster/isabelle/Preliminaries.thy)\n- [An implementation in functional style](cluster/isabelle/Implementation.thy)\n- [An implementation in monadic style, along with a proof it's equivalent to the previous](cluster/isabelle/Monadic.thy)\n- [The proof that each slot is consistent, based on Lamport's Synod algorithm](cluster/isabelle/OneSlot.thy)\n- [The proof that the implementation ensures consistency](cluster/isabelle/Zen.thy)\n\n## How to edit/run TLA+:\n\n- Install the [TLA Toolbox](http://research.microsoft.com/en-us/um/people/lamport/tla/toolbox.html)\n  - If on Mac OS, [move the downloaded app to the Applications folder first](https://groups.google.com/forum/#!topic/tlaplus/bL04c6BiYxo)\n- Read some [documentation](http://research.microsoft.com/en-us/um/people/lamport/tla/book.html)\n\nHow to run the model checker in headless mode:\n\n- Download [tla2tools.jar](http://research.microsoft.com/en-us/um/people/lamport/tla/tools.html)\n- Run the model checker once in TLA+ Toolbox on desktop (can be aborted once started). This generates the folder `elasticsearch.toolbox/model/` that contains all model files that are required to run the model checker in headless mode.\n- Copy the above folder and `tla2tools.jar` to the server running in headless mode.\n- `cd` to the folder and run `java -Xmx30G -cp ../tla2tools.jar tlc2.TLC MC -deadlock -workers 12`. The setting `-Xmx30G` denotes the amount of memory to allocate to the model checker and `-workers 12` the number of worker threads (should be equal to the number of cores on machine). The setting `-deadlock` ensures that TLC explores the full reachable state space, not searching for deadlocks.\n"
  },
  {
    "path": "ReplicaEngine/tla/ReplicaEngine.tla",
    "content": "-------------------------- MODULE ReplicaEngine --------------------------\n\nEXTENDS Naturals, FiniteSets, Sequences, TLC\n\n(* Actions on the Lucene index *)\nCONSTANTS Lucene_addDocuments, Lucene_updateDocuments, Lucene_deleteDocuments\n\nCONSTANTS ADD, RETRY_ADD, UPDATE, DELETE, NULL\n\nCONSTANTS DocContent\n\nCONSTANTS DocAutoIdTimestamp\n\nCONSTANTS DuplicationLimit\n\n(* We model the activity of a single document, since distinct documents\n   (according to their IDs) are independent. Also each indexing operation\n   occurs under a lock for that document ID, so there is not much concurrency\n   to consider. *)\n\n\n(* The set of individual requests that can occur on the document *)\nRequest(request_count)\n    (* ADD: An optimised append-only write can only occur as the first operation\n    on the document ID in seqno order. Any subsequent attempts to ADD the\n    document have the retry flag set and modelled as a RETRY_ADD. Other operations\n    on the document are also possible. *)\n    ==    [type : {ADD}, seqno : {1}, content : DocContent, autoIdTimeStamp : {DocAutoIdTimestamp}]\n    (* RETRY_ADD: A retry of a write that does involve an internally-generated\n       document ID. *)\n    \\cup  [type : {RETRY_ADD}, seqno : 1..request_count, content : DocContent, autoIdTimeStamp : {DocAutoIdTimestamp}]\n    (* UPDATE: A write that does not involve an internally-generated document ID. *)\n    \\cup  [type : {UPDATE}, seqno : 1..request_count, content : DocContent]\n    (* DELETE *)\n    \\cup  [type : {DELETE}, seqno : 1..request_count]\n\n(* The set of sets of requests, which have distinct seqnos *)\nRequestSet(request_count)\n    == { rs \\in SUBSET Request(request_count):\n                /\\ Cardinality(rs)                   = request_count\n                /\\ Cardinality({r.seqno : r \\in rs}) = request_count\n                /\\ (* Also ADDs and RETRY_ADDs should have the same content *)\n                   Cardinality({r.content: r \\in { r \\in rs: r.type \\in {ADD, RETRY_ADD}}}) <= 1\n       }\n\n(* Apply a set of operations to a document in seqno order *)\nRECURSIVE ApplyOps(_, _, _)\nApplyOps(requests, nextSeqno, currentContent)\n    == IF   \\A r \\in requests: r.seqno < nextSeqno\n       THEN currentContent\n       ELSE LET r == CHOOSE r \\in requests: r.seqno = nextSeqno\n            IN IF r \\in requests /\\ r.seqno = nextSeqno\n               THEN ApplyOps(requests, nextSeqno + 1,\n                        CASE r.type = DELETE    -> NULL\n                          [] r.type = ADD       -> r.content\n                          [] r.type = RETRY_ADD -> r.content\n                          [] r.type = UPDATE    -> r.content)\n               ELSE Assert(FALSE, \"Bad sequence\")\n\n(* Calculate the final doc by applying all the requests in order *)\nFinalDoc(requests) == ApplyOps(requests, 1, NULL)\n\n(* Apply each the operation in the Lucene buffer, rejecting an\n   addDocuments when there is already a document present as this\n   would lead to duplication. *)\nRECURSIVE ApplyBufferedOperations(_, _)\nApplyBufferedOperations(buffer, origDoc)\n    == IF buffer = <<>>\n       THEN origDoc\n       ELSE LET nextOp  == Head(buffer)\n         IN ApplyBufferedOperations(Tail(buffer),\n            CASE       nextOp.type = Lucene_deleteDocuments -> NULL\n              [] \\/    nextOp.type = Lucene_updateDocuments\n                 \\/ /\\ nextOp.type = Lucene_addDocuments\n                    /\\ origDoc = NULL                       -> [content |-> nextOp.content, seqno |-> nextOp.seqno]\n              [] OTHER -> Assert(FALSE, \"Error: Lucene_addDocuments when origDoc /= NULL\"))\n\nMax(a,b) == IF a <= b THEN b ELSE a\n\n(* --algorithm basic\n\nvariables\n    request_count \\in 1..4,\n    replication_requests \\in RequestSet(request_count),\n    expected_doc = FinalDoc(replication_requests),\n    versionMap_needsSafeAccess = FALSE,\n    versionMap_isUnsafe = FALSE,\n    versionMap_entry = NULL,\n\n(* Other concurrent activity can flag that the version map needs to be safely accessed *)\nprocess SafeAccessEnablerProcess = \"SafeAccessEnabler\"\nbegin\n    SafeAccessEnablerLoop:\n    while pc[\"Consumer\"] /= \"Done\" do\n        versionMap_needsSafeAccess := (versionMap_needsSafeAccess = FALSE);\n        (* Technically the only way this can go back to FALSE is via a refresh, but\n           we should not need this fact, so model both kinds of change. *)\n    end while;\nend process;\n\n(* Other concurrent activity can make the version map become unsafe, if safe access mode is disabled *)\nprocess UnsafePutterProcess = \"UnsafePutter\"\nbegin\n    UnsafePutterLoop:\n    while pc[\"Consumer\"] /= \"Done\" do\n        await versionMap_needsSafeAccess = FALSE;\n        versionMap_isUnsafe := TRUE;\n    end while;\nend process;\n\n(* Other concurrent activity can increase the maxUnsafeAutoIdTimestamp *)\nprocess MaxUnsafeAutoIdTimestampIncreaserProcess = \"MaxUnsafeAutoIdTimestampIncreaser\"\nbegin\n    MaxUnsafeAutoIdTimestampIncreaserLoop:\n    while pc[\"Consumer\"] /= \"Done\" do\n        with newTimestamp \\in {DocAutoIdTimestamp - 1, DocAutoIdTimestamp, DocAutoIdTimestamp + 1} do\n            await maxUnsafeAutoIdTimestamp < newTimestamp;\n            maxUnsafeAutoIdTimestamp := newTimestamp;\n        end with;\n    end while;\nend process;\n\n(* Lucene refreshes can happen at any time *)\nprocess LuceneProcess = \"ReplicaLucene\"\nvariables\n    lucene_document = NULL,\n    lucene_buffer   = <<>>,\nbegin\n    LuceneLoop:\n    while pc[\"Consumer\"] /= \"Done\" \\/ lucene_buffer /= <<>> do\n\n        lucene_document := ApplyBufferedOperations(lucene_buffer, lucene_document);\n        lucene_buffer := <<>>;\n            \n        (* TODO Model the inner structure of the version map so this refresh can be\n        broken into the individual steps that occur concurrently with ongoing indexing. *)\n                        \n        versionMap_isUnsafe := FALSE;\n        versionMap_needsSafeAccess := FALSE;\n        \n        if versionMap_entry /= NULL\n        then\n            if versionMap_entry.type = UPDATE\n            then\n                versionMap_entry := NULL;\n            else\n                assert versionMap_entry.type = DELETE;\n                versionMap_entry := [ versionMap_entry EXCEPT !.flushed = TRUE ];\n            end if;\n        end if;           \n    end while;\nend process;\n\n(* Flushed deletes expire after a time and are cleaned up *)\nprocess DeleteCollectorProcess = \"DeleteCollector\"\nbegin\n    DeleteCollectorLoop:\n    while pc[\"Consumer\"] /= \"Done\" do\n        await /\\ versionMap_entry /= NULL\n              /\\ versionMap_entry.type = DELETE\n              /\\ versionMap_entry.seqno <= localCheckPoint \\* PR #28790\n              /\\ versionMap_entry.flushed = TRUE;\n        versionMap_entry := NULL;\n    end while;\nend process;\n\n(* Local checkpoint advances as each operation is marked as completed *)\nprocess LocalCheckpointTrackerProcess = \"LocalCheckpointTracker\"\nvariables\n    localCheckPoint = 0,\n    completedSeqnos = {}\nbegin\n    LocalCheckpointTrackerLoop:\n    while pc[\"Consumer\"] /= \"Done\" do\n        await localCheckPoint + 1 \\in completedSeqnos;\n        localCheckPoint := localCheckPoint + 1;\n    end while;\nend process\n\nprocess UnsafeSeqnoIncreaserProcess = \"UnsafeSeqnoIncreaserProcess\"\nvariables\n    maxSeqNoOfNonAppendOnlyOperations = 0,\nbegin\n    UnsafeSeqnoIncreaserProcessLoop:\n    while pc[\"Consumer\"] /= \"Done\" /\\ maxSeqNoOfNonAppendOnlyOperations < request_count + 1 do\n        maxSeqNoOfNonAppendOnlyOperations := maxSeqNoOfNonAppendOnlyOperations + 1;\n    end while;\nend process\n\n\n(* The process that consumes replication requests for a particular document ID, which\n   are processed in series because of the lock in the version map. *)\nprocess ConsumerProcess = \"Consumer\"\nvariables\n    duplicationCount = 0,\n    maxUnsafeAutoIdTimestamp \\in {0, DocAutoIdTimestamp - 1, DocAutoIdTimestamp, DocAutoIdTimestamp + 1},\n    req, plan,\n    deleteFromLucene, currentlyDeleted,\n    currentNotFoundOrDeleted, useLuceneUpdateDocument, indexIntoLucene,\nbegin\n  ConsumerLoop:\n  while replication_requests /= {} do\n    with replication_request \\in replication_requests do\n        if replication_request.type = ADD\n        then\n            (* Never see two ADDs - if duplicated, one of them is a RETRY_ADD *)\n            either\n                (* Process ADD without duplication *)\n                replication_requests := replication_requests \\ {replication_request};\n                req := replication_request;\n            or\n                await duplicationCount < DuplicationLimit;\n                duplicationCount := duplicationCount + 1;\n                \n                (* Process ADD and leave a duplicate RETRY_ADD for later *)\n                replication_requests := (replication_requests \\ {replication_request})\n                    \\cup {[replication_request EXCEPT !.type = RETRY_ADD]};\n                req := replication_request;\n            or\n                await duplicationCount < DuplicationLimit;\n                duplicationCount := duplicationCount + 1;\n\n                (* Process duplicate RETRY_ADD and leave the original ADD *)\n                req := [replication_request EXCEPT !.type = RETRY_ADD];\n            end either;\n        else\n            req := replication_request;\n            either\n                await duplicationCount < DuplicationLimit;\n                duplicationCount := duplicationCount + 1;\n            or\n                replication_requests := replication_requests \\ {replication_request};\n            end either;\n        end if;\n    end with;\n    \n    if req.type = DELETE\n    then\n\n        versionMap_needsSafeAccess := TRUE;    \n    \n        (* planDeletionAsNonPrimary *)\n        \n        maxSeqNoOfNonAppendOnlyOperations := Max(maxSeqNoOfNonAppendOnlyOperations, req.seqno);\n\n        if req.seqno <= localCheckPoint\n        then\n            (* OP_STALE_OR_EQUAL *)\n            plan             := \"processButSkipLucene\";\n            deleteFromLucene := FALSE;\n            currentlyDeleted := FALSE;\n        else\n            if versionMap_isUnsafe\n            then\n                (* Perform a Lucene refresh *)\n                AwaitRefreshOnDelete: \\* Label here to allow for other concurrent activity\n                await lucene_buffer = <<>>;\n                versionMap_needsSafeAccess := TRUE;\n            end if;\n        \n            compareDeleteOpToLuceneDocBasedOnSeqNo: \\* Label needed because of AwaitRefreshOnDelete label\n    \n            if versionMap_entry /= NULL\n            then\n                (* Doc is in version map *)\n                if req.seqno > versionMap_entry.seqno\n                then\n                    (* OP_NEWER *)\n                    plan := \"processNormally\";\n                    deleteFromLucene := TRUE;\n                    currentlyDeleted := FALSE;\n                else\n                    (* OP_STALE_OR_EQUAL *)\n                    plan := \"processButSkipLucene\";\n                    deleteFromLucene := FALSE;\n                    currentlyDeleted := FALSE;\n                end if;\n            else\n                (* Doc is not in version map - check Lucene *)\n                if lucene_document = NULL\n                then\n                    (* LUCENE_DOC_NOT_FOUND *)\n                    plan := \"processNormallyExceptNotFound\";\n                    deleteFromLucene := TRUE;\n                    currentlyDeleted := TRUE;\n                else\n                    if req.seqno > lucene_document.seqno\n                    then\n                        (* OP_NEWER *)\n                        plan := \"processNormally\";                 \n                        deleteFromLucene := TRUE;\n                        currentlyDeleted := FALSE;\n                    else\n                        (* OP_STALE_OR_EQUAL *)\n                        plan := \"processButSkipLucene\";                  \n                        deleteFromLucene := FALSE;\n                        currentlyDeleted := FALSE;\n                    end if;\n                end if;\n            end if;\n        end if;\n        \n        ExecuteDeletePlan:  \\* Label needed because of AwaitRefreshOnDelete label\n        if deleteFromLucene\n        then\n            if currentlyDeleted = FALSE\n            then\n                lucene_buffer := Append(lucene_buffer, [ type |-> Lucene_deleteDocuments ]);\n            end if;\n\n            versionMap_entry := [ type |-> DELETE, seqno |-> req.seqno, flushed |-> FALSE ];\n        end if;\n    \n        completedSeqnos := completedSeqnos \\cup {req.seqno};\n    else\n\n        (* planIndexingAsNonPrimary *)\n        \n        (* A RETRY_ADD has canOptimiseAddDocument = TRUE and\n            mayHaveBeenIndexedBefore = TRUE so is planned normally,\n            but also updates maxUnsafeAutoIdTimestamp within\n            mayHaveBeenIndexedBefore() *)\n\n        if req.type = RETRY_ADD\n        then\n            maxUnsafeAutoIdTimestamp := Max(maxUnsafeAutoIdTimestamp, req.autoIdTimeStamp);\n        end if;\n           \n        (* An ADD can be optimized if mayHaveBeenIndexedBefore = FALSE\n            which is calculated by comparing timestamps. *)\n        \n        if /\\ req.type = ADD\n           /\\ maxUnsafeAutoIdTimestamp < req.autoIdTimeStamp\n           /\\ maxSeqNoOfNonAppendOnlyOperations < req.seqno \\* PR #28787\n        then\n            plan                     := \"optimisedAppendOnly\";\n            currentNotFoundOrDeleted := TRUE;\n            useLuceneUpdateDocument  := FALSE;\n            indexIntoLucene          := TRUE;\n        else\n            if req.type \\notin {ADD, RETRY_ADD}\n            then\n                maxSeqNoOfNonAppendOnlyOperations := Max(maxSeqNoOfNonAppendOnlyOperations, req.seqno);\n            end if;\n        \n            (* All other operations are planned normally *)\n            versionMap_needsSafeAccess := TRUE;\n            \n            if req.seqno <= localCheckPoint\n            then\n                (* OP_STALE_OR_EQUAL *)        \n                plan                     := \"processButSkipLucene\";\n                currentNotFoundOrDeleted := FALSE;\n                useLuceneUpdateDocument  := FALSE;\n                indexIntoLucene          := FALSE;\n            else\n                if versionMap_isUnsafe\n                then\n                    (* Perform a Lucene refresh *)\n                    AwaitRefreshOnIndex: \\* Label here to allow for other concurrent activity\n                    await lucene_buffer = <<>>;\n                    versionMap_needsSafeAccess := TRUE;                \n                end if;\n            \n                compareIndexOpToLuceneDocBasedOnSeqNo: \\* Label needed because of AwaitRefreshOnIndex label\n                \n                if req.seqno <= localCheckPoint                         \\* PR #29276\n                then                                                    \\* PR #29276\n                    (* OP_STALE_OR_EQUAL *)                             \\* PR #29276\n                    plan                     := \"processButSkipLucene\"; \\* PR #29276\n                    currentNotFoundOrDeleted := FALSE;                  \\* PR #29276\n                    useLuceneUpdateDocument  := FALSE;                  \\* PR #29276\n                    indexIntoLucene          := FALSE;                  \\* PR #29276\n                elsif versionMap_entry /= NULL\n                then\n                    (* Doc is in version map *)\n                    if req.seqno > versionMap_entry.seqno\n                    then\n                        (* OP_NEWER *)\n                        plan := \"processNormally\";\n                        currentNotFoundOrDeleted := FALSE;\n                        useLuceneUpdateDocument  := TRUE;\n                        indexIntoLucene          := TRUE;\n                    else\n                        (* OP_STALE_OR_EQUAL *)\n                        plan := \"processButSkipLucene\";\n                        currentNotFoundOrDeleted := FALSE;\n                        useLuceneUpdateDocument  := FALSE;\n                        indexIntoLucene          := FALSE;\n                    end if;\n                else\n                    (* Doc is not in version map - check Lucene *)\n                    if lucene_document = NULL\n                    then\n                        (* LUCENE_DOC_NOT_FOUND *)\n                        plan := \"processNormallyExceptNotFound\";\n                        currentNotFoundOrDeleted := TRUE;\n                        useLuceneUpdateDocument  := FALSE;\n                        indexIntoLucene          := TRUE;\n                    else\n                        if req.seqno > lucene_document.seqno\n                        then\n                            (* OP_NEWER *)\n                            plan := \"processNormally\";                 \n                            currentNotFoundOrDeleted := FALSE;\n                            useLuceneUpdateDocument  := TRUE;\n                            indexIntoLucene          := TRUE;\n                        else\n                            (* OP_STALE_OR_EQUAL *)\n                            plan := \"processButSkipLucene\";                  \n                            currentNotFoundOrDeleted := FALSE;\n                            useLuceneUpdateDocument  := FALSE;\n                            indexIntoLucene          := FALSE;\n                        end if;\n                    end if;\n                end if;\n            end if;\n        end if;\n        \n        (* planIndexingAsNonPrimary finished - now time to execute the plan *)\n        ExecuteIndexPlan: \\* Label needed because of AwaitRefreshOnIndex label\n        \n        if indexIntoLucene\n        then\n            lucene_buffer := Append(lucene_buffer, \n                [ type    |-> IF useLuceneUpdateDocument THEN Lucene_updateDocuments ELSE Lucene_addDocuments\n                , seqno   |-> req.seqno\n                , content |-> req.content\n                ]);\n\n            if versionMap_needsSafeAccess\n            then\n                versionMap_entry := [ type |-> UPDATE, seqno |-> req.seqno ];\n            else\n                versionMap_isUnsafe := TRUE;\n\n                if /\\ versionMap_entry /= NULL\n                   /\\ versionMap_entry.type = DELETE\n                   /\\ versionMap_entry.seqno < req.seqno\n                then\n                    versionMap_entry := NULL; \\* Desync bug #3 (no PR number yet)\n                end if;\n            end if;\n        end if;\n        \n        completedSeqnos := completedSeqnos \\cup {req.seqno}\n    end if;\n  end while;\nend process\n\nend algorithm\n\n*)\n\\* BEGIN TRANSLATION\nCONSTANT defaultInitValue\nVARIABLES request_count, replication_requests, expected_doc, \n          versionMap_needsSafeAccess, versionMap_isUnsafe, versionMap_entry, \n          pc, lucene_document, lucene_buffer, localCheckPoint, \n          completedSeqnos, maxSeqNoOfNonAppendOnlyOperations, \n          duplicationCount, maxUnsafeAutoIdTimestamp, req, plan, \n          deleteFromLucene, currentlyDeleted, currentNotFoundOrDeleted, \n          useLuceneUpdateDocument, indexIntoLucene\n\nvars == << request_count, replication_requests, expected_doc, \n           versionMap_needsSafeAccess, versionMap_isUnsafe, versionMap_entry, \n           pc, lucene_document, lucene_buffer, localCheckPoint, \n           completedSeqnos, maxSeqNoOfNonAppendOnlyOperations, \n           duplicationCount, maxUnsafeAutoIdTimestamp, req, plan, \n           deleteFromLucene, currentlyDeleted, currentNotFoundOrDeleted, \n           useLuceneUpdateDocument, indexIntoLucene >>\n\nProcSet == {\"SafeAccessEnabler\"} \\cup {\"UnsafePutter\"} \\cup {\"MaxUnsafeAutoIdTimestampIncreaser\"} \\cup {\"ReplicaLucene\"} \\cup {\"DeleteCollector\"} \\cup {\"LocalCheckpointTracker\"} \\cup {\"UnsafeSeqnoIncreaserProcess\"} \\cup {\"Consumer\"}\n\nInit == (* Global variables *)\n        /\\ request_count \\in 1..4\n        /\\ replication_requests \\in RequestSet(request_count)\n        /\\ expected_doc = FinalDoc(replication_requests)\n        /\\ versionMap_needsSafeAccess = FALSE\n        /\\ versionMap_isUnsafe = FALSE\n        /\\ versionMap_entry = NULL\n        (* Process LuceneProcess *)\n        /\\ lucene_document = NULL\n        /\\ lucene_buffer = <<>>\n        (* Process LocalCheckpointTrackerProcess *)\n        /\\ localCheckPoint = 0\n        /\\ completedSeqnos = {}\n        (* Process UnsafeSeqnoIncreaserProcess *)\n        /\\ maxSeqNoOfNonAppendOnlyOperations = 0\n        (* Process ConsumerProcess *)\n        /\\ duplicationCount = 0\n        /\\ maxUnsafeAutoIdTimestamp \\in {0, DocAutoIdTimestamp - 1, DocAutoIdTimestamp, DocAutoIdTimestamp + 1}\n        /\\ req = defaultInitValue\n        /\\ plan = defaultInitValue\n        /\\ deleteFromLucene = defaultInitValue\n        /\\ currentlyDeleted = defaultInitValue\n        /\\ currentNotFoundOrDeleted = defaultInitValue\n        /\\ useLuceneUpdateDocument = defaultInitValue\n        /\\ indexIntoLucene = defaultInitValue\n        /\\ pc = [self \\in ProcSet |-> CASE self = \"SafeAccessEnabler\" -> \"SafeAccessEnablerLoop\"\n                                        [] self = \"UnsafePutter\" -> \"UnsafePutterLoop\"\n                                        [] self = \"MaxUnsafeAutoIdTimestampIncreaser\" -> \"MaxUnsafeAutoIdTimestampIncreaserLoop\"\n                                        [] self = \"ReplicaLucene\" -> \"LuceneLoop\"\n                                        [] self = \"DeleteCollector\" -> \"DeleteCollectorLoop\"\n                                        [] self = \"LocalCheckpointTracker\" -> \"LocalCheckpointTrackerLoop\"\n                                        [] self = \"UnsafeSeqnoIncreaserProcess\" -> \"UnsafeSeqnoIncreaserProcessLoop\"\n                                        [] self = \"Consumer\" -> \"ConsumerLoop\"]\n\nSafeAccessEnablerLoop == /\\ pc[\"SafeAccessEnabler\"] = \"SafeAccessEnablerLoop\"\n                         /\\ IF pc[\"Consumer\"] /= \"Done\"\n                               THEN /\\ versionMap_needsSafeAccess' = (versionMap_needsSafeAccess = FALSE)\n                                    /\\ pc' = [pc EXCEPT ![\"SafeAccessEnabler\"] = \"SafeAccessEnablerLoop\"]\n                               ELSE /\\ pc' = [pc EXCEPT ![\"SafeAccessEnabler\"] = \"Done\"]\n                                    /\\ UNCHANGED versionMap_needsSafeAccess\n                         /\\ UNCHANGED << request_count, replication_requests, \n                                         expected_doc, versionMap_isUnsafe, \n                                         versionMap_entry, lucene_document, \n                                         lucene_buffer, localCheckPoint, \n                                         completedSeqnos, \n                                         maxSeqNoOfNonAppendOnlyOperations, \n                                         duplicationCount, \n                                         maxUnsafeAutoIdTimestamp, req, plan, \n                                         deleteFromLucene, currentlyDeleted, \n                                         currentNotFoundOrDeleted, \n                                         useLuceneUpdateDocument, \n                                         indexIntoLucene >>\n\nSafeAccessEnablerProcess == SafeAccessEnablerLoop\n\nUnsafePutterLoop == /\\ pc[\"UnsafePutter\"] = \"UnsafePutterLoop\"\n                    /\\ IF pc[\"Consumer\"] /= \"Done\"\n                          THEN /\\ versionMap_needsSafeAccess = FALSE\n                               /\\ versionMap_isUnsafe' = TRUE\n                               /\\ pc' = [pc EXCEPT ![\"UnsafePutter\"] = \"UnsafePutterLoop\"]\n                          ELSE /\\ pc' = [pc EXCEPT ![\"UnsafePutter\"] = \"Done\"]\n                               /\\ UNCHANGED versionMap_isUnsafe\n                    /\\ UNCHANGED << request_count, replication_requests, \n                                    expected_doc, versionMap_needsSafeAccess, \n                                    versionMap_entry, lucene_document, \n                                    lucene_buffer, localCheckPoint, \n                                    completedSeqnos, \n                                    maxSeqNoOfNonAppendOnlyOperations, \n                                    duplicationCount, maxUnsafeAutoIdTimestamp, \n                                    req, plan, deleteFromLucene, \n                                    currentlyDeleted, currentNotFoundOrDeleted, \n                                    useLuceneUpdateDocument, indexIntoLucene >>\n\nUnsafePutterProcess == UnsafePutterLoop\n\nMaxUnsafeAutoIdTimestampIncreaserLoop == /\\ pc[\"MaxUnsafeAutoIdTimestampIncreaser\"] = \"MaxUnsafeAutoIdTimestampIncreaserLoop\"\n                                         /\\ IF pc[\"Consumer\"] /= \"Done\"\n                                               THEN /\\ \\E newTimestamp \\in {DocAutoIdTimestamp - 1, DocAutoIdTimestamp, DocAutoIdTimestamp + 1}:\n                                                         /\\ maxUnsafeAutoIdTimestamp < newTimestamp\n                                                         /\\ maxUnsafeAutoIdTimestamp' = newTimestamp\n                                                    /\\ pc' = [pc EXCEPT ![\"MaxUnsafeAutoIdTimestampIncreaser\"] = \"MaxUnsafeAutoIdTimestampIncreaserLoop\"]\n                                               ELSE /\\ pc' = [pc EXCEPT ![\"MaxUnsafeAutoIdTimestampIncreaser\"] = \"Done\"]\n                                                    /\\ UNCHANGED maxUnsafeAutoIdTimestamp\n                                         /\\ UNCHANGED << request_count, \n                                                         replication_requests, \n                                                         expected_doc, \n                                                         versionMap_needsSafeAccess, \n                                                         versionMap_isUnsafe, \n                                                         versionMap_entry, \n                                                         lucene_document, \n                                                         lucene_buffer, \n                                                         localCheckPoint, \n                                                         completedSeqnos, \n                                                         maxSeqNoOfNonAppendOnlyOperations, \n                                                         duplicationCount, req, \n                                                         plan, \n                                                         deleteFromLucene, \n                                                         currentlyDeleted, \n                                                         currentNotFoundOrDeleted, \n                                                         useLuceneUpdateDocument, \n                                                         indexIntoLucene >>\n\nMaxUnsafeAutoIdTimestampIncreaserProcess == MaxUnsafeAutoIdTimestampIncreaserLoop\n\nLuceneLoop == /\\ pc[\"ReplicaLucene\"] = \"LuceneLoop\"\n              /\\ IF pc[\"Consumer\"] /= \"Done\" \\/ lucene_buffer /= <<>>\n                    THEN /\\ lucene_document' = ApplyBufferedOperations(lucene_buffer, lucene_document)\n                         /\\ lucene_buffer' = <<>>\n                         /\\ versionMap_isUnsafe' = FALSE\n                         /\\ versionMap_needsSafeAccess' = FALSE\n                         /\\ IF versionMap_entry /= NULL\n                               THEN /\\ IF versionMap_entry.type = UPDATE\n                                          THEN /\\ versionMap_entry' = NULL\n                                          ELSE /\\ Assert(versionMap_entry.type = DELETE, \n                                                         \"Failure of assertion at line 147, column 17.\")\n                                               /\\ versionMap_entry' = [ versionMap_entry EXCEPT !.flushed = TRUE ]\n                               ELSE /\\ TRUE\n                                    /\\ UNCHANGED versionMap_entry\n                         /\\ pc' = [pc EXCEPT ![\"ReplicaLucene\"] = \"LuceneLoop\"]\n                    ELSE /\\ pc' = [pc EXCEPT ![\"ReplicaLucene\"] = \"Done\"]\n                         /\\ UNCHANGED << versionMap_needsSafeAccess, \n                                         versionMap_isUnsafe, versionMap_entry, \n                                         lucene_document, lucene_buffer >>\n              /\\ UNCHANGED << request_count, replication_requests, \n                              expected_doc, localCheckPoint, completedSeqnos, \n                              maxSeqNoOfNonAppendOnlyOperations, \n                              duplicationCount, maxUnsafeAutoIdTimestamp, req, \n                              plan, deleteFromLucene, currentlyDeleted, \n                              currentNotFoundOrDeleted, \n                              useLuceneUpdateDocument, indexIntoLucene >>\n\nLuceneProcess == LuceneLoop\n\nDeleteCollectorLoop == /\\ pc[\"DeleteCollector\"] = \"DeleteCollectorLoop\"\n                       /\\ IF pc[\"Consumer\"] /= \"Done\"\n                             THEN /\\ /\\ versionMap_entry /= NULL\n                                     /\\ versionMap_entry.type = DELETE\n                                     /\\ versionMap_entry.seqno <= localCheckPoint\n                                     /\\ versionMap_entry.flushed = TRUE\n                                  /\\ versionMap_entry' = NULL\n                                  /\\ pc' = [pc EXCEPT ![\"DeleteCollector\"] = \"DeleteCollectorLoop\"]\n                             ELSE /\\ pc' = [pc EXCEPT ![\"DeleteCollector\"] = \"Done\"]\n                                  /\\ UNCHANGED versionMap_entry\n                       /\\ UNCHANGED << request_count, replication_requests, \n                                       expected_doc, \n                                       versionMap_needsSafeAccess, \n                                       versionMap_isUnsafe, lucene_document, \n                                       lucene_buffer, localCheckPoint, \n                                       completedSeqnos, \n                                       maxSeqNoOfNonAppendOnlyOperations, \n                                       duplicationCount, \n                                       maxUnsafeAutoIdTimestamp, req, plan, \n                                       deleteFromLucene, currentlyDeleted, \n                                       currentNotFoundOrDeleted, \n                                       useLuceneUpdateDocument, \n                                       indexIntoLucene >>\n\nDeleteCollectorProcess == DeleteCollectorLoop\n\nLocalCheckpointTrackerLoop == /\\ pc[\"LocalCheckpointTracker\"] = \"LocalCheckpointTrackerLoop\"\n                              /\\ IF pc[\"Consumer\"] /= \"Done\"\n                                    THEN /\\ localCheckPoint + 1 \\in completedSeqnos\n                                         /\\ localCheckPoint' = localCheckPoint + 1\n                                         /\\ pc' = [pc EXCEPT ![\"LocalCheckpointTracker\"] = \"LocalCheckpointTrackerLoop\"]\n                                    ELSE /\\ pc' = [pc EXCEPT ![\"LocalCheckpointTracker\"] = \"Done\"]\n                                         /\\ UNCHANGED localCheckPoint\n                              /\\ UNCHANGED << request_count, \n                                              replication_requests, \n                                              expected_doc, \n                                              versionMap_needsSafeAccess, \n                                              versionMap_isUnsafe, \n                                              versionMap_entry, \n                                              lucene_document, lucene_buffer, \n                                              completedSeqnos, \n                                              maxSeqNoOfNonAppendOnlyOperations, \n                                              duplicationCount, \n                                              maxUnsafeAutoIdTimestamp, req, \n                                              plan, deleteFromLucene, \n                                              currentlyDeleted, \n                                              currentNotFoundOrDeleted, \n                                              useLuceneUpdateDocument, \n                                              indexIntoLucene >>\n\nLocalCheckpointTrackerProcess == LocalCheckpointTrackerLoop\n\nUnsafeSeqnoIncreaserProcessLoop == /\\ pc[\"UnsafeSeqnoIncreaserProcess\"] = \"UnsafeSeqnoIncreaserProcessLoop\"\n                                   /\\ IF pc[\"Consumer\"] /= \"Done\" /\\ maxSeqNoOfNonAppendOnlyOperations < request_count + 1\n                                         THEN /\\ maxSeqNoOfNonAppendOnlyOperations' = maxSeqNoOfNonAppendOnlyOperations + 1\n                                              /\\ pc' = [pc EXCEPT ![\"UnsafeSeqnoIncreaserProcess\"] = \"UnsafeSeqnoIncreaserProcessLoop\"]\n                                         ELSE /\\ pc' = [pc EXCEPT ![\"UnsafeSeqnoIncreaserProcess\"] = \"Done\"]\n                                              /\\ UNCHANGED maxSeqNoOfNonAppendOnlyOperations\n                                   /\\ UNCHANGED << request_count, \n                                                   replication_requests, \n                                                   expected_doc, \n                                                   versionMap_needsSafeAccess, \n                                                   versionMap_isUnsafe, \n                                                   versionMap_entry, \n                                                   lucene_document, \n                                                   lucene_buffer, \n                                                   localCheckPoint, \n                                                   completedSeqnos, \n                                                   duplicationCount, \n                                                   maxUnsafeAutoIdTimestamp, \n                                                   req, plan, deleteFromLucene, \n                                                   currentlyDeleted, \n                                                   currentNotFoundOrDeleted, \n                                                   useLuceneUpdateDocument, \n                                                   indexIntoLucene >>\n\nUnsafeSeqnoIncreaserProcess == UnsafeSeqnoIncreaserProcessLoop\n\nConsumerLoop == /\\ pc[\"Consumer\"] = \"ConsumerLoop\"\n                /\\ IF replication_requests /= {}\n                      THEN /\\ \\E replication_request \\in replication_requests:\n                                IF replication_request.type = ADD\n                                   THEN /\\ \\/ /\\ replication_requests' = replication_requests \\ {replication_request}\n                                              /\\ req' = replication_request\n                                              /\\ UNCHANGED duplicationCount\n                                           \\/ /\\ duplicationCount < DuplicationLimit\n                                              /\\ duplicationCount' = duplicationCount + 1\n                                              /\\ replication_requests' =                     (replication_requests \\ {replication_request})\n                                                                         \\cup {[replication_request EXCEPT !.type = RETRY_ADD]}\n                                              /\\ req' = replication_request\n                                           \\/ /\\ duplicationCount < DuplicationLimit\n                                              /\\ duplicationCount' = duplicationCount + 1\n                                              /\\ req' = [replication_request EXCEPT !.type = RETRY_ADD]\n                                              /\\ UNCHANGED replication_requests\n                                   ELSE /\\ req' = replication_request\n                                        /\\ \\/ /\\ duplicationCount < DuplicationLimit\n                                              /\\ duplicationCount' = duplicationCount + 1\n                                              /\\ UNCHANGED replication_requests\n                                           \\/ /\\ replication_requests' = replication_requests \\ {replication_request}\n                                              /\\ UNCHANGED duplicationCount\n                           /\\ IF req'.type = DELETE\n                                 THEN /\\ versionMap_needsSafeAccess' = TRUE\n                                      /\\ maxSeqNoOfNonAppendOnlyOperations' = Max(maxSeqNoOfNonAppendOnlyOperations, req'.seqno)\n                                      /\\ IF req'.seqno <= localCheckPoint\n                                            THEN /\\ plan' = \"processButSkipLucene\"\n                                                 /\\ deleteFromLucene' = FALSE\n                                                 /\\ currentlyDeleted' = FALSE\n                                                 /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"ExecuteDeletePlan\"]\n                                            ELSE /\\ IF versionMap_isUnsafe\n                                                       THEN /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"AwaitRefreshOnDelete\"]\n                                                       ELSE /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"compareDeleteOpToLuceneDocBasedOnSeqNo\"]\n                                                 /\\ UNCHANGED << plan, \n                                                                 deleteFromLucene, \n                                                                 currentlyDeleted >>\n                                      /\\ UNCHANGED << maxUnsafeAutoIdTimestamp, \n                                                      currentNotFoundOrDeleted, \n                                                      useLuceneUpdateDocument, \n                                                      indexIntoLucene >>\n                                 ELSE /\\ IF req'.type = RETRY_ADD\n                                            THEN /\\ maxUnsafeAutoIdTimestamp' = Max(maxUnsafeAutoIdTimestamp, req'.autoIdTimeStamp)\n                                            ELSE /\\ TRUE\n                                                 /\\ UNCHANGED maxUnsafeAutoIdTimestamp\n                                      /\\ IF /\\ req'.type = ADD\n                                            /\\ maxUnsafeAutoIdTimestamp' < req'.autoIdTimeStamp\n                                            /\\ maxSeqNoOfNonAppendOnlyOperations < req'.seqno\n                                            THEN /\\ plan' = \"optimisedAppendOnly\"\n                                                 /\\ currentNotFoundOrDeleted' = TRUE\n                                                 /\\ useLuceneUpdateDocument' = FALSE\n                                                 /\\ indexIntoLucene' = TRUE\n                                                 /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"ExecuteIndexPlan\"]\n                                                 /\\ UNCHANGED << versionMap_needsSafeAccess, \n                                                                 maxSeqNoOfNonAppendOnlyOperations >>\n                                            ELSE /\\ IF req'.type \\notin {ADD, RETRY_ADD}\n                                                       THEN /\\ maxSeqNoOfNonAppendOnlyOperations' = Max(maxSeqNoOfNonAppendOnlyOperations, req'.seqno)\n                                                       ELSE /\\ TRUE\n                                                            /\\ UNCHANGED maxSeqNoOfNonAppendOnlyOperations\n                                                 /\\ versionMap_needsSafeAccess' = TRUE\n                                                 /\\ IF req'.seqno <= localCheckPoint\n                                                       THEN /\\ plan' = \"processButSkipLucene\"\n                                                            /\\ currentNotFoundOrDeleted' = FALSE\n                                                            /\\ useLuceneUpdateDocument' = FALSE\n                                                            /\\ indexIntoLucene' = FALSE\n                                                            /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"ExecuteIndexPlan\"]\n                                                       ELSE /\\ IF versionMap_isUnsafe\n                                                                  THEN /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"AwaitRefreshOnIndex\"]\n                                                                  ELSE /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"compareIndexOpToLuceneDocBasedOnSeqNo\"]\n                                                            /\\ UNCHANGED << plan, \n                                                                            currentNotFoundOrDeleted, \n                                                                            useLuceneUpdateDocument, \n                                                                            indexIntoLucene >>\n                                      /\\ UNCHANGED << deleteFromLucene, \n                                                      currentlyDeleted >>\n                      ELSE /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"Done\"]\n                           /\\ UNCHANGED << replication_requests, \n                                           versionMap_needsSafeAccess, \n                                           maxSeqNoOfNonAppendOnlyOperations, \n                                           duplicationCount, \n                                           maxUnsafeAutoIdTimestamp, req, plan, \n                                           deleteFromLucene, currentlyDeleted, \n                                           currentNotFoundOrDeleted, \n                                           useLuceneUpdateDocument, \n                                           indexIntoLucene >>\n                /\\ UNCHANGED << request_count, expected_doc, \n                                versionMap_isUnsafe, versionMap_entry, \n                                lucene_document, lucene_buffer, \n                                localCheckPoint, completedSeqnos >>\n\nExecuteDeletePlan == /\\ pc[\"Consumer\"] = \"ExecuteDeletePlan\"\n                     /\\ IF deleteFromLucene\n                           THEN /\\ IF currentlyDeleted = FALSE\n                                      THEN /\\ lucene_buffer' = Append(lucene_buffer, [ type |-> Lucene_deleteDocuments ])\n                                      ELSE /\\ TRUE\n                                           /\\ UNCHANGED lucene_buffer\n                                /\\ versionMap_entry' = [ type |-> DELETE, seqno |-> req.seqno, flushed |-> FALSE ]\n                           ELSE /\\ TRUE\n                                /\\ UNCHANGED << versionMap_entry, \n                                                lucene_buffer >>\n                     /\\ completedSeqnos' = (completedSeqnos \\cup {req.seqno})\n                     /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"ConsumerLoop\"]\n                     /\\ UNCHANGED << request_count, replication_requests, \n                                     expected_doc, versionMap_needsSafeAccess, \n                                     versionMap_isUnsafe, lucene_document, \n                                     localCheckPoint, \n                                     maxSeqNoOfNonAppendOnlyOperations, \n                                     duplicationCount, \n                                     maxUnsafeAutoIdTimestamp, req, plan, \n                                     deleteFromLucene, currentlyDeleted, \n                                     currentNotFoundOrDeleted, \n                                     useLuceneUpdateDocument, indexIntoLucene >>\n\nExecuteIndexPlan == /\\ pc[\"Consumer\"] = \"ExecuteIndexPlan\"\n                    /\\ IF indexIntoLucene\n                          THEN /\\ lucene_buffer' =              Append(lucene_buffer,\n                                                   [ type    |-> IF useLuceneUpdateDocument THEN Lucene_updateDocuments ELSE Lucene_addDocuments\n                                                   , seqno   |-> req.seqno\n                                                   , content |-> req.content\n                                                   ])\n                               /\\ IF versionMap_needsSafeAccess\n                                     THEN /\\ versionMap_entry' = [ type |-> UPDATE, seqno |-> req.seqno ]\n                                          /\\ UNCHANGED versionMap_isUnsafe\n                                     ELSE /\\ versionMap_isUnsafe' = TRUE\n                                          /\\ IF /\\ versionMap_entry /= NULL\n                                                /\\ versionMap_entry.type = DELETE\n                                                /\\ versionMap_entry.seqno < req.seqno\n                                                THEN /\\ versionMap_entry' = NULL\n                                                ELSE /\\ TRUE\n                                                     /\\ UNCHANGED versionMap_entry\n                          ELSE /\\ TRUE\n                               /\\ UNCHANGED << versionMap_isUnsafe, \n                                               versionMap_entry, lucene_buffer >>\n                    /\\ completedSeqnos' = (completedSeqnos \\cup {req.seqno})\n                    /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"ConsumerLoop\"]\n                    /\\ UNCHANGED << request_count, replication_requests, \n                                    expected_doc, versionMap_needsSafeAccess, \n                                    lucene_document, localCheckPoint, \n                                    maxSeqNoOfNonAppendOnlyOperations, \n                                    duplicationCount, maxUnsafeAutoIdTimestamp, \n                                    req, plan, deleteFromLucene, \n                                    currentlyDeleted, currentNotFoundOrDeleted, \n                                    useLuceneUpdateDocument, indexIntoLucene >>\n\ncompareDeleteOpToLuceneDocBasedOnSeqNo == /\\ pc[\"Consumer\"] = \"compareDeleteOpToLuceneDocBasedOnSeqNo\"\n                                          /\\ IF versionMap_entry /= NULL\n                                                THEN /\\ IF req.seqno > versionMap_entry.seqno\n                                                           THEN /\\ plan' = \"processNormally\"\n                                                                /\\ deleteFromLucene' = TRUE\n                                                                /\\ currentlyDeleted' = FALSE\n                                                           ELSE /\\ plan' = \"processButSkipLucene\"\n                                                                /\\ deleteFromLucene' = FALSE\n                                                                /\\ currentlyDeleted' = FALSE\n                                                ELSE /\\ IF lucene_document = NULL\n                                                           THEN /\\ plan' = \"processNormallyExceptNotFound\"\n                                                                /\\ deleteFromLucene' = TRUE\n                                                                /\\ currentlyDeleted' = TRUE\n                                                           ELSE /\\ IF req.seqno > lucene_document.seqno\n                                                                      THEN /\\ plan' = \"processNormally\"\n                                                                           /\\ deleteFromLucene' = TRUE\n                                                                           /\\ currentlyDeleted' = FALSE\n                                                                      ELSE /\\ plan' = \"processButSkipLucene\"\n                                                                           /\\ deleteFromLucene' = FALSE\n                                                                           /\\ currentlyDeleted' = FALSE\n                                          /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"ExecuteDeletePlan\"]\n                                          /\\ UNCHANGED << request_count, \n                                                          replication_requests, \n                                                          expected_doc, \n                                                          versionMap_needsSafeAccess, \n                                                          versionMap_isUnsafe, \n                                                          versionMap_entry, \n                                                          lucene_document, \n                                                          lucene_buffer, \n                                                          localCheckPoint, \n                                                          completedSeqnos, \n                                                          maxSeqNoOfNonAppendOnlyOperations, \n                                                          duplicationCount, \n                                                          maxUnsafeAutoIdTimestamp, \n                                                          req, \n                                                          currentNotFoundOrDeleted, \n                                                          useLuceneUpdateDocument, \n                                                          indexIntoLucene >>\n\nAwaitRefreshOnDelete == /\\ pc[\"Consumer\"] = \"AwaitRefreshOnDelete\"\n                        /\\ lucene_buffer = <<>>\n                        /\\ versionMap_needsSafeAccess' = TRUE\n                        /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"compareDeleteOpToLuceneDocBasedOnSeqNo\"]\n                        /\\ UNCHANGED << request_count, replication_requests, \n                                        expected_doc, versionMap_isUnsafe, \n                                        versionMap_entry, lucene_document, \n                                        lucene_buffer, localCheckPoint, \n                                        completedSeqnos, \n                                        maxSeqNoOfNonAppendOnlyOperations, \n                                        duplicationCount, \n                                        maxUnsafeAutoIdTimestamp, req, plan, \n                                        deleteFromLucene, currentlyDeleted, \n                                        currentNotFoundOrDeleted, \n                                        useLuceneUpdateDocument, \n                                        indexIntoLucene >>\n\ncompareIndexOpToLuceneDocBasedOnSeqNo == /\\ pc[\"Consumer\"] = \"compareIndexOpToLuceneDocBasedOnSeqNo\"\n                                         /\\ IF req.seqno <= localCheckPoint\n                                               THEN /\\ plan' = \"processButSkipLucene\"\n                                                    /\\ currentNotFoundOrDeleted' = FALSE\n                                                    /\\ useLuceneUpdateDocument' = FALSE\n                                                    /\\ indexIntoLucene' = FALSE\n                                               ELSE /\\ IF versionMap_entry /= NULL\n                                                          THEN /\\ IF req.seqno > versionMap_entry.seqno\n                                                                     THEN /\\ plan' = \"processNormally\"\n                                                                          /\\ currentNotFoundOrDeleted' = FALSE\n                                                                          /\\ useLuceneUpdateDocument' = TRUE\n                                                                          /\\ indexIntoLucene' = TRUE\n                                                                     ELSE /\\ plan' = \"processButSkipLucene\"\n                                                                          /\\ currentNotFoundOrDeleted' = FALSE\n                                                                          /\\ useLuceneUpdateDocument' = FALSE\n                                                                          /\\ indexIntoLucene' = FALSE\n                                                          ELSE /\\ IF lucene_document = NULL\n                                                                     THEN /\\ plan' = \"processNormallyExceptNotFound\"\n                                                                          /\\ currentNotFoundOrDeleted' = TRUE\n                                                                          /\\ useLuceneUpdateDocument' = FALSE\n                                                                          /\\ indexIntoLucene' = TRUE\n                                                                     ELSE /\\ IF req.seqno > lucene_document.seqno\n                                                                                THEN /\\ plan' = \"processNormally\"\n                                                                                     /\\ currentNotFoundOrDeleted' = FALSE\n                                                                                     /\\ useLuceneUpdateDocument' = TRUE\n                                                                                     /\\ indexIntoLucene' = TRUE\n                                                                                ELSE /\\ plan' = \"processButSkipLucene\"\n                                                                                     /\\ currentNotFoundOrDeleted' = FALSE\n                                                                                     /\\ useLuceneUpdateDocument' = FALSE\n                                                                                     /\\ indexIntoLucene' = FALSE\n                                         /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"ExecuteIndexPlan\"]\n                                         /\\ UNCHANGED << request_count, \n                                                         replication_requests, \n                                                         expected_doc, \n                                                         versionMap_needsSafeAccess, \n                                                         versionMap_isUnsafe, \n                                                         versionMap_entry, \n                                                         lucene_document, \n                                                         lucene_buffer, \n                                                         localCheckPoint, \n                                                         completedSeqnos, \n                                                         maxSeqNoOfNonAppendOnlyOperations, \n                                                         duplicationCount, \n                                                         maxUnsafeAutoIdTimestamp, \n                                                         req, deleteFromLucene, \n                                                         currentlyDeleted >>\n\nAwaitRefreshOnIndex == /\\ pc[\"Consumer\"] = \"AwaitRefreshOnIndex\"\n                       /\\ lucene_buffer = <<>>\n                       /\\ versionMap_needsSafeAccess' = TRUE\n                       /\\ pc' = [pc EXCEPT ![\"Consumer\"] = \"compareIndexOpToLuceneDocBasedOnSeqNo\"]\n                       /\\ UNCHANGED << request_count, replication_requests, \n                                       expected_doc, versionMap_isUnsafe, \n                                       versionMap_entry, lucene_document, \n                                       lucene_buffer, localCheckPoint, \n                                       completedSeqnos, \n                                       maxSeqNoOfNonAppendOnlyOperations, \n                                       duplicationCount, \n                                       maxUnsafeAutoIdTimestamp, req, plan, \n                                       deleteFromLucene, currentlyDeleted, \n                                       currentNotFoundOrDeleted, \n                                       useLuceneUpdateDocument, \n                                       indexIntoLucene >>\n\nConsumerProcess == ConsumerLoop \\/ ExecuteDeletePlan \\/ ExecuteIndexPlan\n                      \\/ compareDeleteOpToLuceneDocBasedOnSeqNo\n                      \\/ AwaitRefreshOnDelete\n                      \\/ compareIndexOpToLuceneDocBasedOnSeqNo\n                      \\/ AwaitRefreshOnIndex\n\nNext == SafeAccessEnablerProcess \\/ UnsafePutterProcess\n           \\/ MaxUnsafeAutoIdTimestampIncreaserProcess \\/ LuceneProcess\n           \\/ DeleteCollectorProcess \\/ LocalCheckpointTrackerProcess\n           \\/ UnsafeSeqnoIncreaserProcess \\/ ConsumerProcess\n           \\/ (* Disjunct to prevent deadlock on termination *)\n              ((\\A self \\in ProcSet: pc[self] = \"Done\") /\\ UNCHANGED vars)\n\nSpec == Init /\\ [][Next]_vars\n\nTermination == <>(\\A self \\in ProcSet: pc[self] = \"Done\")\n\n\\* END TRANSLATION\n\nTerminated == \\A self \\in ProcSet: pc[self] = \"Done\"\n\nInvariant == Terminated => /\\ expected_doc  = NULL => lucene_document = NULL\n                           /\\ expected_doc /= NULL => lucene_document.content = expected_doc\n\n=============================================================================\n"
  },
  {
    "path": "ReplicaEngine/tla/ReplicaEngine.toolbox/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>ReplicaEngine</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>toolbox.builder.TLAParserBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>toolbox.builder.PCalAlgorithmSearchingBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>toolbox.natures.TLANature</nature>\n\t</natures>\n\t<linkedResources>\n\t\t<link>\n\t\t\t<name>ReplicaEngine.tla</name>\n\t\t\t<type>1</type>\n\t\t\t<locationURI>PARENT-1-PROJECT_LOC/ReplicaEngine.tla</locationURI>\n\t\t</link>\n\t</linkedResources>\n</projectDescription>\n"
  },
  {
    "path": "ReplicaEngine/tla/ReplicaEngine.toolbox/.settings/org.lamport.tla.toolbox.prefs",
    "content": "ProjectRootFile=PARENT-1-PROJECT_LOC/ReplicaEngine.tla\neclipse.preferences.version=1\n"
  },
  {
    "path": "ReplicaEngine/tla/ReplicaEngine.toolbox/ReplicaEngine___model.launch",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<launchConfiguration type=\"org.lamport.tla.toolbox.tool.tlc.modelCheck\">\n<stringAttribute key=\"TLCCmdLineParameters\" value=\"\"/>\n<stringAttribute key=\"configurationName\" value=\"model\"/>\n<intAttribute key=\"dfidDepth\" value=\"100\"/>\n<booleanAttribute key=\"dfidMode\" value=\"false\"/>\n<intAttribute key=\"distributedFPSetCount\" value=\"0\"/>\n<stringAttribute key=\"distributedNetworkInterface\" value=\"192.168.1.39\"/>\n<intAttribute key=\"distributedNodesCount\" value=\"1\"/>\n<stringAttribute key=\"distributedTLC\" value=\"off\"/>\n<stringAttribute key=\"distributedTLCVMArgs\" value=\"\"/>\n<intAttribute key=\"fpBits\" value=\"1\"/>\n<intAttribute key=\"fpIndex\" value=\"1\"/>\n<intAttribute key=\"maxHeapSize\" value=\"25\"/>\n<intAttribute key=\"maxSetSize\" value=\"1000000\"/>\n<booleanAttribute key=\"mcMode\" value=\"true\"/>\n<stringAttribute key=\"modelBehaviorInit\" value=\"\"/>\n<stringAttribute key=\"modelBehaviorNext\" value=\"\"/>\n<stringAttribute key=\"modelBehaviorSpec\" value=\"Spec\"/>\n<intAttribute key=\"modelBehaviorSpecType\" value=\"1\"/>\n<stringAttribute key=\"modelBehaviorVars\" value=\"versionMap_isUnsafe, lucene_buffer, maxSeqNoOfNonAppendOnlyOperations, request_count, expected_doc, duplicationCount, useLuceneUpdateDocument, pc, versionMap_entry, replication_requests, maxUnsafeAutoIdTimestamp, currentlyDeleted, req, lucene_document, indexIntoLucene, versionMap_needsSafeAccess, deleteFromLucene, currentNotFoundOrDeleted, plan, localCheckPoint, completedSeqnos\"/>\n<stringAttribute key=\"modelComments\" value=\"\"/>\n<booleanAttribute key=\"modelCorrectnessCheckDeadlock\" value=\"true\"/>\n<listAttribute key=\"modelCorrectnessInvariants\">\n<listEntry value=\"1Invariant\"/>\n</listAttribute>\n<listAttribute key=\"modelCorrectnessProperties\">\n<listEntry value=\"0Termination\"/>\n<listEntry value=\"1Invariant\"/>\n</listAttribute>\n<stringAttribute key=\"modelExpressionEval\" value=\"\"/>\n<stringAttribute key=\"modelParameterActionConstraint\" value=\"\"/>\n<listAttribute key=\"modelParameterConstants\">\n<listEntry value=\"UPDATE;;UPDATE;1;0\"/>\n<listEntry value=\"NULL;;NULL;1;0\"/>\n<listEntry value=\"ADD;;ADD;1;0\"/>\n<listEntry value=\"DELETE;;DELETE;1;0\"/>\n<listEntry value=\"DocContent;;{DocA, DocB};1;1\"/>\n<listEntry value=\"RETRY_ADD;;RETRY_ADD;1;0\"/>\n<listEntry value=\"Lucene_deleteDocuments;;Lucene_deleteDocuments;1;0\"/>\n<listEntry value=\"Lucene_addDocuments;;Lucene_addDocuments;1;0\"/>\n<listEntry value=\"Lucene_updateDocuments;;Lucene_updateDocuments;1;0\"/>\n<listEntry value=\"DocAutoIdTimestamp;;1000;0;0\"/>\n<listEntry value=\"defaultInitValue;;defaultInitValue;1;0\"/>\n<listEntry value=\"DuplicationLimit;;1;0;0\"/>\n</listAttribute>\n<stringAttribute key=\"modelParameterContraint\" value=\"\"/>\n<listAttribute key=\"modelParameterDefinitions\"/>\n<stringAttribute key=\"modelParameterModelValues\" value=\"{}\"/>\n<stringAttribute key=\"modelParameterNewDefinitions\" value=\"\"/>\n<stringAttribute key=\"modelPropertiesExpand\" value=\"\"/>\n<intAttribute key=\"numberOfWorkers\" value=\"4\"/>\n<booleanAttribute key=\"recover\" value=\"false\"/>\n<stringAttribute key=\"result.mail.address\" value=\"\"/>\n<intAttribute key=\"simuAril\" value=\"-1\"/>\n<intAttribute key=\"simuDepth\" value=\"100\"/>\n<intAttribute key=\"simuSeed\" value=\"-1\"/>\n<stringAttribute key=\"specName\" value=\"ReplicaEngine\"/>\n<stringAttribute key=\"view\" value=\"\"/>\n</launchConfiguration>\n"
  },
  {
    "path": "Storage/tla/Storage.tla",
    "content": "------------------------------ MODULE Storage ------------------------------\nEXTENDS Integers, FiniteSets, TLC\n\nCONSTANTS \n    MaxNewMeta, \\* maximum generation of newMeta to limit the state space\n    MetaDataContent \\* content that is written to the metadata file\n    \nVARIABLES\n    metadata,      \\* metaData[i] = MetaDataContent if metadata of generation i is present\n    manifest,      \\* manifest[j] is generation of metadata j-th manifest is referencing\n    newMeta,       \\* generation of newly created metadata file\n    newManifest,   \\* generation of newly created manifest file\n    state,         \\* current state, describes what to do next\n    possibleStates \\* set of generations of metadata that limits what can be read from disk\n\n--------------------------------------------------------------------------\n(*************************************************************************)\n(* First we define some helper functions to work with files abstraction. *)\n(* Files is a function from file generation to some content.             *)\n(*************************************************************************)\n\n(*************************************************************************)\n(* CurrentGeneration returns the maximum file generation. If there are   *)\n(* no files then -1 is returned.                                         *)                                              \n(*************************************************************************)\nCurrentGeneration(files) == \n    IF DOMAIN files = {} \n        THEN -1 \n    ELSE \n        CHOOSE gen \\in DOMAIN files : \n            \\A otherGen \\in DOMAIN files : gen \\geq otherGen\n\n(*************************************************************************)\n(* DeleteFile removes file with generation delGen.                        *)\n(*************************************************************************)\nDeleteFile(files, delGen) == [gen \\in DOMAIN files \\ {delGen} |-> files[gen]]\n\n(*************************************************************************)\n(* DeleteFilesExcept removes all files except keepGen.                 *)\n(*************************************************************************)\nDeleteFilesExcept(files, keepGen) == (keepGen :> files[keepGen])\n\n(*************************************************************************)\n(* WriteFile creates new file with specified generation and content.     *)\n(*************************************************************************)\nWriteFile(files, gen, content) == (gen :> content) @@ files\n  \n--------------------------------------------------------------------------\n(*************************************************************************)\n(* Now we define functions to emulate write and cleanup of the metadata. *)\n(*************************************************************************)\nWriteMetaOk(gen) == \n    /\\ metadata' = WriteFile(metadata, gen, MetaDataContent)\n    /\\ state' = \"writeManifest\"\n\nWriteMetaFail(gen) == \n    /\\ metadata' = metadata\n    /\\ state' = \"writeMeta\"\n                \nWriteMetaDirty(gen) == \n    /\\ \\/ metadata' = WriteFile(metadata, gen, MetaDataContent)\n       \\/ metadata' = metadata\n    /\\ state' = \"deleteNewMeta\"\n\nDeleteNewMeta == \n    /\\ \\/ metadata' = DeleteFile(metadata, newMeta) \n       \\/ metadata' = metadata\n    /\\ state' = \"writeMeta\"\n    /\\ UNCHANGED <<newMeta, newManifest, manifest, possibleStates>> \n\nDeleteOldMeta ==\n    /\\ \\/ metadata' = DeleteFilesExcept(metadata, newMeta) \n       \\/ metadata' = metadata\n    /\\ state' = \"writeMeta\"\n    /\\ UNCHANGED <<newMeta, newManifest, manifest, possibleStates>>\n\nWriteMeta == \n    LET gen == CurrentGeneration(metadata) + 1 IN \n        /\\ newMeta' = gen\n        /\\ \\/ WriteMetaOk(gen) \n           \\/ WriteMetaFail(gen) \n           \\/ WriteMetaDirty(gen)\n        /\\ UNCHANGED <<newManifest, manifest, possibleStates>>\n\n--------------------------------------------------------------------------\n(*************************************************************************)\n(* Now we define functions to emulate write and cleanup of the manifest  *)\n(* file.                                                                 *)\n(*************************************************************************)      \nWriteManifestOk(gen) == \n    /\\ manifest' = WriteFile(manifest, gen, newMeta)\n    /\\ state' = \"deleteOldManifest\"\n    /\\ possibleStates' = {newMeta}\n\nWriteManifestFail(gen) == \n    /\\ manifest' = manifest\n    /\\ state' = \"deleteNewMeta\"\n    /\\ possibleStates' = possibleStates\n                \nWriteManifestDirty(gen) == \n    /\\ \\/ manifest' = WriteFile(manifest, gen, newMeta)\n       \\/ manifest' = manifest\n    /\\ state' = \"deleteNewManifest\"\n    /\\ possibleStates' = possibleStates \\union {newMeta}\n          \nWriteManifest == \n    LET gen == CurrentGeneration(manifest) + 1 IN\n        /\\ newManifest' = gen\n        /\\ \\/ WriteManifestOk(gen)\n           \\/ WriteManifestFail(gen)\n           \\/ WriteManifestDirty(gen)\n        /\\ UNCHANGED <<newMeta, metadata>>\n\nDeleteOldManifest ==\n    /\\ \\/ manifest' = DeleteFilesExcept(manifest, newManifest)\n       \\/ manifest' = manifest\n    /\\ state' = \"deleteOldMeta\"\n    /\\ UNCHANGED <<newMeta, newManifest, metadata, possibleStates>>\n\n--------------------------------------------------------------------------\n(*************************************************************************)\n(* Below are 3 versions of the same function, that is called when        *)\n(* manifest write was dirty. The buggy one was initially implemented and *)\n(* was caught by https://github.com/elastic/elasticsearch/issues/39077.  *)\n(* Pick one and use in Next function.                                    *)\n(* https://github.com/elastic/elasticsearch/pull/40519 implements        *)\n(* DeleteNewManifestEasy.                                                *)\n(*************************************************************************)    \nDeleteNewManifestBuggy == \n    /\\ \\/ manifest' = DeleteFile(manifest, newManifest)\n       \\/ manifest' = manifest\n    /\\ state' = \"deleteNewMeta\"\n    /\\ UNCHANGED <<newMeta, newManifest, metadata, possibleStates>>\n\nDeleteNewManifestEasy == \n    /\\ \\/ manifest' = DeleteFile(manifest, newManifest)\n       \\/ manifest' = manifest\n    /\\ state' = \"writeMeta\"\n    /\\ UNCHANGED <<newMeta, newManifest, possibleStates, metadata>>\n    \nDeleteNewManifestHard == \n    /\\ \\/ /\\ manifest' = DeleteFile(manifest, newManifest)\n          /\\ state' = \"deleteNewMeta\"\n       \\/ /\\ manifest' = manifest\n          /\\ state' = \"writeMeta\"\n    /\\ UNCHANGED <<newMeta, newManifest, metadata, possibleStates>>\n--------------------------------------------------------------------------\n(*************************************************************************)\n(* We can define Init and Next functions now.                            *)\n(*************************************************************************)   \nInit == \n    /\\ metadata = <<>>\n    /\\ manifest = <<>>\n    /\\ newMeta = -1 \\* no latest metadata file\n    /\\ newManifest = -1 \\* no latest manifest file\n    /\\ state = \"writeMeta\" \\* we start with writing metadata file\n    /\\ possibleStates = {} \\* no metadata can be read from disk\n    \nNext == \n    \\/ (state = \"writeMeta\"         /\\ WriteMeta)\n    \\/ (state = \"writeManifest\"     /\\ WriteManifest)\n    \\/ (state = \"deleteOldManifest\" /\\ DeleteOldManifest)\n    \\/ (state = \"deleteOldMeta\"     /\\ DeleteOldMeta)\n    \\/ (state = \"deleteNewManifest\" /\\ DeleteNewManifestEasy) \\* try DeleteNewManifestBuggy and DeleteNewManifestHard\n    \\/ (state = \"deleteNewMeta\"     /\\ DeleteNewMeta)\n--------------------------------------------------------------------------\n(*************************************************************************)\n(* Our model has 2 invariants.                                           *)\n(*************************************************************************)\nMetadataFileReferencedByManifestExists ==\n    CurrentGeneration(manifest) /= -1 \n        => \n    manifest[CurrentGeneration(manifest)] \\in DOMAIN metadata\n    \nMetadataReferencedByManifestIsValid ==\n    CurrentGeneration(manifest) /= -1 \n        =>\n    \\E meta \\in possibleStates : meta = manifest[CurrentGeneration(manifest)]\n============"
  },
  {
    "path": "Storage/tla/Storage.toolbox/Storage___model.launch",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<launchConfiguration type=\"org.lamport.tla.toolbox.tool.tlc.modelCheck\">\n    <stringAttribute key=\"TLCCmdLineParameters\" value=\"\"/>\n    <stringAttribute key=\"configurationName\" value=\"model\"/>\n    <booleanAttribute key=\"deferLiveness\" value=\"false\"/>\n    <intAttribute key=\"dfidDepth\" value=\"100\"/>\n    <booleanAttribute key=\"dfidMode\" value=\"false\"/>\n    <intAttribute key=\"distributedFPSetCount\" value=\"0\"/>\n    <stringAttribute key=\"distributedNetworkInterface\" value=\"10.2.42.180\"/>\n    <intAttribute key=\"distributedNodesCount\" value=\"1\"/>\n    <stringAttribute key=\"distributedTLC\" value=\"off\"/>\n    <stringAttribute key=\"distributedTLCVMArgs\" value=\"\"/>\n    <intAttribute key=\"fpBits\" value=\"1\"/>\n    <intAttribute key=\"fpIndex\" value=\"0\"/>\n    <booleanAttribute key=\"fpIndexRandom\" value=\"true\"/>\n    <intAttribute key=\"maxHeapSize\" value=\"25\"/>\n    <intAttribute key=\"maxSetSize\" value=\"1000000\"/>\n    <booleanAttribute key=\"mcMode\" value=\"true\"/>\n    <stringAttribute key=\"modelBehaviorInit\" value=\"Init\"/>\n    <stringAttribute key=\"modelBehaviorNext\" value=\"Next\"/>\n    <stringAttribute key=\"modelBehaviorSpec\" value=\"\"/>\n    <intAttribute key=\"modelBehaviorSpecType\" value=\"2\"/>\n    <stringAttribute key=\"modelBehaviorVars\" value=\"state, metadata, newManifest, possibleStates, newMeta, manifest\"/>\n    <stringAttribute key=\"modelComments\" value=\"\"/>\n    <booleanAttribute key=\"modelCorrectnessCheckDeadlock\" value=\"true\"/>\n    <listAttribute key=\"modelCorrectnessInvariants\">\n        <listEntry value=\"1MetadataFileReferencedByManifestExists\"/>\n        <listEntry value=\"1MetadataReferencedByManifestIsValid\"/>\n    </listAttribute>\n    <listAttribute key=\"modelCorrectnessProperties\"/>\n    <stringAttribute key=\"modelExpressionEval\" value=\"\"/>\n    <stringAttribute key=\"modelParameterActionConstraint\" value=\"\"/>\n    <listAttribute key=\"modelParameterConstants\">\n        <listEntry value=\"MaxNewMeta;;5;0;0\"/>\n        <listEntry value=\"MetaDataContent;;MetaDataContent;1;0\"/>\n    </listAttribute>\n    <stringAttribute key=\"modelParameterContraint\" value=\"newMeta &lt; MaxNewMeta\"/>\n    <listAttribute key=\"modelParameterDefinitions\"/>\n    <stringAttribute key=\"modelParameterModelValues\" value=\"{}\"/>\n    <stringAttribute key=\"modelParameterNewDefinitions\" value=\"\"/>\n    <intAttribute key=\"numberOfWorkers\" value=\"6\"/>\n    <booleanAttribute key=\"recover\" value=\"false\"/>\n    <stringAttribute key=\"result.mail.address\" value=\"\"/>\n    <intAttribute key=\"simuAril\" value=\"-1\"/>\n    <intAttribute key=\"simuDepth\" value=\"100\"/>\n    <intAttribute key=\"simuSeed\" value=\"-1\"/>\n    <stringAttribute key=\"specName\" value=\"Storage\"/>\n    <stringAttribute key=\"view\" value=\"\"/>\n    <booleanAttribute key=\"visualizeStateGraph\" value=\"false\"/>\n</launchConfiguration>\n"
  },
  {
    "path": "ZenWithTerms/tla/ZenWithTerms.tla",
    "content": "-------------------------------------------------------------------------------------\n\n-------------------------------- MODULE ZenWithTerms --------------------------------\n\\* Imported modules used in this specification\nEXTENDS Naturals, FiniteSets, Sequences, TLC\n\n----\n\nCONSTANTS Values\n\n\\* Set of node ids (all master-eligible nodes)\nCONSTANTS Nodes\n\n\\* RPC message types\nCONSTANTS\n  Join,\n  PublishRequest,\n  PublishResponse,\n  Commit\n\n----\n\n\\* Set of requests and responses sent between nodes.\nVARIABLE messages\n\n\\* Transitive closure of value updates as done by leaders \nVARIABLE descendant\n\n\\* Values to bootstrap the cluster\nVARIABLE initialConfiguration\nVARIABLE initialValue\nVARIABLE initialAcceptedVersion\n\n\\* node state (map from node id to state)\nVARIABLE currentTerm\nVARIABLE lastCommittedConfiguration\nVARIABLE lastAcceptedTerm\nVARIABLE lastAcceptedVersion\nVARIABLE lastAcceptedValue\nVARIABLE lastAcceptedConfiguration\nVARIABLE joinVotes\nVARIABLE startedJoinSinceLastReboot\nVARIABLE electionWon\nVARIABLE lastPublishedVersion\nVARIABLE lastPublishedConfiguration\nVARIABLE publishVotes\n\n----\n\nTerms == Nat\n\nVersions == Nat\n\n\\* set of valid configurations (i.e. the set of all non-empty subsets of Nodes)\nValidConfigs == SUBSET(Nodes) \\ {{}}\n\n\\* cluster-state versions that might have come from older systems\nInitialVersions == Nat\n\n\\* quorums correspond to majority of votes in a config\nIsQuorum(votes, config) == Cardinality(votes \\cap config) * 2 > Cardinality(config)\n\nIsElectionQuorum(n, votes) ==\n  /\\ IsQuorum(votes, lastCommittedConfiguration[n])\n  /\\ IsQuorum(votes, lastAcceptedConfiguration[n])\n\nIsPublishQuorum(n, votes) ==\n  /\\ IsQuorum(votes, lastCommittedConfiguration[n])\n  /\\ IsQuorum(votes, lastPublishedConfiguration[n])\n\n\\* initial model state\nInit == /\\ messages = {}\n        /\\ descendant = {}\n        /\\ initialConfiguration \\in ValidConfigs\n        /\\ initialValue \\in Values\n        /\\ initialAcceptedVersion \\in [Nodes -> InitialVersions]\n        /\\ currentTerm = [n \\in Nodes |-> 0]\n        /\\ lastCommittedConfiguration = [n \\in Nodes |-> {}] \\* empty config\n        /\\ lastAcceptedTerm = [n \\in Nodes |-> 0]\n        /\\ lastAcceptedVersion = initialAcceptedVersion\n        /\\ lastAcceptedValue \\in {[n \\in Nodes |-> v] : v \\in Values} \\* all agree on initial value\n        /\\ lastAcceptedConfiguration = [n \\in Nodes |-> lastCommittedConfiguration[n]]\n        /\\ joinVotes = [n \\in Nodes |-> {}]\n        /\\ startedJoinSinceLastReboot = [n \\in Nodes |-> FALSE]\n        /\\ electionWon = [n \\in Nodes |-> FALSE]\n        /\\ lastPublishedVersion = [n \\in Nodes |-> 0]\n        /\\ lastPublishedConfiguration = [n \\in Nodes |-> lastCommittedConfiguration[n]]\n        /\\ publishVotes = [n \\in Nodes |-> {}]\n\n\\* Bootstrap node n with the initial state and config \nSetInitialState(n) ==\n  /\\ lastAcceptedConfiguration[n] = {} \\* not already bootstrapped\n  /\\ Assert(lastAcceptedTerm[n] = 0, \"lastAcceptedTerm should be 0\")\n  /\\ Assert(lastCommittedConfiguration[n] = {}, \"lastCommittedConfiguration should be empty\")\n  /\\ Assert(lastPublishedVersion[n] = 0, \"lastPublishedVersion should be 0\")\n  /\\ Assert(lastPublishedConfiguration[n] = {}, \"lastPublishedConfiguration should be empty\")\n  /\\ Assert(electionWon[n] = FALSE, \"electionWon should be FALSE\")\n  /\\ Assert(joinVotes[n] = {}, \"joinVotes should be empty\")\n  /\\ Assert(publishVotes[n] = {}, \"publishVotes should be empty\")\n  /\\ lastAcceptedConfiguration' = [lastAcceptedConfiguration EXCEPT ![n] = initialConfiguration]\n  /\\ lastAcceptedValue' = [lastAcceptedValue EXCEPT ![n] = initialValue]\n  /\\ lastCommittedConfiguration' = [lastCommittedConfiguration EXCEPT ![n] = initialConfiguration]\n  /\\ Assert(lastAcceptedTerm[n] = 0, \"lastAcceptedTerm should be 0\")\n  /\\ Assert(lastAcceptedConfiguration'[n] /= {}, \"lastAcceptedConfiguration should be non-empty\")\n  /\\ Assert(lastCommittedConfiguration'[n] /= {}, \"lastCommittedConfiguration should be non-empty\")\n  /\\ UNCHANGED <<descendant, initialConfiguration, initialValue, messages, lastAcceptedTerm, lastAcceptedVersion,\n                 lastPublishedVersion, lastPublishedConfiguration, electionWon, joinVotes, publishVotes,\n                 startedJoinSinceLastReboot, currentTerm, initialAcceptedVersion>>\n\n\\* Send join request from node n to node nm for term t\nHandleStartJoin(n, nm, t) ==\n  /\\ t > currentTerm[n]\n  /\\ LET\n       joinRequest == [method     |-> Join,\n                       source     |-> n,\n                       dest       |-> nm,\n                       term       |-> t,\n                       laTerm     |-> lastAcceptedTerm[n],\n                       laVersion  |-> lastAcceptedVersion[n]]\n     IN\n       /\\ currentTerm' = [currentTerm EXCEPT ![n] = t]\n       /\\ lastPublishedVersion' = [lastPublishedVersion EXCEPT ![n] = 0]\n       /\\ lastPublishedConfiguration' = [lastPublishedConfiguration EXCEPT ![n] = lastAcceptedConfiguration[n]]\n       /\\ startedJoinSinceLastReboot' = [startedJoinSinceLastReboot EXCEPT ![n] = TRUE]\n       /\\ electionWon' = [electionWon EXCEPT ![n] = FALSE]\n       /\\ joinVotes' = [joinVotes EXCEPT ![n] = {}]\n       /\\ publishVotes' = [publishVotes EXCEPT ![n] = {}]\n       /\\ messages' = messages \\cup { joinRequest }\n       /\\ UNCHANGED <<lastCommittedConfiguration, lastAcceptedConfiguration, lastAcceptedVersion,\n                      lastAcceptedValue, lastAcceptedTerm, descendant, initialConfiguration, initialValue, initialAcceptedVersion>>\n\n\\* node n handles a join request and checks if it has received enough joins (= votes)\n\\* for its term to be elected as master\nHandleJoin(n, m) ==\n  /\\ m.method = Join\n  /\\ m.term = currentTerm[n]\n  /\\ startedJoinSinceLastReboot[n]\n  /\\ \\/ m.laTerm < lastAcceptedTerm[n]\n     \\/ /\\ m.laTerm = lastAcceptedTerm[n]\n        /\\ m.laVersion <= lastAcceptedVersion[n]\n  /\\ lastAcceptedConfiguration[n] /= {} \\* must be bootstrapped\n  /\\ joinVotes' = [joinVotes EXCEPT ![n] = @ \\cup { m.source }]\n  /\\ electionWon' = [electionWon EXCEPT ![n] = IsElectionQuorum(n, joinVotes'[n])]\n  /\\ IF electionWon[n] = FALSE /\\ electionWon'[n]\n     THEN\n       \\* initiating publish version with last accepted version to enable client requests\n       /\\ lastPublishedVersion' = [lastPublishedVersion EXCEPT ![n] = lastAcceptedVersion[n]]\n     ELSE\n       UNCHANGED <<lastPublishedVersion>>\n  /\\ UNCHANGED <<lastCommittedConfiguration, currentTerm, publishVotes, messages, descendant,\n                 lastAcceptedVersion, lastAcceptedValue, lastAcceptedConfiguration,\n                 lastAcceptedTerm, startedJoinSinceLastReboot, lastPublishedConfiguration,\n                 initialConfiguration, initialValue, initialAcceptedVersion>>\n\n\\* client causes a cluster state change val with configuration cfg\nHandleClientValue(n, t, v, val, cfg) ==\n  /\\ electionWon[n]\n  /\\ lastPublishedVersion[n] = lastAcceptedVersion[n] \\* means we have the last published value / config (useful for CAS operations, where we need to read the previous value first)\n  /\\ t = currentTerm[n]\n  /\\ v > lastPublishedVersion[n]\n  /\\ cfg /= lastAcceptedConfiguration[n] => lastCommittedConfiguration[n] = lastAcceptedConfiguration[n] \\* only allow reconfiguration if there is not already a reconfiguration in progress\n  /\\ IsQuorum(joinVotes[n], cfg) \\* only allow reconfiguration if we have a quorum of (join) votes for the new config\n  /\\ LET\n       publishRequests == { [method   |-> PublishRequest,\n                             source   |-> n,\n                             dest     |-> ns,\n                             term     |-> t,\n                             version  |-> v,\n                             value    |-> val,\n                             config   |-> cfg,\n                             commConf |-> lastCommittedConfiguration[n]] : ns \\in Nodes }\n        newEntry == [prevT |-> lastAcceptedTerm[n],\n                     prevV |-> lastAcceptedVersion[n],\n                     nextT |-> t,\n                     nextV |-> v]\n        matchingElems == { e \\in descendant : \n                                /\\ e.nextT = newEntry.prevT\n                                /\\ e.nextV = newEntry.prevV }\n        newTransitiveElems == { [prevT |-> e.prevT,\n                     prevV |-> e.prevV,\n                     nextT |-> newEntry.nextT,\n                     nextV |-> newEntry.nextV] : e \\in matchingElems }\n     IN\n       /\\ descendant' = descendant \\cup {newEntry} \\cup newTransitiveElems\n       /\\ lastPublishedVersion' = [lastPublishedVersion EXCEPT ![n] = v]\n       /\\ lastPublishedConfiguration' = [lastPublishedConfiguration EXCEPT ![n] = cfg]\n       /\\ publishVotes' = [publishVotes EXCEPT ![n] = {}] \\* publishVotes are only counted per publish version\n       /\\ messages' = messages \\cup publishRequests\n       /\\ UNCHANGED <<startedJoinSinceLastReboot, lastCommittedConfiguration, currentTerm, electionWon,\n                      lastAcceptedVersion, lastAcceptedValue, lastAcceptedTerm, lastAcceptedConfiguration,\n                      joinVotes, initialConfiguration, initialValue, initialAcceptedVersion>>\n\n\\* handle publish request m on node n\nHandlePublishRequest(n, m) ==\n  /\\ m.method = PublishRequest\n  /\\ m.term = currentTerm[n]\n  /\\ (m.term = lastAcceptedTerm[n]) => (m.version > lastAcceptedVersion[n])\n  /\\ lastAcceptedTerm' = [lastAcceptedTerm EXCEPT ![n] = m.term]\n  /\\ lastAcceptedVersion' = [lastAcceptedVersion EXCEPT ![n] = m.version]\n  /\\ lastAcceptedValue' = [lastAcceptedValue EXCEPT ![n] = m.value]\n  /\\ lastAcceptedConfiguration' = [lastAcceptedConfiguration EXCEPT ![n] = m.config]\n  /\\ lastCommittedConfiguration' = [lastCommittedConfiguration EXCEPT ![n] = m.commConf] \n  /\\ LET\n       response == [method   |-> PublishResponse,\n                    source   |-> n,\n                    dest     |-> m.source,\n                    term     |-> m.term,\n                    version  |-> m.version]\n     IN\n       /\\ messages' = messages \\cup {response}\n       /\\ UNCHANGED <<startedJoinSinceLastReboot, currentTerm, descendant, lastPublishedConfiguration,\n                      electionWon, lastPublishedVersion, joinVotes, publishVotes, initialConfiguration,\n                      initialValue, initialAcceptedVersion>>\n\n\\* node n commits a change\nHandlePublishResponse(n, m) ==\n  /\\ m.method = PublishResponse\n  /\\ electionWon[n]\n  /\\ m.term = currentTerm[n]\n  /\\ m.version = lastPublishedVersion[n]\n  /\\ publishVotes' = [publishVotes EXCEPT ![n] = @ \\cup {m.source}]\n  /\\ IF\n       IsPublishQuorum(n, publishVotes'[n])\n     THEN\n       LET\n         commitRequests == { [method   |-> Commit,\n                              source   |-> n,\n                              dest     |-> ns,\n                              term     |-> currentTerm[n],\n                              version  |-> lastPublishedVersion[n]] : ns \\in Nodes }\n       IN\n         /\\ messages' = messages \\cup commitRequests\n     ELSE\n       UNCHANGED <<messages>>\n  /\\ UNCHANGED <<startedJoinSinceLastReboot, lastCommittedConfiguration, currentTerm, electionWon, descendant,\n                   lastAcceptedVersion, lastAcceptedValue, lastAcceptedTerm, lastAcceptedConfiguration,\n                   lastPublishedVersion, lastPublishedConfiguration, joinVotes, initialConfiguration,\n                   initialValue, initialAcceptedVersion>>\n\n\\* apply committed configuration to node n\nHandleCommit(n, m) ==\n  /\\ m.method = Commit\n  /\\ m.term = currentTerm[n]\n  /\\ m.term = lastAcceptedTerm[n]\n  /\\ m.version = lastAcceptedVersion[n]\n  /\\ (electionWon[n] => lastAcceptedVersion[n] = lastPublishedVersion[n])\n  /\\ lastCommittedConfiguration' = [lastCommittedConfiguration EXCEPT ![n] = lastAcceptedConfiguration[n]]\n  /\\ UNCHANGED <<currentTerm, joinVotes, messages, lastAcceptedTerm, lastAcceptedValue, startedJoinSinceLastReboot, descendant,\n                 electionWon, lastAcceptedConfiguration, lastAcceptedVersion, lastPublishedVersion, publishVotes,\n                 lastPublishedConfiguration, initialConfiguration, initialValue, initialAcceptedVersion>>\n\n\\* crash/restart node n (loses ephemeral state)\nRestartNode(n) ==\n  /\\ joinVotes' = [joinVotes EXCEPT ![n] = {}]\n  /\\ startedJoinSinceLastReboot' = [startedJoinSinceLastReboot EXCEPT ![n] = FALSE]\n  /\\ electionWon' = [electionWon EXCEPT ![n] = FALSE]\n  /\\ lastPublishedVersion' = [lastPublishedVersion EXCEPT ![n] = 0]\n  /\\ lastPublishedConfiguration' = [lastPublishedConfiguration EXCEPT ![n] = lastAcceptedConfiguration[n]]\n  /\\ publishVotes' = [publishVotes EXCEPT ![n] = {}]\n  /\\ UNCHANGED <<messages, lastAcceptedVersion, currentTerm, lastCommittedConfiguration, descendant,\n                 lastAcceptedTerm, lastAcceptedValue, lastAcceptedConfiguration, initialConfiguration,\n                 initialValue, initialAcceptedVersion>>\n\n\\* next-step relation\nNext ==\n  \\/ \\E n \\in Nodes : SetInitialState(n)\n  \\/ \\E n, nm \\in Nodes : \\E t \\in Terms : HandleStartJoin(n, nm, t)\n  \\/ \\E m \\in messages : HandleJoin(m.dest, m)\n  \\/ \\E n \\in Nodes : \\E t \\in Terms : \\E v \\in Versions : \\E val \\in Values : \\E vs \\in ValidConfigs : HandleClientValue(n, t, v, val, vs)\n  \\/ \\E m \\in messages : HandlePublishRequest(m.dest, m)\n  \\/ \\E m \\in messages : HandlePublishResponse(m.dest, m)\n  \\/ \\E m \\in messages : HandleCommit(m.dest, m)\n  \\/ \\E n \\in Nodes : RestartNode(n)\n\n----\n\n\\* Invariants\n\nSingleNodeInvariant ==\n  \\A n \\in Nodes :\n    /\\ lastAcceptedTerm[n] <= currentTerm[n]\n    /\\ electionWon[n] = IsElectionQuorum(n, joinVotes[n]) \\* cached value is consistent\n    /\\ IF electionWon[n] THEN lastPublishedVersion[n] >= lastAcceptedVersion[n] ELSE lastPublishedVersion[n] = 0\n    /\\ electionWon[n] => startedJoinSinceLastReboot[n]\n    /\\ publishVotes[n] /= {} => electionWon[n]\n\nOneMasterPerTerm ==\n  \\A m1, m2 \\in messages:\n    /\\ m1.method = PublishRequest\n    /\\ m2.method = PublishRequest\n    /\\ m1.term = m2.term\n    => m1.source = m2.source\n\nLogMatching ==\n  \\A m1, m2 \\in messages:\n    /\\ m1.method = PublishRequest\n    /\\ m2.method = PublishRequest\n    /\\ m1.term = m2.term\n    /\\ m1.version = m2.version\n    => m1.value = m2.value\n\nCommittedPublishRequest(mp) ==\n  /\\ mp.method = PublishRequest\n  /\\ \\E mc \\in messages:\n       /\\ mc.method = Commit\n       /\\ mp.term = mc.term\n       /\\ mp.version = mc.version\n\nDescendantRelationIsStrictlyOrdered ==\n    \\A d \\in descendant:\n       /\\ d.prevT <= d.nextT\n       /\\ d.prevV < d.nextV\n\nDescendantRelationIsTransitive ==\n    \\A d1, d2 \\in descendant:\n       d1.nextT = d2.prevT /\\ d1.nextV = d2.prevV \n       => [prevT |-> d1.prevT, prevV |-> d1.prevV, nextT |-> d2.nextT, nextV |-> d2.nextV] \\in descendant\n\nNewerOpsBasedOnOlderCommittedOps ==\n  \\A m1, m2 \\in messages :\n      /\\ CommittedPublishRequest(m1)\n      /\\ m2.method = PublishRequest\n      /\\ m2.term >= m1.term\n      /\\ m2.version > m1.version\n      => [prevT |-> m1.term, prevV |-> m1.version, nextT |-> m2.term, nextV |-> m2.version] \\in descendant\n\n\\* main invariant (follows from NewerOpsBasedOnOlderCommittedOps):\nCommittedValuesDescendantsFromCommittedValues ==\n  \\A m1, m2 \\in messages : \n      /\\ CommittedPublishRequest(m1)\n      /\\ CommittedPublishRequest(m2)\n      /\\ \\/ m1.term /= m2.term\n         \\/ m1.version /= m2.version\n    =>\n      \\/ [prevT |-> m1.term, prevV |-> m1.version, nextT |-> m2.term, nextV |-> m2.version] \\in descendant \n      \\/ [prevT |-> m2.term, prevV |-> m2.version, nextT |-> m1.term, nextV |-> m1.version] \\in descendant\n\nCommittedValuesDescendantsFromInitialValue ==\n    \\E v \\in InitialVersions :\n        /\\ \\E n \\in Nodes : v = initialAcceptedVersion[n]\n        /\\ \\E votes \\in SUBSET(initialConfiguration) :\n                            /\\ IsQuorum(votes, initialConfiguration)\n                            /\\ \\A n \\in votes : initialAcceptedVersion[n] <= v\n        /\\ \\A m \\in messages :\n                CommittedPublishRequest(m)\n            =>\n                [prevT |-> 0, prevV |-> v, nextT |-> m.term, nextV |-> m.version] \\in descendant\n\nCommitHasQuorumVsPreviousCommittedConfiguration ==\n  \\A mc \\in messages: mc.method = Commit\n    => (\\A mprq \\in messages: (/\\ mprq.method  = PublishRequest\n                               /\\ mprq.term    = mc.term\n                               /\\ mprq.version = mc.version) \n\n          => IsQuorum({mprs.source: mprs \\in {mprs \\in messages: /\\ mprs.method = PublishResponse\n                                                                 /\\ mprs.term = mprq.term\n                                                                 /\\ mprs.version = mprq.version\n                      }}, mprq.commConf))\n\nP2bInvariant ==\n  \\A mc \\in messages: mc.method = Commit\n    => (\\A mprq \\in messages: mprq.method = PublishRequest\n            => (mprq.term > mc.term => mprq.version > mc.version))\n\n\\* State-exploration limits\nStateConstraint ==\n  /\\ \\A n \\in Nodes: IF currentTerm[n] <= 1 THEN lastPublishedVersion[n] <= 2 ELSE lastPublishedVersion[n] <= 3\n  /\\ Cardinality(messages) <= 15\n\n====================================================================================================\n"
  },
  {
    "path": "ZenWithTerms/tla/ZenWithTerms.toolbox/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>ZenWithTerms</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>toolbox.builder.TLAParserBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>toolbox.builder.PCalAlgorithmSearchingBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>toolbox.natures.TLANature</nature>\n\t</natures>\n\t<linkedResources>\n\t\t<link>\n\t\t\t<name>ZenWithTerms.tla</name>\n\t\t\t<type>1</type>\n\t\t\t<locationURI>PARENT-1-PROJECT_LOC/ZenWithTerms.tla</locationURI>\n\t\t</link>\n\t</linkedResources>\n</projectDescription>\n"
  },
  {
    "path": "ZenWithTerms/tla/ZenWithTerms.toolbox/.settings/org.lamport.tla.toolbox.prefs",
    "content": "ProjectRootFile=PARENT-1-PROJECT_LOC/ZenWithTerms.tla\neclipse.preferences.version=1\n"
  },
  {
    "path": "ZenWithTerms/tla/ZenWithTerms.toolbox/ZenWithTerms___model.launch",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<launchConfiguration type=\"org.lamport.tla.toolbox.tool.tlc.modelCheck\">\n    <stringAttribute key=\"TLCCmdLineParameters\" value=\"\"/>\n    <stringAttribute key=\"configurationName\" value=\"model\"/>\n    <booleanAttribute key=\"deferLiveness\" value=\"false\"/>\n    <intAttribute key=\"dfidDepth\" value=\"100\"/>\n    <booleanAttribute key=\"dfidMode\" value=\"false\"/>\n    <intAttribute key=\"distributedFPSetCount\" value=\"0\"/>\n    <stringAttribute key=\"distributedNetworkInterface\" value=\"192.168.178.34\"/>\n    <intAttribute key=\"distributedNodesCount\" value=\"1\"/>\n    <stringAttribute key=\"distributedTLC\" value=\"off\"/>\n    <stringAttribute key=\"distributedTLCVMArgs\" value=\"\"/>\n    <intAttribute key=\"fpBits\" value=\"1\"/>\n    <intAttribute key=\"fpIndex\" value=\"1\"/>\n    <intAttribute key=\"maxHeapSize\" value=\"25\"/>\n    <intAttribute key=\"maxSetSize\" value=\"1000000\"/>\n    <booleanAttribute key=\"mcMode\" value=\"true\"/>\n    <stringAttribute key=\"modelBehaviorInit\" value=\"Init\"/>\n    <stringAttribute key=\"modelBehaviorNext\" value=\"Next\"/>\n    <stringAttribute key=\"modelBehaviorSpec\" value=\"\"/>\n    <intAttribute key=\"modelBehaviorSpecType\" value=\"2\"/>\n    <stringAttribute key=\"modelBehaviorVars\" value=\"lastAcceptedTerm, initialConfiguration, messages, initialValue, lastPublishedConfiguration, lastPublishedVersion, electionWon, lastCommittedConfiguration, startedJoinSinceLastReboot, publishVotes, currentTerm, lastAcceptedVersion, descendant, joinVotes, lastAcceptedConfiguration, initialAcceptedVersion, lastAcceptedValue\"/>\n    <stringAttribute key=\"modelComments\" value=\"\"/>\n    <booleanAttribute key=\"modelCorrectnessCheckDeadlock\" value=\"true\"/>\n    <listAttribute key=\"modelCorrectnessInvariants\">\n        <listEntry value=\"1OneMasterPerTerm\"/>\n        <listEntry value=\"1LogMatching\"/>\n        <listEntry value=\"1SingleNodeInvariant\"/>\n        <listEntry value=\"1CommittedValuesDescendantsFromCommittedValues\"/>\n        <listEntry value=\"1CommittedValuesDescendantsFromInitialValue\"/>\n        <listEntry value=\"1DescendantRelationIsStrictlyOrdered\"/>\n        <listEntry value=\"1NewerOpsBasedOnOlderCommittedOps\"/>\n        <listEntry value=\"1CommitHasQuorumVsPreviousCommittedConfiguration\"/>\n        <listEntry value=\"1P2bInvariant\"/>\n        <listEntry value=\"1DescendantRelationIsTransitive\"/>\n    </listAttribute>\n    <listAttribute key=\"modelCorrectnessProperties\"/>\n    <stringAttribute key=\"modelExpressionEval\" value=\"\"/>\n    <stringAttribute key=\"modelParameterActionConstraint\" value=\"\"/>\n    <listAttribute key=\"modelParameterConstants\">\n        <listEntry value=\"Join;;Join;1;0\"/>\n        <listEntry value=\"Nodes;;{n1, n2, n3};1;1\"/>\n        <listEntry value=\"Commit;;Commit;1;0\"/>\n        <listEntry value=\"PublishResponse;;PublishResponse;1;0\"/>\n        <listEntry value=\"Values;;{v1, v2};1;1\"/>\n        <listEntry value=\"PublishRequest;;PublishRequest;1;0\"/>\n    </listAttribute>\n    <stringAttribute key=\"modelParameterContraint\" value=\"StateConstraint\"/>\n    <listAttribute key=\"modelParameterDefinitions\">\n        <listEntry value=\"Terms;;{0,1,2};0;0\"/>\n        <listEntry value=\"Versions;;{0,1,2,3};0;0\"/>\n        <listEntry value=\"InitialVersions;;{0,1,2};0;0\"/>\n    </listAttribute>\n    <stringAttribute key=\"modelParameterModelValues\" value=\"{}\"/>\n    <stringAttribute key=\"modelParameterNewDefinitions\" value=\"\"/>\n    <intAttribute key=\"numberOfWorkers\" value=\"2\"/>\n    <booleanAttribute key=\"recover\" value=\"false\"/>\n    <stringAttribute key=\"result.mail.address\" value=\"\"/>\n    <intAttribute key=\"simuAril\" value=\"-1\"/>\n    <intAttribute key=\"simuDepth\" value=\"100\"/>\n    <intAttribute key=\"simuSeed\" value=\"-1\"/>\n    <stringAttribute key=\"specName\" value=\"ZenWithTerms\"/>\n    <stringAttribute key=\"view\" value=\"\"/>\n    <booleanAttribute key=\"visualizeStateGraph\" value=\"false\"/>\n</launchConfiguration>\n"
  },
  {
    "path": "cluster/isabelle/Implementation.thy",
    "content": "section \\<open>Implementation\\<close>\n\ntext \\<open>This section presents the implementation of the algorithm.\\<close>\n\ntheory Implementation\n  imports Preliminaries\nbegin\n\nsubsection \\<open>Protocol messages\\<close>\n\ntext \\<open>The\nproven-safe core of the protocol works by sending messages as described here. The remainder of the\nprotocol may send other messages too, and may drop, reorder or duplicate any of these messages, but\nmust not send these messages itself to ensure safety. Another way of thinking of these messages is\nto consider them as ``fire-and-forget'' RPC invocations that, on receipt, call some local method, maybe\nupdate the receiving node's state, and maybe yield some further messages. The @{type nat} parameter to each\nmessage refers to a slot number.\\<close>\n\ndatatype TermOption = NO_TERM | SomeTerm Term\n\ninstantiation TermOption :: linorder\nbegin\n\nfun less_TermOption :: \"TermOption \\<Rightarrow> TermOption \\<Rightarrow> bool\"\n  where \"t < NO_TERM = False\"\n  | \"NO_TERM < SomeTerm t = True\"\n  | \"SomeTerm t\\<^sub>1 < SomeTerm t\\<^sub>2 = (t\\<^sub>1 < t\\<^sub>2)\"\n\ndefinition less_eq_TermOption :: \"TermOption \\<Rightarrow> TermOption \\<Rightarrow> bool\"\n  where \"(t\\<^sub>1 :: TermOption) \\<le> t\\<^sub>2 \\<equiv> t\\<^sub>1 = t\\<^sub>2 \\<or> t\\<^sub>1 < t\\<^sub>2\"\n\ninstance proof\n  fix x y z :: TermOption\n  show \"(x < y) = (x \\<le> y \\<and> \\<not> y \\<le> x)\" unfolding less_eq_TermOption_def apply auto\n    using less_TermOption.elims apply fastforce\n    by (metis less_TermOption.elims(2) less_TermOption.simps(3) less_not_sym)\n\n  show \"x \\<le> x\" by (simp add: less_eq_TermOption_def)\n\n  show \"x \\<le> y \\<Longrightarrow> y \\<le> z \\<Longrightarrow> x \\<le> z\" unfolding less_eq_TermOption_def apply auto\n    by (metis TermOption.distinct(1) TermOption.inject dual_order.strict_trans less_TermOption.elims(2) less_TermOption.elims(3))\n\n  show \"x \\<le> y \\<Longrightarrow> y \\<le> x \\<Longrightarrow> x = y\" unfolding less_eq_TermOption_def apply auto\n    using \\<open>(x < y) = (x \\<le> y \\<and> \\<not> y \\<le> x)\\<close> less_eq_TermOption_def by blast\n\n  show \"x \\<le> y \\<or> y \\<le> x\" unfolding less_eq_TermOption_def apply auto\n    by (metis TermOption.distinct(1) TermOption.inject less_TermOption.elims(3) neqE)\nqed\n\nend\n\nlemma NO_TERM_le [simp]: \"NO_TERM \\<le> t\" by (cases t, simp_all add: less_eq_TermOption_def)\nlemma le_NO_TERM [simp]: \"(t \\<le> NO_TERM) = (t = NO_TERM)\" by (cases t, simp_all add: less_eq_TermOption_def)\nlemma le_SomeTerm [simp]: \"(SomeTerm t\\<^sub>1 \\<le> SomeTerm t\\<^sub>2) = (t\\<^sub>1 \\<le> t\\<^sub>2)\" by (auto simp add: less_eq_TermOption_def)\n\ndatatype Message\n  = StartJoin Term\n  | Vote Slot Term TermOption\n  | ClientValue Value\n  | PublishRequest Slot Term Value\n  | PublishResponse Slot Term\n  | ApplyCommit Slot Term\n  | CatchUpRequest\n  | CatchUpResponse Slot \"Node set\" ClusterState\n  | DiscardJoinVotes\n  | Reboot\n\ntext \\<open>Some prose descriptions of these messages follows, in order to give a bit more of an\nintuitive understanding of their purposes.\\<close>\n\ntext \\<open>The message @{term \"StartJoin t\"} may be sent by any node to attempt to start a master\nelection in the given term @{term t}.\\<close>\n\ntext \\<open>The message @{term \"Vote i t a\"} may be sent by a node in response\nto a @{term StartJoin} message. It indicates that the sender knows all committed values for slots\nstrictly below @{term i}, and that the sender will no longer vote (i.e. send an @{term\nPublishResponse}) in any term prior to @{term t}. The field @{term a} is either @{term\nNone} or @{term \"Some t'\"}. In the former case this indicates that\nthe node has not yet sent any @{term PublishResponse} message in slot @{term i}, and in the latter\ncase it indicates that the largest term in which it has previously sent an @{term PublishResponse}\nmessage is @{term t'}.  All\nnodes must avoid sending a @{term Vote} message to two different masters in the same term.\\<close>\n\ntext \\<open>The message @{term \"ClientValue x\"} may be sent by any node and indicates an attempt to\nreach consensus on the value @{term x}.\\<close>\n\ntext \\<open>The message @{term \"PublishRequest i t v\"} may be sent by the elected master of term\n@{term t} to request the other master-eligible nodes to vote for value @{term v} to be committed in\nslot @{term i}.\\<close>\n\ntext \\<open>The message @{term \"PublishResponse i t\"} may be sent by node in response to\nthe corresponding @{term PublishRequest} message, indicating that the sender votes for the value\nproposed by the master of term @{term t} to be committed in slot @{term i}.\\<close>\n\ntext \\<open>The message @{term \"ApplyCommit i t\"} indicates that the value proposed by the master of\nterm @{term t} in slot @{term i} received a quorum of votes and is therefore committed.\\<close>\n\ntext \\<open>The message @{term Reboot} may be sent by any node to represent the restart of a node, which\nloses any ephemeral state.\\<close>\n\ntext \\<open>The abstract model of Zen keeps track of the set of all messages that have ever been\nsent, and asserts that this set obeys certain invariants, listed below. Further below, it will be\nshown that these invariants imply that each slot obeys the @{term oneSlot} invariants above and\nhence that each slot cannot see inconsistent committed values.\\<close>\n\ndatatype Destination = Broadcast | OneNode Node\n\nrecord RoutedMessage =\n  sender :: Node\n  destination :: Destination\n  payload :: Message\n\ntext \\<open>It will be useful to be able to choose the optional term with the greater term,\nso here is a function that does that.\\<close>\n\nsubsection \\<open>Node implementation\\<close>\n\ntext \\<open>Each node holds the following local data.\\<close>\n\nrecord TermValue =\n  tvTerm :: Term\n  tvValue :: Value\n\nrecord NodeData =\n  currentNode :: Node\n  currentTerm :: Term\n  (* committed state *)\n  firstUncommittedSlot :: Slot\n  currentVotingNodes :: \"Node set\"\n  currentClusterState :: ClusterState\n  (* accepted state *)\n  lastAcceptedData :: \"TermValue option\"\n  (* election state *)\n  joinVotes :: \"Node set\"\n  electionWon :: bool\n  (* publish state *)\n  publishPermitted :: bool\n  publishVotes :: \"Node set\"\n\ndefinition lastAcceptedValue :: \"NodeData \\<Rightarrow> Value\"\n  where \"lastAcceptedValue nd \\<equiv> tvValue (THE lad. lastAcceptedData nd = Some lad)\"\n\ndefinition lastAcceptedTerm :: \"NodeData \\<Rightarrow> TermOption\"\n  where \"lastAcceptedTerm nd \\<equiv> case lastAcceptedData nd of None \\<Rightarrow> NO_TERM | Some lad \\<Rightarrow> SomeTerm (tvTerm lad)\"\n\ndefinition isQuorum :: \"NodeData \\<Rightarrow> Node set \\<Rightarrow> bool\"\n  where \"isQuorum nd q \\<equiv> q \\<in> majorities (currentVotingNodes nd)\"\n\nlemma lastAcceptedValue_joinVotes_update[simp]: \"lastAcceptedValue (joinVotes_update f nd) = lastAcceptedValue nd\" by (simp add: lastAcceptedValue_def)\nlemma lastAcceptedTerm_joinVotes_update[simp]: \"lastAcceptedTerm (joinVotes_update f nd) = lastAcceptedTerm nd\" by (simp add: lastAcceptedTerm_def)\n\nlemma lastAcceptedValue_electionWon_update[simp]: \"lastAcceptedValue (electionWon_update f nd) = lastAcceptedValue nd\" by (simp add: lastAcceptedValue_def)\nlemma lastAcceptedTerm_electionWon_update[simp]: \"lastAcceptedTerm (electionWon_update f nd) = lastAcceptedTerm nd\" by (simp add: lastAcceptedTerm_def)\n\ntext \\<open>This method publishes a value via a @{term PublishRequest} message.\\<close>\n\ndefinition publishValue :: \"Value \\<Rightarrow> NodeData \\<Rightarrow> (NodeData * Message option)\"\n  where\n    \"publishValue x nd \\<equiv>\n        if electionWon nd \\<and> publishPermitted nd\n              then ( nd \\<lparr> publishPermitted := False \\<rparr>\n                   , Some (PublishRequest\n                             (firstUncommittedSlot nd)\n                             (currentTerm nd) x) )\n              else (nd, None)\"\n\ntext \\<open>This method updates the node's current term (if necessary) and discards any data associated\nwith the previous term.\\<close>\n\ndefinition ensureCurrentTerm :: \"Term \\<Rightarrow> NodeData \\<Rightarrow> NodeData\"\n  where\n    \"ensureCurrentTerm t nd \\<equiv>\n        if t \\<le> currentTerm nd\n            then nd\n            else nd\n              \\<lparr> joinVotes := {}\n              , currentTerm := t\n              , electionWon := False\n              , publishPermitted := True\n              , publishVotes := {} \\<rparr>\"\n\ntext \\<open>This method updates the node's state on receipt of a vote (a @{term Vote}) in an election.\\<close>\n\ndefinition addElectionVote :: \"Node \\<Rightarrow> Slot => TermOption \\<Rightarrow> NodeData \\<Rightarrow> NodeData\"\n  where\n    \"addElectionVote s i a nd \\<equiv> let newVotes = insert s (joinVotes nd)\n      in nd \\<lparr> joinVotes := newVotes\n            , electionWon := isQuorum nd newVotes \\<rparr>\"\n\ntext \\<open>Clients request the cluster to achieve consensus on certain values using the @{term ClientValue}\nmessage which is handled as follows.\\<close>\n\ndefinition handleClientValue :: \"Value \\<Rightarrow> NodeData \\<Rightarrow> (NodeData * Message option)\"\n  where\n    \"handleClientValue x nd \\<equiv> if lastAcceptedTerm nd = NO_TERM then publishValue x nd else (nd, None)\"\n\ntext \\<open>A @{term StartJoin} message is checked for acceptability and then handled by updating the\nnode's term and yielding a @{term Vote} message as follows.\\<close>\n\ndefinition handleStartJoin :: \"Term \\<Rightarrow> NodeData \\<Rightarrow> (NodeData * Message option)\"\n  where\n    \"handleStartJoin t nd \\<equiv>\n        if currentTerm nd < t\n          then ( ensureCurrentTerm t nd\n               , Some (Vote (firstUncommittedSlot nd)\n                                     t\n                                    (lastAcceptedTerm nd)))\n          else (nd, None)\"\n\ntext \\<open>A @{term Vote} message is checked for acceptability and then handled as follows, perhaps\nyielding a @{term PublishRequest} message.\\<close>\n\ndefinition handleVote :: \"Node \\<Rightarrow> Slot \\<Rightarrow> Term \\<Rightarrow> TermOption \\<Rightarrow> NodeData \\<Rightarrow> (NodeData * Message option)\"\n  where\n    \"handleVote s i t a nd \\<equiv>\n         if t = currentTerm nd\n             \\<and> (i < firstUncommittedSlot nd\n                \\<or> (i = firstUncommittedSlot nd \\<and> a \\<le> lastAcceptedTerm nd))\n          then let nd1 = addElectionVote s i a nd\n               in (if lastAcceptedTerm nd = NO_TERM then (nd1, None) else publishValue (lastAcceptedValue nd1) nd1)\n          else (nd, None)\"\n\ntext \\<open>A @{term PublishRequest} message is checked for acceptability and then handled as follows,\nyielding a @{term PublishResponse} message.\\<close>\n\ndefinition handlePublishRequest :: \"Slot \\<Rightarrow> Term \\<Rightarrow> Value \\<Rightarrow> NodeData \\<Rightarrow> (NodeData * Message option)\"\n  where\n    \"handlePublishRequest i t x nd \\<equiv>\n          if i = firstUncommittedSlot nd\n                \\<and> t = currentTerm nd\n          then ( nd \\<lparr> lastAcceptedData := Some \\<lparr> tvTerm = t, tvValue = x \\<rparr> \\<rparr>\n               , Some (PublishResponse i t))\n          else (nd, None)\"\n\ntext \\<open>This method sends an @{term ApplyCommit} message if a quorum of votes has been received.\\<close>\n\ndefinition commitIfQuorate :: \"NodeData \\<Rightarrow> (NodeData * Message option)\"\n  where\n    \"commitIfQuorate nd = (nd, if isQuorum nd (publishVotes nd)\n                                  then Some (ApplyCommit (firstUncommittedSlot nd) (currentTerm nd)) else None)\"\n\ntext \\<open>A @{term PublishResponse} message is checked for acceptability and handled as follows. If\nthis message, together with the previously-received messages, forms a quorum of votes then the\nvalue is committed, yielding an @{term ApplyCommit} message.\\<close>\n\ndefinition handlePublishResponse :: \"Node \\<Rightarrow> Slot \\<Rightarrow> Term \\<Rightarrow> NodeData \\<Rightarrow> (NodeData * Message option)\"\n  where\n    \"handlePublishResponse s i t nd \\<equiv>\n        if i = firstUncommittedSlot nd \\<and> t = currentTerm nd\n        then commitIfQuorate (nd \\<lparr> publishVotes := insert s (publishVotes nd) \\<rparr>)\n        else (nd, None)\"\n\ntext \\<open>This method updates the node's state when a value is committed.\\<close>\n\ndefinition applyAcceptedValue :: \"NodeData \\<Rightarrow> NodeData\"\n  where\n    \"applyAcceptedValue nd \\<equiv> case lastAcceptedValue nd of\n        NoOp \\<Rightarrow> nd\n      | Reconfigure votingNodes \\<Rightarrow> nd\n          \\<lparr> currentVotingNodes := set votingNodes\n          , electionWon := joinVotes nd \\<in> majorities (set votingNodes) \\<rparr>\n      | ClusterStateDiff diff \\<Rightarrow> nd \\<lparr> currentClusterState := diff (currentClusterState nd) \\<rparr>\"\n\ntext \\<open>An @{term ApplyCommit} message is applied to the current node's state, updating its configuration\nand \\texttt{ClusterState} via the @{term applyValue} method. It yields no messages.\\<close>\n\ndefinition handleApplyCommit :: \"Slot \\<Rightarrow> Term \\<Rightarrow> NodeData \\<Rightarrow> NodeData\"\n  where\n    \"handleApplyCommit i t nd \\<equiv>\n        if i = firstUncommittedSlot nd \\<and> lastAcceptedTerm nd = SomeTerm t\n          then (applyAcceptedValue nd)\n                     \\<lparr> firstUncommittedSlot := i + 1\n                     , lastAcceptedData := None\n                     , publishPermitted := True\n                     , publishVotes := {} \\<rparr>\n          else nd\"\n\ndefinition handleCatchUpRequest :: \"NodeData \\<Rightarrow> (NodeData * Message option)\"\n  where\n    \"handleCatchUpRequest nd = (nd, Some (CatchUpResponse (firstUncommittedSlot nd)\n                                              (currentVotingNodes nd) (currentClusterState nd)))\"\n\ndefinition handleCatchUpResponse :: \"Slot \\<Rightarrow> Node set \\<Rightarrow> ClusterState \\<Rightarrow> NodeData \\<Rightarrow> NodeData\"\n  where\n    \"handleCatchUpResponse i conf cs nd \\<equiv>\n      if firstUncommittedSlot nd < i\n        then nd \\<lparr> firstUncommittedSlot := i\n                , publishPermitted := True\n                , publishVotes := {}\n                , currentVotingNodes := conf\n                , currentClusterState := cs\n                , lastAcceptedData := None\n                , joinVotes := {}\n                , electionWon := False \\<rparr>\n        else nd\"\n\ntext \\<open>A @{term Reboot} message simulates the effect of a reboot, discarding any ephemeral state but\npreserving the persistent state. It yields no messages.\\<close>\n\ndefinition handleReboot :: \"NodeData \\<Rightarrow> NodeData\"\n  where\n    \"handleReboot nd \\<equiv>\n      \\<lparr> currentNode = currentNode nd\n      , currentTerm = currentTerm nd\n      , firstUncommittedSlot = firstUncommittedSlot nd\n      , currentVotingNodes = currentVotingNodes nd\n      , currentClusterState = currentClusterState nd\n      , lastAcceptedData = lastAcceptedData nd\n      , joinVotes = {}\n      , electionWon = False\n      , publishPermitted = False\n      , publishVotes = {} \\<rparr>\"\n\ntext \\<open>A @{term DiscardJoinVotes} message discards the votes received by a node. It yields\nno messages.\\<close>\n\ndefinition handleDiscardJoinVotes :: \"NodeData \\<Rightarrow> NodeData\"\n  where\n  \"handleDiscardJoinVotes nd \\<equiv> nd \\<lparr> electionWon := False, joinVotes := {} \\<rparr>\"\n\ntext \\<open>This function dispatches incoming messages to the appropriate handler method, and\nroutes any responses to the appropriate places. In particular, @{term Vote} messages\n(sent by the @{term handleStartJoin} method) and\n@{term PublishResponse} messages (sent by the @{term handlePublishRequest} method) are\nonly sent to a single node, whereas all other responses are broadcast to all nodes.\\<close>\n\ndefinition ProcessMessage :: \"NodeData \\<Rightarrow> RoutedMessage \\<Rightarrow> (NodeData * RoutedMessage option)\"\n  where\n    \"ProcessMessage nd msg \\<equiv>\n      let respondTo =\n          (\\<lambda> d (nd, mmsg). case mmsg of\n               None \\<Rightarrow> (nd, None)\n             | Some msg \\<Rightarrow> (nd,\n                 Some \\<lparr> sender = currentNode nd, destination = d,\n                             payload = msg \\<rparr>));\n          respondToSender = respondTo (OneNode (sender msg));\n          respondToAll    = respondTo Broadcast\n      in\n        if destination msg \\<in> { Broadcast, OneNode (currentNode nd) }\n        then case payload msg of\n          StartJoin t\n              \\<Rightarrow> respondToSender (handleStartJoin t nd)\n          | Vote i t a\n              \\<Rightarrow> respondToAll (handleVote (sender msg) i t a nd)\n          | ClientValue x\n              \\<Rightarrow> respondToAll (handleClientValue x nd)\n          | PublishRequest i t x\n              \\<Rightarrow> respondToSender (handlePublishRequest i t x nd)\n          | PublishResponse i t\n              \\<Rightarrow> respondToAll (handlePublishResponse (sender msg) i t nd)\n          | ApplyCommit i t\n              \\<Rightarrow> (handleApplyCommit i t nd, None)\n          | CatchUpRequest\n              \\<Rightarrow> respondToSender (handleCatchUpRequest nd)\n          | CatchUpResponse i conf cs\n              \\<Rightarrow> (handleCatchUpResponse i conf cs nd, None)\n          | DiscardJoinVotes\n              \\<Rightarrow> (handleDiscardJoinVotes nd, None)\n          | Reboot\n              \\<Rightarrow> (handleReboot nd, None)\n        else (nd, None)\"\n\ntext \\<open>Nodes are initialised to this state. The data required is the initial configuration, @{term Q\\<^sub>0}\nand the initial \\texttt{ClusterState}, here shown as @{term \"ClusterState 0\"}.\\<close>\n\ndefinition initialNodeState :: \"Node \\<Rightarrow> NodeData\"\n  where \"initialNodeState n =\n      \\<lparr> currentNode = n\n      , currentTerm = 0\n      , firstUncommittedSlot = 0\n      , currentVotingNodes = V\\<^sub>0\n      , currentClusterState = CS\\<^sub>0\n      , lastAcceptedData = None\n      , joinVotes = {}\n      , electionWon = False\n      , publishPermitted = False\n      , publishVotes = {} \\<rparr>\"\n(* Note: publishPermitted could be True initially, but in the actual implementation we call the\nsame constructor whether we're starting up from afresh or recovering from a reboot, and the value\nis really unimportant as we need to run an election in a new term before becoming master anyway,\nso it's hard to justify putting any effort into calculating different values for these two cases.\nInstead just set it to False initially.*)\n\nend\n"
  },
  {
    "path": "cluster/isabelle/Monadic.thy",
    "content": "theory Monadic\n  imports Implementation \"~~/src/HOL/Library/Monad_Syntax\"\nbegin\n\ndatatype Exception = IllegalArgumentException\n\ndatatype ('e,'a) Result = Success 'a | Exception 'e\n\ndatatype 'a Action = Action \"NodeData \\<Rightarrow> (NodeData * RoutedMessage list * (Exception,'a) Result)\"\n\ndefinition runM :: \"'a Action \\<Rightarrow> NodeData \\<Rightarrow> (NodeData * RoutedMessage list * (Exception,'a) Result)\"\n  where \"runM ma \\<equiv> case ma of Action unwrapped_ma \\<Rightarrow> unwrapped_ma\"\n\nlemma runM_Action[simp]: \"runM (Action f) = f\" by (simp add: runM_def)\nlemma runM_inject[intro]: \"(\\<And>nd. runM ma nd = runM mb nd) \\<Longrightarrow> ma = mb\" by (cases ma, cases mb, auto simp add: runM_def)\n\ndefinition return :: \"'a \\<Rightarrow> 'a Action\" where \"return a \\<equiv> Action (\\<lambda> nd. (nd, [], Success a))\"\n\nlemma runM_return[simp]: \"runM (return a) nd = (nd, [], Success a)\" unfolding runM_def return_def by simp\n\ndefinition Action_bind :: \"'a Action \\<Rightarrow> ('a \\<Rightarrow> 'b Action) \\<Rightarrow> 'b Action\"\n  where \"Action_bind ma mf \\<equiv> Action (\\<lambda> nd0. case runM ma nd0 of\n      (nd1, msgs1, result1) \\<Rightarrow> (case result1 of\n          Exception e \\<Rightarrow> (nd1, msgs1, Exception e)\n        | Success a \\<Rightarrow> (case runM (mf a) nd1 of\n             (nd2, msgs2, result2) \\<Rightarrow> (nd2, msgs1 @ msgs2, result2))))\"\n\nadhoc_overloading bind Action_bind\n\nlemma runM_bind: \"runM (a \\<bind> f) nd0 = (case runM a nd0 of (nd1, msgs1, result1) \\<Rightarrow> (case result1 of Exception e \\<Rightarrow> (nd1, msgs1, Exception e) | Success b \\<Rightarrow> (case runM (f b) nd1 of (nd2, msgs2, c) \\<Rightarrow> (nd2, msgs1@msgs2, c))))\"\n  unfolding Action_bind_def by auto\n\nlemma return_bind[simp]: \"do { a' <- return a; f a' } = f a\"\n  apply (intro runM_inject) by (simp add: runM_bind)\nlemma bind_return[simp]: \"do { a' <- f; return a' } = f\"\nproof (intro runM_inject)\n  fix nd\n  obtain nd1 msgs1 result1 where result1: \"runM f nd = (nd1, msgs1, result1)\" by (cases \"runM f nd\", blast)\n  show \"runM (f \\<bind> return) nd = runM f nd\"\n    by (cases result1, simp_all add: runM_bind result1)\nqed\n\nlemma bind_bind_assoc[simp]:\n  fixes f :: \"'a Action\"\n  shows \"do { b <- do { a <- f; g a }; h b } = do { a <- f; b <- g a; h b }\" (is \"?LHS = ?RHS\")\nproof (intro runM_inject)\n  fix nd0\n  show \"runM ?LHS nd0 = runM ?RHS nd0\"\n  proof (cases \"runM f nd0\")\n    case fields1: (fields nd1 msgs1 result1)\n    show ?thesis\n    proof (cases result1)\n      case Exception show ?thesis by (simp add: runM_bind fields1 Exception)\n    next\n      case Success1: (Success b)\n      show ?thesis\n      proof (cases \"runM (g b) nd1\")\n        case fields2: (fields nd2 msgs2 result2)\n        show ?thesis\n        proof (cases result2)\n          case Exception show ?thesis by (simp add: runM_bind fields1 fields2 Success1 Exception)\n        next\n          case Success2: (Success c)\n          show ?thesis\n            by (cases \"runM (h c) nd2\", simp add: runM_bind fields1 Success1 fields2 Success2)\n        qed\n      qed\n    qed\n  qed\nqed\n\ndefinition getNodeData :: \"NodeData Action\" where \"getNodeData \\<equiv> Action (\\<lambda>nd. (nd, [], Success nd))\"\ndefinition setNodeData :: \"NodeData \\<Rightarrow> unit Action\" where \"setNodeData nd \\<equiv> Action (\\<lambda>_. (nd, [], Success ()))\"\n\nlemma runM_getNodeData[simp]: \"runM  getNodeData      nd = (nd,  [], Success nd)\" by (simp add: runM_def getNodeData_def)\nlemma runM_setNodeData[simp]: \"runM (setNodeData nd') nd = (nd', [], Success ())\" by (simp add: runM_def setNodeData_def)\n\nlemma runM_getNodeData_continue[simp]: \"runM (do { nd' <- getNodeData; f nd' }) nd = runM (f nd) nd\" by (simp add: runM_bind)\nlemma runM_setNodeData_continue[simp]: \"runM (do { setNodeData nd'; f }) nd = runM f nd'\" by (simp add: runM_bind)\n\ndefinition modifyNodeData :: \"(NodeData \\<Rightarrow> NodeData) \\<Rightarrow> unit Action\" where \"modifyNodeData f = getNodeData \\<bind> (setNodeData \\<circ> f)\"\n\nlemma runM_modifyNodeData[simp]: \"runM (modifyNodeData f) nd = (f nd, [], Success ())\" by (simp add: modifyNodeData_def runM_bind)\nlemma runM_modifyNodeData_continue[simp]: \"runM (do { modifyNodeData f; a }) nd = runM a (f nd)\" by (simp add: runM_bind)\n\ndefinition tell :: \"RoutedMessage list \\<Rightarrow> unit Action\" where \"tell rms \\<equiv> Action (\\<lambda>nd. (nd, rms, Success ()))\"\nlemma runM_tell[simp]: \"runM (tell rms) nd = (nd, rms, Success ())\" by (simp add: runM_def tell_def)\nlemma runM_tell_contiue[simp]: \"runM (do { tell rms; a }) nd = (let (nd, rms', x) = runM a nd in (nd, rms@rms', x))\" by (simp add: runM_bind tell_def)\n\ndefinition send :: \"RoutedMessage \\<Rightarrow> unit Action\" where \"send rm = tell [rm]\"\n\ndefinition throw :: \"Exception \\<Rightarrow> 'a Action\" where \"throw e = Action (\\<lambda>nd. (nd, [], Exception e))\"\nlemma runM_throw[simp]: \"runM (throw e) nd = (nd, [], Exception e)\" by (simp add: runM_def throw_def)\nlemma throw_continue[simp]: \"do { throw e; a } = throw e\" by (intro runM_inject, simp add: runM_bind)\n\ndefinition catch :: \"'a Action \\<Rightarrow> (Exception \\<Rightarrow> 'a Action) \\<Rightarrow> 'a Action\"\n  where \"catch go onException = Action (\\<lambda>nd0. case runM go nd0 of (nd1, rms1, result1) \\<Rightarrow> (case result1 of Success _ \\<Rightarrow> (nd1, rms1, result1) | Exception e \\<Rightarrow> runM (tell rms1 \\<then> onException e) nd1))\"\nlemma catch_throw[simp]: \"catch (throw e) handle = handle e\" by (intro runM_inject, simp add: catch_def)\nlemma catch_return[simp]: \"catch (return a) handle = return a\" by (intro runM_inject, simp add: catch_def)\n\nlemma catch_getNodeData[simp]: \"catch getNodeData handle = getNodeData\" by (intro runM_inject, simp add: catch_def)\nlemma catch_getNodeData_continue[simp]: \"catch (do { nd <- getNodeData; f nd }) handle = do { nd <- getNodeData; catch (f nd) handle }\" by (intro runM_inject, simp add: catch_def)\nlemma catch_setNodeData[simp]: \"catch (setNodeData nd) handle = setNodeData nd\" by (intro runM_inject, simp add: catch_def)\nlemma catch_setNodeData_continue[simp]: \"catch (do { setNodeData nd; f }) handle = do { setNodeData nd; catch f handle }\" by (intro runM_inject, simp add: catch_def)\nlemma catch_modifyNodeData[simp]: \"catch (modifyNodeData f) handle = modifyNodeData f\" by (intro runM_inject, simp add: catch_def)\nlemma catch_modifyNodeData_continue[simp]: \"catch (do { modifyNodeData f; g }) handle = do { modifyNodeData f; catch g handle }\" by (intro runM_inject, simp add: catch_def)\nlemma catch_tell[simp]: \"catch (tell rms) handle = tell rms\" by (intro runM_inject, simp add: catch_def)\nlemma catch_tell_continue[simp]: \"catch (do { tell rms; f }) handle = do { tell rms; catch f handle }\"\nproof (intro runM_inject)\n  fix nd0\n  show \"runM (catch (do { tell rms; f }) handle) nd0 = runM (do { tell rms; catch f handle }) nd0\"\n  proof (cases \"runM f nd0\")\n    case fields1: (fields nd1 msgs1 result1)\n    show ?thesis\n    proof (cases result1)\n      case (Exception e) show ?thesis by (cases \"runM (handle e) nd1\", simp add: catch_def fields1 Exception)\n    next\n      case Success1: (Success b)\n      show ?thesis\n        by (simp add: catch_def fields1 Success1)\n    qed\n  qed\nqed\nlemma catch_send[simp]: \"catch (send rm) handle = send rm\" by (simp add: send_def)\nlemma catch_send_continue[simp]: \"catch (do { send rm; f }) handle = do { send rm; catch f handle }\" by (simp add: send_def)\n\ndefinition gets :: \"(NodeData \\<Rightarrow> 'a) \\<Rightarrow> 'a Action\" where \"gets f \\<equiv> do { nd <- getNodeData; return (f nd) }\"\ndefinition getCurrentClusterState where \"getCurrentClusterState = gets currentClusterState\"\ndefinition getCurrentNode where \"getCurrentNode = gets currentNode\"\ndefinition getCurrentTerm where \"getCurrentTerm = gets currentTerm\"\ndefinition getCurrentVotingNodes where \"getCurrentVotingNodes = gets currentVotingNodes\"\ndefinition getElectionWon where \"getElectionWon = gets electionWon\"\ndefinition getFirstUncommittedSlot where \"getFirstUncommittedSlot = gets firstUncommittedSlot\"\ndefinition getJoinVotes where \"getJoinVotes = gets joinVotes\"\ndefinition getLastAcceptedData where \"getLastAcceptedData = gets lastAcceptedData\"\ndefinition getPublishPermitted where \"getPublishPermitted = gets publishPermitted\"\ndefinition getPublishVotes where \"getPublishVotes = gets publishVotes\"\n\ndefinition sets where \"sets f x = modifyNodeData (f (\\<lambda>_. x))\"\ndefinition setCurrentClusterState where \"setCurrentClusterState = sets currentClusterState_update\"\ndefinition setCurrentNode where \"setCurrentNode = sets currentNode_update\"\ndefinition setCurrentTerm where \"setCurrentTerm = sets currentTerm_update\"\ndefinition setCurrentVotingNodes where \"setCurrentVotingNodes = sets currentVotingNodes_update\"\ndefinition setElectionWon where \"setElectionWon = sets electionWon_update\"\ndefinition setFirstUncommittedSlot where \"setFirstUncommittedSlot = sets firstUncommittedSlot_update\"\ndefinition setJoinVotes where \"setJoinVotes = sets joinVotes_update\"\ndefinition setLastAcceptedData where \"setLastAcceptedData = sets lastAcceptedData_update\"\ndefinition setPublishPermitted where \"setPublishPermitted = sets publishPermitted_update\"\ndefinition setPublishVotes where \"setPublishVotes = sets publishVotes_update\"\n\ndefinition modifies where \"modifies f g = modifyNodeData (f g)\"\ndefinition modifyJoinVotes where \"modifyJoinVotes = modifies joinVotes_update\"\ndefinition modifyPublishVotes where \"modifyPublishVotes = modifies publishVotes_update\"\ndefinition modifyCurrentClusterState where \"modifyCurrentClusterState = modifies currentClusterState_update\"\n\ndefinition \"when\" :: \"bool \\<Rightarrow> unit Action \\<Rightarrow> unit Action\" where \"when c a \\<equiv> if c then a else return ()\"\ndefinition unless :: \"bool \\<Rightarrow> unit Action \\<Rightarrow> unit Action\" where \"unless \\<equiv> when \\<circ> Not\"\n\nlemma runM_when: \"runM (when c a) nd = (if c then runM a nd else (nd, [], Success ()))\"\n  by (auto simp add: when_def)\nlemma runM_unless: \"runM (unless c a) nd = (if c then (nd, [], Success ()) else runM a nd)\"\n  by (auto simp add: unless_def when_def)\n\nlemma runM_when_continue: \"runM (do { when c a; b }) nd = (if c then runM (do {a;b}) nd else runM b nd)\"\n  by (auto simp add: when_def)\nlemma runM_unless_continue: \"runM (do { unless c a; b }) nd = (if c then runM b nd else runM (do {a;b}) nd)\"\n  by (auto simp add: unless_def when_def)\n\nlemma catch_when[simp]: \"catch (when c a) onException = when c (catch a onException)\"\n  by (intro runM_inject, simp add: catch_def runM_when)\nlemma catch_unless[simp]: \"catch (unless c a) onException = unless c (catch a onException)\"\n  by (intro runM_inject, simp add: catch_def runM_unless)\n\nlemma catch_when_continue[simp]: \"catch (do { when c a; b }) onException = (if c then catch (do {a;b}) onException else catch b onException)\"\n  by (intro runM_inject, simp add: catch_def runM_when_continue)\nlemma catch_unless_continue[simp]: \"catch (do { unless c a; b }) onException = (if c then catch b onException else catch (do {a;b}) onException)\"\n  by (intro runM_inject, simp add: catch_def runM_unless_continue)\n\ndefinition ensureCorrectDestination :: \"Destination \\<Rightarrow> unit Action\"\n  where \"ensureCorrectDestination d \\<equiv> do {\n    n <- getCurrentNode;\n    when (d \\<notin> { Broadcast, OneNode n }) (throw IllegalArgumentException)\n  }\"\n\nlemma runM_ensureCorrectDestination_continue:\n  \"runM (do { ensureCorrectDestination d; go }) nd = (if d \\<in> { Broadcast, OneNode (currentNode nd) } then runM go nd else (nd, [], Exception IllegalArgumentException))\"\n  by (simp add: ensureCorrectDestination_def getCurrentNode_def gets_def runM_when_continue)\n\ndefinition broadcast :: \"Message \\<Rightarrow> unit Action\"\n  where \"broadcast msg \\<equiv> do {\n       n <- getCurrentNode;\n       send \\<lparr> sender = n, destination = Broadcast, payload = msg \\<rparr>\n    }\"\n\nlemma runM_broadcast[simp]: \"runM (broadcast msg) nd = (nd, [\\<lparr> sender = currentNode nd, destination = Broadcast, payload = msg \\<rparr>], Success ())\"\n  by (simp add: broadcast_def getCurrentNode_def gets_def send_def)\n\ndefinition sendTo :: \"Node \\<Rightarrow> Message \\<Rightarrow> unit Action\"\n  where \"sendTo d msg \\<equiv> do {\n       n <- getCurrentNode;\n       send \\<lparr> sender = n, destination = OneNode d, payload = msg \\<rparr>\n    }\"\n\nlemma runM_sendTo[simp]: \"runM (sendTo d msg) nd = (nd, [\\<lparr> sender = currentNode nd, destination = OneNode d, payload = msg \\<rparr>], Success ())\"\n  by (simp add: sendTo_def getCurrentNode_def gets_def send_def)\n\ndefinition ignoringExceptions :: \"unit Action \\<Rightarrow> unit Action\" where \"ignoringExceptions go \\<equiv> catch go (\\<lambda>_. return ())\"\n\nlemma None_lt[simp]: \"NO_TERM < t = (t \\<noteq> NO_TERM)\" by (cases t, simp_all)\n\ndefinition getLastAcceptedTerm :: \"TermOption Action\"\n  where\n    \"getLastAcceptedTerm \\<equiv> do {\n      lastAcceptedData <- getLastAcceptedData;\n      case lastAcceptedData of\n          None \\<Rightarrow> return NO_TERM\n        | Some tv \\<Rightarrow> return (SomeTerm (tvTerm tv))\n    }\"\n\ndefinition doStartJoin :: \"Node \\<Rightarrow> Term \\<Rightarrow> unit Action\"\n  where\n    \"doStartJoin newMaster newTerm \\<equiv> do {\n        currentTerm <- getCurrentTerm;\n\n        when (newTerm \\<le> currentTerm) (throw IllegalArgumentException);\n\n        setCurrentTerm newTerm;\n        setJoinVotes {};\n        setElectionWon False;\n        setPublishPermitted True;\n        setPublishVotes {};\n\n        firstUncommittedSlot <- getFirstUncommittedSlot;\n        lastAcceptedTerm <- getLastAcceptedTerm;\n        sendTo newMaster (Vote firstUncommittedSlot newTerm lastAcceptedTerm)\n\n      }\"\n\ndefinition doVote :: \"Node \\<Rightarrow> Slot \\<Rightarrow> Term \\<Rightarrow> TermOption \\<Rightarrow> unit Action\"\n  where\n    \"doVote sourceNode voteFirstUncommittedSlot voteTerm voteLastAcceptedTerm \\<equiv> do {\n\n      currentTerm <- getCurrentTerm;\n      when (voteTerm \\<noteq> currentTerm) (throw IllegalArgumentException);\n\n      firstUncommittedSlot <- getFirstUncommittedSlot;\n      when (voteFirstUncommittedSlot > firstUncommittedSlot) (throw IllegalArgumentException);\n\n      lastAcceptedTerm <- getLastAcceptedTerm;\n      when (voteFirstUncommittedSlot = firstUncommittedSlot\n              \\<and> voteLastAcceptedTerm > lastAcceptedTerm)\n          (throw IllegalArgumentException);\n\n      modifyJoinVotes (insert sourceNode);\n\n      joinVotes <- getJoinVotes;\n      currentVotingNodes <- getCurrentVotingNodes;\n\n      let electionWon' = card (joinVotes \\<inter> currentVotingNodes) * 2 > card currentVotingNodes;\n      setElectionWon electionWon';\n      publishPermitted <- getPublishPermitted;\n      when (electionWon' \\<and> publishPermitted \\<and> lastAcceptedTerm \\<noteq> NO_TERM) (do {\n        setPublishPermitted False;\n\n        lastAcceptedValue <- gets lastAcceptedValue; (* NB must be present since lastAcceptedTermInSlot \\<noteq> NO_TERM *)\n        broadcast (PublishRequest firstUncommittedSlot currentTerm lastAcceptedValue)\n      })\n    }\"\n\ndefinition doPublishRequest :: \"Node \\<Rightarrow> Slot \\<Rightarrow> TermValue \\<Rightarrow> unit Action\"\n  where\n    \"doPublishRequest sourceNode requestSlot newAcceptedState \\<equiv> do {\n\n      currentTerm <- getCurrentTerm;\n      when (tvTerm newAcceptedState \\<noteq> currentTerm) (throw IllegalArgumentException);\n\n      firstUncommittedSlot <- getFirstUncommittedSlot;\n      when (requestSlot \\<noteq> firstUncommittedSlot) (throw IllegalArgumentException);\n\n      setLastAcceptedData (Some newAcceptedState);\n      sendTo sourceNode (PublishResponse requestSlot (tvTerm newAcceptedState))\n    }\"\n\nrecord SlotTerm =\n  stSlot :: Slot\n  stTerm :: Term\n\ndefinition ApplyCommitFromSlotTerm :: \"SlotTerm \\<Rightarrow> Message\"\n  where \"ApplyCommitFromSlotTerm st = ApplyCommit (stSlot st) (stTerm st)\"\n\ndefinition doPublishResponse :: \"Node \\<Rightarrow> SlotTerm \\<Rightarrow> unit Action\"\n  where\n    \"doPublishResponse sourceNode slotTerm \\<equiv> do {\n\n      currentTerm <- getCurrentTerm;\n      when (stTerm slotTerm \\<noteq> currentTerm) (throw IllegalArgumentException);\n\n      firstUncommittedSlot <- getFirstUncommittedSlot;\n      when (stSlot slotTerm \\<noteq> firstUncommittedSlot) (throw IllegalArgumentException);\n\n      modifyPublishVotes (insert sourceNode);\n      publishVotes <- getPublishVotes;\n      currentVotingNodes <- getCurrentVotingNodes;\n      when (card (publishVotes \\<inter> currentVotingNodes) * 2 > card currentVotingNodes)\n        (broadcast (ApplyCommitFromSlotTerm slotTerm))\n    }\"\n\ndefinition doCommit :: \"SlotTerm \\<Rightarrow> unit Action\"\n  where\n    \"doCommit slotTerm \\<equiv> do {\n\n      lastAcceptedTermInSlot <- getLastAcceptedTerm;\n      when (SomeTerm (stTerm slotTerm) \\<noteq> lastAcceptedTermInSlot) (throw IllegalArgumentException);\n\n      firstUncommittedSlot <- getFirstUncommittedSlot;\n      when (stSlot slotTerm \\<noteq> firstUncommittedSlot) (throw IllegalArgumentException);\n\n      lastAcceptedValue <- gets lastAcceptedValue;  (* NB must be not None since lastAcceptedTerm = Some t *)\n      (case lastAcceptedValue of\n        ClusterStateDiff diff\n            \\<Rightarrow> modifyCurrentClusterState diff\n        | Reconfigure votingNodes \\<Rightarrow> do {\n               setCurrentVotingNodes (set votingNodes);\n               joinVotes <- getJoinVotes;\n               setElectionWon (card (joinVotes \\<inter> (set votingNodes)) * 2 > card (set votingNodes))\n             }\n        | NoOp \\<Rightarrow> return ());\n\n      setFirstUncommittedSlot (firstUncommittedSlot + 1);\n      setLastAcceptedData None;\n      setPublishPermitted True;\n      setPublishVotes {}\n    }\"\n\ndefinition generateCatchup :: \"Node \\<Rightarrow> unit Action\"\n  where\n    \"generateCatchup sourceNode \\<equiv> do {\n\n      firstUncommittedSlot <- getFirstUncommittedSlot;\n      currentVotingNodes <- getCurrentVotingNodes;\n      currentClusterState <- getCurrentClusterState;\n\n      sendTo sourceNode (CatchUpResponse firstUncommittedSlot currentVotingNodes currentClusterState)\n    }\"\n\ndefinition applyCatchup :: \"Slot \\<Rightarrow> Node set \\<Rightarrow> ClusterState \\<Rightarrow> unit Action\"\n  where\n    \"applyCatchup catchUpSlot catchUpConfiguration catchUpState \\<equiv> do {\n\n      firstUncommittedSlot <- getFirstUncommittedSlot;\n      when (catchUpSlot \\<le> firstUncommittedSlot) (throw IllegalArgumentException);\n\n      setFirstUncommittedSlot catchUpSlot;\n      setCurrentVotingNodes catchUpConfiguration;\n      setCurrentClusterState catchUpState;\n      setLastAcceptedData None;\n\n      setJoinVotes {};\n      setElectionWon False;\n\n      setPublishVotes {};\n      setPublishPermitted True\n    }\"\n\ndefinition doClientValue :: \"Value \\<Rightarrow> unit Action\"\n  where\n    \"doClientValue x \\<equiv> do {\n\n      electionWon <- getElectionWon;\n      when (\\<not> electionWon) (throw IllegalArgumentException);\n\n      publishPermitted <- getPublishPermitted;\n      when (\\<not> publishPermitted) (throw IllegalArgumentException);\n\n      lastAcceptedTermInSlot <- getLastAcceptedTerm;\n      when (lastAcceptedTermInSlot \\<noteq> NO_TERM) (throw IllegalArgumentException);\n\n      setPublishPermitted False;\n\n      currentTerm <- getCurrentTerm;\n      firstUncommittedSlot <- getFirstUncommittedSlot;\n      broadcast (PublishRequest firstUncommittedSlot currentTerm x)\n    }\"\n\ndefinition doDiscardJoinVotes :: \"unit Action\"\n  where\n    \"doDiscardJoinVotes \\<equiv> do {\n      setJoinVotes {};\n      setElectionWon False\n    }\"\n\ndefinition doReboot :: \"unit Action\"\n  where\n    \"doReboot \\<equiv> modifyNodeData (\\<lambda>nd.\n                      (* persistent fields *)\n                  \\<lparr> currentNode = currentNode nd\n                  , currentTerm = currentTerm nd\n                  , firstUncommittedSlot = firstUncommittedSlot nd\n                  , currentVotingNodes = currentVotingNodes nd\n                  , currentClusterState = currentClusterState nd\n                  , lastAcceptedData = lastAcceptedData nd\n                      (* transient fields *)\n                  , joinVotes = {}\n                  , electionWon = False\n                  , publishPermitted = False\n                  , publishVotes = {} \\<rparr>)\"\n\ndefinition ProcessMessageAction :: \"RoutedMessage \\<Rightarrow> unit Action\"\n  where \"ProcessMessageAction rm \\<equiv> Action (\\<lambda>nd. case ProcessMessage nd rm of (nd', messageOption) \\<Rightarrow> (nd', case messageOption of None \\<Rightarrow> [] | Some m \\<Rightarrow> [m], Success ()))\"\n\ndefinition dispatchMessageInner :: \"RoutedMessage \\<Rightarrow> unit Action\"\n  where \"dispatchMessageInner m \\<equiv> case payload m of\n          StartJoin t \\<Rightarrow> doStartJoin (sender m) t\n          | Vote i t a \\<Rightarrow> doVote (sender m) i t a\n          | ClientValue x \\<Rightarrow> doClientValue x\n          | PublishRequest i t x \\<Rightarrow> doPublishRequest (sender m) i \\<lparr> tvTerm = t, tvValue = x \\<rparr>\n          | PublishResponse i t \\<Rightarrow> doPublishResponse (sender m) \\<lparr> stSlot = i, stTerm = t \\<rparr>\n          | ApplyCommit i t \\<Rightarrow> doCommit \\<lparr> stSlot = i, stTerm = t \\<rparr>\n          | CatchUpRequest \\<Rightarrow> generateCatchup (sender m)\n          | CatchUpResponse i conf cs \\<Rightarrow> applyCatchup i conf cs\n          | DiscardJoinVotes \\<Rightarrow> doDiscardJoinVotes\n          | Reboot \\<Rightarrow> doReboot\"\n\ndefinition dispatchMessage :: \"RoutedMessage \\<Rightarrow> unit Action\"\n  where \"dispatchMessage m \\<equiv> ignoringExceptions (do {\n      ensureCorrectDestination (destination m);\n      dispatchMessageInner m\n    })\"\n\nlemma getLastAcceptedTermInSlot_gets[simp]: \"getLastAcceptedTerm = gets lastAcceptedTerm\"\nproof (intro runM_inject)\n  fix nd\n  show \"runM getLastAcceptedTerm nd = runM (gets lastAcceptedTerm) nd\"\n    by (cases \"lastAcceptedData nd\", simp_all add: gets_def getLastAcceptedTerm_def getLastAcceptedData_def\n        getFirstUncommittedSlot_def lastAcceptedTerm_def)\nqed\n\nlemma monadic_implementation_is_faithful:\n  \"dispatchMessage = ProcessMessageAction\"\nproof (intro ext runM_inject)\n  fix rm nd\n  show \"runM (dispatchMessage rm) nd = runM (ProcessMessageAction rm) nd\" (is \"?LHS = ?RHS\")\n  proof (cases \"destination rm \\<in> {Broadcast, OneNode (currentNode nd)}\")\n    case False\n\n    hence 1: \"\\<And>f. runM (do { ensureCorrectDestination (destination rm); f }) nd = (nd, [], Exception IllegalArgumentException)\"\n      by (simp add: runM_ensureCorrectDestination_continue)\n\n    from False\n    show ?thesis\n      unfolding ProcessMessageAction_def dispatchMessage_def\n      by (simp add: ignoringExceptions_def catch_def 1 ProcessMessage_def)\n  next\n    case dest_ok: True\n\n    hence 1: \"runM (dispatchMessage rm) nd = runM (ignoringExceptions (dispatchMessageInner rm)) nd\"\n      by (simp add: dispatchMessage_def ignoringExceptions_def catch_def runM_ensureCorrectDestination_continue)\n\n    also have \"... = runM (ProcessMessageAction rm) nd\" (is \"?LHS = ?RHS\")\n    proof (cases \"payload rm\")\n      case (StartJoin t)\n\n      have \"?LHS = runM (ignoringExceptions (doStartJoin (sender rm) t)) nd\" (is \"_ = ?STEP\")\n        by (simp add: dispatchMessageInner_def StartJoin)\n\n      also consider\n        (a) \"t \\<le> currentTerm nd\"\n        | (b) \"currentTerm nd < t\" \"case lastAcceptedTerm nd of NO_TERM \\<Rightarrow> False | SomeTerm x \\<Rightarrow> t \\<le> x\"\n        | (c) \"currentTerm nd < t\" \"case lastAcceptedTerm nd of NO_TERM \\<Rightarrow> True | SomeTerm x \\<Rightarrow> x < t\"\n      proof (cases \"t \\<le> currentTerm nd\")\n        case True thus ?thesis by (intro a)\n      next\n        case 1: False\n        with b c show ?thesis\n          by (cases \"case lastAcceptedTerm nd of NO_TERM \\<Rightarrow> False | SomeTerm x \\<Rightarrow> t \\<le> x\", auto, cases \"lastAcceptedTerm nd\", auto)\n      qed\n\n      hence \"?STEP = ?RHS\"\n      proof cases\n        case a\n        thus ?thesis\n          by (simp add: StartJoin ProcessMessageAction_def dispatchMessage_def ProcessMessage_def Let_def runM_unless\n              doStartJoin_def getCurrentTerm_def gets_def setJoinVotes_def sets_def setCurrentTerm_def\n              setPublishPermitted_def setPublishVotes_def getFirstUncommittedSlot_def handleStartJoin_def ensureCurrentTerm_def setElectionWon_def\n              ignoringExceptions_def catch_def runM_when_continue)\n      next\n        case b\n        with StartJoin dest_ok show ?thesis\n          by (cases \"lastAcceptedTerm nd \", simp_all add: ProcessMessageAction_def dispatchMessage_def ProcessMessage_def Let_def\n              doStartJoin_def getCurrentTerm_def gets_def setJoinVotes_def sets_def setCurrentTerm_def runM_unless lastAcceptedTerm_def\n              setPublishPermitted_def setPublishVotes_def getFirstUncommittedSlot_def handleStartJoin_def ensureCurrentTerm_def setElectionWon_def\n              ignoringExceptions_def catch_def runM_when_continue)\n      next\n        case c with StartJoin dest_ok show ?thesis\n          by (cases \"lastAcceptedTerm nd\", simp_all add: ProcessMessageAction_def dispatchMessage_def ProcessMessage_def Let_def\n              doStartJoin_def getCurrentTerm_def gets_def setJoinVotes_def sets_def setCurrentTerm_def runM_unless lastAcceptedTerm_def\n              setPublishPermitted_def setPublishVotes_def getFirstUncommittedSlot_def handleStartJoin_def ensureCurrentTerm_def setElectionWon_def\n              ignoringExceptions_def catch_def runM_when_continue)\n      qed\n\n      finally show ?thesis by simp\n\n    next\n      case (Vote i t a)\n\n      have \"?LHS = runM (ignoringExceptions (doVote (sender rm) i t a)) nd\" (is \"_ = ?STEP\")\n        by (simp add: dispatchMessageInner_def Vote)\n\n      also have \"... = ?RHS\"\n      proof (cases \"firstUncommittedSlot nd < i\")\n        case True\n        with Vote dest_ok show ?thesis\n          by (simp add: dispatchMessage_def runM_unless\n              doVote_def gets_def getFirstUncommittedSlot_def ProcessMessage_def\n              ProcessMessageAction_def handleVote_def ignoringExceptions_def getCurrentTerm_def)\n      next\n        case False hence le: \"i \\<le> firstUncommittedSlot nd\" by simp\n\n        show ?thesis\n        proof (cases \"t = currentTerm nd\")\n          case False\n          with Vote dest_ok le show ?thesis\n            by (simp add: dispatchMessage_def runM_when runM_unless\n                doVote_def gets_def getFirstUncommittedSlot_def getCurrentTerm_def\n                ProcessMessage_def ProcessMessageAction_def handleVote_def ignoringExceptions_def)\n\n        next\n          case t: True\n\n          show ?thesis\n          proof (cases \"i = firstUncommittedSlot nd\")\n            case False\n            with Vote dest_ok le t show ?thesis\n              by (simp add: dispatchMessage_def Let_def runM_when_continue\n                  doVote_def runM_when runM_unless\n                  gets_def getFirstUncommittedSlot_def getCurrentTerm_def\n                  getJoinVotes_def getCurrentVotingNodes_def\n                  getPublishPermitted_def ignoringExceptions_def broadcast_def getCurrentNode_def\n                  modifies_def modifyJoinVotes_def send_def\n                  sets_def setElectionWon_def setPublishPermitted_def lastAcceptedValue_def\n                  ProcessMessage_def ProcessMessageAction_def handleVote_def\n                  addElectionVote_def publishValue_def isQuorum_def majorities_def)\n          next\n            case i: True\n            show ?thesis\n            proof (cases a)\n              case a: NO_TERM\n\n              show ?thesis\n              proof (cases \"isQuorum nd (insert (sender rm) (joinVotes nd))\")\n                case not_quorum: False\n                hence not_quorum_card: \"\\<not> card (currentVotingNodes nd) < card (insert (sender rm) (joinVotes nd) \\<inter> currentVotingNodes nd) * 2\"\n                  by (simp add: isQuorum_def majorities_def)\n\n                have \"?STEP = (nd\\<lparr>electionWon := False, joinVotes := insert (sender rm) (joinVotes nd)\\<rparr>, [], Success ())\"\n                  by (simp add: ignoringExceptions_def i t a doVote_def catch_def\n                      gets_def getCurrentTerm_def runM_when_continue getFirstUncommittedSlot_def\n                      modifyJoinVotes_def modifies_def getJoinVotes_def\n                      getCurrentVotingNodes_def Let_def setElectionWon_def sets_def runM_when\n                      not_quorum_card getPublishPermitted_def)\n\n                also from dest_ok have \"... = ?RHS\"\n                  by (simp add: ProcessMessageAction_def ProcessMessage_def Vote handleVote_def\n                      i t a addElectionVote_def not_quorum publishValue_def Let_def)\n\n                finally show ?thesis .\n\n              next\n                case quorum: True\n                hence quorum_card: \"card (currentVotingNodes nd) < card (insert (sender rm) (joinVotes nd) \\<inter> currentVotingNodes nd) * 2\"\n                  by (simp add: isQuorum_def majorities_def)\n\n                show ?thesis\n                proof (cases \"publishPermitted nd \\<and> lastAcceptedTerm nd \\<noteq> NO_TERM\")\n                  case False\n\n                  hence \"?STEP = (nd\\<lparr>electionWon := True, joinVotes := insert (sender rm) (joinVotes nd)\\<rparr>, [], Success ())\"\n                    by (auto simp add: ignoringExceptions_def i t a doVote_def catch_def\n                        gets_def getCurrentTerm_def runM_when_continue getFirstUncommittedSlot_def\n                        modifyJoinVotes_def modifies_def getJoinVotes_def\n                        getCurrentVotingNodes_def Let_def setElectionWon_def sets_def runM_when\n                        quorum_card getPublishPermitted_def)\n\n                  also from False dest_ok have \"... = ?RHS\"\n                    by (simp add: ProcessMessageAction_def ProcessMessage_def Vote handleVote_def\n                        i t a addElectionVote_def quorum publishValue_def Let_def)\n\n                  finally show ?thesis .\n\n                next\n                  case True\n\n                  hence \"?STEP = (nd\\<lparr>electionWon := True, publishPermitted := False,\n                                    joinVotes := insert (sender rm) (joinVotes nd)\\<rparr>,\n                                [\\<lparr>sender = currentNode nd, destination = Broadcast,\n                                  payload = PublishRequest (firstUncommittedSlot nd) (currentTerm nd)\n                                                           (lastAcceptedValue nd) \\<rparr>], Success ())\"\n                    by (auto simp add: ignoringExceptions_def i t a doVote_def catch_def\n                        gets_def getCurrentTerm_def runM_when_continue getFirstUncommittedSlot_def\n                        modifyJoinVotes_def modifies_def getJoinVotes_def\n                        getCurrentVotingNodes_def Let_def setElectionWon_def sets_def runM_when\n                        quorum_card getPublishPermitted_def setPublishPermitted_def lastAcceptedValue_def)\n\n                  also from True dest_ok have \"... = ?RHS\"\n                    by (simp add: ProcessMessageAction_def ProcessMessage_def Vote handleVote_def\n                        i t a addElectionVote_def quorum publishValue_def Let_def lastAcceptedValue_def)\n\n                  finally show ?thesis .\n\n                qed\n              qed\n\n            next\n              case a: (SomeTerm voteLastAcceptedTerm)\n\n              show ?thesis\n              proof (cases \"lastAcceptedTerm nd\")\n                case lat: NO_TERM\n\n                have \"?STEP = (nd, [], Success ())\"\n                  by (auto simp add: ignoringExceptions_def i t a lat doVote_def catch_def\n                      gets_def getCurrentTerm_def runM_when_continue getFirstUncommittedSlot_def)\n\n                also from dest_ok have \"... = ?RHS\"\n                  by (simp add: ProcessMessageAction_def ProcessMessage_def Vote handleVote_def\n                      i t a lat)\n\n                finally show ?thesis .\n\n              next\n                case lat: (SomeTerm nodeLastAcceptedTerm)\n\n                show ?thesis\n                proof (cases \"voteLastAcceptedTerm \\<le> nodeLastAcceptedTerm\")\n                  case False\n                  hence \"?STEP = (nd, [], Success ())\"\n                    by (simp add: ignoringExceptions_def i t a lat doVote_def catch_def\n                        gets_def getCurrentTerm_def runM_when_continue getFirstUncommittedSlot_def)\n                  also from False dest_ok have \"... = ?RHS\"\n                    by (simp add: ProcessMessageAction_def ProcessMessage_def Vote handleVote_def\n                        i t a lat max_def addElectionVote_def publishValue_def)\n\n                  finally show ?thesis by simp\n                next\n                  case True\n\n                  show ?thesis\n                  proof (cases \"isQuorum nd (insert (sender rm) (joinVotes nd))\")\n                    case not_quorum: False\n                    hence not_quorum_card: \"\\<not> card (currentVotingNodes nd) < card (insert (sender rm) (joinVotes nd) \\<inter> currentVotingNodes nd) * 2\"\n                      by (simp add: isQuorum_def majorities_def)\n\n                    from True\n                    have \"?STEP = (nd\\<lparr>electionWon := False,\n                                    joinVotes := insert (sender rm) (joinVotes nd)\\<rparr>, [], Success ())\"\n                      by (simp add: ignoringExceptions_def i t a lat doVote_def catch_def\n                          gets_def getCurrentTerm_def runM_when_continue getFirstUncommittedSlot_def\n                          modifyJoinVotes_def modifies_def getJoinVotes_def\n                          getCurrentVotingNodes_def Let_def setElectionWon_def sets_def runM_when\n                          not_quorum_card getPublishPermitted_def)\n\n                    also from dest_ok True have \"... = ?RHS\"\n                      by (simp add: ProcessMessageAction_def ProcessMessage_def Vote handleVote_def\n                          i t a lat max_def addElectionVote_def not_quorum publishValue_def Let_def)\n\n                    finally show ?thesis .\n\n                  next\n                    case quorum: True\n                    hence quorum_card: \"card (currentVotingNodes nd) < card (insert (sender rm) (joinVotes nd) \\<inter> currentVotingNodes nd) * 2\"\n                      by (simp add: isQuorum_def majorities_def)\n\n                    show ?thesis\n                    proof (cases \"publishPermitted nd\")\n                      case False\n\n                      with True\n                      have \"?STEP = (nd\\<lparr>electionWon := True,\n                                    joinVotes := insert (sender rm) (joinVotes nd)\\<rparr>, [], Success ())\"\n                        by (simp add: ignoringExceptions_def i t a lat doVote_def catch_def\n                            gets_def getCurrentTerm_def runM_when_continue getFirstUncommittedSlot_def\n                            modifyJoinVotes_def modifies_def getJoinVotes_def\n                            getCurrentVotingNodes_def Let_def setElectionWon_def sets_def runM_when\n                            quorum_card getPublishPermitted_def setPublishPermitted_def)\n\n                      also from False dest_ok have \"... = ?RHS\"\n                        by (simp add: ProcessMessageAction_def ProcessMessage_def Vote handleVote_def\n                            i t a lat True addElectionVote_def quorum publishValue_def Let_def)\n\n                      finally show ?thesis .\n\n                    next\n                      case publishPermitted: True\n\n                      have \"?STEP = (nd\\<lparr>electionWon := True, publishPermitted := False,\n                                    joinVotes := insert (sender rm) (joinVotes nd)\\<rparr>,\n                                [\\<lparr>sender = currentNode nd, destination = Broadcast,\n                                  payload = PublishRequest (firstUncommittedSlot nd) (currentTerm nd)\n                                                           (lastAcceptedValue nd) \\<rparr>], Success ())\"\n                        apply (auto simp add: ignoringExceptions_def i t a lat True doVote_def catch_def\n                            gets_def getCurrentTerm_def runM_when_continue getFirstUncommittedSlot_def\n                            modifyJoinVotes_def modifies_def getJoinVotes_def\n                            getCurrentVotingNodes_def Let_def setElectionWon_def sets_def runM_when\n                            quorum_card getPublishPermitted_def setPublishPermitted_def lastAcceptedValue_def)\n                        using True publishPermitted by auto\n\n                      also from publishPermitted True dest_ok have \"... = ?RHS\"\n                        by (simp add: ProcessMessageAction_def ProcessMessage_def Vote handleVote_def\n                            i t a lat True addElectionVote_def quorum publishValue_def Let_def lastAcceptedValue_def)\n\n                      finally show ?thesis .\n\n                    qed\n                  qed\n                qed\n              qed\n            qed\n          qed\n        qed\n      qed\n\n      finally show ?thesis .\n\n    next\n      case (ClientValue x)\n\n      with dest_ok show ?thesis\n        by (simp add: ProcessMessageAction_def dispatchMessageInner_def\n            doClientValue_def gets_def getElectionWon_def\n            runM_unless getPublishPermitted_def setPublishPermitted_def sets_def\n            getCurrentTerm_def getFirstUncommittedSlot_def ProcessMessage_def handleClientValue_def\n            publishValue_def runM_when ignoringExceptions_def ClientValue catch_def runM_when_continue)\n\n    next\n      case (PublishRequest i t x) with dest_ok show ?thesis\n        by (simp add: ProcessMessageAction_def dispatchMessageInner_def\n          doPublishRequest_def gets_def getCurrentTerm_def getFirstUncommittedSlot_def\n          sets_def setLastAcceptedData_def ignoringExceptions_def catch_def runM_when_continue\n          getCurrentNode_def runM_unless send_def\n          ProcessMessage_def handlePublishRequest_def runM_when)\n\n    next\n      case (PublishResponse i t) with dest_ok show ?thesis\n        by (simp add: ProcessMessageAction_def dispatchMessageInner_def\n          doPublishResponse_def gets_def getCurrentTerm_def getFirstUncommittedSlot_def\n          broadcast_def getCurrentNode_def runM_unless send_def\n          modifyPublishVotes_def modifies_def getPublishVotes_def getCurrentVotingNodes_def\n          runM_when ignoringExceptions_def catch_def runM_when_continue\n          ProcessMessage_def handlePublishResponse_def commitIfQuorate_def isQuorum_def majorities_def\n          ApplyCommitFromSlotTerm_def)\n\n    next\n      case (ApplyCommit i t)\n\n      show ?thesis\n      proof (cases \"lastAcceptedValue nd\")\n        case NoOp\n        with ApplyCommit dest_ok show ?thesis\n          by (simp add: ProcessMessageAction_def dispatchMessageInner_def\n            doCommit_def runM_unless runM_when\n            gets_def getFirstUncommittedSlot_def\n            sets_def setFirstUncommittedSlot_def setLastAcceptedData_def\n            setPublishPermitted_def setPublishVotes_def\n            ProcessMessage_def handleApplyCommit_def applyAcceptedValue_def\n            ignoringExceptions_def catch_def runM_when_continue)\n      next\n        case Reconfigure\n        with ApplyCommit dest_ok show ?thesis\n          by (simp add: ProcessMessageAction_def dispatchMessageInner_def\n            doCommit_def runM_unless runM_when\n            gets_def getFirstUncommittedSlot_def\n            getJoinVotes_def\n            sets_def setFirstUncommittedSlot_def setLastAcceptedData_def\n            setPublishPermitted_def setPublishVotes_def\n            setCurrentVotingNodes_def setElectionWon_def\n            ProcessMessage_def handleApplyCommit_def applyAcceptedValue_def majorities_def\n            ignoringExceptions_def catch_def runM_when_continue)\n      next\n        case ClusterStateDiff\n        with ApplyCommit dest_ok show ?thesis\n          by (simp add: ProcessMessageAction_def dispatchMessageInner_def\n            doCommit_def runM_unless runM_when\n            gets_def getFirstUncommittedSlot_def\n            sets_def setFirstUncommittedSlot_def\n            modifies_def modifyCurrentClusterState_def\n            setPublishPermitted_def setPublishVotes_def setLastAcceptedData_def\n            ProcessMessage_def handleApplyCommit_def applyAcceptedValue_def\n            ignoringExceptions_def catch_def runM_when_continue)\n      qed\n\n    next\n      case CatchUpRequest\n      with dest_ok show ?thesis\n        by (simp add: ProcessMessageAction_def dispatchMessageInner_def\n          generateCatchup_def\n          gets_def getFirstUncommittedSlot_def getCurrentVotingNodes_def getCurrentClusterState_def\n          ProcessMessage_def handleCatchUpRequest_def ignoringExceptions_def catch_def runM_when_continue)\n\n    next\n      case (CatchUpResponse i conf cs)\n      with dest_ok show ?thesis\n        by (simp add: ProcessMessageAction_def dispatchMessageInner_def\n            applyCatchup_def gets_def getFirstUncommittedSlot_def\n            sets_def setFirstUncommittedSlot_def\n            setPublishPermitted_def setPublishVotes_def setLastAcceptedData_def\n            setCurrentVotingNodes_def setCurrentClusterState_def setJoinVotes_def\n            setElectionWon_def runM_unless\n            ProcessMessage_def handleCatchUpResponse_def\n            ignoringExceptions_def catch_def runM_when_continue)\n\n    next\n      case Reboot\n      with dest_ok show ?thesis\n        by (simp add: ProcessMessageAction_def dispatchMessageInner_def\n            doReboot_def ProcessMessage_def handleReboot_def ignoringExceptions_def catch_def runM_when_continue)\n\n    next\n      case DiscardJoinVotes\n      with dest_ok show ?thesis\n        by (simp add: ProcessMessageAction_def dispatchMessageInner_def\n            doDiscardJoinVotes_def ProcessMessage_def handleDiscardJoinVotes_def ignoringExceptions_def catch_def \n            runM_when_continue setJoinVotes_def sets_def setElectionWon_def)\n\n    qed\n\n    finally show ?thesis .\n  qed\nqed\n\nend\n"
  },
  {
    "path": "cluster/isabelle/OneSlot.thy",
    "content": "section \\<open>One-slot consistency\\<close>\n\ntext \\<open>The replicated state machine determines the values that are committed in each of a sequence\nof \\textit{slots}. Each slot runs a logically-separate consensus algorithm which is shown to be\nconsistent here. Further below, the protocol is shown to refine this slot-by-slot model correctly.\\<close>\n\ntext \\<open>Consistency is shown to follow from the invariants listed below. Further below, the protocol\nis shown to preserve these invariants in each step, which means it is not enormously important\nto understand these in detail.\\<close>\n\ntheory OneSlot\n  imports Preliminaries\nbegin\n\nlocale oneSlot =\n  (* basic functions *)\n  fixes Q :: \"Node set set\"\n  fixes v :: \"Term \\<Rightarrow> Value\"\n    (* message-sent predicates *)\n  fixes promised\\<^sub>f :: \"Node \\<Rightarrow> Term \\<Rightarrow> bool\"\n  fixes promised\\<^sub>b :: \"Node \\<Rightarrow> Term \\<Rightarrow> Term \\<Rightarrow> bool\"\n  fixes proposed :: \"Term \\<Rightarrow> bool\"\n  fixes accepted :: \"Node \\<Rightarrow> Term \\<Rightarrow> bool\"\n  fixes committed :: \"Term \\<Rightarrow> bool\"\n    (* other definitions *)\n  fixes promised :: \"Node \\<Rightarrow> Term \\<Rightarrow> bool\"\n  defines \"promised n t \\<equiv> promised\\<^sub>f n t \\<or> (\\<exists> t'. promised\\<^sub>b n t t')\"\n  fixes prevAccepted :: \"Term \\<Rightarrow> Node set \\<Rightarrow> Term set\"\n  defines \"prevAccepted t ns \\<equiv> {t'. \\<exists> n \\<in> ns. promised\\<^sub>b n t t'}\"\n    (* invariants *)\n  assumes Q_intersects: \"Q \\<frown> Q\"\n  assumes promised\\<^sub>f: \"\\<lbrakk> promised\\<^sub>f n t; t' < t \\<rbrakk> \\<Longrightarrow> \\<not> accepted n t'\"\n  assumes promised\\<^sub>b_lt: \"promised\\<^sub>b n t t' \\<Longrightarrow> t' < t\"\n  assumes promised\\<^sub>b_accepted: \"promised\\<^sub>b n t t' \\<Longrightarrow> accepted n t'\"\n  assumes promised\\<^sub>b_max: \"\\<lbrakk> promised\\<^sub>b n t t'; t' < t''; t'' < t \\<rbrakk>\n   \\<Longrightarrow> \\<not> accepted n t''\"\n  assumes proposed: \"proposed t\n     \\<Longrightarrow> \\<exists> q \\<in> Q. (\\<forall> n \\<in> q. promised n t)\n                     \\<and> (prevAccepted t q = {}\n                          \\<or> (\\<exists> t'. v t = v t' \\<and> maxTerm (prevAccepted t q) \\<le> t' \\<and> proposed t' \\<and> t' < t))\"\n  assumes proposed_finite: \"finite {t. proposed t}\"\n  assumes accepted: \"accepted n t \\<Longrightarrow> proposed t\"\n  assumes committed: \"committed t \\<Longrightarrow> \\<exists> q \\<in> Q. \\<forall> n \\<in> q. accepted n t\"\n\nlemma (in oneSlot) prevAccepted_proposed: \"prevAccepted t ns \\<subseteq> {t. proposed t}\"\n  using accepted prevAccepted_def promised\\<^sub>b_accepted by fastforce\n\nlemma (in oneSlot) prevAccepted_finite: \"finite (prevAccepted p ns)\"\n  using prevAccepted_proposed proposed_finite by (meson rev_finite_subset)\n\nlemma (in oneSlot) Q_nonempty: \"\\<And>q. q \\<in> Q \\<Longrightarrow> q \\<noteq> {}\"\n  using Q_intersects by (auto simp add: intersects_def)\n\ntext \\<open>The heart of the consistency proof is property P2b from \\textit{Paxos made simple} by Lamport:\\<close>\n\nlemma (in oneSlot) p2b:\n  assumes \"proposed t\\<^sub>1\" and \"committed t\\<^sub>2\" and \"t\\<^sub>2 < t\\<^sub>1\"\n  shows \"v t\\<^sub>1 = v t\\<^sub>2\"\n  using assms\nproof (induct t\\<^sub>1 rule: less_induct)\n  case (less t\\<^sub>1)\n\n  hence hyp: \"\\<And> t\\<^sub>1'. \\<lbrakk> t\\<^sub>1' < t\\<^sub>1; proposed t\\<^sub>1'; t\\<^sub>2 \\<le> t\\<^sub>1' \\<rbrakk> \\<Longrightarrow> v t\\<^sub>1' = v t\\<^sub>2\"\n    using le_imp_less_or_eq by blast\n\n  from `proposed t\\<^sub>1` obtain q\\<^sub>1 t\\<^sub>1' where\n    q\\<^sub>1_quorum:   \"q\\<^sub>1 \\<in> Q\" and\n    q\\<^sub>1_promised: \"\\<And>n. n \\<in> q\\<^sub>1 \\<Longrightarrow> promised n t\\<^sub>1\" and\n    q\\<^sub>1_value:    \"prevAccepted t\\<^sub>1 q\\<^sub>1 = {} \\<or> (v t\\<^sub>1 = v t\\<^sub>1' \\<and> maxTerm (prevAccepted t\\<^sub>1 q\\<^sub>1) \\<le> t\\<^sub>1' \\<and> proposed t\\<^sub>1' \\<and> t\\<^sub>1' < t\\<^sub>1)\"\n    by (meson proposed)\n\n  from `committed t\\<^sub>2` obtain q\\<^sub>2 where\n    q\\<^sub>2_quorum:   \"q\\<^sub>2 \\<in> Q\" and\n    q\\<^sub>2_accepted: \"\\<And>n. n \\<in> q\\<^sub>2 \\<Longrightarrow> accepted n t\\<^sub>2\"\n    using committed by force\n\n  have \"q\\<^sub>1 \\<inter> q\\<^sub>2 \\<noteq> {}\"\n    using Q_intersects intersects_def less.prems q\\<^sub>1_quorum q\\<^sub>2_quorum by auto\n\n  then obtain n where n\\<^sub>1: \"n \\<in> q\\<^sub>1\" and n\\<^sub>2: \"n \\<in> q\\<^sub>2\" by auto\n\n  from n\\<^sub>1 q\\<^sub>1_promised have \"promised n t\\<^sub>1\" by simp\n  moreover from n\\<^sub>2 q\\<^sub>2_accepted have \"accepted n t\\<^sub>2\" by simp\n  ultimately obtain t\\<^sub>2' where t\\<^sub>2': \"promised\\<^sub>b n t\\<^sub>1 t\\<^sub>2'\"\n    using less.prems(3) promised\\<^sub>f promised_def by blast\n\n  have q\\<^sub>1_value: \"v t\\<^sub>1 = v t\\<^sub>1'\" \"maxTerm (prevAccepted t\\<^sub>1 q\\<^sub>1) \\<le> t\\<^sub>1'\" \"proposed t\\<^sub>1'\" \"t\\<^sub>1' < t\\<^sub>1\"\n    using n\\<^sub>1 prevAccepted_def q\\<^sub>1_value t\\<^sub>2' by auto\n\n  note `v t\\<^sub>1 = v t\\<^sub>1'`\n  also have \"v t\\<^sub>1' = v t\\<^sub>2\"\n  proof (intro hyp)\n    have p: \"maxTerm (prevAccepted t\\<^sub>1 q\\<^sub>1) \\<in> prevAccepted t\\<^sub>1 q\\<^sub>1\"\n      apply (intro maxTerm_mem prevAccepted_finite)\n      using n\\<^sub>1 prevAccepted_def t\\<^sub>2' by auto\n\n    show \"t\\<^sub>1' < t\\<^sub>1\" \"proposed t\\<^sub>1'\" using q\\<^sub>1_value by simp_all\n\n    have \"t\\<^sub>2 \\<le> t\\<^sub>2'\"\n      by (meson \\<open>accepted n t\\<^sub>2\\<close> less.prems(3) not_le promised\\<^sub>b_max t\\<^sub>2')\n    also have \"t\\<^sub>2' \\<le> maxTerm (prevAccepted t\\<^sub>1 q\\<^sub>1)\"\n      using n\\<^sub>1 prevAccepted_def t\\<^sub>2' prevAccepted_finite by (intro maxTerm_max, auto)\n    also have \"... \\<le> t\\<^sub>1'\" using q\\<^sub>1_value by simp\n    finally show \"t\\<^sub>2 \\<le> t\\<^sub>1'\" .\n  qed\n\n  finally show ?case .\nqed\n\ntext \\<open>From this, it follows that any two committed values are equal as desired.\\<close>\n\nlemma (in oneSlot) consistent:\n  assumes \"committed t\\<^sub>1\" and \"committed t\\<^sub>2\"\n  shows \"v t\\<^sub>1 = v t\\<^sub>2\"\n  using assms by (metis Q_nonempty accepted all_not_in_conv committed not_less_iff_gr_or_eq p2b)\n\ntext \\<open>It will be useful later to know the conditions under which a value in a term can be committed,\nwhich is spelled out here:\\<close>\n\nlemma (in oneSlot) commit:\n  assumes q_quorum: \"q \\<in> Q\"\n  assumes q_accepted: \"\\<And>n. n \\<in> q \\<Longrightarrow> accepted n t\\<^sub>0\"\n  defines \"committed' t \\<equiv> committed t \\<or> t = t\\<^sub>0\"\n  shows \"oneSlot Q v promised\\<^sub>f promised\\<^sub>b proposed accepted committed'\"\n  by (smt committed'_def Q_intersects oneSlot_axioms oneSlot_def q_accepted q_quorum)\n\nend\n"
  },
  {
    "path": "cluster/isabelle/Preliminaries.thy",
    "content": "section \\<open>Preliminaries\\<close>\n\ntext \\<open>We start with some definitions of the types involved.\\<close>\n\ntheory Preliminaries\n  imports Main\nbegin\n\nsubsection \\<open>Slots\\<close>\n\ntext \\<open>Slots are identified by natural numbers.\\<close>\n\ntype_synonym Slot = nat\n\nsubsection \\<open>Terms\\<close>\n\ntext \\<open>Terms are identified by natural numbers.\\<close>\n\ntype_synonym Term = nat\n\nsubsubsection \\<open>Maximum term of a set\\<close>\n\ntext \\<open>A function for finding the maximum term in a set is as follows.\\<close>\n\ndefinition maxTerm :: \"Term set \\<Rightarrow> Term\"\n  where \"maxTerm S \\<equiv> THE t. t \\<in> S \\<and> (\\<forall> t' \\<in> S. t' \\<le> t)\"\n\ntext \\<open>It works correctly on finite and nonempty sets as follows:\\<close>\n\ntheorem\n  fixes S :: \"Term set\"\n  assumes finite: \"finite S\"\n  shows maxTerm_mem: \"S \\<noteq> {} \\<Longrightarrow> maxTerm S \\<in> S\"\n    and maxTerm_max: \"\\<And> t'. t' \\<in> S \\<Longrightarrow> t' \\<le> maxTerm S\"\nproof -\n  presume \"S \\<noteq> {}\"\n  with assms\n  obtain t where t: \"t \\<in> S\" \"\\<And> t'. t' \\<in> S \\<Longrightarrow> t' \\<le> t\"\n  proof (induct arbitrary: thesis)\n    case empty\n    then show ?case by simp\n  next\n    case (insert t S)\n    show ?case\n    proof (cases \"S = {}\")\n      case True hence [simp]: \"insert t S = {t}\" by simp\n      from insert.prems show ?thesis by simp\n    next\n      case False\n      obtain t' where t': \"t' \\<in> S\" \"\\<forall> t'' \\<in> S. t'' \\<le> t'\"\n        by (meson False insert.hyps(3))\n\n      from t'\n      show ?thesis\n      proof (intro insert.prems ballI)\n        fix t'' assume t'': \"t'' \\<in> insert t S\"\n        show \"t'' \\<le> (if t \\<le> t' then t' else t)\"\n        proof (cases \"t'' = t\")\n          case False\n          with t'' have \"t'' \\<in> S\" by simp\n          with t' have \"t'' \\<le> t'\" by simp\n          thus ?thesis by auto\n        qed simp\n      qed simp\n    qed\n  qed\n\n  from t have \"maxTerm S = t\"\n    by (unfold maxTerm_def, intro the_equality, simp_all add: eq_iff)\n\n  with t show \"maxTerm S \\<in> S\" \"\\<And>t'. t' \\<in> S \\<Longrightarrow> t' \\<le> maxTerm S\" by simp_all\nqed auto\n\nlemma\n  assumes \"\\<And>t. t \\<in> S \\<Longrightarrow> t \\<le> t'\" \"finite S\" \"S \\<noteq> {}\"\n  shows maxTerm_le: \"maxTerm S \\<le> t'\" using assms maxTerm_mem by auto\n\nsubsection \\<open>Configurations and quorums\\<close>\n\ntext \\<open>Nodes are simply identified by a natural number.\\<close>\n\ndatatype Node = Node nat\n\ndefinition natOfNode :: \"Node \\<Rightarrow> nat\" where \"natOfNode node \\<equiv> case node of Node n \\<Rightarrow> n\"\nlemma natOfNode_Node[simp]: \"natOfNode (Node n) = n\" by (simp add: natOfNode_def)\nlemma Node_natOfNode[simp]: \"Node (natOfNode n) = n\" by (cases n, simp add: natOfNode_def)\nlemma natOfNode_inj[simp]: \"(natOfNode n\\<^sub>1 = natOfNode n\\<^sub>2) = (n\\<^sub>1 = n\\<^sub>2)\" by (metis Node_natOfNode)\n\ntext \\<open>It is useful to be able to talk about whether sets-of-sets-of nodes mutually intersect or not.\\<close>\n\ndefinition intersects :: \"Node set set \\<Rightarrow> Node set set \\<Rightarrow> bool\" (infixl \"\\<frown>\" 50)\n  where \"A \\<frown> B \\<equiv> \\<forall> a \\<in> A. \\<forall> b \\<in> B. a \\<inter> b \\<noteq> {}\"\n\ndefinition majorities :: \"Node set \\<Rightarrow> Node set set\"\n  where \"majorities votingNodes = { q. card votingNodes < card (q \\<inter> votingNodes) * 2 }\"\n\nlemma majorities_nonempty: assumes \"q \\<in> majorities Q\" shows \"q \\<noteq> {}\"\n  using assms by (auto simp add: majorities_def)\n\nlemma majorities_member: assumes \"q \\<in> majorities Q\" obtains n where \"n \\<in> q\"\n  using majorities_nonempty assms by fastforce\n\nlemma majorities_intersect:\n  assumes \"finite votingNodes\"\n  shows \"majorities votingNodes \\<frown> majorities votingNodes\"\n  unfolding intersects_def\nproof (intro ballI notI)\n  fix q\\<^sub>1 assume q\\<^sub>1: \"q\\<^sub>1 \\<in> majorities votingNodes\"\n  fix q\\<^sub>2 assume q\\<^sub>2: \"q\\<^sub>2 \\<in> majorities votingNodes\"\n  assume disj: \"q\\<^sub>1 \\<inter> q\\<^sub>2 = {}\"\n\n  have 1: \"card ((q\\<^sub>1 \\<inter> votingNodes) \\<union> (q\\<^sub>2 \\<inter> votingNodes)) = card (q\\<^sub>1 \\<inter> votingNodes) + card (q\\<^sub>2 \\<inter> votingNodes)\"\n  proof (intro card_Un_disjoint)\n    from assms show \"finite (q\\<^sub>1 \\<inter> votingNodes)\" by simp\n    from assms show \"finite (q\\<^sub>2 \\<inter> votingNodes)\" by simp\n    from disj show \"q\\<^sub>1 \\<inter> votingNodes \\<inter> (q\\<^sub>2 \\<inter> votingNodes) = {}\" by auto\n  qed\n\n  have \"card ((q\\<^sub>1 \\<inter> votingNodes) \\<union> (q\\<^sub>2 \\<inter> votingNodes)) \\<le> card votingNodes\" by (simp add: assms card_mono)\n  hence 2: \"2 * card (q\\<^sub>1 \\<inter> votingNodes) + 2 * card (q\\<^sub>2 \\<inter> votingNodes) \\<le> 2 * card votingNodes\" by (simp add: 1)\n\n  from q\\<^sub>1 q\\<^sub>2 have 3: \"card votingNodes + card votingNodes < 2 * card (q\\<^sub>1 \\<inter> votingNodes) + 2 * card (q\\<^sub>2 \\<inter> votingNodes)\"\n    unfolding majorities_def by auto\n\n  from 2 3 show False by simp\nqed\n\ntext \\<open>A configuration of the system defines the sets of master-eligible nodes whose votes count when calculating quorums.\nThe initial configuration of the system is fixed to some arbitrary value.\\<close>\n\nconsts Vs\\<^sub>0 :: \"Node list\"\ndefinition V\\<^sub>0 :: \"Node set\" where \"V\\<^sub>0 \\<equiv> set Vs\\<^sub>0\"\n\nlemma finite_V\\<^sub>0: \"finite V\\<^sub>0\" unfolding V\\<^sub>0_def by auto\nlemma V\\<^sub>0_intersects: \"majorities V\\<^sub>0 \\<frown> majorities V\\<^sub>0\" using finite_V\\<^sub>0 by (intro majorities_intersect)\n\nsubsection \\<open>Values\\<close>\n\ntext \\<open>The model is a replicated state machine, with transitions that either do nothing, alter\nthe configuration of the system or set a new \\texttt{ClusterState}. \\texttt{ClusterState} values\nare modelled simply as natural numbers.\\<close>\n\ndatatype ClusterState = ClusterState nat\nconsts CS\\<^sub>0 :: ClusterState\n\ndatatype Value\n  = NoOp\n  | Reconfigure \"Node list\" (* update the set of voting nodes. A list rather than a set to force it to be finite *)\n  | ClusterStateDiff \"ClusterState \\<Rightarrow> ClusterState\" (* a ClusterState diff *)\n\ntext \\<open>Some useful definitions and lemmas follow.\\<close>\n\nfun isReconfiguration :: \"Value \\<Rightarrow> bool\"\n  where \"isReconfiguration (Reconfigure _) = True\"\n  | \"isReconfiguration _ = False\"\n\nfun getConf :: \"Value \\<Rightarrow> Node set\"\n  where \"getConf (Reconfigure conf) = set conf\"\n  | \"getConf _                      = {}\"\n\nlemma getConf_finite: \"finite (getConf v)\"\n  by (metis List.finite_set getConf.elims infinite_imp_nonempty)\n\nlemma getConf_intersects: \"majorities (getConf v) \\<frown> majorities (getConf v)\"\n  by (simp add: getConf_finite majorities_intersect)\n\nend\n"
  },
  {
    "path": "cluster/isabelle/ROOT",
    "content": "session \"elasticsearch-isabelle\" = \"HOL\" +\n  options [document = pdf, document_output = \"output\", document_variants=\"document:outline=/proof\"]\n  theories [document = false]\n    (* Foo *)\n    (* Bar *)\n  theories\n    Preliminaries\n    Implementation\n    Monadic\n    OneSlot\n    Zen\n  document_files\n    \"root.tex\"\n"
  },
  {
    "path": "cluster/isabelle/Zen.thy",
    "content": "section \\<open>Safety Properties\\<close>\n\ntext \\<open>This section describes the invariants that hold in the system, shows that the implementation\npreserves the invariants, and shows that the invariants imply the required safety properties.\\<close>\n\ntheory Zen\n  imports Implementation OneSlot\nbegin\n\nsubsection \\<open>Invariants on messages\\<close>\n\ntext \\<open>Firstly, a set of invariants that hold on the set of messages that\nhave ever been sent, without considering the state of any individual\nnode.\\<close>\n\nfun nat_inductive_def :: \"'a \\<Rightarrow> (nat \\<Rightarrow> 'a \\<Rightarrow> 'a) \\<Rightarrow> nat \\<Rightarrow> 'a\"\n  where\n    \"nat_inductive_def zeroCase sucCase 0 = zeroCase\"\n  | \"nat_inductive_def zeroCase sucCase (Suc i) = sucCase i (nat_inductive_def zeroCase sucCase i)\"\n\nlocale zenMessages =\n  fixes messages :: \"RoutedMessage set\"\n  fixes isMessageFromTo :: \"Node \\<Rightarrow> Message \\<Rightarrow> Destination \\<Rightarrow> bool\" (\"(_) \\<midarrow>\\<langle> _ \\<rangle>\\<rightarrow> (_)\" [1000,55,1000])\n  defines \"s \\<midarrow>\\<langle> m \\<rangle>\\<rightarrow> d \\<equiv> \\<lparr> sender = s, destination = d, payload = m \\<rparr> \\<in> messages\"\n  fixes isMessageFrom :: \"Node \\<Rightarrow> Message \\<Rightarrow> bool\" (\"(_) \\<midarrow>\\<langle> _ \\<rangle>\\<leadsto>\" [1000,55])\n  defines \"s \\<midarrow>\\<langle> m \\<rangle>\\<leadsto> \\<equiv> \\<exists> d. s \\<midarrow>\\<langle> m \\<rangle>\\<rightarrow> d\"\n  fixes isMessageTo :: \"Message \\<Rightarrow> Destination \\<Rightarrow> bool\" (\"\\<langle> _ \\<rangle>\\<rightarrow> (_)\" [55,1000])\n  defines \"\\<langle> m \\<rangle>\\<rightarrow> d \\<equiv> \\<exists> s. s \\<midarrow>\\<langle> m \\<rangle>\\<rightarrow> d\"\n  fixes isMessage :: \"Message \\<Rightarrow> bool\" (\"\\<langle> _ \\<rangle>\\<leadsto>\" [55])\n  defines \"\\<langle> m \\<rangle>\\<leadsto> \\<equiv> \\<exists> s. s \\<midarrow>\\<langle> m \\<rangle>\\<leadsto>\"\n    (* value proposed in a slot & a term *)\n  fixes v :: \"Slot \\<Rightarrow> Term \\<Rightarrow> Value\"\n  defines \"v i t \\<equiv> THE x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\"\n    (* whether a slot is committed *)\n  fixes isCommitted :: \"Slot \\<Rightarrow> bool\"\n  defines \"isCommitted i \\<equiv> \\<exists> t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>\"\n    (* whether all preceding slots are committed *)\n  fixes committedTo :: \"Slot \\<Rightarrow> bool\" (\"committed\\<^sub><\")\n  defines \"committed\\<^sub>< i \\<equiv> \\<forall> j < i. isCommitted j\"\n    (* the committed value in a slot *)\n  fixes v\\<^sub>c :: \"Slot \\<Rightarrow> Value\"\n  defines \"v\\<^sub>c i \\<equiv> v i (SOME t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\"\n    (* the configuration of a slot *)\n  fixes V :: \"Slot \\<Rightarrow> Node set\"\n  defines \"V \\<equiv> nat_inductive_def V\\<^sub>0 (\\<lambda>i Vi. if isReconfiguration (v\\<^sub>c i) then getConf (v\\<^sub>c i) else Vi)\"\n    (* predicate to say whether an applicable Vote has been sent *)\n  fixes promised :: \"Slot \\<Rightarrow> Node \\<Rightarrow> Node \\<Rightarrow> Term \\<Rightarrow> bool\"\n  defines \"promised i s dn t \\<equiv> \\<exists> i' \\<le> i. \\<exists> a. s \\<midarrow>\\<langle> Vote i' t a \\<rangle>\\<rightarrow> (OneNode dn)\"\n    (* set of previously-accepted terms *)\n  fixes prevAccepted :: \"Slot \\<Rightarrow> Term \\<Rightarrow> Node set \\<Rightarrow> Term set\"\n  defines \"prevAccepted i t senders\n      \\<equiv> {t'. \\<exists> s \\<in> senders. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> }\"\n  fixes lastCommittedClusterStateBefore :: \"Slot \\<Rightarrow> ClusterState\"\n  defines \"lastCommittedClusterStateBefore \\<equiv> nat_inductive_def CS\\<^sub>0\n      (\\<lambda>i CSi. case v\\<^sub>c i of ClusterStateDiff diff \\<Rightarrow> diff CSi | _ \\<Rightarrow> CSi)\"\n\n(* ASSUMPTIONS *)\nassumes Vote_future:\n  \"\\<And>i i' s t t' a.\n        \\<lbrakk> s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>; i < i'; t' < t \\<rbrakk>\n            \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\"\nassumes Vote_None:\n  \"\\<And>i s t t'.\n        \\<lbrakk> s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto>; t' < t \\<rbrakk>\n            \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\"\nassumes Vote_Some_lt:\n  \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>\n      \\<Longrightarrow> t' < t\"\nassumes Vote_Some_PublishResponse:\n  \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>\n      \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\"\nassumes Vote_Some_max:\n  \"\\<And>i s t t' t''. \\<lbrakk> s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>; t' < t''; t'' < t \\<rbrakk>\n      \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\"\nassumes Vote_not_broadcast:\n  \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\"\nassumes Vote_unique_destination:\n  \"\\<And>i s t a a' d d'. \\<lbrakk> s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d; s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<rbrakk>\n      \\<Longrightarrow> d = d'\"\nassumes PublishRequest_committedTo:\n  \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committedTo i\"\nassumes PublishRequest_quorum:\n  \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\n      \\<Longrightarrow> \\<exists> q \\<in> majorities (V i). (\\<forall> n \\<in> q. promised i n s t) \\<and>\n            (prevAccepted i t q = {}\n                \\<or> (\\<exists> t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t'\n                                        \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\"\nassumes PublishRequest_function:\n  \"\\<And>i t x x'. \\<lbrakk> \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>; \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<rbrakk>\n       \\<Longrightarrow> x = x'\"\nassumes finite_messages:\n  \"finite messages\"\nassumes PublishResponse_PublishRequest:\n  \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists> x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\"\nassumes ApplyCommit_quorum:\n  \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>\n                        \\<Longrightarrow> \\<exists> q \\<in> majorities (V i). \\<forall> s \\<in> q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\"\nassumes CatchUpResponse_committedTo:\n  \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\"\nassumes CatchUpResponse_V:\n  \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> V i = conf\"\nassumes CatchUpResponse_lastCommittedClusterStateBefore:\n  \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\"\n\ndefinition (in zenMessages) votedFor :: \"Node \\<Rightarrow> Node \\<Rightarrow> Term \\<Rightarrow> bool\"\n  where \"votedFor n\\<^sub>1 n\\<^sub>2 t \\<equiv> \\<exists> i. promised i n\\<^sub>1 n\\<^sub>2 t\"\n\nlemma (in zenMessages) votedFor_unique:\n  assumes \"votedFor n n\\<^sub>1 t\"\n  assumes \"votedFor n n\\<^sub>2 t\"\n  shows \"n\\<^sub>1 = n\\<^sub>2\"\n  using assms unfolding votedFor_def by (meson Destination.inject Vote_unique_destination promised_def)\n\nlemma (in zenMessages) V_simps[simp]:\n  \"V 0 = V\\<^sub>0\"\n  \"V (Suc i) = (if isReconfiguration (v\\<^sub>c i) then getConf (v\\<^sub>c i) else V i)\"\n  unfolding V_def by simp_all\n\nlemma (in zenMessages) lastCommittedClusterStateBefore_simps[simp]:\n  \"lastCommittedClusterStateBefore 0 = CS\\<^sub>0\"\n  \"lastCommittedClusterStateBefore (Suc i) = (case v\\<^sub>c i of ClusterStateDiff diff \\<Rightarrow> diff | _ \\<Rightarrow> id) (lastCommittedClusterStateBefore i)\"\n  unfolding lastCommittedClusterStateBefore_def by (simp, cases \"v\\<^sub>c i\", auto)\n\ndeclare [[goals_limit = 40]]\n\nsubsubsection \\<open>Utility lemmas\\<close>\n\ntext \\<open>Some results that are useful later:\\<close>\n\nlemma (in zenMessages) V_finite: \"finite (V i)\"\n  by (induct i, simp_all add: finite_V\\<^sub>0 getConf_finite)\n\nlemma (in zenMessages) V_intersects: \"majorities (V i) \\<frown> majorities (V i)\"\n  using V_finite majorities_intersect by simp\n\nlemma (in zenMessages) ApplyCommit_PublishResponse:\n  assumes \"\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>\"\n  obtains s where \"s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\"\n  by (meson ApplyCommit_quorum majorities_member assms)\n\nlemma (in zenMessages) ApplyCommit_PublishRequest:\n  assumes \"\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>\"\n  shows \"\\<langle> PublishRequest i t (v i t) \\<rangle>\\<leadsto>\"\n  by (metis ApplyCommit_PublishResponse PublishResponse_PublishRequest assms the_equality v_def PublishRequest_function)\n\nlemma (in zenMessages) PublishRequest_Vote:\n  assumes \"s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\"\n  obtains i' n a where \"i' \\<le> i\" \"n \\<midarrow>\\<langle> Vote i' t a \\<rangle>\\<rightarrow> (OneNode s)\"\n  by (meson PublishRequest_quorum majorities_member assms isMessage_def promised_def)\n\nlemma (in zenMessages) finite_prevAccepted: \"finite (prevAccepted i t ns)\"\nproof -\n  fix t\\<^sub>0\n  define f :: \"RoutedMessage \\<Rightarrow> Term\" where \"f \\<equiv> \\<lambda> m. case payload m of Vote _ _ (SomeTerm t') \\<Rightarrow> t' | _ \\<Rightarrow> t\\<^sub>0\"\n  have \"prevAccepted i t ns \\<subseteq> f ` messages\"\n    apply (simp add: prevAccepted_def f_def isMessageFrom_def isMessageFromTo_def, intro subsetI)\n    using image_iff by fastforce\n  with finite_messages show ?thesis using finite_surj by auto\nqed\n\nlemma (in zenMessages) promised_long_def: \"\\<exists>d. promised i s d t\n     \\<equiv> (s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto>\n           \\<or> (\\<exists>i'<i. \\<exists>a. s \\<midarrow>\\<langle> Vote i' t a \\<rangle>\\<leadsto>))\n           \\<or> (\\<exists>t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>)\"\n  (is \"?LHS == ?RHS\")\nproof -\n  have \"?LHS = ?RHS\"\n    apply (intro iffI)\n    apply (metis TermOption.exhaust isMessageFrom_def nat_less_le promised_def)\n    by (metis Destination.exhaust Vote_not_broadcast isMessageFrom_def isMessageTo_def nat_less_le not_le promised_def)\n  thus \"?LHS == ?RHS\" by simp\nqed\n\nlemma (in zenMessages) Vote_value_function:\n  assumes \"s \\<midarrow>\\<langle> Vote i t a\\<^sub>1 \\<rangle>\\<leadsto>\" and \"s \\<midarrow>\\<langle> Vote i t a\\<^sub>2 \\<rangle>\\<leadsto>\"\n  shows \"a\\<^sub>1 = a\\<^sub>2\"\nproof (cases a\\<^sub>1)\n  case NO_TERM\n  with assms show ?thesis\n    by (metis TermOption.exhaust Vote_None Vote_Some_PublishResponse Vote_Some_lt)\nnext\n  case (SomeTerm t\\<^sub>1)\n  with assms obtain t\\<^sub>2 where a\\<^sub>2: \"a\\<^sub>2 = SomeTerm t\\<^sub>2\"\n    using Vote_None Vote_Some_PublishResponse Vote_Some_lt TermOption.exhaust by metis\n\n  from SomeTerm a\\<^sub>2 assms show ?thesis\n    by (metis Vote_Some_PublishResponse Vote_Some_lt less_linear Vote_Some_max)\nqed\n\nlemma (in zenMessages) shows finite_messages_insert: \"finite (insert m messages)\"\n  using finite_messages by auto\n\nlemma (in zenMessages) isCommitted_committedTo:\n  assumes \"isCommitted i\"\n  shows \"committed\\<^sub>< i\"\n  using ApplyCommit_PublishRequest PublishRequest_committedTo assms isCommitted_def by blast\n\nlemma (in zenMessages) isCommitted_committedTo_Suc:\n  assumes \"isCommitted i\"\n  shows \"committed\\<^sub>< (Suc i)\"\n  using assms committedTo_def isCommitted_committedTo less_antisym by blast\n\nlemma (in zenMessages) promised_unique:\n  assumes \"promised i s d t\" and \"promised i' s d' t\"\n  shows \"d = d'\"\n  by (meson Destination.inject Vote_unique_destination assms promised_def)\n\nlemma (in zenMessages) PublishResponse_PublishRequest_v:\n  assumes \"\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\"\n  shows \"\\<langle> PublishRequest i t (v i t) \\<rangle>\\<leadsto>\"\nproof -\n  from assms obtain s where \"s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" unfolding isMessage_def by blast\n  with PublishResponse_PublishRequest\n  obtain x where x: \"\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\" by blast\n  have \"v i t = x\" unfolding v_def using x by (intro the_equality PublishRequest_function)\n  with x show ?thesis by simp\nqed\n\nlemma (in zenMessages) Vote_PublishRequest_v:\n  assumes \"\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>\"\n  shows \"\\<langle> PublishRequest i t' (v i t') \\<rangle>\\<leadsto>\"\n  using assms Vote_Some_PublishResponse PublishResponse_PublishRequest_v\n  unfolding isMessage_def by metis\n\nsubsubsection \\<open>Relationship to @{term oneSlot}\\<close>\n\ntext \\<open>This shows that each slot @{term i} in Zen satisfies the assumptions of the @{term\noneSlot} model above.\\<close>\n\nlemma (in zenMessages) zen_is_oneSlot:\n  fixes i\n  shows \"oneSlot (majorities (V i)) (v i)\n    (\\<lambda> s t. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto>\n        \\<or> (\\<exists> i' < i. \\<exists> a. s \\<midarrow>\\<langle> Vote i' t a \\<rangle>\\<leadsto>))\n    (\\<lambda> s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>)\n    (\\<lambda> t. \\<exists> x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>)\n    (\\<lambda> s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>)\n    (\\<lambda> t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\"\nproof (unfold_locales, fold prevAccepted_def promised_long_def)\n  from V_intersects show \"majorities (V i) \\<frown> majorities (V i)\".\nnext\n  fix s t t'\n  assume \"t' < t\" \"s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<or> (\\<exists>i'<i. \\<exists>a. s \\<midarrow>\\<langle> Vote i' t a \\<rangle>\\<leadsto>)\"\n  thus \"\\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\"\n    using Vote_None Vote_future by auto\nnext\n  fix s t t'\n  assume j: \"s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>\"\n  from j show \"t' < t\" using Vote_Some_lt by blast\n  from j show \"s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\" using Vote_Some_PublishResponse by blast\n\n  fix t'' assume \"t' < t''\" \"t'' < t\"\n  with j show \"\\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\" using Vote_Some_max by blast\nnext\n  fix t\n  assume \"\\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\"\n  then obtain x s where \"s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\" by (auto simp add: isMessage_def)\n  from PublishRequest_quorum [OF this] PublishResponse_PublishRequest\n  show \"\\<exists>q \\<in> majorities (V i). (\\<forall>n\\<in>q. \\<exists>d. promised i n d t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> (\\<exists>x. \\<langle> PublishRequest i t' x \\<rangle>\\<leadsto>) \\<and> t' < t))\"\n    unfolding isMessageFrom_def by (meson PublishResponse_PublishRequest_v)\nnext\n  fix s t assume \"s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\"\n  thus \"\\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\"\n    by (simp add: PublishResponse_PublishRequest)\nnext\n  fix t assume \"\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>\"\n  thus \"\\<exists>q \\<in> majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\"\n    by (simp add: ApplyCommit_quorum)\nnext\n  fix t\\<^sub>0\n  define f :: \"RoutedMessage \\<Rightarrow> Term\"\n    where \"f \\<equiv> \\<lambda> m. case payload m of PublishRequest i t x \\<Rightarrow> t | _ \\<Rightarrow> t\\<^sub>0\"\n\n  have \"{t. \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>} \\<subseteq> f ` messages\"\n    apply (unfold isMessage_def isMessageFrom_def isMessageFromTo_def)\n    using f_def image_iff by fastforce\n\n  moreover have \"finite (f ` messages)\"\n    by (simp add: finite_messages)\n\n  ultimately show \"finite {t. \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>}\"\n    using finite_subset by blast\nqed\n\ntext \\<open>From this it follows that all committed values are equal.\\<close>\n\ntheorem (in zenMessages) consistent:\n  assumes \"\\<langle> ApplyCommit  i t\\<^sub>1 \\<rangle>\\<leadsto>\"\n  assumes \"\\<langle> ApplyCommit  i t\\<^sub>2 \\<rangle>\\<leadsto>\"\n  assumes \"\\<langle> PublishRequest i t\\<^sub>1 v\\<^sub>1 \\<rangle>\\<leadsto>\"\n  assumes \"\\<langle> PublishRequest i t\\<^sub>2 v\\<^sub>2 \\<rangle>\\<leadsto>\"\n  shows \"v\\<^sub>1 = v\\<^sub>2\"\nproof -\n  from oneSlot.consistent [OF zen_is_oneSlot] assms\n  have \"v i t\\<^sub>1 = v i t\\<^sub>2\" by blast\n  moreover have \"v\\<^sub>1 = v i t\\<^sub>1\" using ApplyCommit_PublishRequest assms PublishRequest_function by blast\n  moreover have \"v\\<^sub>2 = v i t\\<^sub>2\" using ApplyCommit_PublishRequest assms PublishRequest_function by blast\n  ultimately show ?thesis by simp\nqed\n\nlemma (in zenMessages) ApplyCommit_v\\<^sub>c:\n  assumes \"\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>\"\n  shows \"v\\<^sub>c i = v i t\"\nproof (unfold v\\<^sub>c_def, intro someI2 [where Q = \"\\<lambda>t'. v i t' = v i t\"])\n  from assms show \"\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>\" .\n  fix t' assume \"\\<langle> ApplyCommit i t' \\<rangle>\\<leadsto>\"\n  thus \"v i t' = v i t\" by (intro oneSlot.consistent [OF zen_is_oneSlot] assms)\nqed\n\nlemma (in zenMessages) ApplyCommit_PublishRequest_v\\<^sub>c:\n  assumes \"\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>\"\n  shows \"\\<langle> PublishRequest i t (v\\<^sub>c i) \\<rangle>\\<leadsto>\"\n  unfolding ApplyCommit_v\\<^sub>c [OF assms]\n  using ApplyCommit_PublishRequest assms .\n\nsubsection \\<open>Invariants on node states\\<close>\n\ntext \\<open>A set of invariants which relate the states of the individual nodes to the set of messages sent.\\<close>\n\nlocale zen = zenMessages +\n  fixes nodeState :: \"Node \\<Rightarrow> NodeData\"\n  assumes currentNode_nodeState: \"\\<And>n. currentNode (nodeState n) = n\"\n  assumes committedTo_firstUncommittedSlot:\n    \"\\<And>n. committed\\<^sub>< (firstUncommittedSlot (nodeState n))\"\n  assumes currentVotingNodes_firstUncommittedSlot:\n    \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))\"\n  assumes firstUncommittedSlot_PublishRequest:\n    \"\\<And>i n t x. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\"\n  assumes firstUncommittedSlot_PublishResponse:\n    \"\\<And>i n t. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\"\n  assumes lastAcceptedTerm_None: \"\\<And>n t. lastAcceptedTerm (nodeState n) = NO_TERM\n    \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\"\n  assumes lastAcceptedTerm_Some_sent: \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t\n    \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\"\n  assumes lastAcceptedTerm_Some_max: \"\\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t\n    \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \\<rangle>\\<leadsto>\n    \\<Longrightarrow> t' \\<le> t\"\n  assumes lastAcceptedTerm_Some_currentTerm: \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t\n    \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\"\n  assumes lastAcceptedTerm_Some_value: \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t\n    \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \\<rangle>\\<leadsto>\"\n  assumes Vote_currentTerm:\n    \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\"\n  assumes Vote_slot_function:\n    \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\"\n  assumes PublishRequest_currentTerm:\n    \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto>\n        \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\"\n  assumes PublishRequest_publishPermitted_currentTerm:\n    \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto>\n        \\<Longrightarrow> publishPermitted (nodeState n)\n        \\<Longrightarrow> t < currentTerm (nodeState n)\"\n  assumes joinVotes:\n    \"\\<And> n n'. n' \\<in> joinVotes (nodeState n)\n      \\<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))\"\n  assumes electionWon_isQuorum:\n    \"\\<And>n. electionWon (nodeState n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))\"\n  assumes joinVotes_max: \"\\<And>n n' a'.\n    \\<lbrakk> \\<not> (\\<exists> x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n))\n                               (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>);\n      n' \\<in> joinVotes (nodeState n);\n      n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n))\n                                (currentTerm (nodeState n))\n                                a' \\<rangle>\\<rightarrow> (OneNode n) \\<rbrakk>\n    \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState n)\"\n  assumes publishVotes: \"\\<And>n n'. n' \\<in> publishVotes (nodeState n)\n    \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n))\n                              (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\"\n  assumes currentClusterState_lastCommittedClusterStateBefore:\n    \"\\<And>n. currentClusterState (nodeState n)\n              = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\"\n\nlemma (in zen) joinVotes_votedFor:\n  assumes \"n' \\<in> joinVotes (nodeState n)\"\n  shows \"votedFor n' n (currentTerm (nodeState n))\"\n  using joinVotes assms unfolding votedFor_def by auto\n\nlocale zenStep = zen +\n  fixes messages' :: \"RoutedMessage set\"\n  fixes nodeState' :: \"Node \\<Rightarrow> NodeData\"\n  fixes n\\<^sub>0 :: Node\n\nassumes messages_subset: \"messages \\<subseteq> messages'\"\nfixes nd :: NodeData\ndefines \"nd \\<equiv> nodeState n\\<^sub>0\"\nfixes nd' :: NodeData\ndefines \"nd' \\<equiv> nodeState' n\\<^sub>0\"\nassumes nodeState_unchanged: \"\\<And>n. n \\<noteq> n\\<^sub>0 \\<Longrightarrow> nodeState' n = nodeState n\"\n  (* updated definitions from zenMessages *)\nfixes isMessageFromTo' :: \"Node \\<Rightarrow> Message \\<Rightarrow> Destination \\<Rightarrow> bool\" (\"(_) \\<midarrow>\\<langle> _ \\<rangle>\\<rightarrow>' (_)\" [1000,55,1000])\ndefines \"s \\<midarrow>\\<langle> m \\<rangle>\\<rightarrow>' d \\<equiv> \\<lparr> sender = s, destination = d, payload = m \\<rparr> \\<in> messages'\"\nfixes isMessageFrom' :: \"Node \\<Rightarrow> Message \\<Rightarrow> bool\" (\"(_) \\<midarrow>\\<langle> _ \\<rangle>\\<leadsto>'\" [1000,55])\ndefines \"s \\<midarrow>\\<langle> m \\<rangle>\\<leadsto>' \\<equiv> \\<exists> d. s \\<midarrow>\\<langle> m \\<rangle>\\<rightarrow>' d\"\nfixes isMessageTo' :: \"Message \\<Rightarrow> Destination \\<Rightarrow> bool\" (\"\\<langle> _ \\<rangle>\\<rightarrow>' (_)\" [55,1000])\ndefines \"\\<langle> m \\<rangle>\\<rightarrow>' d \\<equiv> \\<exists> s. s \\<midarrow>\\<langle> m \\<rangle>\\<rightarrow>' d\"\nfixes isMessage' :: \"Message \\<Rightarrow> bool\" (\"\\<langle> _ \\<rangle>\\<leadsto>'\" [55])\ndefines \"\\<langle> m \\<rangle>\\<leadsto>' \\<equiv> \\<exists> s. s \\<midarrow>\\<langle> m \\<rangle>\\<leadsto>'\"\n  (* value proposed in a slot & a term *)\nfixes v' :: \"nat \\<Rightarrow> Term \\<Rightarrow> Value\"\ndefines \"v' i t \\<equiv> THE x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>'\"\n  (* whether a slot is committed *)\nfixes isCommitted' :: \"nat \\<Rightarrow> bool\"\ndefines \"isCommitted' i \\<equiv> \\<exists> t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>'\"\n  (* whether all preceding slots are committed *)\nfixes committedTo' :: \"nat \\<Rightarrow> bool\" (\"committed\\<^sub><'\")\ndefines \"committed\\<^sub><' i \\<equiv> \\<forall> j < i. isCommitted' j\"\n  (* the committed value in a slot *)\nfixes v\\<^sub>c' :: \"nat \\<Rightarrow> Value\"\ndefines \"v\\<^sub>c' i \\<equiv> v' i (SOME t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>')\"\n  (* the configuration of a slot *)\nfixes V' :: \"Slot \\<Rightarrow> Node set\"\ndefines \"V' \\<equiv> nat_inductive_def V\\<^sub>0 (\\<lambda>i Vi. if isReconfiguration (v\\<^sub>c' i) then getConf (v\\<^sub>c' i) else Vi)\"\n  (* predicate to say whether an applicable Vote has been sent *)\nfixes promised' :: \"nat \\<Rightarrow> Node \\<Rightarrow> Node \\<Rightarrow> Term \\<Rightarrow> bool\"\ndefines \"promised' i s dn t \\<equiv> \\<exists> i' \\<le> i. \\<exists> a. s \\<midarrow>\\<langle> Vote i' t a \\<rangle>\\<rightarrow>' (OneNode dn)\"\n  (* set of previously-accepted terms *)\nfixes prevAccepted' :: \"nat \\<Rightarrow> Term \\<Rightarrow> Node set \\<Rightarrow> Term set\"\ndefines \"prevAccepted' i t senders\n      \\<equiv> {t'. \\<exists> s \\<in> senders. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>' }\"\nfixes lastCommittedClusterStateBefore' :: \"nat \\<Rightarrow> ClusterState\"\ndefines \"lastCommittedClusterStateBefore' \\<equiv> nat_inductive_def CS\\<^sub>0\n      (\\<lambda>i CSi. case v\\<^sub>c' i of ClusterStateDiff diff \\<Rightarrow> diff CSi | _ \\<Rightarrow> CSi)\"\nfixes sendTo :: \"Destination \\<Rightarrow> (NodeData * Message option) \\<Rightarrow> RoutedMessage set\"\ndefines \"sendTo d result \\<equiv> case snd result of\n    None \\<Rightarrow> messages | Some m \\<Rightarrow> insert \\<lparr> sender = n\\<^sub>0, destination = d, payload = m \\<rparr> messages\"\n\nlemma (in zenStep) nodeState'_def: \"nodeState' n \\<equiv> if n = n\\<^sub>0 then nd' else nodeState n\"\n  using nodeState_unchanged nd'_def by presburger\n\nlemma (in zenStep) V'_simps[simp]:\n  \"V' 0 = V\\<^sub>0\"\n  \"V' (Suc i) = (if isReconfiguration (v\\<^sub>c' i) then getConf (v\\<^sub>c' i) else V' i)\"\n  unfolding V'_def by simp_all\n\nlemma (in zenStep) lastCommittedClusterStateBefore'_simps[simp]:\n  \"lastCommittedClusterStateBefore' 0 = CS\\<^sub>0\"\n  \"lastCommittedClusterStateBefore' (Suc i) = (case v\\<^sub>c' i of ClusterStateDiff diff \\<Rightarrow> diff | _ \\<Rightarrow> id) (lastCommittedClusterStateBefore' i)\"\n  unfolding lastCommittedClusterStateBefore'_def by (simp, cases \"v\\<^sub>c' i\", auto)\n\nlemma (in zenStep) sendTo_simps[simp]:\n  \"sendTo d (nd'', None) = messages\"\n  \"sendTo d (nd'', Some m) = insert \\<lparr> sender = n\\<^sub>0, destination = d, payload = m \\<rparr> messages\"\n  by (auto simp add: sendTo_def)\n\nlemma currentTerm_ensureCurrentTerm[simp]: \"currentTerm nd \\<le> t \\<Longrightarrow> currentTerm (ensureCurrentTerm t nd) = t\"\n  by (auto simp add: ensureCurrentTerm_def)\n\nlemma (in zenStep)\n  assumes \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>' \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>'\"\n  assumes \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto>' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>'\"\n  assumes \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>' \\<Longrightarrow> t' < t\"\n  assumes \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>' \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>'\"\n  assumes \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>' \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>'\"\n  assumes \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow>' d \\<Longrightarrow> d \\<noteq> Broadcast\"\n  assumes \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow>' d' \\<Longrightarrow> d = d'\"\n  assumes \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>' \\<Longrightarrow> committed\\<^sub><' i\"\n  assumes \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>' \\<Longrightarrow> \\<exists>q\\<in>majorities (V' i). (\\<forall>n\\<in>q. promised' i n s t) \\<and> (prevAccepted' i t q = {} \\<or> (\\<exists>t'. v' i t = v' i t' \\<and> maxTerm (prevAccepted' i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto>' \\<and> t' < t))\"\n  assumes \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>' \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto>' \\<Longrightarrow> x = x'\"\n  assumes \"finite messages'\"\n  assumes \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>' \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>'\"\n  assumes \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>' \\<Longrightarrow> \\<exists>q\\<in>majorities (V' i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>'\"\n  assumes \"\\<And>n. currentNode (nodeState' n) = n\"\n  assumes \"\\<And>n. committed\\<^sub><' (firstUncommittedSlot (nodeState' n))\"\n  assumes \"\\<And>n. currentVotingNodes (nodeState' n) = V' (firstUncommittedSlot (nodeState' n))\"\n  assumes \"\\<And>i n t x. firstUncommittedSlot (nodeState' n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>'\"\n  assumes \"\\<And>i n t. firstUncommittedSlot (nodeState' n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>'\"\n  assumes \"\\<And>n t. lastAcceptedTerm (nodeState' n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \\<rangle>\\<leadsto>'\"\n  assumes \"\\<And>n t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \\<rangle>\\<leadsto>'\"\n  assumes \"\\<And>n t t'. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t' \\<rangle>\\<leadsto>' \\<Longrightarrow> t' \\<le> t\"\n  assumes \"\\<And>n t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t (lastAcceptedValue (nodeState' n)) \\<rangle>\\<leadsto>'\"\n  assumes \"\\<And>n t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState' n)\"\n  assumes \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>' \\<Longrightarrow> t \\<le> currentTerm (nodeState' n)\"\n  assumes \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>' \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto>' \\<Longrightarrow> i = i'\"\n  assumes \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \\<rangle>\\<leadsto>' \\<Longrightarrow> t \\<le> currentTerm (nodeState' n)\"\n  assumes \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \\<rangle>\\<leadsto>' \\<Longrightarrow> publishPermitted (nodeState' n) \\<Longrightarrow> t < currentTerm (nodeState' n)\"\n  assumes \"\\<And>n n'. n' \\<in> joinVotes (nodeState' n) \\<Longrightarrow> promised' (firstUncommittedSlot (nodeState' n)) n' n (currentTerm (nodeState' n))\"\n  assumes \"\\<And>n. electionWon (nodeState' n) \\<Longrightarrow> isQuorum (nodeState' n) (joinVotes (nodeState' n))\"\n  assumes \"\\<And>n n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState' n)) x \\<rangle>\\<leadsto>') \\<Longrightarrow> n' \\<in> joinVotes (nodeState' n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState' n)) a' \\<rangle>\\<rightarrow>' (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState' n)\"\n  assumes \"\\<And>n n'. n' \\<in> publishVotes (nodeState' n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState' n)) \\<rangle>\\<leadsto>'\"\n  assumes \"\\<And>n. currentClusterState (nodeState' n) = lastCommittedClusterStateBefore' (firstUncommittedSlot (nodeState' n))\"\n  assumes \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>' \\<Longrightarrow> committed\\<^sub><' i\"\n  assumes \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>' \\<Longrightarrow> V' i = conf\"\n  assumes \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>' \\<Longrightarrow> lastCommittedClusterStateBefore' i = cs\"\n  shows zenI: \"zen messages' nodeState'\"\n  apply (unfold_locales)\n                      apply (fold isMessageFromTo'_def)\n                      apply (fold isMessageTo'_def)\n                      apply (fold isMessageFrom'_def)\n                      apply (fold isMessage'_def)\n                      apply (fold v'_def)\n                      apply (fold isCommitted'_def)\n                      apply (fold committedTo'_def)\n                      apply (fold v\\<^sub>c'_def)\n                      apply (fold V'_def)\n                      apply (fold promised'_def)\n                      apply (fold prevAccepted'_def)\n                      apply (fold lastCommittedClusterStateBefore'_def)\n  using assms proof - qed\n\nlemma (in zenStep)\n  assumes \"zen messages' nodeState'\" \"messages' \\<subseteq> messages''\" \"\\<And>n. n \\<noteq> n\\<^sub>0 \\<Longrightarrow> nodeState' n = nodeState'' n\"\n  shows zenStepI1: \"zenStep messages' nodeState' messages'' nodeState'' n\\<^sub>0\"\nproof (intro_locales)\n  from `zen messages' nodeState'`\n  show \"zenMessages messages'\" \"zen_axioms messages' nodeState'\"\n    unfolding zen_def by simp_all\n\n  from assms\n  show \"zenStep_axioms messages' nodeState' messages'' nodeState'' n\\<^sub>0\"\n    by (intro zenStep_axioms.intro, auto)\nqed\n\nlemma (in zenStep)\n  assumes \"messages \\<subseteq> messages''\" \"\\<And>n. n \\<noteq> n\\<^sub>0 \\<Longrightarrow> nodeState n = nodeState'' n\"\n  shows zenStepI2: \"zenStep messages nodeState messages'' nodeState'' n\\<^sub>0\"\nproof (intro_locales)\n  from assms\n  show \"zenStep_axioms messages nodeState messages'' nodeState'' n\\<^sub>0\"\n    by (intro zenStep_axioms.intro, auto)\nqed\n\nlemma (in zenStep) Broadcast_to_OneNode:\n  fixes x\n  assumes nodeState': \"nodeState' = nodeState\"\n  assumes sent: \"n\\<^sub>0 \\<midarrow>\\<langle> m \\<rangle>\\<rightarrow> Broadcast\"\n  assumes messages': \"messages' = sendTo (OneNode d) (nd'', Some m)\"\n  shows \"zen messages' nodeState'\"\nproof -\n  have messages': \"messages' = insert \\<lparr>sender = n\\<^sub>0, destination = OneNode d, payload = m \\<rparr> messages\"\n    by (simp add: messages')\n\n  from Vote_not_broadcast sent have not_Vote: \"\\<And>i t a. m \\<noteq> Vote i t a\"\n    unfolding isMessageTo_def by blast\n\n  from sent not_Vote have message_simps:\n    \"\\<And>s m'. (s \\<midarrow>\\<langle> m' \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> m' \\<rangle>\\<leadsto>)\"\n    \"\\<And>m'. (\\<langle> m' \\<rangle>\\<leadsto>') = (\\<langle> m' \\<rangle>\\<leadsto>)\"\n    \"\\<And>s d i t a. (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t a. (\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d) = (\\<langle> Vote i t a \\<rangle>\\<rightarrow> d)\"\n    by (auto simp add: isMessageFromTo'_def isMessageTo'_def isMessage'_def isMessageFrom'_def,\n        auto simp add: isMessageFromTo_def isMessageTo_def isMessage_def isMessageFrom_def messages')\n\n  have property_simps[simp]:\n    \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\"\n    \"\\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)\"\n    \"\\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)\"\n    \"\\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q\"\n    \"\\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)\"\n    \"\\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)\"\n    \"\\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)\"\n    \"\\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)\"\n    \"\\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)\"\n    \"\\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)\"\n    \"\\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)\"\n    \"\\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)\"\n    by (unfold nodeState', auto)\n\n  have v_eq[simp]: \"v' = v\" by (intro ext, auto simp add: v'_def v_def message_simps)\n  have v\\<^sub>c_eq[simp]: \"v\\<^sub>c' = v\\<^sub>c\" by (intro ext, auto simp add: v\\<^sub>c'_def v\\<^sub>c_def message_simps)\n  have isCommitted_eq[simp]: \"isCommitted' = isCommitted\" by (intro ext, auto simp add: isCommitted'_def isCommitted_def message_simps)\n  have committedTo_eq[simp]: \"committed\\<^sub><' = committed\\<^sub><\" by (intro ext, auto simp add: committedTo'_def committedTo_def)\n  have V_eq[simp]: \"V' = V\" using v\\<^sub>c_eq V'_def V_def by blast\n  have lastCommittedClusterStateBefore_eq[simp]: \"lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore\"\n    unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\\<^sub>c_eq ..\n  have promised_eq[simp]: \"promised' = promised\" by (intro ext, auto simp add: promised'_def promised_def message_simps)\n  have prevAccepted_eq[simp]: \"prevAccepted' = prevAccepted\" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def message_simps)\n\n  show ?thesis\n    apply (intro zenI)\n                        apply (unfold message_simps committedTo_eq V_eq v_eq\n        lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)\n  proof -\n    from finite_messages show \"finite messages'\" by (simp add: messages')\n    from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\".\n    from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n    from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\".\n    from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n    from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n    from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n    from committedTo_firstUncommittedSlot show \"\\<And>n. committed\\<^sub>< (firstUncommittedSlot (nodeState n))\" .\n    from firstUncommittedSlot_PublishResponse show \"\\<And>n i t. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" .\n    from lastAcceptedTerm_None show \"\\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_sent show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_max show \"\\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\".\n    from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n    from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))\".\n    from joinVotes_max show \" \\<And>n n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>) \\<Longrightarrow> n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow> (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState n)\".\n    from publishVotes show \"\\<And>n n'. n' \\<in> publishVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\".\n    from currentClusterState_lastCommittedClusterStateBefore show \"\\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\".\n    from joinVotes show \"\\<And>n n'. n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))\".\n    from PublishRequest_committedTo show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from PublishRequest_quorum show \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\".\n    from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n    from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from ApplyCommit_quorum show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\".\n    from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))\".\n    from firstUncommittedSlot_PublishRequest show \"\\<And>i n t x. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_value show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \\<rangle>\\<leadsto>\".\n    from PublishRequest_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from PublishRequest_publishPermitted_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState n) \\<Longrightarrow> t < currentTerm (nodeState n)\".\n    from CatchUpResponse_committedTo show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from CatchUpResponse_V show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> V i = conf\".\n    from CatchUpResponse_lastCommittedClusterStateBefore show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\".\n    from lastAcceptedTerm_Some_currentTerm show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n  qed\nqed\n\nlemma (in zenStep) send_spontaneous_message:\n  assumes messages': \"messages' = sendTo d\\<^sub>0 (nd, Some m)\"\n  assumes spontaneous: \"case m of StartJoin _ \\<Rightarrow> True | ClientValue _ \\<Rightarrow> True | Reboot \\<Rightarrow> True | CatchUpRequest \\<Rightarrow> True | _ \\<Rightarrow> False\"\n  assumes nodeState': \"nodeState' = nodeState\"\n  shows \"zen messages' nodeState'\"\nproof -\n  have messages': \"messages' = insert \\<lparr>sender = n\\<^sub>0, destination = d\\<^sub>0, payload = m \\<rparr> messages\"\n    by (simp add: messages')\n\n  from spontaneous\n  have message_simps[simp]:\n    \"\\<And>s d i t a. (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t. (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t x. (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t. (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t a. (\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d) = (\\<langle> Vote i t a \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t. (\\<langle> PublishResponse i t \\<rangle>\\<rightarrow>' d) = (\\<langle> PublishResponse i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t x. (\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow>' d) = (\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t. (\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow>' d) = (\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s i t a. (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t. (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t x. (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t. (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>d i t a. (\\<langle> Vote i t a \\<rangle>\\<leadsto>') = (\\<langle> Vote i t a \\<rangle>\\<leadsto>)\"\n    \"\\<And>d i t. (\\<langle> PublishResponse i t \\<rangle>\\<leadsto>') = (\\<langle> PublishResponse i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>d i t x. (\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>') = (\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>)\"\n    \"\\<And>d i t. (\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') = (\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>s d i conf cs. (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i conf cs. (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow>' d) = (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s i conf cs. (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>)\"\n    \"\\<And>d i conf cs. (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>') = (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>)\"\n    by (auto simp add: isMessageFromTo'_def isMessageTo'_def isMessage'_def isMessageFrom'_def,\n        auto simp add: isMessageFromTo_def isMessageTo_def isMessage_def isMessageFrom_def messages')\n\n  have property_simps[simp]:\n    \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\"\n    \"\\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)\"\n    \"\\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)\"\n    \"\\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q\"\n    \"\\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)\"\n    \"\\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)\"\n    \"\\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)\"\n    \"\\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)\"\n    \"\\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)\"\n    \"\\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)\"\n    \"\\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)\"\n    \"\\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)\"\n    by (unfold nodeState', auto)\n\n  have v_eq[simp]: \"v' = v\" by (intro ext, auto simp add: v'_def v_def)\n  have v\\<^sub>c_eq[simp]: \"v\\<^sub>c' = v\\<^sub>c\" by (intro ext, auto simp add: v\\<^sub>c'_def v\\<^sub>c_def)\n  have isCommitted_eq[simp]: \"isCommitted' = isCommitted\" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)\n  have committedTo_eq[simp]: \"committed\\<^sub><' = committed\\<^sub><\" by (intro ext, auto simp add: committedTo'_def committedTo_def)\n  have V_eq[simp]: \"V' = V\" using v\\<^sub>c_eq V'_def V_def by blast\n  have lastCommittedClusterStateBefore_eq[simp]: \"lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore\"\n    unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\\<^sub>c_eq ..\n  have promised_eq[simp]: \"promised' = promised\" by (intro ext, auto simp add: promised'_def promised_def)\n  have prevAccepted_eq[simp]: \"prevAccepted' = prevAccepted\" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)\n\n  show ?thesis\n    apply (intro zenI)\n                        apply (unfold message_simps committedTo_eq V_eq v_eq\n        lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)\n  proof -\n    from finite_messages show \"finite messages'\" by (simp add: messages')\n    from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\".\n    from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n    from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\".\n    from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n    from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n    from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n    from committedTo_firstUncommittedSlot show \"\\<And>n. committed\\<^sub>< (firstUncommittedSlot (nodeState n))\" .\n    from firstUncommittedSlot_PublishResponse show \"\\<And>n i t. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" .\n    from lastAcceptedTerm_None show \"\\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_sent show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_max show \"\\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\".\n    from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n    from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))\".\n    from joinVotes_max show \" \\<And>n n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>) \\<Longrightarrow> n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow> (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState n)\".\n    from publishVotes show \"\\<And>n n'. n' \\<in> publishVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\".\n    from currentClusterState_lastCommittedClusterStateBefore show \"\\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\".\n    from joinVotes show \"\\<And>n n'. n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))\".\n    from PublishRequest_committedTo show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from PublishRequest_quorum show \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\".\n    from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n    from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from ApplyCommit_quorum show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\".\n    from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))\".\n    from firstUncommittedSlot_PublishRequest show \"\\<And>i n t x. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_value show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \\<rangle>\\<leadsto>\".\n    from PublishRequest_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from PublishRequest_publishPermitted_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState n) \\<Longrightarrow> t < currentTerm (nodeState n)\".\n    from CatchUpResponse_committedTo show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from CatchUpResponse_V show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> V i = conf\".\n    from CatchUpResponse_lastCommittedClusterStateBefore show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\".\n    from lastAcceptedTerm_Some_currentTerm show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n  qed\nqed\n\nlemma (in zenStep) send_StartJoin:\n  assumes messages': \"messages' = sendTo d\\<^sub>0 (nd, Some (StartJoin t\\<^sub>0))\"\n  assumes nodeState': \"nodeState' = nodeState\"\n  shows \"zen messages' nodeState'\"\n  using assms by (intro send_spontaneous_message, auto)\n\nlemma (in zenStep) send_ClientValue:\n  assumes messages': \"messages' = sendTo d\\<^sub>0 (nd, Some (ClientValue x\\<^sub>0))\"\n  assumes nodeState': \"nodeState' = nodeState\"\n  shows \"zen messages' nodeState'\"\n  using assms by (intro send_spontaneous_message, auto)\n\nlemma (in zenStep) send_CatchUpRequest:\n  assumes messages': \"messages' = sendTo d\\<^sub>0 (nd, Some CatchUpRequest)\"\n  assumes nodeState': \"nodeState' = nodeState\"\n  shows \"zen messages' nodeState'\"\n  using assms by (intro send_spontaneous_message, auto)\n\nlemma (in zenStep) send_Reboot:\n  assumes messages': \"messages' = sendTo d\\<^sub>0 (nd, Some Reboot)\"\n  assumes nodeState': \"nodeState' = nodeState\"\n  shows \"zen messages' nodeState'\"\n  using assms by (intro send_spontaneous_message, auto)\n\nlemma (in zenStep) ensureCurrentTerm_invariants:\n  assumes nd': \"nd' = ensureCurrentTerm t nd\"\n  assumes messages': \"messages' = messages\"\n  shows \"zen messages' nodeState'\"\nproof (cases \"t \\<le> currentTerm nd\")\n  case True\n  hence \"nodeState' = nodeState\"\n    by (intro ext, unfold nodeState'_def, auto simp add: nd' ensureCurrentTerm_def nd_def)\n  with zen_axioms messages' show ?thesis by simp\nnext\n  case False hence t: \"currentTerm nd < t\" by simp\n\n  have message_simps[simp]:\n    \"\\<And>s p d. (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>p d. (\\<langle> p \\<rangle>\\<rightarrow>' d) = (\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s p. (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>)\"\n    \"\\<And>p. (\\<langle> p \\<rangle>\\<leadsto>') = (\\<langle> p \\<rangle>\\<leadsto>)\"\n    by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,\n        auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)\n\n  have property_simps[simp]:\n    \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\"\n    \"\\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)\"\n    \"\\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)\"\n    \"\\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)\"\n    \"\\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q\"\n    \"\\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)\"\n    \"\\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)\"\n    \"currentTerm (nodeState' n\\<^sub>0) = t\"\n    \"electionWon (nodeState' n\\<^sub>0) = False\"\n    \"joinVotes (nodeState' n\\<^sub>0) = {}\"\n    \"publishPermitted (nodeState' n\\<^sub>0) = True\"\n    \"publishVotes (nodeState' n\\<^sub>0) = {}\"\n    using t\n    by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' ensureCurrentTerm_def\n        lastAcceptedTerm_def lastAcceptedValue_def)\n\n  have currentTerm_increases: \"\\<And>n. currentTerm (nodeState n) \\<le> currentTerm (nodeState' n)\"\n    using nd_def nodeState'_def property_simps t by auto\n\n  have v_eq[simp]: \"v' = v\" by (intro ext, auto simp add: v'_def v_def)\n  have v\\<^sub>c_eq[simp]: \"v\\<^sub>c' = v\\<^sub>c\" by (intro ext, auto simp add: v\\<^sub>c'_def v\\<^sub>c_def)\n  have isCommitted_eq[simp]: \"isCommitted' = isCommitted\" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)\n  have committedTo_eq[simp]: \"committed\\<^sub><' = committed\\<^sub><\" by (intro ext, auto simp add: committedTo'_def committedTo_def)\n  have V_eq[simp]: \"V' = V\" using v\\<^sub>c_eq V'_def V_def by blast\n  have lastCommittedClusterStateBefore_eq[simp]: \"lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore\"\n    unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\\<^sub>c_eq ..\n  have promised_eq: \"\\<And>i n n' t. promised' i n n' t = promised i n n' t\" by (simp add: promised_def promised'_def)\n  have prevAccepted_eq: \"\\<And>i t q. prevAccepted' i t q  = prevAccepted i t q\" by (simp add: prevAccepted_def prevAccepted'_def)\n\n  show ?thesis\n    apply (intro zenI)\n                        apply (unfold message_simps committedTo_eq V_eq v_eq\n        lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)\n  proof -\n    from finite_messages show \"finite messages'\" by (simp add: messages')\n    from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\".\n    from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n    from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\".\n    from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n    from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n    from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n    from committedTo_firstUncommittedSlot show \"\\<And>n. committed\\<^sub>< (firstUncommittedSlot (nodeState n))\" .\n    from firstUncommittedSlot_PublishResponse show \"\\<And>n i t. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" .\n    from lastAcceptedTerm_None show \"\\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_sent show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_max show \"\\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\".\n    from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n    from currentClusterState_lastCommittedClusterStateBefore show \"\\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\".\n    from PublishRequest_committedTo show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n    from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from ApplyCommit_quorum show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\".\n    from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))\".\n    from firstUncommittedSlot_PublishRequest show \"\\<And>i n t x. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_value show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \\<rangle>\\<leadsto>\".\n    from PublishRequest_quorum show \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\".\n    from CatchUpResponse_committedTo show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from CatchUpResponse_V show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> V i = conf\".\n    from CatchUpResponse_lastCommittedClusterStateBefore show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\".\n\n    from Vote_currentTerm currentTerm_increases\n    show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState' n)\"\n      using dual_order.trans by blast\n\n    from PublishRequest_publishPermitted_currentTerm currentTerm_increases property_simps\n    show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState' n) \\<Longrightarrow> t < currentTerm (nodeState' n)\"\n      by (metis False PublishRequest_currentTerm dual_order.trans leI nd_def nodeState_unchanged)\n\n    from joinVotes\n    show \"\\<And>n n'. n' \\<in> joinVotes (nodeState' n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState' n))\"\n      unfolding nodeState'_def by (auto simp add: nd'_def)\n\n    from PublishRequest_currentTerm currentTerm_increases\n    show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState' n)\"\n      using dual_order.trans by blast\n\n    from publishVotes\n    show \"\\<And>n n'. n' \\<in> publishVotes (nodeState' n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState' n)) \\<rangle>\\<leadsto>\"\n      unfolding nodeState'_def by (auto simp add: nd'_def)\n\n    from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState' n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState' n))\"\n      unfolding nodeState'_def by (auto simp add: nd'_def)\n\n    from lastAcceptedTerm_Some_currentTerm currentTerm_increases\n    show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState' n)\"\n      using dual_order.trans by blast\n\n    show \"\\<And>n n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState' n)) x \\<rangle>\\<leadsto>) \\<Longrightarrow> n' \\<in> joinVotes (nodeState' n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState' n)) a' \\<rangle>\\<rightarrow> (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState n)\"\n      by (metis ex_in_conv joinVotes_max nodeState_unchanged property_simps(10))\n  qed\nqed\n\nlemma (in zenStep) sendVote_invariants:\n  assumes messages': \"messages' = sendTo (OneNode d\\<^sub>0) (nd'',\n    Some (Vote (firstUncommittedSlot nd) (currentTerm nd) (lastAcceptedTerm nd)))\"\n  assumes nd': \"nd' = nd\"\n  assumes not_sent: \"\\<And>i a. \\<not> n\\<^sub>0 \\<midarrow>\\<langle> Vote i (currentTerm nd) a \\<rangle>\\<leadsto>\"\n  assumes not_accepted: \"\\<And>t'. lastAcceptedTerm nd = SomeTerm t' \\<Longrightarrow> t' < currentTerm nd\"\n  shows \"zen messages' nodeState'\"\nproof -\n  have messages': \"messages' = insert \\<lparr>sender = n\\<^sub>0, destination = OneNode d\\<^sub>0,\n                       payload = Vote (firstUncommittedSlot nd) (currentTerm nd) (lastAcceptedTerm nd)\\<rparr> messages\"\n    by (simp add: messages')\n\n  have nodeState'[simp]: \"nodeState' = nodeState\"\n    by (intro ext, auto simp add: nodeState'_def nd' nd_def)\n\n  have message_simps[simp]:\n    \"\\<And>s d i t. (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t x. (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t. (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t. (\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow>' d) = (\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t x. (\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow>' d) = (\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t. (\\<langle> PublishResponse i t \\<rangle>\\<rightarrow>' d) = (\\<langle> PublishResponse i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s i t. (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t x. (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t. (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>i t. (\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') = (\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>i t x. (\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>') = (\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>)\"\n    \"\\<And>i t. (\\<langle> PublishResponse i t \\<rangle>\\<leadsto>') = (\\<langle> PublishResponse i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>s d i conf cs. (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i conf cs. (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow>' d) = (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s i conf cs. (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>)\"\n    \"\\<And>d i conf cs. (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>') = (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>)\"\n    by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,\n        auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)\n\n  have Vote':\n    \"\\<And>s d i t' a. (s \\<midarrow>\\<langle> Vote i t' a \\<rangle>\\<rightarrow>' d) =\n    ((s \\<midarrow>\\<langle> Vote i t' a \\<rangle>\\<rightarrow> d)\n      \\<or> (s, i, t', a, d) = (n\\<^sub>0, firstUncommittedSlot nd, currentTerm nd, lastAcceptedTerm nd, OneNode d\\<^sub>0))\"\n    \"\\<And>d i t' a. (\\<langle> Vote i t' a \\<rangle>\\<rightarrow>' d) =\n    ((\\<langle> Vote i t' a \\<rangle>\\<rightarrow> d)\n      \\<or> (i, t', a, d) = (firstUncommittedSlot nd, currentTerm nd, lastAcceptedTerm nd, OneNode d\\<^sub>0))\"\n    \"\\<And>s i t' a. (s \\<midarrow>\\<langle> Vote i t' a \\<rangle>\\<leadsto>') =\n    ((s \\<midarrow>\\<langle> Vote i t' a \\<rangle>\\<leadsto>)\n      \\<or> (s, i, t', a) = (n\\<^sub>0, firstUncommittedSlot nd, currentTerm nd, lastAcceptedTerm nd))\"\n    \"\\<And>i t' a. (\\<langle> Vote i t' a \\<rangle>\\<leadsto>') =\n    ((\\<langle> Vote i t' a \\<rangle>\\<leadsto>)\n      \\<or> (i, t', a) = (firstUncommittedSlot nd, currentTerm nd, lastAcceptedTerm nd))\"\n    by (unfold isMessageFromTo'_def isMessageFromTo_def isMessageTo'_def isMessageTo_def\n        isMessageFrom'_def isMessageFrom_def isMessage'_def isMessage_def, auto simp add: messages')\n\n  have v_eq[simp]: \"v' = v\" by (intro ext, auto simp add: v'_def v_def)\n  have v\\<^sub>c_eq[simp]: \"v\\<^sub>c' = v\\<^sub>c\" by (intro ext, auto simp add: v\\<^sub>c'_def v\\<^sub>c_def)\n  have isCommitted_eq[simp]: \"isCommitted' = isCommitted\" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)\n  have committedTo_eq[simp]: \"committed\\<^sub><' = committed\\<^sub><\" by (intro ext, auto simp add: committedTo'_def committedTo_def)\n  have V_eq[simp]: \"V' = V\" using v\\<^sub>c_eq V'_def V_def by blast\n  have lastCommittedClusterStateBefore_eq[simp]: \"lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore\"\n    unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\\<^sub>c_eq ..\n\n  have promised_eq: \"\\<And>i s dn t. promised' i s dn t = (promised i s dn t \\<or> (firstUncommittedSlot nd \\<le> i \\<and> s = n\\<^sub>0 \\<and> dn = d\\<^sub>0 \\<and> t = currentTerm nd))\"\n    unfolding promised'_def promised_def Vote' by auto\n\n  have prevAccepted_eq: \"\\<And>i t q. prevAccepted' i t q = prevAccepted i t q \\<union> {t'. n\\<^sub>0 \\<in> q \\<and> i = firstUncommittedSlot nd \\<and> t = currentTerm nd \\<and> lastAcceptedTerm nd = SomeTerm t'}\"\n    unfolding prevAccepted_def prevAccepted'_def Vote' by auto\n\n  have property_simps[simp]:\n    \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\"\n    \"\\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)\"\n    \"\\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)\"\n    \"\\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q\"\n    \"\\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)\"\n    \"\\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)\"\n    \"\\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)\"\n    \"\\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)\"\n    \"\\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)\"\n    \"\\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)\"\n    \"\\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)\"\n    \"\\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)\"\n    by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' addElectionVote_def Let_def)\n\n  show \"zen messages' nodeState'\"\n    apply (intro zenI)\n                        apply (unfold message_simps property_simps committedTo_eq V_eq lastCommittedClusterStateBefore_eq v_eq)\n  proof -\n    from finite_messages show \"finite messages'\" by (simp add: messages')\n    from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n    from committedTo_firstUncommittedSlot show \"\\<And>n. committed\\<^sub>< (firstUncommittedSlot (nodeState n))\" .\n    from firstUncommittedSlot_PublishResponse show \"\\<And>n i t. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" .\n    from lastAcceptedTerm_None show \"\\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_sent show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_max show \"\\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\".\n    from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))\".\n    from publishVotes show \"\\<And>n n'. n' \\<in> publishVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\".\n    from currentClusterState_lastCommittedClusterStateBefore show \"\\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\".\n    from PublishRequest_committedTo show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n    from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from ApplyCommit_quorum show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\".\n    from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))\".\n    from firstUncommittedSlot_PublishRequest show \"\\<And>i n t x. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_value show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \\<rangle>\\<leadsto>\".\n    from PublishRequest_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from PublishRequest_publishPermitted_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState n) \\<Longrightarrow> t < currentTerm (nodeState n)\".\n    from CatchUpResponse_committedTo show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from CatchUpResponse_V show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> V i = conf\".\n    from CatchUpResponse_lastCommittedClusterStateBefore show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\".\n    from lastAcceptedTerm_Some_currentTerm show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n\n    from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>' \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\"\n      unfolding Vote' by (auto simp add: nd_def)\n\n    from joinVotes show \"\\<And>n n'. n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> promised' (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))\"\n      unfolding promised_eq by simp\n\n    from Vote_future firstUncommittedSlot_PublishResponse\n    show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>' \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\"\n      unfolding Vote' nd_def by auto\n\n    from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto>' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\"\n      unfolding Vote' using Vote_future lastAcceptedTerm_None nd' nd'_def by auto\n\n    from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>' \\<Longrightarrow> t' < t\"\n      unfolding Vote' using not_accepted lastAcceptedTerm_def\n      by (smt fst_conv TermOption.distinct(1) snd_conv)\n\n    from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>' \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\"\n      unfolding Vote' using lastAcceptedTerm_Some_sent nd' nd'_def nd_def\n      by (smt Pair_inject TermOption.distinct(1))\n\n    from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>' \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\"\n      unfolding Vote' nd_def\n      by (smt Pair_inject TermOption.distinct(1) \\<open>\\<And>t' t na. \\<lbrakk>lastAcceptedTerm (nodeState na) = SomeTerm t; na \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState na)) t' \\<rangle>\\<leadsto>\\<rbrakk> \\<Longrightarrow> t' \\<le> t\\<close> leD)\n\n    from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow>' d \\<Longrightarrow> d \\<noteq> Broadcast\"\n      unfolding Vote' by blast\n\n    from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow>' d' \\<Longrightarrow> d = d'\"\n      unfolding Vote'  using isMessageFrom_def not_sent by auto\n\n    from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>' \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto>' \\<Longrightarrow> i = i'\"\n      unfolding Vote'\n      by (metis Vote'(3) Message.inject(2) RoutedMessage.ext_inject insert_iff isMessageFrom'_def isMessageFromTo'_def isMessageFromTo_def isMessageFrom_def messages' not_sent)\n\n    from joinVotes_max show \"\\<And>n n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>) \\<Longrightarrow> n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow>' (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState n)\"\n      unfolding Vote'\n      by (smt Vote'(1) Message.inject(2) RoutedMessage.ext_inject insert_iff isMessageFromTo'_def isMessageFrom_def joinVotes messages' not_sent promised_def zen.Vote_slot_function zenMessages.Vote_value_function zenMessages_axioms zen_axioms)\n\n    fix i s t x\n    assume \"s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\"\n    from PublishRequest_quorum [OF this]\n    obtain q where q_majority: \"q \\<in> majorities (V i)\" \n      and q_promised: \"\\<And>n. n \\<in> q \\<Longrightarrow> promised i n s t\"\n      and q_value: \"prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t)\" by blast\n\n    from not_sent q_promised\n    have no_new_terms: \"{t'. n\\<^sub>0 \\<in> q \\<and> i = firstUncommittedSlot nd \\<and> t = currentTerm nd \\<and> lastAcceptedTerm nd = SomeTerm t'} = {}\"\n      unfolding isMessageFrom_def promised_def by blast\n    hence prevAccepted_eq: \"prevAccepted' i t q = prevAccepted i t q\"\n      unfolding prevAccepted_eq by auto\n\n    show \"\\<exists>q\\<in>majorities (V i). (\\<forall>n\\<in>q. promised' i n s t) \\<and> (prevAccepted' i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted' i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\"\n    proof (intro bexI conjI)\n      from q_majority show \"q \\<in> majorities (V i)\" .\n      from q_promised show \"\\<forall>n\\<in>q. promised' i n s t\" unfolding promised_eq by simp\n\n      from q_value show \"prevAccepted' i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted' i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t)\"\n        unfolding prevAccepted_eq by simp\n    qed\n  qed\nqed\n\nlemma (in zenStep) handleStartJoin_invariants:\n  fixes t\n  defines \"result \\<equiv> handleStartJoin t nd\"\n  assumes nd': \"nd' = fst result\"\n  assumes sent: \"s \\<midarrow>\\<langle> StartJoin t \\<rangle>\\<leadsto>\"\n  assumes messages': \"messages' = sendTo (OneNode s) result\"\n  shows \"zen messages' nodeState'\"\nproof (cases \"currentTerm nd < t\")\n  case False\n  hence result: \"result = (nd, None)\" by (simp add: result_def handleStartJoin_def)\n  have \"messages' = messages\" by (auto simp add: messages' result)\n  moreover\n  have \"nodeState' = nodeState\" by (intro ext, unfold nodeState'_def, simp add: nd' result nd_def)\n  moreover note zen_axioms\n  ultimately show ?thesis by simp\nnext\n  case True\n  hence new_term: \"currentTerm nd < t\" by simp\n\n  have result: \"result = (ensureCurrentTerm t nd, Some (Vote (firstUncommittedSlot nd) t (lastAcceptedTerm nd)))\"\n    by (simp add: result_def handleStartJoin_def True)\n\n  have nd': \"nd' = ensureCurrentTerm t nd\" by (simp add: nd' result)\n\n  have zen1: \"zen messages nodeState'\"\n  proof (intro zenStep.ensureCurrentTerm_invariants)\n    show \"messages = messages\" ..\n    from nd' show \"nodeState' n\\<^sub>0 = ensureCurrentTerm t (nodeState n\\<^sub>0)\" by (simp add: nd'_def nd_def)\n    show \"zenStep messages nodeState messages nodeState' n\\<^sub>0\"\n      by (intro_locales, intro zenStep_axioms.intro nodeState_unchanged, simp_all)\n  qed\n\n  with nodeState_unchanged messages_subset\n  have zenStep1: \"zenStep messages nodeState' messages' nodeState' n\\<^sub>0\"\n    by (intro_locales, simp add: zen_def, intro zenStep_axioms.intro, auto)\n\n  have nodeState': \"nodeState' = (\\<lambda> n. if n = n\\<^sub>0 then nd' else nodeState' n)\"\n    by (auto simp add: nodeState'_def)\n\n  have nd'_eq: \"nodeState' n\\<^sub>0 = nd'\"\n    by (simp add: nodeState'_def)\n\n  from True\n  have currentTerm_nd': \"currentTerm nd' = t\" by (auto simp add: nd')\n\n  have [simp]: \"firstUncommittedSlot nd' = firstUncommittedSlot nd\"\n    \"lastAcceptedTerm nd' = lastAcceptedTerm nd\"\n    by (auto simp add: nd' ensureCurrentTerm_def lastAcceptedTerm_def\n        lastAcceptedValue_def)\n\n  show \"zen messages' nodeState'\"\n  proof (intro zenStep.sendVote_invariants [OF zenStep1], unfold nd'_eq currentTerm_nd', simp_all add: messages' result)\n    show \"\\<And>i a. \\<forall>d. \\<lparr>sender = n\\<^sub>0, destination = d, payload = Vote i t a\\<rparr> \\<notin> messages\"\n      using nd_def new_term zen.Vote_currentTerm zen_axioms by fastforce\n    show \"\\<And>t'. lastAcceptedTerm nd = SomeTerm t' \\<Longrightarrow> t' < t\" using True lastAcceptedTerm_Some_currentTerm unfolding nd_def by fastforce\n  qed\nqed\n\nlemma (in zenStep) addElectionVote_invariants:\n  assumes nd': \"nd' = addElectionVote s i a nd\"\n  assumes messages': \"messages' = messages\"\n  assumes sent: \"s \\<midarrow>\\<langle> Vote i (currentTerm nd) a \\<rangle>\\<rightarrow> (OneNode n\\<^sub>0)\"\n  assumes precondition:\n    \"i < firstUncommittedSlot nd \\<or> (i = firstUncommittedSlot nd \\<and> a \\<le> lastAcceptedTerm nd)\"\n  shows \"zen messages' nodeState'\"\nproof -\n  from precondition have slot: \"i \\<le> firstUncommittedSlot nd\" by auto\n\n  have message_simps[simp]:\n    \"\\<And>s p d. (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>p d. (\\<langle> p \\<rangle>\\<rightarrow>' d) = (\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s p. (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>)\"\n    \"\\<And>p. (\\<langle> p \\<rangle>\\<leadsto>') = (\\<langle> p \\<rangle>\\<leadsto>)\"\n    by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,\n        auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)\n\n  have property_simps[simp]:\n    \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\"\n    \"\\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)\"\n    \"\\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)\"\n    \"\\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q\"\n    \"\\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)\"\n    \"\\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)\"\n    \"\\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)\"\n    \"\\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)\"\n    \"\\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)\"\n    \"\\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)\"\n    by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' addElectionVote_def Let_def\n        lastAcceptedValue_def lastAcceptedTerm_def)\n\n  have updated_properties:\n    \"\\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n) \\<union> (if n = n\\<^sub>0 then {s} else {})\"\n    \"\\<And>n. electionWon (nodeState' n) = (if n = n\\<^sub>0 then isQuorum nd (insert s (joinVotes nd)) else electionWon (nodeState n))\"\n    unfolding nodeState'_def by (auto simp add: nd' addElectionVote_def Let_def nd_def)\n\n  have v_eq[simp]: \"v' = v\" by (intro ext, auto simp add: v'_def v_def)\n  have v\\<^sub>c_eq[simp]: \"v\\<^sub>c' = v\\<^sub>c\" by (intro ext, auto simp add: v\\<^sub>c'_def v\\<^sub>c_def)\n  have isCommitted_eq[simp]: \"isCommitted' = isCommitted\" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)\n  have committedTo_eq[simp]: \"committed\\<^sub><' = committed\\<^sub><\" by (intro ext, auto simp add: committedTo'_def committedTo_def)\n  have V_eq[simp]: \"V' = V\" using v\\<^sub>c_eq V'_def V_def by blast\n  have promised_eq[simp]: \"promised' = promised\" by (intro ext, auto simp add: promised'_def promised_def)\n  have prevAccepted_eq[simp]: \"prevAccepted' = prevAccepted\" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)\n  have lastCommittedClusterStateBefore_eq[simp]: \"lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore\"\n    unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\\<^sub>c_eq ..\n\n  show \"zen messages' nodeState'\"\n    apply (intro zenI)\n                        apply (unfold message_simps property_simps committedTo_eq v_eq V_eq promised_eq lastCommittedClusterStateBefore_eq prevAccepted_eq)\n  proof -\n    from finite_messages show \"finite messages'\" by (simp add: messages')\n    from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\".\n    from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n    from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\".\n    from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n    from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n    from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n    from committedTo_firstUncommittedSlot show \"\\<And>n. committed\\<^sub>< (firstUncommittedSlot (nodeState n))\" .\n    from firstUncommittedSlot_PublishResponse show \"\\<And>n i t. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" .\n    from lastAcceptedTerm_None show \"\\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_sent show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_max show \"\\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\".\n    from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n    from publishVotes show \"\\<And>n n'. n' \\<in> publishVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\".\n    from currentClusterState_lastCommittedClusterStateBefore show \"\\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\".\n    from PublishRequest_committedTo show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n    from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from ApplyCommit_quorum show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\".\n    from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))\".\n    from firstUncommittedSlot_PublishRequest show \"\\<And>i n t x. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_value show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \\<rangle>\\<leadsto>\".\n    from PublishRequest_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from PublishRequest_publishPermitted_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState n) \\<Longrightarrow> t < currentTerm (nodeState n)\".\n    from PublishRequest_quorum show \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\".\n    from CatchUpResponse_committedTo show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from CatchUpResponse_V show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> V i = conf\".\n    from CatchUpResponse_lastCommittedClusterStateBefore show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\".\n    from lastAcceptedTerm_Some_currentTerm show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n\n    from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState' n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState' n))\"\n      unfolding updated_properties by (auto simp add: nd_def)\n\n    fix n\n\n    from joinVotes nd_def precondition sent\n    show \"\\<And>n'. n' \\<in> joinVotes (nodeState' n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))\"\n      using precondition sent unfolding updated_properties nd_def apply (cases \"n = n\\<^sub>0\", simp_all)\n      using nd_def promised_def slot by blast\n\n    fix n' a'\n    assume fresh_request: \"\\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>)\"\n      and n'_joinVotes: \"n' \\<in> joinVotes (nodeState' n)\"\n      and n'_vote: \"n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow> (OneNode n)\"\n\n    show \"a' \\<le> lastAcceptedTerm (nodeState n)\"\n    proof (cases \"n = n\\<^sub>0\")\n      case False\n      with fresh_request n'_joinVotes n'_vote joinVotes_max\n      show ?thesis by (simp add: updated_properties)\n    next\n      case n_eq: True\n\n      show ?thesis\n      proof (cases \"n' = s\")\n        case n'_eq: True\n        have i: \"i = firstUncommittedSlot nd\"\n        proof (intro Vote_slot_function)\n          from n'_vote show \"n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot nd) (currentTerm nd) a' \\<rangle>\\<leadsto>\"\n            unfolding isMessageFrom_def nd_def n_eq by auto\n          from sent show \"n' \\<midarrow>\\<langle> Vote i (currentTerm nd) a \\<rangle>\\<leadsto>\"\n            unfolding isMessageFrom_def nd_def n'_eq by auto\n        qed\n\n        have a: \"a = a'\"\n        proof (intro Vote_value_function)\n          from n'_vote show \"n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot nd) (currentTerm nd) a' \\<rangle>\\<leadsto>\"\n            unfolding isMessageFrom_def nd_def n_eq by auto\n          from sent show \"n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot nd) (currentTerm nd) a \\<rangle>\\<leadsto>\"\n            unfolding isMessageFrom_def nd_def n'_eq i by auto\n        qed\n\n        from precondition show ?thesis by (auto simp add: i a n_eq nd_def)\n      next\n        case False with n'_joinVotes have n'_joinVotes: \"n' \\<in> joinVotes nd\" by (simp add: nd_def n_eq updated_properties)\n        with fresh_request n'_vote joinVotes_max show ?thesis unfolding nd_def n_eq by auto\n      qed\n    qed\n  qed\nqed\n\nlemma (in zenStep) publishValue_invariants:\n  fixes x\n  defines \"result \\<equiv> publishValue x nd\"\n  assumes nd': \"nd' = fst result\"\n  assumes messages': \"messages' = sendTo Broadcast result\"\n  assumes x: \"lastAcceptedTerm nd \\<noteq> NO_TERM \\<Longrightarrow> x = lastAcceptedValue nd\"\n  shows \"zen messages' nodeState'\"\nproof (cases \"electionWon nd \\<and> publishPermitted nd\")\n  case False\n  hence result: \"result = (nd, None)\" by (simp add: result_def publishValue_def)\n  have \"messages' = messages\" by (auto simp add: messages' result)\n  moreover\n  have \"nodeState' = nodeState\" by (intro ext, unfold nodeState'_def, simp add: nd' result nd_def)\n  moreover note zen_axioms\n  ultimately show ?thesis by simp\nnext\n  case won: True\n  hence result: \"result = (nd \\<lparr> publishPermitted := False \\<rparr>,\n                           Some (PublishRequest (firstUncommittedSlot nd) (currentTerm nd) x))\"\n    by (simp add: result_def publishValue_def)\n\n  have messages': \"messages' = insert \\<lparr>sender = n\\<^sub>0, destination = Broadcast, payload = PublishRequest (firstUncommittedSlot nd) (currentTerm nd) x\\<rparr> messages\"\n    by (simp add: messages' result)\n\n  have message_simps:\n    \"\\<And>s d i t a. (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t. (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t. (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t a. (\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d) = (\\<langle> Vote i t a \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t. (\\<langle> PublishResponse i t \\<rangle>\\<rightarrow>' d) = (\\<langle> PublishResponse i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t. (\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow>' d) = (\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s i t a. (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t. (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t. (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>d i t a. (\\<langle> Vote i t a \\<rangle>\\<leadsto>') = (\\<langle> Vote i t a \\<rangle>\\<leadsto>)\"\n    \"\\<And>d i t. (\\<langle> PublishResponse i t \\<rangle>\\<leadsto>') = (\\<langle> PublishResponse i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>d i t. (\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') = (\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>s d i conf cs. (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i conf cs. (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow>' d) = (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s i conf cs. (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>)\"\n    \"\\<And>d i conf cs. (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>') = (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>)\"\n    by (auto simp add: isMessageFromTo'_def isMessageTo'_def isMessage'_def isMessageFrom'_def,\n        auto simp add: isMessageFromTo_def isMessageTo_def isMessage_def isMessageFrom_def messages')\n\n  have PublishRequest': \"\\<And>s d i t x'. (s \\<midarrow>\\<langle> PublishRequest i t x' \\<rangle>\\<rightarrow>' d) = ((s \\<midarrow>\\<langle> PublishRequest i t x' \\<rangle>\\<rightarrow> d)\n          \\<or> (s, d, i, t, x') = (n\\<^sub>0, Broadcast, firstUncommittedSlot nd, currentTerm nd, x))\"\n    \"\\<And>s i t x'. (s \\<midarrow>\\<langle> PublishRequest i t x' \\<rangle>\\<leadsto>') = ((s \\<midarrow>\\<langle> PublishRequest i t x' \\<rangle>\\<leadsto>)\n          \\<or> (s, i, t, x') = (n\\<^sub>0, firstUncommittedSlot nd, currentTerm nd, x))\"\n    \"\\<And>d i t x'. (\\<langle> PublishRequest i t x' \\<rangle>\\<rightarrow>' d) = ((\\<langle> PublishRequest i t x' \\<rangle>\\<rightarrow> d)\n          \\<or> (d, i, t, x') = (Broadcast, firstUncommittedSlot nd, currentTerm nd, x))\"\n    \"\\<And>i t x'. (\\<langle> PublishRequest i t x' \\<rangle>\\<leadsto>') = ((\\<langle> PublishRequest i t x' \\<rangle>\\<leadsto>)\n          \\<or> (i, t, x') = (firstUncommittedSlot nd, currentTerm nd, x))\"\n    by (auto simp add: isMessageFromTo'_def isMessageFrom'_def isMessageTo'_def isMessage'_def,\n        auto simp add: messages' isMessageFromTo_def isMessageFrom_def isMessageTo_def isMessage_def)\n\n  have fresh_request: \"\\<And>x. \\<not> \\<langle> PublishRequest (firstUncommittedSlot nd) (currentTerm nd) x \\<rangle>\\<leadsto>\"\n  proof (intro notI)\n    fix x'\n    assume \"\\<langle> PublishRequest (firstUncommittedSlot nd) (currentTerm nd) x' \\<rangle>\\<leadsto>\"\n    with won obtain s d where\n      s: \"s \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot nd) (currentTerm nd) x' \\<rangle>\\<rightarrow> d\"\n      by (auto simp add: isMessage_def isMessageFrom_def)\n\n    with PublishRequest_quorum [where s = s and i = \"firstUncommittedSlot nd\" and t = \"currentTerm nd\" and x = x']\n    obtain q where q: \"q \\<in> majorities (V (firstUncommittedSlot nd))\" and promised: \"\\<And>n. n \\<in> q \\<Longrightarrow> promised (firstUncommittedSlot nd) n s (currentTerm nd)\"\n      by (auto simp add: isMessageFrom_def, blast)\n\n    from won have \"isQuorum nd (joinVotes nd)\"\n      by (unfold nd_def, intro electionWon_isQuorum, simp)\n    with currentVotingNodes_firstUncommittedSlot [of n\\<^sub>0]\n    have \"joinVotes nd \\<in> majorities (V (firstUncommittedSlot nd))\" using nd_def isQuorum_def by auto\n\n    from q this V_intersects have \"q \\<inter> joinVotes nd \\<noteq> {}\"\n      by (auto simp add: intersects_def)\n    then obtain n where n: \"n \\<in> q\" \"n \\<in> joinVotes nd\" by auto\n\n    from promised [OF `n \\<in> q`]\n    obtain i' a' where \"n \\<midarrow>\\<langle> Vote i' (currentTerm nd) a' \\<rangle>\\<rightarrow> (OneNode s)\"\n      by (auto simp add: promised_def)\n\n    moreover from joinVotes n\n    obtain i'' a'' where \"n \\<midarrow>\\<langle> Vote i'' (currentTerm nd) a'' \\<rangle>\\<rightarrow> (OneNode n\\<^sub>0)\"\n      by (auto simp add: nd_def promised_def, blast)\n\n    ultimately have \"OneNode s = OneNode n\\<^sub>0\"\n      by (intro Vote_unique_destination)\n\n    with s have \"n\\<^sub>0 \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot nd) (currentTerm nd) x' \\<rangle>\\<leadsto>\"\n      by (auto simp add: isMessageFrom_def)\n\n    hence \"currentTerm nd < currentTerm (nodeState n\\<^sub>0)\"\n    proof (intro PublishRequest_publishPermitted_currentTerm, fold nd_def)\n      from won show \"publishPermitted nd\" by (simp add: nd_def)\n    qed\n    thus False by (simp add: nd_def)\n  qed\n\n  have v_eq: \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> v' i t = v i t\"\n  proof -\n    fix i t x'\n\n    assume \"\\<langle> PublishRequest i t x' \\<rangle>\\<leadsto>\"\n    with fresh_request have ne: \"(i, t) \\<noteq> (firstUncommittedSlot nd, currentTerm nd)\" by auto\n\n    have sent_eq: \"\\<And>x''. \\<langle> PublishRequest i t x'' \\<rangle>\\<leadsto>' = \\<langle> PublishRequest i t x'' \\<rangle>\\<leadsto>\"\n    proof (intro iffI)\n      fix x''\n      show \"\\<langle> PublishRequest i t x'' \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x'' \\<rangle>\\<leadsto>'\" by (simp add: PublishRequest')\n      assume \"\\<langle> PublishRequest i t x'' \\<rangle>\\<leadsto>'\" with ne show \"\\<langle> PublishRequest i t x'' \\<rangle>\\<leadsto>\"\n        by (unfold PublishRequest', auto)\n    qed\n\n    show \"v' i t = v i t\"\n      by (unfold v'_def v_def sent_eq, simp)\n  qed\n\n  have isCommitted_eq: \"isCommitted' = isCommitted\"\n    by (intro ext, simp add: isCommitted_def isCommitted'_def message_simps)\n\n  have committedTo_eq: \"committed\\<^sub><' = committed\\<^sub><\"\n    by (intro ext, simp add: committedTo_def committedTo'_def isCommitted_eq)\n\n  have v\\<^sub>c_eq: \"\\<And>i. isCommitted i \\<Longrightarrow> v\\<^sub>c' i = v\\<^sub>c i\"\n  proof -\n    fix i assume i: \"isCommitted i\"\n    define t where \"t \\<equiv> SOME t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>\"\n    have t: \"\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>\"\n    proof -\n      from i obtain t where t: \"\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>\" by (auto simp add: isCommitted_def)\n      thus ?thesis by (unfold t_def, intro someI)\n    qed\n    hence v_eq: \"v' i t = v i t\" by (intro v_eq [OF ApplyCommit_PublishRequest])\n\n    have \"v\\<^sub>c' i = v' i t\" by (simp add: v\\<^sub>c'_def t_def message_simps)\n    also note v_eq\n    also have \"v i t = v\\<^sub>c i\" by (simp add: v\\<^sub>c_def t_def)\n    finally show \"?thesis i\" by simp\n  qed\n\n  have V_eq: \"\\<And>i. committed\\<^sub>< i \\<Longrightarrow> V' i = V i\"\n  proof -\n    fix i assume i: \"committed\\<^sub>< i\"\n    thus \"?thesis i\"\n    proof (induct i)\n      case (Suc i')\n      hence prems: \"committed\\<^sub>< i'\" \"isCommitted i'\" unfolding committedTo_def by auto\n      thus ?case using Suc v\\<^sub>c_eq by simp\n    qed simp\n  qed\n\n  have lastCommittedClusterStateBefore_eq: \"\\<And>i. committed\\<^sub>< i \\<Longrightarrow> lastCommittedClusterStateBefore' i = lastCommittedClusterStateBefore i\"\n  proof -\n    fix i assume \"committed\\<^sub>< i\"\n    thus \"?thesis i\"\n    proof (induct i)\n      case (Suc i')\n      hence prems: \"committed\\<^sub>< i'\" \"isCommitted i'\" unfolding committedTo_def by auto\n      thus ?case using Suc v\\<^sub>c_eq by (cases \"v\\<^sub>c i'\", simp_all)\n    qed simp\n  qed\n\n  have promised_eq: \"\\<And>i n n' t. promised' i n n' t = promised i n n' t\"\n    by (simp add: promised_def promised'_def message_simps)\n\n  have prevAccepted_eq: \"\\<And>i t q. prevAccepted' i t q  = prevAccepted i t q\"\n    by (simp add: prevAccepted_def prevAccepted'_def message_simps)\n\n  from committedTo_firstUncommittedSlot V_eq\n  have V_slot_eq: \"\\<And>n. V' (firstUncommittedSlot (nodeState n)) = V (firstUncommittedSlot (nodeState n))\" by blast\n\n  have lastCommittedClusterStateBefore_slot_eq: \"\\<And>n. lastCommittedClusterStateBefore' (firstUncommittedSlot (nodeState n)) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\"\n    by (intro lastCommittedClusterStateBefore_eq committedTo_firstUncommittedSlot)\n\n  have v_prevAccepted_eq: \"\\<And>i t q. prevAccepted i t q \\<noteq> {} \\<Longrightarrow> v' i (maxTerm (prevAccepted i t q)) = v i (maxTerm (prevAccepted i t q))\"\n  proof -\n    fix i t q\n    assume nonempty: \"prevAccepted i t q \\<noteq> {}\"\n    have \"maxTerm (prevAccepted i t q) \\<in> prevAccepted i t q\"\n      by (intro maxTerm_mem finite_prevAccepted nonempty)\n    hence \"\\<langle> Vote i t (SomeTerm (maxTerm (prevAccepted i t q))) \\<rangle>\\<leadsto>\"\n      by (auto simp add: prevAccepted_def isMessage_def)\n    hence \"\\<langle> PublishResponse i (maxTerm (prevAccepted i t q)) \\<rangle>\\<leadsto>\"\n      using Vote_Some_PublishResponse unfolding isMessage_def by blast\n    then obtain x' where \"\\<langle> PublishRequest i (maxTerm (prevAccepted i t q)) x' \\<rangle>\\<leadsto>\"\n      using PublishResponse_PublishRequest unfolding isMessage_def by blast\n    thus \"?thesis i t q\" by (intro v_eq)\n  qed\n\n  have nd': \"nd' = nd \\<lparr> publishPermitted := False \\<rparr>\" by (simp add: nd' result)\n\n  have property_simps[simp]:\n    \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\"\n    \"\\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)\"\n    \"\\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)\"\n    \"\\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q\"\n    \"\\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)\"\n    \"\\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)\"\n    \"\\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)\"\n    \"\\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)\"\n    \"\\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)\"\n    \"\\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)\"\n    \"\\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)\"\n    by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' addElectionVote_def Let_def\n        lastAcceptedTerm_def lastAcceptedValue_def)\n\n  show ?thesis\n    apply (intro zenI)\n                        apply (unfold message_simps committedTo_eq V_slot_eq\n        lastCommittedClusterStateBefore_slot_eq property_simps promised_eq prevAccepted_eq)\n  proof -\n    from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\".\n    from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n    from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\".\n    from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n    from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n    from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n    from committedTo_firstUncommittedSlot show \"\\<And>n. committed\\<^sub>< (firstUncommittedSlot (nodeState n))\" .\n    from firstUncommittedSlot_PublishResponse show \"\\<And>n i t. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" .\n    from lastAcceptedTerm_None show \"\\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_sent show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_max show \"\\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\".\n    from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n    from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))\".\n    from publishVotes show \"\\<And>n n'. n' \\<in> publishVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\".\n    from currentClusterState_lastCommittedClusterStateBefore show \"\\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\".\n    from joinVotes show \"\\<And>n n'. n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))\".\n    from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))\".\n    from lastAcceptedTerm_Some_currentTerm show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n\n    {\n      fix i conf cs assume a: \"\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>\"\n      with CatchUpResponse_committedTo show \"committed\\<^sub>< i\" .\n      with a V_eq lastCommittedClusterStateBefore_eq CatchUpResponse_V CatchUpResponse_lastCommittedClusterStateBefore\n      show \"V' i = conf\" \"lastCommittedClusterStateBefore' i = cs\" by auto\n    }\n\n    from lastAcceptedTerm_Some_value  PublishRequest'\n    show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \\<rangle>\\<leadsto>'\"\n      by (meson isMessage'_def isMessageFrom'_def isMessageFrom_def isMessage_def)\n\n    from PublishRequest_currentTerm\n    show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto>' \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\"\n      using PublishRequest' isMessageFrom'_def isMessageFrom_def nd_def by fastforce\n\n    from fresh_request PublishRequest_function\n    show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>' \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto>' \\<Longrightarrow> x = x'\"\n      unfolding PublishRequest' by auto\n\n    from messages' finite_messages show \"finite messages'\" by simp\n\n    from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>'\"\n      unfolding PublishRequest' by blast\n\n    from ApplyCommit_quorum V_eq isCommitted_committedTo\n    show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V' i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\"\n      unfolding isCommitted_def by fastforce\n\n    fix n\n\n    from firstUncommittedSlot_PublishRequest\n    show \"\\<And>i t x. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>'\"\n      by (cases \"n = n\\<^sub>0\", unfold nodeState'_def PublishRequest' isMessageFrom'_def isMessageFrom_def, auto simp add: nd' nd_def)\n\n    from PublishRequest_publishPermitted_currentTerm\n    show \"\\<And>t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto>' \\<Longrightarrow> publishPermitted (nodeState' n) \\<Longrightarrow> t < currentTerm (nodeState n)\"\n      unfolding isMessageFrom'_def PublishRequest'\n      by (cases \"n = n\\<^sub>0\", auto simp add: nodeState'_def nd' isMessageFrom_def)\n\n    show PublishRequest_committedTo': \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>' \\<Longrightarrow> committed\\<^sub>< i\"\n      using PublishRequest_committedTo committedTo_firstUncommittedSlot\n      by (auto simp add: committedTo_def PublishRequest' nd_def)\n\n    from joinVotes_max\n    show \"\\<And>n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>') \\<Longrightarrow> n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow> (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState n)\"\n      by (cases \"n = n\\<^sub>0\", auto simp add: nodeState'_def nd' PublishRequest')\n\n    {\n      fix i s t x'\n      assume \"s \\<midarrow>\\<langle> PublishRequest i t x' \\<rangle>\\<leadsto>'\"\n      thus \"\\<exists>q\\<in>majorities (V' i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v' i t = v' i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\"\n        unfolding PublishRequest'\n      proof (elim disjE)\n        assume sent: \"s \\<midarrow>\\<langle> PublishRequest i t x' \\<rangle>\\<leadsto>\"\n        from sent have [simp]: \"V' i = V i\" by (intro V_eq PublishRequest_committedTo, auto simp add: isMessage_def)\n        from sent have [simp]: \"v' i t = v i t\" by (intro v_eq, auto simp add: isMessage_def)\n\n        from PublishRequest_quorum [OF sent]\n        obtain q where q_quorum: \"q \\<in> majorities (V i)\"\n          and q_promised: \"\\<And>n. n \\<in> q \\<Longrightarrow> promised i n s t\"\n          and q_value: \"prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t)\"\n          by blast\n\n        show ?thesis\n        proof (cases \"prevAccepted i t q = {}\")\n          case True with q_quorum q_promised show ?thesis by auto\n        next\n          case False\n          with q_value obtain t' where t': \"v i t = v i t'\" \"maxTerm (prevAccepted i t q) \\<le> t'\" \"\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\" \"t' < t\" by blast\n\n          show ?thesis\n          proof (intro bexI conjI disjI2 exI ballI)\n            from q_promised show \"\\<And>n. n \\<in> q \\<Longrightarrow> promised i n s t\" .\n            from t' show \"maxTerm (prevAccepted i t q) \\<le> t'\" \"\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\" \"t' < t\" by simp_all\n            from q_quorum show \"q \\<in> majorities (V' i)\" by simp\n\n            have \"v' i t = v i t\" by simp\n            also have \"... = v i t'\" using t' by simp\n            also have \"... = v' i t'\" unfolding v_def v'_def PublishRequest' using t'\n              by (metis PublishResponse_PublishRequest_v fresh_request fst_conv snd_conv)\n            finally show \"v' i t = v' i t'\" .\n          qed\n        qed\n      next\n        assume \"(s, i, t, x') = (n\\<^sub>0, firstUncommittedSlot nd, currentTerm nd, x)\"\n        hence [simp]: \"s = n\\<^sub>0\" \"i = firstUncommittedSlot nd\" \"t = currentTerm nd\" \"x' = x\" by simp_all\n\n        have Vi: \"V' i = V i\"\n          using committedTo_firstUncommittedSlot by (intro V_eq, simp add: nd_def)\n        define q where \"q \\<equiv> joinVotes nd\"\n\n        show ?thesis\n        proof (intro bexI conjI ballI)\n          from won have \"isQuorum nd q\" unfolding nd_def q_def by (intro electionWon_isQuorum, simp)\n          with currentVotingNodes_firstUncommittedSlot Vi show \"q \\<in> majorities (V' i)\" by (auto simp add: nd_def isQuorum_def)\n          fix n assume \"n \\<in> q\"\n          with joinVotes show \"promised i n s t\" by (simp add: nd_def q_def)\n        next\n          show \"prevAccepted i t q = {} \\<or> (\\<exists>t'. v' i t = v' i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t)\"\n          proof (cases \"prevAccepted i t q = {}\")\n            case True thus ?thesis by simp\n          next\n            case False\n            then obtain t' n' where n'_vote: \"n' \\<in> q\" and n'_sent: \"n' \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto>\"\n              unfolding prevAccepted_def by auto\n\n            from n'_sent n'_vote\n            have n'_sent: \"n' \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<rightarrow> (OneNode n\\<^sub>0)\" unfolding isMessageFrom_def q_def nd_def\n              using \\<open>t = currentTerm nd\\<close> isMessageFromTo_def nd_def zen.joinVotes zenMessages.Vote_unique_destination zenMessages_axioms zen_axioms by blast\n\n            have t'_latis: \"SomeTerm t' \\<le> lastAcceptedTerm nd\"\n              unfolding nd_def\n            proof (intro joinVotes_max)\n              from fresh_request\n              show \"\\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n\\<^sub>0)) (currentTerm (nodeState n\\<^sub>0)) x \\<rangle>\\<leadsto>)\"\n                unfolding nd_def by auto\n\n              from n'_vote show \"n' \\<in> joinVotes (nodeState n\\<^sub>0)\" by (simp add: q_def nd_def)\n\n              from n'_sent\n              show \"n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n\\<^sub>0)) (currentTerm (nodeState n\\<^sub>0)) (SomeTerm t') \\<rangle>\\<rightarrow> (OneNode n\\<^sub>0)\"\n                by (simp add: nd_def)\n            qed\n\n            then obtain t'' where t'': \"lastAcceptedTerm nd = SomeTerm t''\"\n              by (cases \"lastAcceptedTerm nd\", auto)\n\n            show ?thesis\n            proof (intro disjI2 exI conjI)\n              from t''\n              have slots: \"firstUncommittedSlot nd = firstUncommittedSlot nd\"\n                by (cases \"firstUncommittedSlot nd = firstUncommittedSlot nd\", simp_all add: lastAcceptedTerm_def)\n              \n              from t'' have lat: \"lastAcceptedTerm nd = SomeTerm t''\"\n                by (cases \"firstUncommittedSlot nd = firstUncommittedSlot nd\", simp_all add: lastAcceptedTerm_def)\n              \n              from lastAcceptedTerm_Some_sent lat slots\n              show accepted: \"\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\" by (auto simp add: nd_def isMessage_def)\n              \n              from fresh_request\n              have \"\\<And>x'. \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto>' \\<Longrightarrow> x' = x\" unfolding PublishRequest' by simp\n              hence \"v' i t = x\" unfolding v'_def using \\<open>s \\<midarrow>\\<langle> PublishRequest i t x' \\<rangle>\\<leadsto>'\\<close> isMessage'_def by blast\n              \n              also from x have \"x = lastAcceptedValue nd\" by (simp add: t'')\n              \n              also have \"... = v i t''\"\n              proof (intro PublishRequest_function)\n                from accepted PublishResponse_PublishRequest_v show \"\\<langle> PublishRequest i t'' (v i t'') \\<rangle>\\<leadsto>\" by simp\n              \n                from lat lastAcceptedTerm_Some_value slots\n                show \"\\<langle> PublishRequest i t'' (lastAcceptedValue nd) \\<rangle>\\<leadsto>\"\n                  by (simp add: nd_def)\n              qed\n              \n              also have \"... = v' i t''\"\n              proof (intro sym [OF v_eq])\n                from accepted PublishResponse_PublishRequest_v show \"\\<langle> PublishRequest i t'' (v i t'') \\<rangle>\\<leadsto>\" by simp\n              qed\n              \n              finally show \"v' i t = v' i t''\" .\n              \n              show \"maxTerm (prevAccepted i t q) \\<le> t''\"\n              proof (intro maxTerm_le False finite_prevAccepted)\n                fix t''' assume \"t''' \\<in> prevAccepted i t q\"\n                thus \"t''' \\<le> t''\" unfolding prevAccepted_def apply auto\n                  by (metis \\<open>\\<And>t s i' ia d' d a' a. \\<lbrakk>s \\<midarrow>\\<langle> Vote ia t a \\<rangle>\\<rightarrow> d; s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d'\\<rbrakk> \\<Longrightarrow> d = d'\\<close> fresh_request isMessageFrom_def joinVotes joinVotes_max le_SomeTerm nd_def promised_def q_def t'')\n              qed\n              \n              have \"t'' \\<le> t\" using \\<open>t = currentTerm nd\\<close> lastAcceptedTerm_Some_currentTerm lat nd_def by blast\n              moreover have \"t'' \\<noteq> t\" apply (intro notI) using accepted fresh_request\n                using lastAcceptedTerm_Some_value lat nd_def slots by auto\n              ultimately show \"t'' < t\" by simp\n            qed\n          qed\n        qed\n      qed\n    }\n  qed\nqed\n\nlemma (in zenStep) handleVote_invariants:\n  fixes s i t a\n  defines \"result \\<equiv> handleVote s i t a nd\"\n  assumes nd': \"nd' = fst result\"\n  assumes messages': \"messages' = sendTo Broadcast result\"\n  assumes sent: \"s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> (OneNode n\\<^sub>0)\"\n  shows \"zen messages' nodeState'\"\nproof (cases \"t = currentTerm nd\n             \\<and> (i < firstUncommittedSlot nd\n                \\<or> (i = firstUncommittedSlot nd\n                    \\<and> (a \\<le> lastAcceptedTerm nd)))\")\n  case False\n  have [simp]: \"result = (nd, None)\" unfolding result_def handleVote_def by (simp add: False Let_def)\n  have [simp]: \"messages' = messages\" by (simp add: messages')\n  have [simp]: \"nodeState' = nodeState\" unfolding nodeState'_def by (intro ext, simp add: nd' nd_def)\n  from zen_axioms show ?thesis by simp\nnext\n  case True\n  hence True': \"i \\<le> firstUncommittedSlot nd\"\n    \"t = currentTerm nd\"\n    \"i < firstUncommittedSlot nd \\<or> (i = firstUncommittedSlot nd \\<and> a \\<le> lastAcceptedTerm nd)\"\n    by auto\n\n  define nd1 where \"nd1 \\<equiv> addElectionVote s i a nd\"\n  define nodeState1 where \"\\<And>n. nodeState1 n \\<equiv> if n = n\\<^sub>0 then nd1 else nodeState n\"\n\n  have zenStep1: \"zenStep messages nodeState messages nodeState1 n\\<^sub>0\"\n    by (intro zenStepI2, auto simp add: nodeState1_def)\n\n  have zenStep2: \"zenStep messages nodeState1 messages' nodeState' n\\<^sub>0\"\n  proof (intro zenStep.zenStepI1 [OF zenStep1] zenStep.addElectionVote_invariants [OF zenStep1] refl messages_subset,\n      fold nd_def isMessageFromTo_def)\n    show \"nodeState1 n\\<^sub>0 = addElectionVote s i a nd\" by (simp add: nodeState1_def nd1_def)\n    from True' sent show \"s \\<midarrow>\\<langle> Vote i (currentTerm nd) a \\<rangle>\\<rightarrow> (OneNode n\\<^sub>0)\" by simp\n    from True' show \"i < firstUncommittedSlot nd \\<or> (i = firstUncommittedSlot nd \\<and> a \\<le> lastAcceptedTerm nd)\" by simp\n    show \"\\<And>n. n \\<noteq> n\\<^sub>0 \\<Longrightarrow> nodeState1 n = nodeState' n\" unfolding nodeState1_def nodeState'_def by simp\n  qed\n\n  note zenStep.publishValue_invariants\n  have latis_eq: \"lastAcceptedTerm nd1 = lastAcceptedTerm nd\"\n    by (simp add: nd1_def addElectionVote_def Let_def)\n\n  show ?thesis\n  proof (cases \"lastAcceptedTerm nd1\")\n    case (SomeTerm t')\n    with True' latis_eq\n    have handleVote_eq: \"handleVote s i t a nd = publishValue (lastAcceptedValue nd1) nd1\"\n      unfolding handleVote_def nd1_def by (simp add: addElectionVote_def Let_def)\n\n    show ?thesis\n    proof (intro zenStep.publishValue_invariants [OF zenStep2])\n      show \"nodeState' n\\<^sub>0 = fst (publishValue (lastAcceptedValue nd1) (nodeState1 n\\<^sub>0))\"\n        by (simp add: nodeState1_def nd1_def nodeState'_def nd' result_def handleVote_eq)\n\n      show \"messages' = (case snd (publishValue (lastAcceptedValue nd1) (nodeState1 n\\<^sub>0)) of None \\<Rightarrow> messages | Some m \\<Rightarrow> insert \\<lparr>sender = n\\<^sub>0, destination = Broadcast, payload = m\\<rparr> messages)\"\n        by (cases \"publishValue (lastAcceptedValue nd1) nd1\", cases \"snd (publishValue (lastAcceptedValue nd1) nd1)\",\n            simp_all add: nodeState1_def messages' result_def handleVote_eq)\n\n      show \"lastAcceptedValue nd1 = lastAcceptedValue (nodeState1 n\\<^sub>0)\" by (simp add: nodeState1_def)\n    qed\n\n  next\n    case NO_TERM\n    with True' latis_eq\n    have handleVote_eq: \"handleVote s i t a nd = (nd1, None)\" unfolding handleVote_def nd1_def by simp\n    have [simp]: \"messages' = messages\" by (simp add: messages' result_def handleVote_eq)\n    have [simp]: \"nodeState' = nodeState1\" by (intro ext, simp add: nodeState'_def nodeState1_def nd' result_def handleVote_eq)\n    from zenStep2 show ?thesis by (simp add: zenStep_def)\n  qed\nqed\n\nlemma (in zenStep) handleClientValue_invariants:\n  fixes x\n  defines \"result \\<equiv> handleClientValue x nd\"\n  assumes nd': \"nd' = fst result\"\n  assumes messages': \"messages' = sendTo Broadcast result\"\n  shows \"zen messages' nodeState'\"\nproof (cases \"lastAcceptedTerm nd\")\n  case (SomeTerm t')\n  hence \"handleClientValue x nd = (nd, None)\" by (auto simp add: handleClientValue_def)\n  hence [simp]: \"result = (nd, None)\" by (simp add: result_def)\n  have [simp]: \"messages' = messages\" by (simp add: messages')\n  have [simp]: \"nodeState' = nodeState\" unfolding nodeState'_def by (intro ext, simp add: nd' nd_def)\n  from zen_axioms show ?thesis by simp\nnext\n  case NO_TERM\n  hence handleClientValue_eq[simp]: \"handleClientValue x nd = publishValue x nd\"\n    by (auto simp add: handleClientValue_def)\n\n  have result: \"result = publishValue x nd\"\n    unfolding result_def by simp\n\n  show ?thesis\n  proof (intro publishValue_invariants)\n    show \"nd' = fst (publishValue x nd)\" by (simp add: result nd')\n    show \"messages' = sendTo Broadcast (publishValue x nd)\" by (simp_all add: messages' result)\n    from NO_TERM show \"lastAcceptedTerm nd \\<noteq> NO_TERM \\<Longrightarrow> x = lastAcceptedValue nd\"\n      by simp\n  qed\nqed\n\nlemma (in zenStep) handlePublishRequest_invariants:\n  fixes i t x\n  defines \"result \\<equiv> handlePublishRequest i t x nd\"\n  assumes nd': \"nd' = fst result\"\n  assumes messages': \"messages' = sendTo (OneNode s) result\"\n  assumes sent: \"s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\"\n  shows \"zen messages' nodeState'\"\nproof (cases \"i = firstUncommittedSlot nd \\<and> t = currentTerm nd\")\n  case False\n  hence [simp]: \"result = (nd, None)\"\n    by (simp add: result_def handlePublishRequest_def)\n\n  have [simp]: \"messages' = messages\"\n    by (simp add: messages')\n\n  have [simp]: \"nodeState' = nodeState\"\n    unfolding nodeState'_def\n    by (intro ext, simp add: nd' nd_def)\n\n  from zen_axioms show ?thesis by simp\n\nnext\n  case precondition: True\n\n  hence result: \"result = (nd\\<lparr>lastAcceptedData := Some \\<lparr> tvTerm = t, tvValue = x\\<rparr> \\<rparr>,\n      Some (PublishResponse i t))\"\n    by (auto simp add: result_def handlePublishRequest_def)\n\n  have messages': \"messages' = insert \\<lparr> sender = n\\<^sub>0, destination = OneNode s, payload = PublishResponse i t \\<rparr> messages\"\n    by (simp add: messages' result)\n\n  have message_simps[simp]:\n    \"\\<And>s d i t. (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t x. (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t a. (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t. (\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow>' d) = (\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t x. (\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow>' d) = (\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t a. (\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d) = (\\<langle> Vote i t a \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s i t. (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t x. (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t a. (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>)\"\n    \"\\<And>i t. (\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') = (\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>i t x. (\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>') = (\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>)\"\n    \"\\<And>i t a. (\\<langle> Vote i t a \\<rangle>\\<leadsto>') = (\\<langle> Vote i t a \\<rangle>\\<leadsto>)\"\n    \"\\<And>s d i conf cs. (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i conf cs. (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow>' d) = (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s i conf cs. (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>)\"\n    \"\\<And>d i conf cs. (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>') = (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>)\"\n    by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,\n        auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)\n\n  have property_simps[simp]:\n    \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\"\n    \"\\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)\"\n    \"\\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)\"\n    \"\\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q\"\n    \"\\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)\"\n    \"\\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)\"\n    \"\\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)\"\n    \"\\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)\"\n    \"\\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)\"\n    \"\\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)\"\n    \"lastAcceptedTerm nd' = SomeTerm t\"\n    \"lastAcceptedValue nd' = x\"\n    using precondition\n    by (unfold nodeState'_def, auto simp add: result nd' nd_def isQuorum_def\n        lastAcceptedTerm_def lastAcceptedValue_def)\n\n  have updated_properties:\n    \"\\<And>n. lastAcceptedTerm (nodeState' n) = (if n = n\\<^sub>0 then SomeTerm t else lastAcceptedTerm (nodeState n))\"\n    \"\\<And>n. lastAcceptedValue (nodeState' n) = (if n = n\\<^sub>0 then x else lastAcceptedValue (nodeState n))\"\n    by (unfold nodeState'_def, auto simp add: result nd' nd_def\n        lastAcceptedTerm_def lastAcceptedValue_def)\n\n  have PublishResponse': \"\\<And>s' d i t'. (s' \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<rightarrow>' d) =\n    ((s' \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<rightarrow> d) \\<or> (s', i, t', d) = (n\\<^sub>0, firstUncommittedSlot nd, t, OneNode s))\"\n    \"\\<And>d i t'. (\\<langle> PublishResponse i t' \\<rangle>\\<rightarrow>' d) =\n    ((\\<langle> PublishResponse i t' \\<rangle>\\<rightarrow> d) \\<or> (i, t', d) = (firstUncommittedSlot nd, t, OneNode s))\"\n    \"\\<And>s' i t'. (s' \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>') =\n    ((s' \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>) \\<or> (s', i, t') = (n\\<^sub>0, firstUncommittedSlot nd, t))\"\n    \"\\<And>i t'. (\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>') =\n    ((\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>) \\<or> (i, t') = (firstUncommittedSlot nd, t))\"\n    unfolding isMessageFromTo_def isMessageFromTo'_def isMessageFrom_def isMessageFrom'_def isMessageTo_def isMessageTo'_def isMessage_def isMessage'_def\n    by (auto simp add: messages' precondition)\n\n  have v_eq[simp]: \"v' = v\" by (intro ext, auto simp add: v'_def v_def)\n  have v\\<^sub>c_eq[simp]: \"v\\<^sub>c' = v\\<^sub>c\" by (intro ext, auto simp add: v\\<^sub>c'_def v\\<^sub>c_def)\n  have isCommitted_eq[simp]: \"isCommitted' = isCommitted\" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)\n  have committedTo_eq[simp]: \"committed\\<^sub><' = committed\\<^sub><\" by (intro ext, auto simp add: committedTo'_def committedTo_def)\n  have V_eq[simp]: \"V' = V\" using v\\<^sub>c_eq V'_def V_def by blast\n  have lastCommittedClusterStateBefore_eq[simp]: \"lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore\"\n    unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\\<^sub>c_eq ..\n  have promised_eq[simp]: \"promised' = promised\" by (intro ext, auto simp add: promised'_def promised_def)\n  have prevAccepted_eq[simp]: \"prevAccepted' = prevAccepted\" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)\n\n  show ?thesis\n    apply (intro zenI)\n                        apply (unfold message_simps committedTo_eq V_eq v_eq\n        lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)\n  proof -\n    from finite_messages show \"finite messages'\" by (simp add: messages')\n    from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n    from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n    from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n    from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n    from committedTo_firstUncommittedSlot show \"\\<And>n. committed\\<^sub>< (firstUncommittedSlot (nodeState n))\" .\n    from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n    from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))\".\n    from currentClusterState_lastCommittedClusterStateBefore show \"\\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\".\n    from joinVotes show \"\\<And>n n'. n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))\".\n    from PublishRequest_committedTo show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n    from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))\".\n    from firstUncommittedSlot_PublishRequest show \"\\<And>i n t x. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from PublishRequest_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from PublishRequest_publishPermitted_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState n) \\<Longrightarrow> t < currentTerm (nodeState n)\".\n    from CatchUpResponse_committedTo show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from CatchUpResponse_V show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> V i = conf\".\n    from CatchUpResponse_lastCommittedClusterStateBefore show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\".\n\n    from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>'\"\n      using precondition unfolding PublishResponse' nd_def by (metis Vote_currentTerm Pair_inject leD)\n\n    from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>'\"\n      using precondition unfolding PublishResponse' nd_def by (metis Vote_currentTerm Pair_inject leD)\n\n    from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>'\"\n      using precondition unfolding PublishResponse' nd_def by metis\n\n    from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>'\"\n      using precondition unfolding PublishResponse' nd_def using Vote_currentTerm by fastforce\n\n    from PublishRequest_quorum show \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto>' \\<and> t' < t))\" \n      unfolding PublishResponse' by meson\n\n    fix n\n\n    from firstUncommittedSlot_PublishResponse show \"\\<And>i t. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>'\" \n      using precondition property_simps unfolding PublishResponse' nd_def by (cases \"n = n\\<^sub>0\", auto)\n\n    from lastAcceptedTerm_None show \"\\<And>i t. lastAcceptedTerm (nodeState' n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>'\"\n      using precondition property_simps updated_properties unfolding PublishResponse' nd_def by (cases \"n = n\\<^sub>0\", auto)\n\n    from lastAcceptedTerm_Some_sent show \"\\<And>n t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>'\"\n      using precondition property_simps unfolding PublishResponse' nd_def\n      by (metis nd'_def nodeState_unchanged TermOption.inject)\n\n    from lastAcceptedTerm_Some_max show \"\\<And>t t'. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \\<rangle>\\<leadsto>' \\<Longrightarrow> t' \\<le> t\"\n      using precondition property_simps updated_properties unfolding PublishResponse' nd_def apply (cases \"n = n\\<^sub>0\", auto)\n      by (meson TermOption.exhaust lastAcceptedTerm_None lastAcceptedTerm_Some_currentTerm le_trans)\n    \n    from joinVotes_max show \"\\<And>n n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>) \\<Longrightarrow> n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow> (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState' n)\"\n      using precondition property_simps unfolding PublishResponse' nd_def\n      by (metis isMessage_def nodeState_unchanged sent)\n\n    from publishVotes show \"\\<And>n n'. n' \\<in> publishVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>'\"\n      using precondition property_simps unfolding PublishResponse' nd_def\n      by blast\n\n    from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>' \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\"\n      using precondition property_simps unfolding PublishResponse' nd_def\n      using isMessage_def sent by auto\n\n    from ApplyCommit_quorum show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>'\"\n      using precondition property_simps unfolding PublishResponse' nd_def\n      by meson\n\n    from lastAcceptedTerm_Some_value show \"\\<And>n t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState' n)) \\<rangle>\\<leadsto>\"\n      using precondition property_simps unfolding PublishResponse' nd_def\n      by (metis isMessage_def nd'_def nodeState_unchanged TermOption.inject sent)\n\n    from lastAcceptedTerm_Some_currentTerm show \"\\<And>n t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\"\n      using precondition property_simps unfolding PublishResponse' nd_def\n      by (metis eq_imp_le TermOption.inject updated_properties(1))\n  qed\nqed\n\nlemma (in zenStep) addPublishVote_invariants:\n  assumes nd': \"nd' = nd \\<lparr> publishVotes := insert s (publishVotes nd) \\<rparr>\"\n  assumes messages': \"messages' = messages\"\n  assumes sent: \"s \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot nd) (currentTerm nd) \\<rangle>\\<leadsto>\"\n  shows \"zen messages' nodeState'\"\nproof -\n  have message_simps[simp]:\n    \"\\<And>s p d. (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>p d. (\\<langle> p \\<rangle>\\<rightarrow>' d) = (\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s p. (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>)\"\n    \"\\<And>p. (\\<langle> p \\<rangle>\\<leadsto>') = (\\<langle> p \\<rangle>\\<leadsto>)\"\n    by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,\n        auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)\n\n  have property_simps[simp]:\n    \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\"\n    \"\\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)\"\n    \"\\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)\"\n    \"\\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q\"\n    \"\\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)\"\n    \"\\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)\"\n    \"\\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)\"\n    \"\\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)\"\n    \"\\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)\"\n    \"\\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)\"\n    \"\\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)\"\n    by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' addElectionVote_def Let_def\n        lastAcceptedTerm_def lastAcceptedValue_def)\n\n  have updated_properties[simp]:\n    \"\\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n) \\<union> (if n = n\\<^sub>0 then {s} else {})\"\n    by (unfold nodeState'_def, auto simp add: nd' nd_def isQuorum_def)\n\n  have v_eq[simp]: \"v' = v\" by (intro ext, auto simp add: v'_def v_def)\n  have v\\<^sub>c_eq[simp]: \"v\\<^sub>c' = v\\<^sub>c\" by (intro ext, auto simp add: v\\<^sub>c'_def v\\<^sub>c_def)\n  have isCommitted_eq[simp]: \"isCommitted' = isCommitted\" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)\n  have committedTo_eq[simp]: \"committed\\<^sub><' = committed\\<^sub><\" by (intro ext, auto simp add: committedTo'_def committedTo_def)\n  have V_eq[simp]: \"V' = V\" using v\\<^sub>c_eq V'_def V_def by blast\n  have promised_eq[simp]: \"promised' = promised\" by (intro ext, auto simp add: promised'_def promised_def)\n  have lastCommittedClusterStateBefore_eq[simp]: \"lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore\"\n    unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\\<^sub>c_eq ..\n  have prevAccepted_eq[simp]: \"prevAccepted' = prevAccepted\" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)\n\n  show ?thesis\n    apply (intro zenI)\n                        apply (unfold message_simps committedTo_eq V_eq v_eq\n        lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)\n  proof -\n    from finite_messages show \"finite messages'\" by (simp add: messages')\n    from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\".\n    from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n    from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\".\n    from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n    from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n    from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n    from committedTo_firstUncommittedSlot show \"\\<And>n. committed\\<^sub>< (firstUncommittedSlot (nodeState n))\" .\n    from firstUncommittedSlot_PublishResponse show \"\\<And>n i t. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" .\n    from lastAcceptedTerm_None show \"\\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_sent show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_max show \"\\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\".\n    from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n    from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))\".\n    from joinVotes_max show \"\\<And>n n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>) \\<Longrightarrow> n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow> (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState n)\".\n    from currentClusterState_lastCommittedClusterStateBefore show \"\\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\".\n    from joinVotes show \"\\<And>n n'. n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))\".\n    from PublishRequest_committedTo show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from PublishRequest_quorum show \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\".\n    from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n    from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from ApplyCommit_quorum show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\".\n    from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))\".\n    from firstUncommittedSlot_PublishRequest show \"\\<And>i n t x. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_value show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \\<rangle>\\<leadsto>\".\n    from PublishRequest_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from PublishRequest_publishPermitted_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState n) \\<Longrightarrow> t < currentTerm (nodeState n)\".\n    from CatchUpResponse_committedTo show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from CatchUpResponse_V show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> V i = conf\".\n    from CatchUpResponse_lastCommittedClusterStateBefore show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\".\n    from lastAcceptedTerm_Some_currentTerm show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n\n    from publishVotes show \"\\<And>n n'. n' \\<in> publishVotes (nodeState' n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\"\n      unfolding updated_properties using sent apply auto by (metis empty_iff nd_def singleton_iff)\n  qed\nqed\n\nlemma (in zenStep) commitIfQuorate_invariants:\n  fixes s i t\n  defines \"result \\<equiv> commitIfQuorate nd\"\n  assumes nd': \"nd' = fst result\"\n  assumes messages': \"messages' = sendTo Broadcast result\"\n  shows \"zen messages' nodeState'\"\nproof (cases \"isQuorum nd (publishVotes nd)\")\n  case False\n  hence [simp]: \"result = (nd, None)\"\n    by (simp add: result_def commitIfQuorate_def)\n\n  have [simp]: \"messages' = messages\"\n    by (simp add: messages')\n\n  have [simp]: \"nodeState' = nodeState\"\n    unfolding nodeState'_def\n    by (intro ext, simp add: nd' nd_def)\n\n  from zen_axioms show ?thesis by simp\n\nnext\n  case isQuorum: True\n  hence result: \"result = (nd, Some (ApplyCommit (firstUncommittedSlot nd) (currentTerm nd)))\"\n    by (simp add: result_def commitIfQuorate_def)\n\n  have nodeState': \"nodeState' = nodeState\"\n    unfolding nodeState'_def\n    by (intro ext, simp add: nd' nd_def result)\n\n  have messages': \"messages' = insert \\<lparr> sender = n\\<^sub>0, destination = Broadcast, payload = ApplyCommit (firstUncommittedSlot nd) (currentTerm nd) \\<rparr> messages\"\n    by (simp add: messages' result)\n\n  have message_simps[simp]:\n    \"\\<And>s d i t. (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t x. (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t a. (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t. (\\<langle> PublishResponse i t \\<rangle>\\<rightarrow>' d) = (\\<langle> PublishResponse i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t x. (\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow>' d) = (\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t a. (\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d) = (\\<langle> Vote i t a \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s i t. (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t x. (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t a. (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>)\"\n    \"\\<And>i t. (\\<langle> PublishResponse i t \\<rangle>\\<leadsto>') = (\\<langle> PublishResponse i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>i t x. (\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>') = (\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>)\"\n    \"\\<And>i t a. (\\<langle> Vote i t a \\<rangle>\\<leadsto>') = (\\<langle> Vote i t a \\<rangle>\\<leadsto>)\"\n    \"\\<And>s d i conf cs. (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i conf cs. (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow>' d) = (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s i conf cs. (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>)\"\n    \"\\<And>d i conf cs. (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>') = (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>)\"\n    by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,\n        auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)\n\n  have ApplyCommit': \"\\<And>s d i t. (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow>' d) = ((s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow> d)\n      \\<or> (s, i, t, d) = (n\\<^sub>0, firstUncommittedSlot nd, currentTerm nd, Broadcast))\"\n    \"\\<And>s i t. (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') = ((s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\n      \\<or> (s, i, t) = (n\\<^sub>0, firstUncommittedSlot nd, currentTerm nd))\"\n    \"\\<And>d i t. (\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow>' d) = ((\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow> d)\n      \\<or> (i, t, d) = (firstUncommittedSlot nd, currentTerm nd, Broadcast))\"\n    \"\\<And>i t. (\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') = ((\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\n      \\<or> (i, t) = (firstUncommittedSlot nd, currentTerm nd))\"\n    unfolding isMessageFromTo_def isMessageFromTo'_def isMessageFrom_def isMessageFrom'_def isMessageTo_def isMessageTo'_def isMessage_def isMessage'_def\n    by (auto simp add: messages')\n\n  from committedTo_firstUncommittedSlot\n  have committedTo_current: \"committed\\<^sub>< (firstUncommittedSlot nd)\"\n    by (simp add: nd_def)\n\n  have isCommitted_eq: \"\\<And>i. isCommitted' i = (isCommitted i \\<or> i = firstUncommittedSlot nd)\"\n    using isCommitted'_def isCommitted_def by (auto simp add: ApplyCommit')\n\n  have committedTo_eq: \"\\<And>i. committed\\<^sub><' i = ((committed\\<^sub>< i) \\<or> (i = Suc (firstUncommittedSlot nd)))\"\n  proof -\n    fix i\n    show \"?thesis i\"\n    proof (cases \"isCommitted (firstUncommittedSlot nd)\")\n      case True with isCommitted_eq have 1: \"isCommitted' = isCommitted\" by (intro ext, auto)\n      from True isCommitted_committedTo_Suc have 2: \"committed\\<^sub>< (Suc (firstUncommittedSlot nd))\" by simp\n      from 1 2 show ?thesis by (simp add: committedTo'_def committedTo_def, blast)\n    next\n      case False\n      with committedTo_current isCommitted_committedTo\n      have isCommitted_lt[simp]: \"\\<And>j. isCommitted j = (j < firstUncommittedSlot nd)\"\n        using committedTo_def nat_neq_iff by blast\n      have isCommitted'_le[simp]: \"\\<And>j. isCommitted' j = (j \\<le> firstUncommittedSlot nd)\"\n        by (auto simp add: isCommitted_eq)\n      show ?thesis\n        by (simp add: committedTo'_def committedTo_def, auto, presburger)\n    qed\n  qed\n\n  have v_eq[simp]: \"v' = v\" by (intro ext, auto simp add: v'_def v_def)\n\n  note oneSlot.consistent [OF oneSlot.commit [OF zen_is_oneSlot]]\n\n  have v\\<^sub>c_eq: \"\\<And>i. isCommitted i \\<Longrightarrow> v\\<^sub>c' i = v\\<^sub>c i\"\n  proof -\n    fix i assume \"isCommitted i\" then obtain t where t: \"\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>\" unfolding isCommitted_def by blast\n    show \"?thesis i\"\n    proof (cases \"i = firstUncommittedSlot nd\")\n      case False thus ?thesis unfolding v\\<^sub>c_def v\\<^sub>c'_def v_eq ApplyCommit' by simp\n    next\n      case i: True\n      show \"v\\<^sub>c' i = v\\<^sub>c i\"\n        unfolding v\\<^sub>c_def v\\<^sub>c'_def v_eq\n      proof (intro oneSlot.consistent [OF oneSlot.commit [OF zen_is_oneSlot]])\n        from isQuorum show \"publishVotes nd \\<in> majorities (V i)\" unfolding nd_def i isQuorum_def using currentVotingNodes_firstUncommittedSlot by simp\n        from publishVotes show \"\\<And>n. n \\<in> publishVotes nd \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse i (currentTerm nd) \\<rangle>\\<leadsto>\" unfolding nd_def i .\n        from t have \"\\<langle> ApplyCommit i (SOME t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>) \\<rangle>\\<leadsto>\" by (intro someI)\n        thus \"\\<langle> ApplyCommit i (SOME t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>) \\<rangle>\\<leadsto> \\<or> (SOME t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>) = currentTerm nd\" by simp\n        show \"\\<langle> ApplyCommit i (SOME t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') \\<rangle>\\<leadsto> \\<or> (SOME t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') = currentTerm nd\"\n        proof (rule someI2)\n          from t show \"\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>'\"\n            \"\\<And>x. \\<langle> ApplyCommit i x \\<rangle>\\<leadsto>' \\<Longrightarrow> \\<langle> ApplyCommit i x \\<rangle>\\<leadsto> \\<or> x = currentTerm nd\"\n            by (simp_all add: ApplyCommit' i)\n        qed\n      qed\n    qed\n  qed\n\n  have V_eq: \"\\<And>i. committed\\<^sub>< i \\<Longrightarrow> V' i = V i\"\n  proof -\n    fix i assume i: \"committed\\<^sub>< i\"\n    thus \"?thesis i\"\n    proof (induct i)\n      case (Suc i')\n      hence prems: \"committed\\<^sub>< i'\" \"isCommitted i'\" unfolding committedTo_def by auto\n      thus ?case using Suc v\\<^sub>c_eq by simp\n    qed simp\n  qed\n  hence V_era_eq: \"\\<And>n. V' (firstUncommittedSlot (nodeState n)) = V (firstUncommittedSlot (nodeState n))\"\n    using committedTo_firstUncommittedSlot by blast\n\n  have lastCommittedClusterStateBefore_eq: \"\\<And>i. committed\\<^sub>< i \\<Longrightarrow> lastCommittedClusterStateBefore' i = lastCommittedClusterStateBefore i\"\n  proof -\n    fix i assume \"committed\\<^sub>< i\"\n    thus \"?thesis i\"\n    proof (induct i)\n      case (Suc i')\n      hence prems: \"committed\\<^sub>< i'\" \"isCommitted i'\" unfolding committedTo_def by auto\n      thus ?case using Suc v\\<^sub>c_eq by (cases \"v\\<^sub>c i'\", simp_all)\n    qed simp\n  qed\n  hence lastCommittedClusterStateBefore_slot_eq:\n    \"\\<And>n. lastCommittedClusterStateBefore' (firstUncommittedSlot (nodeState n))\n        = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\"\n    using committedTo_firstUncommittedSlot by blast\n\n  have promised_eq[simp]: \"promised' = promised\" by (intro ext, auto simp add: promised'_def promised_def)\n  have prevAccepted_eq[simp]: \"prevAccepted' = prevAccepted\" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)\n\n  show ?thesis\n    apply (intro zenI)\n                        apply (unfold nodeState' message_simps V_era_eq lastCommittedClusterStateBefore_slot_eq promised_eq prevAccepted_eq v_eq)\n  proof -\n    from finite_messages show \"finite messages'\" by (simp add: messages')\n    from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\".\n    from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n    from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\".\n    from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n    from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n    from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n    from firstUncommittedSlot_PublishResponse show \"\\<And>n i t. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" .\n    from lastAcceptedTerm_None show \"\\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_sent show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_max show \"\\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\".\n    from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n    from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))\".\n    from joinVotes_max show \"\\<And>n n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>) \\<Longrightarrow> n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow> (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState n)\".\n    from publishVotes show \"\\<And>n n'. n' \\<in> publishVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\".\n    from currentClusterState_lastCommittedClusterStateBefore show \"\\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\".\n    from joinVotes show \"\\<And>n n'. n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))\".\n    from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n    from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))\".\n    from firstUncommittedSlot_PublishRequest show \"\\<And>i n t x. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_value show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \\<rangle>\\<leadsto>\".\n    from PublishRequest_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from PublishRequest_publishPermitted_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState n) \\<Longrightarrow> t < currentTerm (nodeState n)\".\n    from lastAcceptedTerm_Some_currentTerm show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n\n    {\n      fix i conf cs assume a: \"\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>\"\n      with CatchUpResponse_committedTo have committedTo: \"committed\\<^sub>< i\" .\n      thus \"committed\\<^sub><' i\" unfolding committedTo_eq by simp\n      from a committedTo V_eq lastCommittedClusterStateBefore_eq CatchUpResponse_V CatchUpResponse_lastCommittedClusterStateBefore\n      show \"V' i = conf\" \"lastCommittedClusterStateBefore' i = cs\" by auto\n    }\n\n    from committedTo_firstUncommittedSlot\n    show \"\\<And>n. committed\\<^sub><' (firstUncommittedSlot (nodeState n))\"\n      unfolding committedTo_eq by simp\n\n    from PublishRequest_committedTo\n    show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub><' i\"\n      unfolding committedTo_eq by simp\n\n    from PublishRequest_quorum\n    show \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V' i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\"\n      using V_eq PublishRequest_committedTo isMessage_def by metis\n\n    from ApplyCommit_quorum\n    show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto>' \\<Longrightarrow> \\<exists>q\\<in>majorities (V' i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\"\n      using V_eq committedTo_firstUncommittedSlot unfolding ApplyCommit' committedTo_def isCommitted_def\n      by (metis ApplyCommit_PublishRequest_v\\<^sub>c PublishRequest_committedTo V_eq isQuorum currentVotingNodes_firstUncommittedSlot nd_def prod.inject publishVotes isQuorum_def)\n  qed\nqed\n\nlemma (in zenStep) handlePublishResponse_invariants:\n  fixes s i t\n  defines \"result \\<equiv> handlePublishResponse s i t nd\"\n  assumes nd': \"nd' = fst result\"\n  assumes messages': \"messages' = sendTo Broadcast result\"\n  assumes sent: \"s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\"\n  shows \"zen messages' nodeState'\"\nproof (cases \"i = firstUncommittedSlot nd \\<and> t = currentTerm nd\")\n  case False\n  hence [simp]: \"result = (nd, None)\"\n    by (auto simp add: result_def handlePublishResponse_def Let_def)\n\n  have [simp]: \"messages' = messages\"\n    by (simp add: messages')\n\n  have [simp]: \"nodeState' = nodeState\"\n    unfolding nodeState'_def\n    by (intro ext, simp add: nd' nd_def)\n\n  from zen_axioms show ?thesis by simp\n\nnext\n  case True\n  hence i: \"i = firstUncommittedSlot nd\"\n    and t: \"t = currentTerm nd\"\n    by simp_all\n\n  define nd1 where \"nd1 \\<equiv> nd \\<lparr>publishVotes := insert s (publishVotes nd)\\<rparr>\"\n  define nodeState1 where \"nodeState1 \\<equiv> \\<lambda>n. if n = n\\<^sub>0 then nd1 else nodeState n\"\n\n  have result: \"result = commitIfQuorate nd1\"\n    by (simp add: result_def handlePublishResponse_def i t nd1_def)\n\n  have zenStep1: \"zenStep messages nodeState messages nodeState1 n\\<^sub>0\"\n    by (intro zenStepI2, auto simp add: nodeState1_def)\n\n  have zenStep2: \"zenStep messages nodeState1 messages' nodeState' n\\<^sub>0\"\n  proof (intro zenStep.zenStepI1 [OF zenStep1] zenStep.addPublishVote_invariants [OF zenStep1] refl messages_subset,\n      fold isMessageFromTo_def isMessageFrom_def nd_def)\n    show \"nodeState1 n\\<^sub>0 = nd\\<lparr>publishVotes := insert s (publishVotes nd)\\<rparr>\"\n      by (simp add: nodeState1_def nd1_def)\n    from sent show \"s \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot nd) (currentTerm nd) \\<rangle>\\<leadsto>\" by (simp add: True)\n    show \"\\<And>n. n \\<noteq> n\\<^sub>0 \\<Longrightarrow> nodeState1 n = nodeState' n\" unfolding nodeState1_def nodeState'_def by simp\n  qed\n\n  show ?thesis\n  proof (intro zenStep.commitIfQuorate_invariants [OF zenStep2])\n    show \"nodeState' n\\<^sub>0 = fst (commitIfQuorate (nodeState1 n\\<^sub>0))\"\n      by (simp add: nodeState'_def nd' result nodeState1_def)\n    show \"messages' = (case snd (commitIfQuorate (nodeState1 n\\<^sub>0)) of None \\<Rightarrow> messages | Some m \\<Rightarrow> insert \\<lparr>sender = n\\<^sub>0, destination = Broadcast, payload = m\\<rparr> messages)\"\n      by (cases \"commitIfQuorate (nodeState1 n\\<^sub>0)\", cases \"snd (commitIfQuorate (nodeState1 n\\<^sub>0))\",\n          simp_all add: nodeState1_def messages' result_def handlePublishResponse_def i t nd1_def)\n  qed\nqed\n\nlemma (in zenStep) handleApplyCommit_invariants:\n  assumes nd': \"nd' = handleApplyCommit i t nd\"\n  assumes messages'[simp]: \"messages' = messages\"\n  assumes sent: \"\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>\"\n  shows \"zen messages' nodeState'\"\nproof (cases \"i = firstUncommittedSlot nd \\<and> lastAcceptedTerm nd = SomeTerm t\")\n  case False\n  hence nd'[simp]: \"nd' = nd\"\n    by (auto simp add: nd' handleApplyCommit_def)\n\n  have nodeState'[simp]: \"nodeState' = nodeState\" unfolding nodeState'_def by (intro ext, simp add: nd_def)\n\n  from zen_axioms show ?thesis unfolding nodeState' by simp\n\nnext\n  case True\n  hence i: \"i = firstUncommittedSlot nd\"\n    and t: \"lastAcceptedTerm nd = SomeTerm t\" by simp_all\n\n  have message_simps[simp]:\n    \"\\<And>s p d. (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>p d. (\\<langle> p \\<rangle>\\<rightarrow>' d) = (\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s p. (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>)\"\n    \"\\<And>p. (\\<langle> p \\<rangle>\\<leadsto>') = (\\<langle> p \\<rangle>\\<leadsto>)\"\n    by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,\n        auto simp add: isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)\n\n  have v_eq[simp]: \"v' = v\" by (intro ext, auto simp add: v'_def v_def)\n  have v\\<^sub>c_eq[simp]: \"v\\<^sub>c' = v\\<^sub>c\" by (intro ext, auto simp add: v\\<^sub>c'_def v\\<^sub>c_def)\n  have isCommitted_eq[simp]: \"isCommitted' = isCommitted\" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)\n  have committedTo_eq[simp]: \"committed\\<^sub><' = committed\\<^sub><\" by (intro ext, auto simp add: committedTo'_def committedTo_def)\n  have V_eq[simp]: \"V' = V\" using v\\<^sub>c_eq V'_def V_def by blast\n  have promised_eq[simp]: \"promised' = promised\" by (intro ext, auto simp add: promised'_def promised_def)\n  have lastCommittedClusterStateBefore_eq[simp]: \"lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore\"\n    unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\\<^sub>c_eq ..\n  have prevAccepted_eq[simp]: \"prevAccepted' = prevAccepted\" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)\n\n  from sent t\n  have lastAcceptedValue_eq: \"v\\<^sub>c i = lastAcceptedValue nd\"\n    unfolding i nd_def using lastAcceptedTerm_Some_value [of n\\<^sub>0 t]\n    by (intro PublishRequest_function [OF ApplyCommit_PublishRequest_v\\<^sub>c])\n\n  show ?thesis\n  proof (cases \"isReconfiguration (v\\<^sub>c i)\")\n    case False\n\n    have \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\n      \\<and> currentTerm (nodeState' n) = currentTerm (nodeState n)\n      \\<and> currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)\n      \\<and> joinVotes (nodeState' n) = joinVotes (nodeState n)\n      \\<and> electionWon (nodeState' n) = electionWon (nodeState n)\n      \\<and> isQuorum (nodeState' n) = isQuorum (nodeState n)\"\n    proof (cases \"lastAcceptedValue nd\")\n      case NoOp thus \"\\<And>n. ?thesis n\"\n        unfolding nodeState'_def nd' handleApplyCommit_def i t applyAcceptedValue_def isQuorum_def nd_def\n        by simp\n    next\n      case ClusterStateDiff thus \"\\<And>n. ?thesis n\"\n        unfolding nodeState'_def nd' handleApplyCommit_def i t applyAcceptedValue_def isQuorum_def nd_def\n        by simp\n    next\n      case Reconfigure with False lastAcceptedValue_eq show \"\\<And>n. ?thesis n\" by simp\n    qed\n    hence property_simps[simp]:\n      \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\"\n      \"\\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)\"\n      \"\\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)\"\n      \"\\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)\"\n      \"\\<And>n. electionWon (nodeState' n) = electionWon (nodeState n)\"\n      \"\\<And>n. isQuorum (nodeState' n) = isQuorum (nodeState n)\"\n      by simp_all\n\n    have \"\\<And>n. firstUncommittedSlot (nodeState' n) = (if n = n\\<^sub>0 then Suc (firstUncommittedSlot (nodeState n)) else firstUncommittedSlot (nodeState n))\n     \\<and> publishPermitted (nodeState' n) = (publishPermitted (nodeState n) \\<or> n = n\\<^sub>0)\n     \\<and> publishVotes (nodeState' n) = (if n = n\\<^sub>0 then {} else publishVotes (nodeState n))\n     \\<and> lastAcceptedTerm (nodeState' n) = (if n = n\\<^sub>0 then NO_TERM else lastAcceptedTerm (nodeState n))\"\n    proof (cases \"lastAcceptedValue nd\")\n      case NoOp\n      with i t show \"\\<And>n. ?thesis n\"\n        by (unfold nodeState'_def, auto simp add: lastAcceptedValue_eq nd_def nd' applyAcceptedValue_def isQuorum_def handleApplyCommit_def lastAcceptedTerm_def)\n    next\n      case ClusterStateDiff\n      with i t show \"\\<And>n. ?thesis n\"\n        by (unfold nodeState'_def, auto simp add: lastAcceptedValue_eq nd_def nd' applyAcceptedValue_def isQuorum_def handleApplyCommit_def lastAcceptedTerm_def)\n    next\n      case Reconfigure with False lastAcceptedValue_eq show \"\\<And>n. ?thesis n\" by simp\n    qed\n    hence updated_properties:\n      \"\\<And>n. firstUncommittedSlot (nodeState' n) = (if n = n\\<^sub>0 then Suc (firstUncommittedSlot (nodeState n)) else firstUncommittedSlot (nodeState n)) \"\n      \"\\<And>n. publishPermitted (nodeState' n) = (publishPermitted (nodeState n) \\<or> n = n\\<^sub>0)\"\n      \"\\<And>n. publishVotes (nodeState' n) = (if n = n\\<^sub>0 then {} else publishVotes (nodeState n))\"\n      \"\\<And>n. lastAcceptedTerm (nodeState' n) = (if n = n\\<^sub>0 then NO_TERM else lastAcceptedTerm (nodeState n))\"\n      by simp_all\n\n    show ?thesis\n      apply (intro zenI)\n                          apply (unfold messages' message_simps committedTo_eq V_eq v_eq\n          lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)\n    proof -\n      from finite_messages show \"finite messages\" .\n      from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\".\n      from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n      from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n      from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n      from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\".\n      from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n      from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n      from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n      from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n      from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n      from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))\".\n      from PublishRequest_committedTo show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n      from PublishRequest_quorum show \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\".\n      from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n      from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n      from ApplyCommit_quorum show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\".\n      from CatchUpResponse_committedTo show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n      from CatchUpResponse_V show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> V i = conf\".\n      from CatchUpResponse_lastCommittedClusterStateBefore show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\".\n\n      fix n\n\n      from firstUncommittedSlot_PublishResponse show \"\\<And>i t. firstUncommittedSlot (nodeState' n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" \n        using updated_properties by (cases \"n = n\\<^sub>0\", auto)\n\n      from lastAcceptedTerm_None show \"\\<And>i t. lastAcceptedTerm (nodeState' n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \\<rangle>\\<leadsto>\"\n        using updated_properties firstUncommittedSlot_PublishResponse by (cases \"n = n\\<^sub>0\", auto)\n\n      from lastAcceptedTerm_Some_sent show \"\\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \\<rangle>\\<leadsto>\"\n        using updated_properties by (cases \"n = n\\<^sub>0\", auto)\n\n      from lastAcceptedTerm_Some_max show \"\\<And>t t'. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\"\n        using updated_properties by (cases \"n = n\\<^sub>0\", auto)\n\n      from lastAcceptedTerm_Some_value show \"\\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t (lastAcceptedValue (nodeState' n)) \\<rangle>\\<leadsto>\"\n        using updated_properties by (cases \"n = n\\<^sub>0\", auto, simp add: nodeState'_def)\n\n      from lastAcceptedTerm_Some_currentTerm show \"\\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\"\n        using updated_properties by (cases \"n = n\\<^sub>0\", auto)\n\n      from committedTo_firstUncommittedSlot show \"committed\\<^sub>< (firstUncommittedSlot (nodeState' n))\"\n        unfolding updated_properties committedTo_def apply (cases \"n = n\\<^sub>0\", auto)\n        using i isCommitted_def less_antisym nd_def sent by blast\n\n      from joinVotes_max show \"\\<And>n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>) \\<Longrightarrow> n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow> (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState' n)\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto)\n        using isMessageFromTo_def zen.Vote_slot_function zen.joinVotes zen_axioms by fastforce\n\n      from publishVotes show \"\\<And>n'. n' \\<in> publishVotes (nodeState' n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto) done\n\n      from joinVotes show \"\\<And>n'. n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState' n)) n' n (currentTerm (nodeState n))\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto)\n        by (meson le_SucI promised_def)\n\n      from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState' n))\"\n        unfolding updated_properties using False i nd_def by (cases \"n = n\\<^sub>0\", auto)\n\n      from firstUncommittedSlot_PublishRequest show \"\\<And>i t x. firstUncommittedSlot (nodeState' n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto) done\n\n      from PublishRequest_currentTerm show \"\\<And>t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto simp add: firstUncommittedSlot_PublishRequest) done\n\n      from PublishRequest_publishPermitted_currentTerm show \"\\<And>t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState' n) \\<Longrightarrow> t < currentTerm (nodeState n)\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto simp add: firstUncommittedSlot_PublishRequest) done\n\n      from currentClusterState_lastCommittedClusterStateBefore\n      show \"currentClusterState (nodeState' n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState' n))\"\n      proof (cases \"n = n\\<^sub>0\")\n        case False with currentClusterState_lastCommittedClusterStateBefore\n        show ?thesis unfolding nodeState'_def by auto\n      next\n        case True\n        show ?thesis\n        proof (cases \"v\\<^sub>c i\")\n          case NoOp\n          with currentClusterState_lastCommittedClusterStateBefore True lastAcceptedValue_eq i t\n          show ?thesis\n            unfolding nodeState'_def\n            by (simp add: nd' nd_def applyAcceptedValue_def handleApplyCommit_def)\n        next\n          case Reconfigure with False show ?thesis by simp\n        next\n          case (ClusterStateDiff diff)\n          with lastAcceptedValue_eq have \"lastAcceptedValue nd = ClusterStateDiff diff\" by simp\n          with ClusterStateDiff True i t currentClusterState_lastCommittedClusterStateBefore\n          show ?thesis\n            unfolding nodeState'_def\n            by (simp add: nd' nd_def applyAcceptedValue_def handleApplyCommit_def)\n        qed\n      qed\n    qed\n\n  next\n    case True\n    then obtain newConfig where Reconfigure: \"v\\<^sub>c i = Reconfigure newConfig\" by (cases \"v\\<^sub>c i\", auto)\n    with lastAcceptedValue_eq have lastAcceptedValue_eq: \"lastAcceptedValue nd = Reconfigure newConfig\" by simp\n\n    hence property_simps[simp]:\n      \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\"\n      \"\\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)\"\n      \"\\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)\"\n      \"\\<And>n. joinVotes (nodeState' n) = joinVotes (nodeState n)\"\n      unfolding nodeState'_def by (auto simp add: nd' handleApplyCommit_def applyAcceptedValue_def nd_def\n          lastAcceptedTerm_def firstUncommittedSlot_def lastAcceptedValue_def)\n\n    have updated_properties:\n      \"\\<And>n. firstUncommittedSlot (nodeState' n) = (if n = n\\<^sub>0 then Suc (firstUncommittedSlot (nodeState n)) else firstUncommittedSlot (nodeState n)) \"\n      \"\\<And>n. publishPermitted (nodeState' n) = (publishPermitted (nodeState n) \\<or> n = n\\<^sub>0)\"\n      \"\\<And>n. publishVotes (nodeState' n) = (if n = n\\<^sub>0 then {} else publishVotes (nodeState n))\"\n      \"\\<And>n. currentVotingNodes (nodeState' n) = (if n = n\\<^sub>0 then set newConfig else currentVotingNodes (nodeState n))\"\n      \"\\<And>n. electionWon (nodeState' n) = (if n = n\\<^sub>0 then joinVotes nd \\<in> majorities (set newConfig) else electionWon (nodeState n))\"\n      \"\\<And>n. isQuorum (nodeState' n) = (if n = n\\<^sub>0 then (\\<lambda>q. q \\<in> majorities (set newConfig)) else isQuorum (nodeState n))\"\n      \"\\<And>n. currentVotingNodes (nodeState' n) = (if n = n\\<^sub>0 then set newConfig else currentVotingNodes (nodeState n))\"\n      \"\\<And>n. lastAcceptedTerm (nodeState' n) = (if n = n\\<^sub>0 then NO_TERM else lastAcceptedTerm (nodeState n))\"\n      \"\\<And>n. n \\<noteq> n\\<^sub>0 \\<Longrightarrow> lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)\"\n      unfolding nodeState'_def using i t lastAcceptedValue_eq\n      by (auto simp add: nd' handleApplyCommit_def applyAcceptedValue_def nd_def isQuorum_def lastAcceptedTerm_def)\n\n    show ?thesis\n      apply (intro zenI)\n                          apply (unfold messages' message_simps committedTo_eq V_eq v_eq\n          lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)\n    proof -\n      from finite_messages show \"finite messages\" .\n      from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\".\n      from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n      from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n      from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n      from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\".\n      from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n      from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n      from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n      from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n      from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n      from PublishRequest_committedTo show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n      from PublishRequest_quorum show \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\".\n      from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n      from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n      from ApplyCommit_quorum show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\".\n      from CatchUpResponse_committedTo show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n      from CatchUpResponse_V show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> V i = conf\".\n      from CatchUpResponse_lastCommittedClusterStateBefore show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\".\n\n      fix n\n\n      from firstUncommittedSlot_PublishResponse show \"\\<And>i t. firstUncommittedSlot (nodeState' n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\"\n        using updated_properties by (cases \"n = n\\<^sub>0\", auto)\n\n      from lastAcceptedTerm_None show \"\\<And>i t. lastAcceptedTerm (nodeState' n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \\<rangle>\\<leadsto>\"\n        using updated_properties firstUncommittedSlot_PublishResponse by (cases \"n = n\\<^sub>0\", auto)\n\n      from lastAcceptedTerm_Some_sent show \"\\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \\<rangle>\\<leadsto>\"\n        using updated_properties by (cases \"n = n\\<^sub>0\", auto)\n\n      from lastAcceptedTerm_Some_max show \"\\<And>t t'. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\"\n        using updated_properties by (cases \"n = n\\<^sub>0\", auto)\n\n      from lastAcceptedTerm_Some_value show \"\\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t (lastAcceptedValue (nodeState' n)) \\<rangle>\\<leadsto>\"\n        using updated_properties by (cases \"n = n\\<^sub>0\", auto)\n\n      from committedTo_firstUncommittedSlot show \"committed\\<^sub>< (firstUncommittedSlot (nodeState' n))\"\n        unfolding updated_properties committedTo_def apply (cases \"n = n\\<^sub>0\", auto)\n        using i isCommitted_def less_antisym nd_def sent by blast\n\n      from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState' n) \\<Longrightarrow> isQuorum (nodeState' n) (joinVotes (nodeState n))\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto simp add: nd_def) done\n\n      from joinVotes_max show \"\\<And>n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>) \\<Longrightarrow> n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow> (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState' n)\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto)\n        using isMessageFromTo_def zen.Vote_slot_function zen.joinVotes zen_axioms by fastforce\n\n      from publishVotes show \"\\<And>n'. n' \\<in> publishVotes (nodeState' n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto) done\n\n      from joinVotes show \"\\<And>n'. n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState' n)) n' n (currentTerm (nodeState n))\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto)\n        by (meson le_SucI promised_def)\n\n      from firstUncommittedSlot_PublishRequest show \"\\<And>i t x. firstUncommittedSlot (nodeState' n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto) done\n\n      from PublishRequest_currentTerm show \"\\<And>t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto simp add: firstUncommittedSlot_PublishRequest) done\n\n      from PublishRequest_publishPermitted_currentTerm show \"\\<And>t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState' n) \\<Longrightarrow> t < currentTerm (nodeState n)\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto simp add: firstUncommittedSlot_PublishRequest) done\n\n      from currentClusterState_lastCommittedClusterStateBefore Reconfigure i nd_def\n      show \"currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState' n))\"\n        unfolding updated_properties committedTo_def by (cases \"n = n\\<^sub>0\", auto)\n\n      from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState' n) = V (firstUncommittedSlot (nodeState' n))\"\n        unfolding updated_properties committedTo_def using Reconfigure i nd_def by (cases \"n = n\\<^sub>0\", auto)\n\n      from lastAcceptedTerm_Some_currentTerm show \"\\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\"\n        unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto) done\n    qed\n  qed\nqed\n\nlemma (in zenStep) handleCatchUpRequest_invariants:\n  fixes s i t\n  defines \"result \\<equiv> handleCatchUpRequest nd\"\n  assumes nd': \"nd' = fst result\"\n  assumes messages': \"messages' = sendTo d\\<^sub>0 result\"\n  shows \"zen messages' nodeState'\"\nproof -\n\n  have result: \"result = (nd, Some (CatchUpResponse (firstUncommittedSlot nd) (currentVotingNodes nd) (currentClusterState nd)))\"\n    by (simp add: result_def handleCatchUpRequest_def)\n\n  have nd'[simp]: \"nd' = nd\" by (simp add: nd' result)\n  have nodeState'[simp]: \"nodeState' = nodeState\" by (intro ext, simp add: nodeState'_def result nd_def)\n\n  have messages': \"messages' = insert \\<lparr> sender = n\\<^sub>0, destination = d\\<^sub>0, payload = CatchUpResponse (firstUncommittedSlot nd) (currentVotingNodes nd) (currentClusterState nd) \\<rparr> messages\"\n    by (simp add: messages' result)\n\n  have message_simps[simp]:\n    \"\\<And>s d i t. (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t. (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t x. (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s d i t a. (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t. (\\<langle> PublishResponse i t \\<rangle>\\<rightarrow>' d) = (\\<langle> PublishResponse i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t. (\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow>' d) = (\\<langle> ApplyCommit i t \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t x. (\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow>' d) = (\\<langle> PublishRequest i t x \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>d i t a. (\\<langle> Vote i t a \\<rangle>\\<rightarrow>' d) = (\\<langle> Vote i t a \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s i t. (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t. (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t x. (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>)\"\n    \"\\<And>s i t a. (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto>)\"\n    \"\\<And>i t. (\\<langle> PublishResponse i t \\<rangle>\\<leadsto>') = (\\<langle> PublishResponse i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>i t. (\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>') = (\\<langle> ApplyCommit i t \\<rangle>\\<leadsto>)\"\n    \"\\<And>i t x. (\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>') = (\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>)\"\n    \"\\<And>i t a. (\\<langle> Vote i t a \\<rangle>\\<leadsto>') = (\\<langle> Vote i t a \\<rangle>\\<leadsto>)\"\n    by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,\n        auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)\n\n  have CatchUpResponse':\n    \"\\<And>s d i conf cs. (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow> d\n      \\<or> (s, i, conf, cs, d) = (n\\<^sub>0, firstUncommittedSlot nd, currentVotingNodes nd, currentClusterState nd, d\\<^sub>0))\"\n    \"\\<And>d i conf cs. (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow>' d) = (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<rightarrow> d\n      \\<or> (i, conf, cs, d) = (firstUncommittedSlot nd, currentVotingNodes nd, currentClusterState nd, d\\<^sub>0))\"\n    \"\\<And>s i conf cs. (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>\n      \\<or> (s, i, conf, cs) = (n\\<^sub>0, firstUncommittedSlot nd, currentVotingNodes nd, currentClusterState nd))\"\n    \"\\<And>i conf cs. (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>') = (\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>\n      \\<or> (i, conf, cs) = (firstUncommittedSlot nd, currentVotingNodes nd, currentClusterState nd))\"\n    unfolding isMessageFromTo_def isMessageFromTo'_def isMessageFrom_def isMessageFrom'_def isMessageTo_def isMessageTo'_def isMessage_def isMessage'_def\n    by (auto simp add: messages')\n\n  have v_eq[simp]: \"v' = v\" by (intro ext, auto simp add: v'_def v_def)\n  have v\\<^sub>c_eq[simp]: \"v\\<^sub>c' = v\\<^sub>c\" by (intro ext, auto simp add: v\\<^sub>c'_def v\\<^sub>c_def)\n  have isCommitted_eq[simp]: \"isCommitted' = isCommitted\" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)\n  have committedTo_eq[simp]: \"committed\\<^sub><' = committed\\<^sub><\" by (intro ext, auto simp add: committedTo'_def committedTo_def)\n  have V_eq[simp]: \"V' = V\" using v\\<^sub>c_eq V'_def V_def by blast\n  have promised_eq[simp]: \"promised' = promised\" by (intro ext, auto simp add: promised'_def promised_def)\n  have lastCommittedClusterStateBefore_eq[simp]: \"lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore\"\n    unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\\<^sub>c_eq ..\n  have prevAccepted_eq[simp]: \"prevAccepted' = prevAccepted\" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)\n\n  show ?thesis\n    apply (intro zenI)\n                        apply (unfold message_simps committedTo_eq V_eq v_eq\n        lastCommittedClusterStateBefore_eq promised_eq prevAccepted_eq nodeState')\n  proof -\n    from finite_messages show \"finite messages'\" by (simp add: messages')\n    from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\".\n    from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n    from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\".\n    from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n    from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n    from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n    from committedTo_firstUncommittedSlot show \"\\<And>n. committed\\<^sub>< (firstUncommittedSlot (nodeState n))\" .\n    from firstUncommittedSlot_PublishResponse show \"\\<And>n i t. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" .\n    from lastAcceptedTerm_None show \"\\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_sent show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_max show \"\\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\".\n    from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n    from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState n))\".\n    from joinVotes_max show \"\\<And>n n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>) \\<Longrightarrow> n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow> (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState n)\".\n    from publishVotes show \"\\<And>n n'. n' \\<in> publishVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\".\n    from currentClusterState_lastCommittedClusterStateBefore show \"\\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\".\n    from joinVotes show \"\\<And>n n'. n' \\<in> joinVotes (nodeState n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))\".\n    from PublishRequest_committedTo show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from PublishRequest_quorum show \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\".\n    from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n    from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from ApplyCommit_quorum show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\".\n    from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))\".\n    from firstUncommittedSlot_PublishRequest show \"\\<And>i n t x. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_value show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \\<rangle>\\<leadsto>\".\n    from PublishRequest_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from PublishRequest_publishPermitted_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState n) \\<Longrightarrow> t < currentTerm (nodeState n)\".\n    from lastAcceptedTerm_Some_currentTerm show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n\n    from CatchUpResponse_committedTo committedTo_firstUncommittedSlot\n    show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>' \\<Longrightarrow> committed\\<^sub>< i\"\n      unfolding CatchUpResponse' nd_def by blast\n\n    from CatchUpResponse_V currentVotingNodes_firstUncommittedSlot\n    show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>' \\<Longrightarrow> V i = conf\"\n      unfolding CatchUpResponse' nd_def isQuorum_def by auto\n\n    from CatchUpResponse_lastCommittedClusterStateBefore currentClusterState_lastCommittedClusterStateBefore\n    show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>' \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\"\n      unfolding CatchUpResponse' nd_def by auto\n  qed\nqed\n\n\nlemma (in zenStep) handleCatchUpResponse_invariants:\n  assumes nd': \"nd' = handleCatchUpResponse i conf cs nd\"\n  assumes messages'[simp]: \"messages' = messages\"\n  assumes sent: \"\\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto>\"\n  shows \"zen messages' nodeState'\"\nproof (cases \"firstUncommittedSlot nd < i\")\n  case False\n  hence nd'[simp]: \"nd' = nd\"\n    by (auto simp add: nd' handleCatchUpResponse_def)\n\n  have nodeState'[simp]: \"nodeState' = nodeState\" unfolding nodeState'_def by (intro ext, simp add: nd_def)\n\n  from zen_axioms show ?thesis unfolding nodeState' by simp\n\nnext\n  case True\n\n  hence nd': \"nd' = nd \\<lparr> firstUncommittedSlot := i\n                , publishPermitted := True\n                , publishVotes := {}\n                , currentVotingNodes := conf\n                , currentClusterState := cs\n                , joinVotes := {}\n                , electionWon := False\n                , lastAcceptedData := None \\<rparr>\"\n    by (simp add: nd', simp add: handleCatchUpResponse_def)\n\n  have message_simps[simp]:\n    \"\\<And>s p d. (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>p d. (\\<langle> p \\<rangle>\\<rightarrow>' d) = (\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s p. (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>)\"\n    \"\\<And>p. (\\<langle> p \\<rangle>\\<leadsto>') = (\\<langle> p \\<rangle>\\<leadsto>)\"\n    by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,\n        auto simp add: isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)\n\n  have v_eq[simp]: \"v' = v\" by (intro ext, auto simp add: v'_def v_def)\n  have v\\<^sub>c_eq[simp]: \"v\\<^sub>c' = v\\<^sub>c\" by (intro ext, auto simp add: v\\<^sub>c'_def v\\<^sub>c_def)\n  have isCommitted_eq[simp]: \"isCommitted' = isCommitted\" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)\n  have committedTo_eq[simp]: \"committed\\<^sub><' = committed\\<^sub><\" by (intro ext, auto simp add: committedTo'_def committedTo_def)\n  have V_eq[simp]: \"V' = V\" using v\\<^sub>c_eq V'_def V_def by blast\n  have promised_eq[simp]: \"promised' = promised\" by (intro ext, auto simp add: promised'_def promised_def)\n  have lastCommittedClusterStateBefore_eq[simp]: \"lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore\"\n    unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\\<^sub>c_eq ..\n  have prevAccepted_eq[simp]: \"prevAccepted' = prevAccepted\" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)\n\n  have property_simps[simp]:\n    \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\"\n    \"\\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)\"\n    unfolding nodeState'_def by (auto simp add: nd' nd_def lastAcceptedTerm_def firstUncommittedSlot_def lastAcceptedValue_def)\n\n  have updated_properties:\n    \"\\<And>n. firstUncommittedSlot (nodeState' n) = (if n = n\\<^sub>0 then i else firstUncommittedSlot (nodeState n)) \"\n    \"\\<And>n. publishPermitted (nodeState' n) = (publishPermitted (nodeState n) \\<or> n = n\\<^sub>0)\"\n    \"\\<And>n. publishVotes (nodeState' n) = (if n = n\\<^sub>0 then {} else publishVotes (nodeState n))\"\n    \"\\<And>n. currentVotingNodes (nodeState' n) = (if n = n\\<^sub>0 then conf else currentVotingNodes (nodeState n))\"\n    \"\\<And>n. joinVotes (nodeState' n) = (if n = n\\<^sub>0 then {} else joinVotes (nodeState n))\"\n    \"\\<And>n. electionWon (nodeState' n) = (electionWon (nodeState n) \\<and> n \\<noteq> n\\<^sub>0)\"\n    \"\\<And>n. currentVotingNodes (nodeState' n) = (if n = n\\<^sub>0 then conf else currentVotingNodes (nodeState n))\"\n    \"\\<And>n. isQuorum (nodeState' n) = (if n = n\\<^sub>0 then (\\<lambda>q. q \\<in> majorities conf) else isQuorum (nodeState n))\"\n    \"\\<And>n. currentClusterState (nodeState' n) = (if n = n\\<^sub>0 then cs else currentClusterState (nodeState n))\"\n    unfolding nodeState'_def\n    by (auto simp add: nd' nd_def isQuorum_def)\n\n  have \"\\<And>n. lastAcceptedTerm (nodeState' n) = (if n = n\\<^sub>0 then NO_TERM else lastAcceptedTerm (nodeState n))\"\n    using True unfolding lastAcceptedTerm_def updated_properties property_simps nd_def\n    using not_le by (simp add: nodeState'_def nd')\n  note updated_properties = updated_properties this\n\n  show ?thesis\n    apply (intro zenI)\n                        apply (unfold messages' message_simps committedTo_eq V_eq v_eq\n        lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)\n  proof -\n    from finite_messages show \"finite messages\" .\n    from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\".\n    from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n    from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\".\n    from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n    from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n    from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n    from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n    from PublishRequest_committedTo show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from PublishRequest_quorum show \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\".\n    from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n    from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from ApplyCommit_quorum show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\".\n    from CatchUpResponse_committedTo show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from CatchUpResponse_V show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> V i = conf\".\n    from CatchUpResponse_lastCommittedClusterStateBefore show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\".\n\n    from committedTo_firstUncommittedSlot show \"\\<And>n. committed\\<^sub>< (firstUncommittedSlot (nodeState' n))\"\n      unfolding updated_properties apply auto\n      using CatchUpResponse_committedTo sent by blast\n\n    from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState' n) \\<Longrightarrow> isQuorum (nodeState' n) (joinVotes (nodeState' n))\"\n      unfolding updated_properties apply auto done\n\n    from joinVotes_max show \"\\<And>n n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>) \\<Longrightarrow> n' \\<in> joinVotes (nodeState' n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow> (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState' n)\"\n      unfolding updated_properties apply auto done\n\n    from publishVotes show \"\\<And>n n'. n' \\<in> publishVotes (nodeState' n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\"\n      unfolding updated_properties apply auto done\n\n    from joinVotes show \"\\<And>n n'. n' \\<in> joinVotes (nodeState' n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState' n)) n' n (currentTerm (nodeState n))\"\n      unfolding updated_properties apply auto done\n\n    fix n\n\n    from firstUncommittedSlot_PublishRequest show \"\\<And>i t x. firstUncommittedSlot (nodeState' n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\"\n      unfolding updated_properties using True nd_def by (cases \"n = n\\<^sub>0\", auto)\n\n    from PublishRequest_currentTerm show \"\\<And>t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\"\n      unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto)\n      using True firstUncommittedSlot_PublishRequest nd_def by blast\n\n    from PublishRequest_publishPermitted_currentTerm show \"\\<And>t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState' n) \\<Longrightarrow> t < currentTerm (nodeState n)\"\n      unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto)\n      using True firstUncommittedSlot_PublishRequest nd_def by blast\n\n    from currentClusterState_lastCommittedClusterStateBefore show \"currentClusterState (nodeState' n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState' n))\"\n      unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto)\n      using CatchUpResponse_lastCommittedClusterStateBefore sent by blast\n\n    from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState' n) = V (firstUncommittedSlot (nodeState' n))\"\n      unfolding updated_properties using CatchUpResponse_V sent by (cases \"n = n\\<^sub>0\", auto)\n\n    from firstUncommittedSlot_PublishResponse show \"\\<And>i t. firstUncommittedSlot (nodeState' n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" \n      unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto)\n      using True dual_order.strict_trans nd_def by blast\n\n    from lastAcceptedTerm_None show \"\\<And>i t. lastAcceptedTerm (nodeState' n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \\<rangle>\\<leadsto>\"\n      unfolding updated_properties apply (cases \"n = n\\<^sub>0\", auto)\n      using True firstUncommittedSlot_PublishResponse nd_def by blast\n\n    from lastAcceptedTerm_Some_sent show \"\\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t \\<rangle>\\<leadsto>\"\n      unfolding updated_properties by (cases \"n = n\\<^sub>0\", auto)\n\n    from lastAcceptedTerm_Some_max show \"\\<And>t t'. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState' n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\" \n      unfolding updated_properties by (cases \"n = n\\<^sub>0\", auto)\n\n    from lastAcceptedTerm_Some_value show \"\\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState' n)) t (lastAcceptedValue (nodeState' n)) \\<rangle>\\<leadsto>\" \n      unfolding updated_properties lastAcceptedValue_def by (cases \"n = n\\<^sub>0\", auto simp add: nodeState'_def)\n\n    from lastAcceptedTerm_Some_currentTerm show \"\\<And>t. lastAcceptedTerm (nodeState' n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\" \n      unfolding updated_properties by (cases \"n = n\\<^sub>0\", auto)\n  qed\nqed\n\nlemma (in zenStep) handleDiscardJoinVotes_invariants:\n  assumes nd': \"nd' = handleDiscardJoinVotes nd\"\n  assumes messages': \"messages' = messages\"\n  shows \"zen messages' nodeState'\"\nproof -\n  have message_simps[simp]:\n    \"\\<And>s p d. (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>p d. (\\<langle> p \\<rangle>\\<rightarrow>' d) = (\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s p. (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>)\"\n    \"\\<And>p. (\\<langle> p \\<rangle>\\<leadsto>') = (\\<langle> p \\<rangle>\\<leadsto>)\"\n    by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,\n        auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)\n\n  have property_simps[simp]:\n    \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\"\n    \"\\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)\"\n    \"\\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)\"\n    \"\\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q\"\n    \"\\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)\"\n    \"\\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)\"\n    \"\\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)\"\n    \"\\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)\"\n    \"\\<And>n. publishPermitted (nodeState' n) = publishPermitted (nodeState n)\"\n    \"\\<And>n. publishVotes (nodeState' n) = publishVotes (nodeState n)\"\n    by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' handleDiscardJoinVotes_def Let_def\n        lastAcceptedValue_def lastAcceptedTerm_def)\n\n  have updated_properties:\n    \"\\<And>n. joinVotes (nodeState' n) = (if n = n\\<^sub>0 then {} else joinVotes (nodeState n))\"\n    \"\\<And>n. electionWon (nodeState' n) = (electionWon (nodeState n) \\<and> n \\<noteq> n\\<^sub>0)\"\n    by (unfold nodeState'_def, auto simp add: nd' nd_def handleDiscardJoinVotes_def)\n\n  have v_eq[simp]: \"v' = v\" by (intro ext, auto simp add: v'_def v_def)\n  have v\\<^sub>c_eq[simp]: \"v\\<^sub>c' = v\\<^sub>c\" by (intro ext, auto simp add: v\\<^sub>c'_def v\\<^sub>c_def)\n  have isCommitted_eq[simp]: \"isCommitted' = isCommitted\" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)\n  have committedTo_eq[simp]: \"committed\\<^sub><' = committed\\<^sub><\" by (intro ext, auto simp add: committedTo'_def committedTo_def)\n  have V_eq[simp]: \"V' = V\" using v\\<^sub>c_eq V'_def V_def by blast\n  have promised_eq[simp]: \"promised' = promised\" by (intro ext, auto simp add: promised'_def promised_def)\n  have lastCommittedClusterStateBefore_eq[simp]: \"lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore\"\n    unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\\<^sub>c_eq ..\n  have prevAccepted_eq[simp]: \"prevAccepted' = prevAccepted\" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)\n\n  show ?thesis\n    apply (intro zenI)\n                        apply (unfold message_simps committedTo_eq V_eq v_eq\n        lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)\n  proof -\n    from finite_messages show \"finite messages'\" by (simp add: messages')\n    from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\".\n    from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n    from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\".\n    from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n    from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n    from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n    from committedTo_firstUncommittedSlot show \"\\<And>n. committed\\<^sub>< (firstUncommittedSlot (nodeState n))\" .\n    from firstUncommittedSlot_PublishResponse show \"\\<And>n i t. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" .\n    from lastAcceptedTerm_None show \"\\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_sent show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\" .\n    from lastAcceptedTerm_Some_max show \"\\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\" .\n    from lastAcceptedTerm_Some_value show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \\<rangle>\\<leadsto>\" .\n    from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n    from currentClusterState_lastCommittedClusterStateBefore show \"\\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\".\n    from PublishRequest_committedTo show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from PublishRequest_quorum show \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\".\n    from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n    from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from ApplyCommit_quorum show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\".\n    from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))\".\n    from firstUncommittedSlot_PublishRequest show \"\\<And>i n t x. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from PublishRequest_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from CatchUpResponse_committedTo show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from CatchUpResponse_V show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> V i = conf\".\n    from CatchUpResponse_lastCommittedClusterStateBefore show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\".\n    from lastAcceptedTerm_Some_currentTerm show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from PublishRequest_publishPermitted_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState n) \\<Longrightarrow> t < currentTerm (nodeState n)\".\n    from publishVotes show \"\\<And>n n'. n' \\<in> publishVotes (nodeState n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\".\n\n    from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState' n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState' n))\"\n      unfolding updated_properties by simp\n\n    fix n\n\n    from joinVotes show \"\\<And>n'. n' \\<in> joinVotes (nodeState' n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))\"\n      unfolding updated_properties by (cases \"n = n\\<^sub>0\", simp_all)\n    from joinVotes_max show \"\\<And>n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>) \\<Longrightarrow> n' \\<in> joinVotes (nodeState' n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow> (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState n)\"\n      unfolding updated_properties by (cases \"n = n\\<^sub>0\", simp_all)\n  qed\nqed\n\nlemma (in zenStep) handleReboot_invariants:\n  assumes nd': \"nd' = handleReboot nd\"\n  assumes messages': \"messages' = messages\"\n  shows \"zen messages' nodeState'\"\nproof -\n  have message_simps[simp]:\n    \"\\<And>s p d. (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow>' d) = (s \\<midarrow>\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>p d. (\\<langle> p \\<rangle>\\<rightarrow>' d) = (\\<langle> p \\<rangle>\\<rightarrow> d)\"\n    \"\\<And>s p. (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>') = (s \\<midarrow>\\<langle> p \\<rangle>\\<leadsto>)\"\n    \"\\<And>p. (\\<langle> p \\<rangle>\\<leadsto>') = (\\<langle> p \\<rangle>\\<leadsto>)\"\n    by (unfold isMessageFromTo'_def isMessageTo'_def isMessageFrom'_def isMessage'_def,\n        auto simp add: messages' isMessageFromTo_def isMessageTo_def isMessageFrom_def isMessage_def)\n\n  have property_simps[simp]:\n    \"\\<And>n. currentNode (nodeState' n) = currentNode (nodeState n)\"\n    \"\\<And>n. firstUncommittedSlot (nodeState' n) = firstUncommittedSlot (nodeState n)\"\n    \"\\<And>n. currentVotingNodes (nodeState' n) = currentVotingNodes (nodeState n)\"\n    \"\\<And>n q. isQuorum (nodeState' n) q = isQuorum (nodeState n) q\"\n    \"\\<And>n. lastAcceptedTerm (nodeState' n) = lastAcceptedTerm (nodeState n)\"\n    \"\\<And>n. lastAcceptedValue (nodeState' n) = lastAcceptedValue (nodeState n)\"\n    \"\\<And>n. currentTerm (nodeState' n) = currentTerm (nodeState n)\"\n    \"\\<And>n. currentClusterState (nodeState' n) = currentClusterState (nodeState n)\"\n    by (unfold nodeState'_def, auto simp add: nd_def isQuorum_def nd' handleReboot_def Let_def\n        lastAcceptedValue_def lastAcceptedTerm_def)\n\n  have updated_properties:\n    \"\\<And>n. publishPermitted (nodeState' n) = (publishPermitted (nodeState n) \\<and> n \\<noteq> n\\<^sub>0)\"\n    \"\\<And>n. joinVotes (nodeState' n) = (if n = n\\<^sub>0 then {} else joinVotes (nodeState n))\"\n    \"\\<And>n. electionWon (nodeState' n) = (electionWon (nodeState n) \\<and> n \\<noteq> n\\<^sub>0)\"\n    \"\\<And>n. publishVotes (nodeState' n) = (if n = n\\<^sub>0 then {} else publishVotes (nodeState n))\"\n    by (unfold nodeState'_def, auto simp add: nd' nd_def handleReboot_def)\n\n  have v_eq[simp]: \"v' = v\" by (intro ext, auto simp add: v'_def v_def)\n  have v\\<^sub>c_eq[simp]: \"v\\<^sub>c' = v\\<^sub>c\" by (intro ext, auto simp add: v\\<^sub>c'_def v\\<^sub>c_def)\n  have isCommitted_eq[simp]: \"isCommitted' = isCommitted\" by (intro ext, auto simp add: isCommitted'_def isCommitted_def)\n  have committedTo_eq[simp]: \"committed\\<^sub><' = committed\\<^sub><\" by (intro ext, auto simp add: committedTo'_def committedTo_def)\n  have V_eq[simp]: \"V' = V\" using v\\<^sub>c_eq V'_def V_def by blast\n  have promised_eq[simp]: \"promised' = promised\" by (intro ext, auto simp add: promised'_def promised_def)\n  have lastCommittedClusterStateBefore_eq[simp]: \"lastCommittedClusterStateBefore' = lastCommittedClusterStateBefore\"\n    unfolding lastCommittedClusterStateBefore_def lastCommittedClusterStateBefore'_def v\\<^sub>c_eq ..\n  have prevAccepted_eq[simp]: \"prevAccepted' = prevAccepted\" by (intro ext, auto simp add: prevAccepted'_def prevAccepted_def)\n\n  show ?thesis\n    apply (intro zenI)\n                        apply (unfold message_simps committedTo_eq V_eq v_eq\n        lastCommittedClusterStateBefore_eq property_simps promised_eq prevAccepted_eq)\n  proof -\n    from finite_messages show \"finite messages'\" by (simp add: messages')\n    from Vote_future show \"\\<And>i i' s t t' a. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> i < i' \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i' t' \\<rangle>\\<leadsto>\".\n    from Vote_None show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t NO_TERM \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_lt show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t\".\n    from Vote_Some_PublishResponse show \"\\<And>i s t t'. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> s \\<midarrow>\\<langle> PublishResponse i t' \\<rangle>\\<leadsto>\".\n    from Vote_Some_max show \"\\<And>i s t t' t''. s \\<midarrow>\\<langle> Vote i t (SomeTerm t') \\<rangle>\\<leadsto> \\<Longrightarrow> t' < t'' \\<Longrightarrow> t'' < t \\<Longrightarrow> \\<not> s \\<midarrow>\\<langle> PublishResponse i t'' \\<rangle>\\<leadsto>\".\n    from Vote_not_broadcast show \"\\<And>i t a d. \\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> d \\<noteq> Broadcast\".\n    from Vote_unique_destination show \"\\<And>i' i s t a a' d d'. s \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> d \\<Longrightarrow> s \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<rightarrow> d' \\<Longrightarrow> d = d'\".\n    from currentNode_nodeState show \"\\<And>n. currentNode (nodeState n) = n\" .\n    from committedTo_firstUncommittedSlot show \"\\<And>n. committed\\<^sub>< (firstUncommittedSlot (nodeState n))\" .\n    from firstUncommittedSlot_PublishResponse show \"\\<And>n i t. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\" .\n    from lastAcceptedTerm_None show \"\\<And>n i t. lastAcceptedTerm (nodeState n) = NO_TERM \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\".\n    from lastAcceptedTerm_Some_sent show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t \\<rangle>\\<leadsto>\" .\n    from lastAcceptedTerm_Some_max show \"\\<And>n t t'. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> n \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) t' \\<rangle>\\<leadsto> \\<Longrightarrow> t' \\<le> t\" .\n    from lastAcceptedTerm_Some_value show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t (lastAcceptedValue (nodeState n)) \\<rangle>\\<leadsto>\" .\n    from Vote_currentTerm show \"\\<And>n i t a. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from Vote_slot_function show \"\\<And>n i i' t a a'. n \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<leadsto> \\<Longrightarrow> n \\<midarrow>\\<langle> Vote i' t a' \\<rangle>\\<leadsto> \\<Longrightarrow> i = i'\".\n    from currentClusterState_lastCommittedClusterStateBefore show \"\\<And>n. currentClusterState (nodeState n) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n))\".\n    from PublishRequest_committedTo show \"\\<And>i t x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from PublishRequest_quorum show \"\\<And>i s t x. s \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). (\\<forall>n\\<in>q. promised i n s t) \\<and> (prevAccepted i t q = {} \\<or> (\\<exists>t'. v i t = v i t' \\<and> maxTerm (prevAccepted i t q) \\<le> t' \\<and> \\<langle> PublishResponse i t' \\<rangle>\\<leadsto> \\<and> t' < t))\".\n    from PublishRequest_function show \"\\<And>i t x x'. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto> \\<Longrightarrow> \\<langle> PublishRequest i t x' \\<rangle>\\<leadsto> \\<Longrightarrow> x = x'\".\n    from PublishResponse_PublishRequest show \"\\<And>i s t. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>x. \\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from ApplyCommit_quorum show \"\\<And>i t. \\<langle> ApplyCommit i t \\<rangle>\\<leadsto> \\<Longrightarrow> \\<exists>q\\<in>majorities (V i). \\<forall>s\\<in>q. s \\<midarrow>\\<langle> PublishResponse i t \\<rangle>\\<leadsto>\".\n    from currentVotingNodes_firstUncommittedSlot show \"\\<And>n. currentVotingNodes (nodeState n) = V (firstUncommittedSlot (nodeState n))\".\n    from firstUncommittedSlot_PublishRequest show \"\\<And>i n t x. firstUncommittedSlot (nodeState n) < i \\<Longrightarrow> \\<not> n \\<midarrow>\\<langle> PublishRequest i t x \\<rangle>\\<leadsto>\".\n    from PublishRequest_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n    from CatchUpResponse_committedTo show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> committed\\<^sub>< i\".\n    from CatchUpResponse_V show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> V i = conf\".\n    from CatchUpResponse_lastCommittedClusterStateBefore show \"\\<And>i conf cs. \\<langle> CatchUpResponse i conf cs \\<rangle>\\<leadsto> \\<Longrightarrow> lastCommittedClusterStateBefore i = cs\".\n    from lastAcceptedTerm_Some_currentTerm show \"\\<And>n t. lastAcceptedTerm (nodeState n) = SomeTerm t \\<Longrightarrow> t \\<le> currentTerm (nodeState n)\".\n\n    from electionWon_isQuorum show \"\\<And>n. electionWon (nodeState' n) \\<Longrightarrow> isQuorum (nodeState n) (joinVotes (nodeState' n))\"\n      unfolding updated_properties by simp\n    from PublishRequest_publishPermitted_currentTerm show \"\\<And>n t x. n \\<midarrow>\\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) t x \\<rangle>\\<leadsto> \\<Longrightarrow> publishPermitted (nodeState' n) \\<Longrightarrow> t < currentTerm (nodeState n)\"\n      unfolding updated_properties by simp\n\n    fix n\n\n    from joinVotes show \"\\<And>n'. n' \\<in> joinVotes (nodeState' n) \\<Longrightarrow> promised (firstUncommittedSlot (nodeState n)) n' n (currentTerm (nodeState n))\"\n      unfolding updated_properties by (cases \"n = n\\<^sub>0\", simp_all)\n    from publishVotes show \"\\<And>n'. n' \\<in> publishVotes (nodeState' n) \\<Longrightarrow> n' \\<midarrow>\\<langle> PublishResponse (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) \\<rangle>\\<leadsto>\"\n      unfolding updated_properties by (cases \"n = n\\<^sub>0\", simp_all)\n    from joinVotes_max show \"\\<And>n' a'. \\<not> (\\<exists>x. \\<langle> PublishRequest (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) x \\<rangle>\\<leadsto>) \\<Longrightarrow> n' \\<in> joinVotes (nodeState' n) \\<Longrightarrow> n' \\<midarrow>\\<langle> Vote (firstUncommittedSlot (nodeState n)) (currentTerm (nodeState n)) a' \\<rangle>\\<rightarrow> (OneNode n) \\<Longrightarrow> a' \\<le> lastAcceptedTerm (nodeState n)\"\n      unfolding updated_properties by (cases \"n = n\\<^sub>0\", simp_all)\n  qed\nqed\n\nfun insertOption :: \"RoutedMessage option \\<Rightarrow> RoutedMessage set \\<Rightarrow> RoutedMessage set\"\n  where\n    \"insertOption None = id\"\n  | \"insertOption (Some m) = insert m\"\n\nlemma currentNode_ensureCurrentTerm[simp]: \"currentNode (ensureCurrentTerm t nd) = currentNode nd\"\n  by (auto simp add: ensureCurrentTerm_def)\n\nlemma currentNode_publishValue[simp]: \"currentNode (fst (publishValue x nd)) = currentNode nd\"\n  by (auto simp add: publishValue_def)\n\nlemma currentNode_addElectionVote[simp]: \"currentNode (addElectionVote s i a nd) = currentNode nd\"\n  by (auto simp add: addElectionVote_def Let_def)\n\nlemma currentNode_handleVote[simp]: \"currentNode (fst (handleVote s i t a nd)) = currentNode nd\"\n  by (auto simp add: handleVote_def Let_def)\n\ntext \\<open>\\pagebreak\\<close>\n\nlemma initial_state_satisfies_invariants:\n  shows \"zen {} initialNodeState\"\n  by (unfold_locales, simp_all add: initialNodeState_def isQuorum_def\n      lastAcceptedTerm_def lastAcceptedValue_def)\n\nlemma (in zen) invariants_preserved_by_ProcessMessage:\n  fixes n\\<^sub>0\n  assumes \"m \\<in> messages\"\n  defines \"nd \\<equiv> nodeState n\\<^sub>0\"\n  defines \"result \\<equiv> ProcessMessage nd m\"\n  defines \"nodeState' \\<equiv> \\<lambda>n. if n = n\\<^sub>0 then (fst result) else nodeState n\"\n  defines \"messages' \\<equiv> insertOption (snd result) messages\"\n  shows \"zen messages' nodeState'\"\nproof -\n  {\n    assume r: \"result = (nd, None)\"\n    from r have \"nodeState' = nodeState\"\n      by (auto simp add: nodeState'_def nd_def)\n    moreover from r have \"messages' = messages\" by (simp add: messages'_def)\n    ultimately have \"zen messages' nodeState'\"\n      using zen_axioms by blast\n  }\n  note noop = this\n\n  from `m \\<in> messages`\n  have m: \"(sender m) \\<midarrow>\\<langle> payload m \\<rangle>\\<rightarrow> (destination m)\"\n    by (cases m, auto simp add: isMessageFromTo_def)\n\n  have currentNode[simp]: \"currentNode nd = n\\<^sub>0\" \"\\<And>n. currentNode (nodeState n) = n\"\n    by (simp_all add: nd_def currentNode_nodeState)\n\n  have zenStep: \"zenStep messages nodeState messages' nodeState' n\\<^sub>0\"\n  proof (intro_locales, intro zenStep_axioms.intro)\n    show \"messages \\<subseteq> messages'\"\n      by (cases \"snd result\", auto simp add: messages'_def)\n  qed (simp add: nodeState'_def)\n\n  have [simp]: \"nodeState n\\<^sub>0 = nd\" by (simp add: nd_def)\n\n  define broadcast' :: \"(NodeData * Message option) \\<Rightarrow> (NodeData * RoutedMessage option)\" where\n    \"\\<And>p. broadcast' p \\<equiv> case p of\n            (nd, Some m') \\<Rightarrow> (nd, Some \\<lparr>sender = currentNode nd,\n                                   destination = Broadcast,\n                                   payload = m' \\<rparr>)\n            | (nd, None) \\<Rightarrow> (nd, None)\"\n\n  define respond' :: \"(NodeData * Message option) \\<Rightarrow> (NodeData * RoutedMessage option)\" where\n    \"\\<And>p. respond' p \\<equiv> case p of\n            (nd, Some m') \\<Rightarrow> (nd, Some \\<lparr>sender = currentNode nd,\n                                   destination = OneNode (sender m),\n                                   payload = m' \\<rparr>)\n            | (nd, None) \\<Rightarrow> (nd, None)\"\n\n  have fst_broadcast[simp]: \"\\<And>p. fst (broadcast' p) = fst p\"\n    unfolding broadcast'_def by (simp add: case_prod_unfold option.case_eq_if)\n\n  have fst_respond[simp]: \"\\<And>p. fst (respond' p) = fst p\"\n    unfolding respond'_def by (simp add: case_prod_unfold option.case_eq_if)\n\n  show ?thesis\n  proof (cases \"destination m = Broadcast \\<or> destination m = OneNode (currentNode nd)\")\n    case False\n    hence \"result = (nd, None)\"\n      unfolding result_def ProcessMessage_def Let_def by simp\n    thus ?thesis by (intro noop)\n  next\n    case dest_ok: True\n    have dest_True: \"destination m \\<in> {Broadcast, OneNode (currentNode nd)} = True\"\n      using dest_ok by simp\n    show ?thesis\n    proof (cases \"payload m\")\n      case (StartJoin t)\n\n      have result: \"result = respond' (handleStartJoin t nd)\"\n        unfolding result_def respond'_def ProcessMessage_def dest_True StartJoin by auto\n\n      have currentNode_eq: \"currentNode (nodeState' n\\<^sub>0) = currentNode (nodeState n\\<^sub>0)\"\n        unfolding nodeState'_def result by (auto simp add: handleStartJoin_def)\n\n      show ?thesis\n      proof (intro zenStep.handleStartJoin_invariants [OF zenStep])\n        show \"nodeState' n\\<^sub>0 = fst (handleStartJoin t (nodeState n\\<^sub>0))\"\n          by (simp add: result nodeState'_def)\n\n        from currentNode_eq\n        show \"messages' = (case snd (handleStartJoin t (nodeState n\\<^sub>0)) of None \\<Rightarrow> messages | Some m' \\<Rightarrow> insert \\<lparr>sender = n\\<^sub>0, destination = OneNode (sender m), payload = m'\\<rparr> messages)\"\n          unfolding messages'_def result respond'_def nodeState'_def by (cases \"handleStartJoin t nd\", cases \"snd (handleStartJoin t nd)\", auto)\n\n        from m show \"\\<exists>d. \\<lparr>sender = sender m, destination = d, payload = StartJoin t\\<rparr> \\<in> messages\"\n          by (auto simp add: isMessageFromTo_def StartJoin)\n      qed\n    next\n      case (Vote i t a)\n\n      from Vote_not_broadcast m Vote dest_ok\n      have dest_m: \"destination m = OneNode n\\<^sub>0\"\n        apply (cases \"destination m\")\n        using isMessageTo_def apply fastforce\n        by auto\n\n      from Vote_not_broadcast m Vote dest_ok\n      have m: \"(sender m) \\<midarrow>\\<langle> Vote i t a \\<rangle>\\<rightarrow> (OneNode n\\<^sub>0)\"\n        apply (cases \"destination m\")\n        using isMessageTo_def apply fastforce\n        by auto\n\n      have result: \"result = broadcast' (handleVote (sender m) i t a nd)\"\n        unfolding result_def ProcessMessage_def Vote dest_True broadcast'_def by simp\n\n      have currentNode_eq: \"currentNode (nodeState' n\\<^sub>0) = currentNode (nodeState n\\<^sub>0)\"\n        unfolding nodeState'_def result by simp\n\n      show ?thesis\n      proof (intro zenStep.handleVote_invariants [OF zenStep])\n        show \"nodeState' n\\<^sub>0 = fst (handleVote (sender m) i t a (nodeState n\\<^sub>0))\"\n          by (simp add: result nodeState'_def)\n\n        from currentNode_eq\n        show \"messages' = (case snd (handleVote (sender m) i t a (nodeState n\\<^sub>0)) of None \\<Rightarrow> messages | Some m \\<Rightarrow> insert \\<lparr>sender = n\\<^sub>0, destination = Broadcast, payload = m\\<rparr> messages)\"\n          unfolding messages'_def result broadcast'_def nodeState'_def by (cases \"handleVote (sender m) i t a nd\", cases \"snd (handleVote (sender m) i t a nd)\", auto)\n\n        from m\n        show \"\\<lparr>sender = sender m, destination = OneNode n\\<^sub>0, payload = Vote i t a\\<rparr> \\<in> messages\"\n          by (auto simp add: Vote isMessageFromTo_def)\n      qed\n\n    next\n      case (ClientValue x)\n\n      have result: \"result = broadcast' (handleClientValue x nd)\"\n        unfolding result_def ProcessMessage_def ClientValue dest_True broadcast'_def by simp\n\n      have currentNode_eq: \"currentNode (nodeState' n\\<^sub>0) = currentNode (nodeState n\\<^sub>0)\"\n        unfolding nodeState'_def result by (simp add: handleClientValue_def)\n\n      show ?thesis\n      proof (intro zenStep.handleClientValue_invariants [OF zenStep])\n        show \"nodeState' n\\<^sub>0 = fst (handleClientValue x (nodeState n\\<^sub>0))\"\n          by (simp add: result nodeState'_def)\n\n        from currentNode_eq\n        show \"messages' = (case snd (handleClientValue x (nodeState n\\<^sub>0)) of None \\<Rightarrow> messages | Some m \\<Rightarrow> insert \\<lparr>sender = n\\<^sub>0, destination = Broadcast, payload = m\\<rparr> messages)\"\n          unfolding messages'_def result broadcast'_def nodeState'_def by (cases \"handleClientValue x (nodeState n\\<^sub>0)\", cases \"snd (handleClientValue x (nodeState n\\<^sub>0))\", auto)\n      qed\n\n    next\n      case (PublishRequest i t x)\n\n      have result: \"result = respond' (handlePublishRequest i t x nd)\"\n        unfolding result_def ProcessMessage_def PublishRequest dest_True by (simp add: respond'_def)\n\n      have currentNode_eq: \"currentNode (nodeState' n\\<^sub>0) = currentNode (nodeState n\\<^sub>0)\"\n        unfolding nodeState'_def result by (simp add: handlePublishRequest_def)\n\n      show ?thesis\n      proof (intro zenStep.handlePublishRequest_invariants [OF zenStep])\n        show \"nodeState' n\\<^sub>0 = fst (handlePublishRequest i t x (nodeState n\\<^sub>0))\"\n          by (simp add: nodeState'_def result)\n\n        from currentNode_eq\n        show \"messages' = (case snd (handlePublishRequest i t x (nodeState n\\<^sub>0)) of None \\<Rightarrow> messages | Some m' \\<Rightarrow> insert \\<lparr>sender = n\\<^sub>0, destination = OneNode (sender m), payload = m'\\<rparr> messages)\"\n          unfolding messages'_def result respond'_def nodeState'_def by (cases \"handlePublishRequest i t x (nodeState n\\<^sub>0)\", cases \"snd (handlePublishRequest i t x (nodeState n\\<^sub>0))\", auto)\n\n        from m\n        show \"\\<exists>d. \\<lparr>sender = sender m, destination = d, payload = PublishRequest i t x\\<rparr> \\<in> messages\"\n          by (auto simp add: PublishRequest isMessageFromTo_def)\n      qed\n\n    next\n      case (PublishResponse i t)\n\n      have result: \"result = broadcast' (handlePublishResponse (sender m) i t nd)\"\n        unfolding result_def ProcessMessage_def PublishResponse dest_True by (simp add: broadcast'_def)\n\n      show ?thesis\n      proof (intro zenStep.handlePublishResponse_invariants [OF zenStep])\n        show \"nodeState' n\\<^sub>0 = fst (handlePublishResponse (sender m) i t (nodeState n\\<^sub>0))\"\n          by (simp add: result nodeState'_def)\n\n        show \"messages' = (case snd (handlePublishResponse (sender m) i t (nodeState n\\<^sub>0)) of None \\<Rightarrow> messages | Some m \\<Rightarrow> insert \\<lparr>sender = n\\<^sub>0, destination = Broadcast, payload = m\\<rparr> messages)\"\n          by (simp_all add: messages'_def result broadcast'_def handlePublishResponse_def commitIfQuorate_def)\n\n        from m\n        show \"\\<exists>d. \\<lparr>sender = sender m, destination = d, payload = PublishResponse i t\\<rparr> \\<in> messages\"\n          by (auto simp add: PublishResponse isMessageFromTo_def)\n      qed\n\n    next\n      case (ApplyCommit i t)\n\n      have result: \"result = (handleApplyCommit i t nd, None)\"\n        unfolding result_def ProcessMessage_def ApplyCommit dest_True by simp\n\n      have currentNode_eq: \"currentNode (nodeState' n\\<^sub>0) = currentNode (nodeState n\\<^sub>0)\"\n        unfolding nodeState'_def result by (cases \"lastAcceptedValue nd\", simp_all add: handleApplyCommit_def applyAcceptedValue_def)\n\n      show ?thesis\n      proof (intro zenStep.handleApplyCommit_invariants [OF zenStep])\n        show \"nodeState' n\\<^sub>0 = handleApplyCommit i t (nodeState n\\<^sub>0)\"\n          by (simp add: result nodeState'_def)\n        show \"messages' = messages\"\n          by (simp add: result messages'_def)\n        from m show \"\\<exists>s d. \\<lparr>sender = s, destination = d, payload = ApplyCommit i t\\<rparr> \\<in> messages\"\n          by (auto simp add: ApplyCommit isMessageFromTo_def)\n      qed\n\n    next\n      case Reboot\n\n      have result: \"result = (handleReboot nd, None)\"\n        unfolding result_def ProcessMessage_def Reboot dest_True by simp\n\n      show ?thesis\n      proof (intro zenStep.handleReboot_invariants [OF zenStep])\n        show \"nodeState' n\\<^sub>0 = handleReboot (nodeState n\\<^sub>0)\"\n          by (simp add: nodeState'_def result)\n\n        show \"messages' = messages\"\n          by (simp add: result messages'_def)\n      qed\n\n    next\n      case DiscardJoinVotes\n\n      have result: \"result = (handleDiscardJoinVotes nd, None)\"\n        unfolding result_def ProcessMessage_def DiscardJoinVotes dest_True by simp\n\n      show ?thesis\n      proof (intro zenStep.handleDiscardJoinVotes_invariants [OF zenStep])\n        show \"nodeState' n\\<^sub>0 = handleDiscardJoinVotes (nodeState n\\<^sub>0)\"\n          by (simp add: nodeState'_def result)\n\n        show \"messages' = messages\"\n          by (simp add: result messages'_def)\n      qed\n\n    next\n      case CatchUpRequest\n\n      have result: \"result = respond' (handleCatchUpRequest nd)\"\n        unfolding result_def ProcessMessage_def CatchUpRequest dest_True by (simp add: respond'_def)\n\n      have currentNode_eq: \"currentNode (nodeState' n\\<^sub>0) = currentNode (nodeState n\\<^sub>0)\"\n        unfolding nodeState'_def result by (cases \"lastAcceptedValue nd\", simp_all add: handleCatchUpRequest_def)\n\n      show ?thesis\n      proof (intro zenStep.handleCatchUpRequest_invariants [OF zenStep])\n        show \"nodeState' n\\<^sub>0 = fst (handleCatchUpRequest (nodeState n\\<^sub>0))\"\n          by (simp add: nodeState'_def result)\n\n        show \"messages' = (case snd (handleCatchUpRequest (nodeState n\\<^sub>0)) of None \\<Rightarrow> messages | Some m' \\<Rightarrow> insert \\<lparr>sender = n\\<^sub>0, destination = OneNode (sender m), payload = m'\\<rparr> messages)\"\n          by (simp_all add: messages'_def result respond'_def handleCatchUpRequest_def)\n      qed\n\n    next\n      case (CatchUpResponse i conf cs)\n\n      have result: \"result = (handleCatchUpResponse i conf cs nd, None)\"\n        unfolding result_def ProcessMessage_def CatchUpResponse dest_True by simp\n\n      show ?thesis\n      proof (intro zenStep.handleCatchUpResponse_invariants [OF zenStep])\n        show \"nodeState' n\\<^sub>0 = handleCatchUpResponse i conf cs (nodeState n\\<^sub>0)\"\n          by (simp add: nodeState'_def result)\n\n        show \"messages' = messages\"\n          by (simp add: result messages'_def)\n\n        from m show \"\\<exists>s d. \\<lparr>sender = s, destination = d, payload = CatchUpResponse i conf cs\\<rparr> \\<in> messages\"\n          unfolding CatchUpResponse isMessageFromTo_def by auto\n      qed\n    qed\n  qed\nqed\n\ntheorem (in zen) invariants_imply_consistent_states:\n  assumes\n    \"firstUncommittedSlot (nodeState n\\<^sub>1) = firstUncommittedSlot (nodeState n\\<^sub>2)\"\n  shows\n    \"currentClusterState (nodeState n\\<^sub>1) = currentClusterState (nodeState n\\<^sub>2)\"\nproof -\n  have \"currentClusterState (nodeState n\\<^sub>1) = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n\\<^sub>1))\"\n    using currentClusterState_lastCommittedClusterStateBefore .\n  also have \"... = lastCommittedClusterStateBefore (firstUncommittedSlot (nodeState n\\<^sub>2))\" using assms by simp\n  also have \"... = currentClusterState (nodeState n\\<^sub>2)\"\n    using currentClusterState_lastCommittedClusterStateBefore ..\n  finally show ?thesis .\nqed\n\nend\n"
  },
  {
    "path": "cluster/isabelle/document/root.tex",
    "content": "\\documentclass[11pt,a4paper]{article}\n\\usepackage{isabelle,isabellesym}\n\\usepackage{latexsym}\n\n% further packages required for unusual symbols (see also\n% isabellesym.sty), use only when needed\n\n%\\usepackage{amssymb}\n  %for \\<leadsto>, \\<box>, \\<diamond>, \\<sqsupset>, \\<mho>, \\<Join>,\n  %\\<lhd>, \\<lesssim>, \\<greatersim>, \\<lessapprox>, \\<greaterapprox>,\n  %\\<triangleq>, \\<yen>, \\<lozenge>\n\n%\\usepackage{eurosym}\n  %for \\<euro>\n\n%\\usepackage[only,bigsqcap]{stmaryrd}\n  %for \\<Sqinter>\n\n%\\usepackage{eufrak}\n  %for \\<AA> ... \\<ZZ>, \\<aa> ... \\<zz> (also included in amssymb)\n\n%\\usepackage{textcomp}\n  %for \\<onequarter>, \\<onehalf>, \\<threequarters>, \\<degree>, \\<cent>,\n  %\\<currency>\n\n% this should be the last package used\n\\usepackage{pdfsetup}\n\n% urls in roman style, theory text in math-similar italics\n\\urlstyle{rm}\n\\isabellestyle{it}\n\n% for uniform font size\n%\\renewcommand{\\isastyle}{\\isastyleminor}\n\n\n\\begin{document}\n\n\\title{elasticsearch-isabelle}\n\\author{David Turner}\n\\maketitle\n\n\\tableofcontents\n\n% sane default for proof documents\n\\parindent 0pt\\parskip 0.5ex\n\n\\section{Introduction}\n\nThis is a presentation of an Isabelle/HOL theory that describes, and proves correct,\na protocol for sharing \\texttt{ClusterState} updates in Elasticsearch.\n\n% generated text of all theories\n\\input{session}\n\n% optional bibliography\n%\\bibliographystyle{abbrv}\n%\\bibliography{root}\n\n\\end{document}\n\n%%% Local Variables:\n%%% mode: latex\n%%% TeX-master: t\n%%% End:\n"
  },
  {
    "path": "cluster/tla/consensus.tla",
    "content": "`^\\Large\\bf\nTLA+ Model of an improved Zen consensus algorithm with reconfiguration capabilities ^'\n-------------------------------------------------------------------------------------\n\n-------------------------------- MODULE consensus -----------------------------------\n\\* Imported modules used in this specification\nEXTENDS Naturals, FiniteSets, Sequences, TLC\n\n----\n\n\\* `^\\Large\\bf Constants ^'\n\n\\* The specification first defines the constants of the model, which amount to values or sets of\n\\* values that are fixed.\n\nCONSTANTS Values\n\n\\* Set of node ids (all master-eligible nodes)\nCONSTANTS Nodes\n\n\\* The constant \"Nil\" denotes a place-holder for a non-existing value\nCONSTANTS Nil\n\n\\* RPC message types\nCONSTANTS\n  Join, \\* only request is modeled\n  PublishRequest,\n  PublishResponse,\n  Commit, \\* only request is modeled\n  Catchup \\* only response is modeled\n\n\\* Publish request types\nCONSTANTS\n  Reconfigure,\n  ApplyCSDiff  \n\n----\n\n\\* `^\\Large\\bf Variables ^'\n\n\\* The following describes the variable state of the model.\n\n\\* Set of requests and responses sent between nodes.\nVARIABLE messages\n\n\\* node state (map from node id to state)\nVARIABLE firstUncommittedSlot\nVARIABLE currentTerm\nVARIABLE currentConfiguration\nVARIABLE currentClusterState\nVARIABLE lastAcceptedTerm\nVARIABLE lastAcceptedValue\nVARIABLE joinVotes\nVARIABLE electionWon\nVARIABLE publishPermitted\nVARIABLE publishVotes\n\n----\n\n\\* set of valid configurations (i.e. the set of all non-empty subsets of Nodes)\nValidConfigs == SUBSET(Nodes) \\ {{}}\n\n\\* quorums correspond to majority of votes in a config\nIsQuorum(votes, config) == Cardinality(votes \\cap config) * 2 > Cardinality(config)\n\n\\* checks whether two configurations only have intersecting quorums\nIntersectingQuorums(config1, config2) ==\n  /\\ \\lnot IsQuorum(config1 \\ config2, config1)\n  /\\ \\lnot IsQuorum(config2 \\ config1, config2)\n\n\\* initial model state\nInit == /\\ messages = {}\n        /\\ firstUncommittedSlot = [n \\in Nodes |-> 0]\n        /\\ currentTerm = [n \\in Nodes |-> 0]\n        /\\ currentConfiguration \\in {[n \\in Nodes |-> vc] : vc \\in ValidConfigs} \\* all agree on initial config\n        /\\ currentClusterState \\in {[n \\in Nodes |-> v] : v \\in Values} \\* all agree on initial value\n        /\\ lastAcceptedTerm = [n \\in Nodes |-> Nil]\n        /\\ lastAcceptedValue = [n \\in Nodes |-> Nil]\n        /\\ joinVotes = [n \\in Nodes |-> {}]\n        /\\ electionWon = [n \\in Nodes |-> FALSE]\n        /\\ publishPermitted = [n \\in Nodes |-> FALSE]\n        /\\ publishVotes = [n \\in Nodes |-> {}]\n\n\\* Send join request from node n to node nm for term t\nHandleStartJoin(n, nm, t) ==\n  /\\ t > currentTerm[n]\n  /\\ LET\n       joinRequest == [method  |-> Join,\n                       source  |-> n,\n                       dest    |-> nm,\n                       slot    |-> firstUncommittedSlot[n],\n                       term    |-> t,\n                       laTerm  |-> lastAcceptedTerm[n]]\n     IN\n       /\\ currentTerm' = [currentTerm EXCEPT ![n] = t]\n       /\\ publishPermitted' = [publishPermitted EXCEPT ![n] = TRUE]\n       /\\ electionWon' = [electionWon EXCEPT ![n] = FALSE]\n       /\\ joinVotes' = [joinVotes EXCEPT ![n] = {}]\n       /\\ publishVotes' = [publishVotes EXCEPT ![n] = {}]\n       /\\ messages' = messages \\cup { joinRequest }\n       /\\ UNCHANGED <<currentClusterState, currentConfiguration,\n                      firstUncommittedSlot, lastAcceptedValue, lastAcceptedTerm>>\n\n\\* node n handles a join request and checks if it has received enough joins (= votes)\n\\* for its term to be elected as master\nHandleJoinRequest(n, m) ==\n  /\\ m.method = Join\n  /\\ m.term = currentTerm[n]\n  /\\ \\/ /\\ m.slot < firstUncommittedSlot[n]\n     \\/ /\\ m.slot = firstUncommittedSlot[n]\n        /\\ (m.laTerm /= Nil => lastAcceptedTerm[n] /= Nil /\\ m.laTerm <= lastAcceptedTerm[n])\n  /\\ joinVotes' = [joinVotes EXCEPT ![n] = @ \\cup { m.source }]\n  /\\ electionWon' = [electionWon EXCEPT ![n] = IsQuorum(joinVotes'[n], currentConfiguration[n])]\n  /\\ IF electionWon'[n] /\\ publishPermitted[n] /\\ lastAcceptedTerm[n] /= Nil \n     THEN LET publishRequests == { [method  |-> PublishRequest,\n                                    source  |-> n,\n                                    dest    |-> ns,\n                                    term    |-> currentTerm[n],\n                                    slot    |-> firstUncommittedSlot[n],\n                                    value   |-> lastAcceptedValue[n]] : ns \\in Nodes }\n     IN\n       /\\ messages' = messages \\cup publishRequests\n       /\\ publishPermitted' = [publishPermitted EXCEPT ![n] = FALSE]\n     ELSE\n       /\\ UNCHANGED <<messages, publishPermitted>>\n  /\\ UNCHANGED <<currentClusterState, currentConfiguration, currentTerm, publishVotes,\n                 firstUncommittedSlot, lastAcceptedValue, lastAcceptedTerm>>\n\n\\* client causes a cluster state change v\nClientRequest(n, v) ==\n  /\\ electionWon[n]\n  /\\ publishPermitted[n]\n  /\\ LET\n       publishRequests == { [method  |-> PublishRequest,\n                             source  |-> n,\n                             dest    |-> ns,\n                             term    |-> currentTerm[n],\n                             slot    |-> firstUncommittedSlot[n],\n                             value   |-> [type |-> ApplyCSDiff, \n                                          val  |-> (currentClusterState[n] :> v)]\n                            ] : ns \\in Nodes }\n     IN\n       /\\ publishPermitted' = [publishPermitted EXCEPT ![n] = FALSE]\n       /\\ messages' = messages \\cup publishRequests\n       /\\ UNCHANGED <<currentClusterState, currentConfiguration, currentTerm, electionWon,\n                      firstUncommittedSlot, lastAcceptedValue, lastAcceptedTerm, joinVotes, publishVotes>>\n\n\\* change the set of voters\nChangeVoters(n, vs) ==\n  /\\ electionWon[n]\n  /\\ publishPermitted[n]\n  /\\ LET\n       publishRequests == { [method  |-> PublishRequest,\n                             source  |-> n,\n                             dest    |-> ns,\n                             term    |-> currentTerm[n],\n                             slot    |-> firstUncommittedSlot[n],\n                             value   |-> [type |-> Reconfigure, val |-> vs]] : ns \\in Nodes }\n     IN\n       /\\ publishPermitted' = [publishPermitted EXCEPT ![n] = FALSE]\n       /\\ messages' = messages \\cup publishRequests\n       /\\ UNCHANGED <<currentClusterState, currentConfiguration, currentTerm, electionWon,\n                      firstUncommittedSlot, lastAcceptedValue, lastAcceptedTerm, joinVotes, publishVotes>>\n\n\\* handle publish request m on node n\nHandlePublishRequest(n, m) ==\n  /\\ m.method = PublishRequest\n  /\\ m.slot = firstUncommittedSlot[n]\n  /\\ m.term = currentTerm[n]\n  /\\ lastAcceptedTerm' = [lastAcceptedTerm EXCEPT ![n] = m.term]\n  /\\ lastAcceptedValue' = [lastAcceptedValue EXCEPT ![n] = m.value]\n  /\\ LET\n       response == [method  |-> PublishResponse,\n                    source  |-> n,\n                    dest    |-> m.source,\n                    success |-> TRUE,\n                    term    |-> m.term,\n                    slot    |-> m.slot]\n     IN\n       /\\ messages' = messages \\cup {response}\n       /\\ UNCHANGED <<currentClusterState, currentConfiguration, currentTerm,\n                      electionWon, firstUncommittedSlot, publishPermitted, joinVotes, publishVotes>>\n\n\\* node n commits a change\nHandlePublishResponse(n, m) ==\n  /\\ m.method = PublishResponse\n  /\\ m.slot = firstUncommittedSlot[n]\n  /\\ m.term = currentTerm[n]\n  /\\ publishVotes' = [publishVotes EXCEPT ![n] = @ \\cup {m.source}]\n  /\\ IF IsQuorum(publishVotes'[n], currentConfiguration[n])\n     THEN\n       LET\n         commitRequests == { [method  |-> Commit,\n                              source  |-> n,\n                              dest    |-> ns,\n                              term    |-> currentTerm[n],\n                              slot    |-> firstUncommittedSlot[n]] : ns \\in Nodes }\n       IN\n         /\\ messages' = messages \\cup commitRequests\n     ELSE\n       UNCHANGED <<messages>>\n  /\\ UNCHANGED <<currentClusterState, currentConfiguration, currentTerm, electionWon,\n                   firstUncommittedSlot, lastAcceptedValue, lastAcceptedTerm,\n                   publishPermitted, joinVotes>>\n\n\\* apply committed change to node n\nHandleCommitRequest(n, m) ==\n  /\\ m.method = Commit\n  /\\ m.slot = firstUncommittedSlot[n]\n  /\\ m.term = lastAcceptedTerm[n]\n  /\\ firstUncommittedSlot' = [firstUncommittedSlot EXCEPT ![n] = @ + 1]\n  /\\ lastAcceptedTerm' = [lastAcceptedTerm EXCEPT ![n] = Nil]\n  /\\ lastAcceptedValue' = [lastAcceptedValue EXCEPT ![n] = Nil]\n  /\\ publishPermitted' = [publishPermitted EXCEPT ![n] = TRUE]\n  /\\ publishVotes' = [publishVotes EXCEPT ![n] = {}]\n  /\\ IF lastAcceptedValue[n].type = Reconfigure THEN\n       /\\ currentConfiguration' = [currentConfiguration EXCEPT ![n] = lastAcceptedValue[n].val]\n       /\\ electionWon' = [electionWon EXCEPT ![n] = IsQuorum(joinVotes[n], currentConfiguration'[n])]\n       /\\ UNCHANGED <<currentClusterState>>\n     ELSE\n       /\\ Assert(lastAcceptedValue[n].type = ApplyCSDiff, \"unexpected type\")\n       /\\ Assert(DOMAIN(lastAcceptedValue[n].val) = {currentClusterState[n]}, \"diff mismatch\")\n       /\\ currentClusterState' = [currentClusterState EXCEPT ![n] = lastAcceptedValue[n].val[@]] \\* apply diff\n       /\\ UNCHANGED <<currentConfiguration, electionWon>>\n  /\\ UNCHANGED <<currentTerm, joinVotes, messages>>\n\n\\* node n captures current state and sends a catch up message\nSendCatchupResponse(n) ==\n  /\\ LET\n       catchupMessage == [method  |-> Catchup,\n                          slot    |-> firstUncommittedSlot[n],\n                          config  |-> currentConfiguration[n],\n                          state   |-> currentClusterState[n]]\n     IN\n       /\\ messages' = messages \\cup { catchupMessage }\n       /\\ UNCHANGED <<currentClusterState, currentConfiguration, currentTerm, \n                      lastAcceptedValue, electionWon, firstUncommittedSlot, publishPermitted,\n                      joinVotes, lastAcceptedTerm, publishVotes>>\n\n\\* node n handles a catchup message\nHandleCatchupResponse(n, m) ==\n  /\\ m.method = Catchup\n  /\\ m.slot > firstUncommittedSlot[n]\n  /\\ firstUncommittedSlot' = [firstUncommittedSlot EXCEPT ![n] = m.slot]\n  /\\ lastAcceptedTerm' = [lastAcceptedTerm EXCEPT ![n] = Nil]\n  /\\ lastAcceptedValue' = [lastAcceptedValue EXCEPT ![n] = Nil]\n  /\\ publishPermitted' = [publishPermitted EXCEPT ![n] = TRUE]\n  /\\ electionWon' = [electionWon EXCEPT ![n] = FALSE]\n  /\\ currentConfiguration' = [currentConfiguration EXCEPT ![n] = m.config]\n  /\\ currentClusterState' = [currentClusterState EXCEPT ![n] = m.state]\n  /\\ joinVotes' = [joinVotes EXCEPT ![n] = {}]\n  /\\ publishVotes' = [publishVotes EXCEPT ![n] = {}]\n  /\\ UNCHANGED <<currentTerm, messages>>\n  \n\n\\* crash/restart node n (loses ephemeral state)\nRestartNode(n) ==\n  /\\ electionWon' = [electionWon EXCEPT ![n] = FALSE]\n  /\\ publishPermitted' = [publishPermitted EXCEPT ![n] = FALSE]\n  /\\ joinVotes' = [joinVotes EXCEPT ![n] = {}]\n  /\\ publishVotes' = [publishVotes EXCEPT ![n] = {}]\n  /\\ UNCHANGED <<messages, firstUncommittedSlot, currentTerm, currentConfiguration, \n                 currentClusterState, lastAcceptedTerm, lastAcceptedValue>>\n\n\\* next-step relation\nNext ==\n  \\/ \\E n, nm \\in Nodes : HandleStartJoin(n, nm, currentTerm[n] + 1)\n  \\/ \\E m \\in messages : HandleJoinRequest(m.dest, m)\n  \\/ \\E n \\in Nodes : \\E v \\in Values : ClientRequest(n, v)\n  \\/ \\E m \\in messages : HandlePublishRequest(m.dest, m)\n  \\/ \\E m \\in messages : HandlePublishResponse(m.dest, m)\n  \\/ \\E m \\in messages : HandleCommitRequest(m.dest, m)\n  \\/ \\E n \\in Nodes : RestartNode(n)\n  \\/ \\E n \\in Nodes : \\E vs \\in ValidConfigs : ChangeVoters(n, vs)\n  \\/ \\E n \\in Nodes : SendCatchupResponse(n)\n  \\/ \\E n \\in Nodes : \\E m \\in messages : HandleCatchupResponse(n, m)\n\n----\n\n\\* main invariant:\nStateMachineSafety ==\n  \\A n1, n2 \\in Nodes :\n    firstUncommittedSlot[n1] = firstUncommittedSlot[n2] => \n      /\\ currentClusterState[n1] = currentClusterState[n2]\n      /\\ currentConfiguration[n1] = currentConfiguration[n2]\n\nOneMasterPerTerm ==\n  \\A n1, n2 \\in Nodes :\n    /\\ electionWon[n1]\n    /\\ electionWon[n2]\n    /\\ currentTerm[n1] = currentTerm[n2]\n    /\\ IntersectingQuorums(currentConfiguration[n1], currentConfiguration[n2])\n    => n1 = n2\n\nLogMatching ==\n  \\A n1, n2 \\in Nodes :\n    /\\ firstUncommittedSlot[n1] = firstUncommittedSlot[n2]\n    /\\ lastAcceptedTerm[n1] = lastAcceptedTerm[n2]\n    => lastAcceptedValue[n1] = lastAcceptedValue[n2]\n\nSingleNodeInvariant ==\n  \\A n \\in Nodes :\n    /\\ (lastAcceptedTerm[n] = Nil) = (lastAcceptedValue[n] = Nil)\n    /\\ lastAcceptedTerm[n] /= Nil => (lastAcceptedTerm[n] <= currentTerm[n])\n    /\\ electionWon[n] = IsQuorum(joinVotes[n], currentConfiguration[n]) \\* cached value is consistent\n    /\\ electionWon[n] /\\ publishPermitted[n] => lastAcceptedValue[n] = Nil\n\nLogMatchingMessages ==\n  \\A m1, m2 \\in messages:\n    /\\ m1.method = PublishRequest\n    /\\ m2.method = PublishRequest\n    /\\ m1.slot = m2.slot\n    /\\ m1.term = m2.term\n    => m1.value = m2.value\n\nSafeCatchupMessages ==\n  \\A m1, m2 \\in messages:\n    /\\ m1.method = Catchup\n    /\\ m2.method = Catchup\n    /\\ m1.slot = m2.slot\n    => m1.config = m2.config /\\ m1.state = m2.state\n\n\\* State-exploration limits\nStateConstraint ==\n  /\\ \\A n \\in Nodes: currentTerm[n] <= 3\n  /\\ \\A n \\in Nodes: firstUncommittedSlot[n] <= 2\n  /\\ Cardinality(messages) <= 15\n\n====================================================================================================\n"
  },
  {
    "path": "cluster/tla/consensus.toolbox/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>zen</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>toolbox.builder.TLAParserBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>toolbox.builder.PCalAlgorithmSearchingBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>toolbox.natures.TLANature</nature>\n\t</natures>\n\t<linkedResources>\n\t\t<link>\n\t\t\t<name>consensus.tla</name>\n\t\t\t<type>1</type>\n\t\t\t<locationURI>PARENT-1-PROJECT_LOC/consensus.tla</locationURI>\n\t\t</link>\n\t</linkedResources>\n</projectDescription>\n"
  },
  {
    "path": "cluster/tla/consensus.toolbox/.settings/org.lamport.tla.toolbox.prefs",
    "content": "ProjectRootFile=PARENT-1-PROJECT_LOC/consensus.tla\neclipse.preferences.version=1\n"
  },
  {
    "path": "cluster/tla/consensus.toolbox/consensus___model.launch",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<launchConfiguration type=\"org.lamport.tla.toolbox.tool.tlc.modelCheck\">\n    <stringAttribute key=\"TLCCmdLineParameters\" value=\"\"/>\n    <intAttribute key=\"autoLockTime\" value=\"15\"/>\n    <stringAttribute key=\"configurationName\" value=\"model\"/>\n    <booleanAttribute key=\"deferLiveness\" value=\"false\"/>\n    <intAttribute key=\"dfidDepth\" value=\"100\"/>\n    <booleanAttribute key=\"dfidMode\" value=\"false\"/>\n    <intAttribute key=\"distributedFPSetCount\" value=\"0\"/>\n    <stringAttribute key=\"distributedNetworkInterface\" value=\"192.168.178.34\"/>\n    <intAttribute key=\"distributedNodesCount\" value=\"1\"/>\n    <stringAttribute key=\"distributedTLC\" value=\"off\"/>\n    <stringAttribute key=\"distributedTLCVMArgs\" value=\"\"/>\n    <intAttribute key=\"fpBits\" value=\"0\"/>\n    <intAttribute key=\"fpIndex\" value=\"1\"/>\n    <intAttribute key=\"maxHeapSize\" value=\"25\"/>\n    <intAttribute key=\"maxSetSize\" value=\"1000000\"/>\n    <booleanAttribute key=\"mcMode\" value=\"true\"/>\n    <stringAttribute key=\"modelBehaviorInit\" value=\"Init\"/>\n    <stringAttribute key=\"modelBehaviorNext\" value=\"Next\"/>\n    <stringAttribute key=\"modelBehaviorSpec\" value=\"\"/>\n    <intAttribute key=\"modelBehaviorSpecType\" value=\"2\"/>\n    <stringAttribute key=\"modelBehaviorVars\" value=\"lastAcceptedTerm, currentClusterState, messages, firstUncommittedSlot, electionWon, publishVotes, currentTerm, currentConfiguration, joinVotes, publishPermitted, lastAcceptedValue\"/>\n    <stringAttribute key=\"modelComments\" value=\"\"/>\n    <booleanAttribute key=\"modelCorrectnessCheckDeadlock\" value=\"true\"/>\n    <listAttribute key=\"modelCorrectnessInvariants\">\n        <listEntry value=\"1StateMachineSafety\"/>\n        <listEntry value=\"1OneMasterPerTerm\"/>\n        <listEntry value=\"1LogMatching\"/>\n        <listEntry value=\"1SingleNodeInvariant\"/>\n        <listEntry value=\"1LogMatchingMessages\"/>\n        <listEntry value=\"1SafeCatchupMessages\"/>\n    </listAttribute>\n    <listAttribute key=\"modelCorrectnessProperties\"/>\n    <stringAttribute key=\"modelExpressionEval\" value=\"\"/>\n    <stringAttribute key=\"modelParameterActionConstraint\" value=\"\"/>\n    <listAttribute key=\"modelParameterConstants\">\n        <listEntry value=\"Nodes;;{n1, n2, n3};1;1\"/>\n        <listEntry value=\"Nil;;Nil;1;0\"/>\n        <listEntry value=\"Join;;Join;1;0\"/>\n        <listEntry value=\"Reconfigure;;Reconfigure;1;0\"/>\n        <listEntry value=\"ApplyCSDiff;;ApplyCSDiff;1;0\"/>\n        <listEntry value=\"Values;;{v1, v2};1;1\"/>\n        <listEntry value=\"Commit;;Commit;1;0\"/>\n        <listEntry value=\"Catchup;;Catchup;1;0\"/>\n        <listEntry value=\"PublishResponse;;PublishResponse;1;0\"/>\n        <listEntry value=\"PublishRequest;;PublishRequest;1;0\"/>\n    </listAttribute>\n    <stringAttribute key=\"modelParameterContraint\" value=\"StateConstraint\"/>\n    <listAttribute key=\"modelParameterDefinitions\"/>\n    <stringAttribute key=\"modelParameterModelValues\" value=\"{}\"/>\n    <stringAttribute key=\"modelParameterNewDefinitions\" value=\"\"/>\n    <intAttribute key=\"numberOfWorkers\" value=\"3\"/>\n    <booleanAttribute key=\"recover\" value=\"false\"/>\n    <stringAttribute key=\"result.mail.address\" value=\"\"/>\n    <intAttribute key=\"simuAril\" value=\"-1\"/>\n    <intAttribute key=\"simuDepth\" value=\"100\"/>\n    <intAttribute key=\"simuSeed\" value=\"-1\"/>\n    <stringAttribute key=\"specName\" value=\"consensus\"/>\n    <stringAttribute key=\"view\" value=\"\"/>\n    <booleanAttribute key=\"visualizeStateGraph\" value=\"false\"/>\n</launchConfiguration>\n"
  },
  {
    "path": "data/tla/replication.tla",
    "content": "`^\\Large\\bf\nTLA+ Model of the Elasticsearch data replication approach ^'\n-------------------------------------------------------------------------------------\n\nThis file provides a formal specification of how data replication will work in future versions of\nElasticsearch. We consider this work-in-progress: Model as well as implementation are still evolving\nand might differ in substantial ways.\n\nIntroduction\n------------\n\nAn index, which is a collection of documents, can be divided into multiple pieces, known as shards,\neach of which can be stored on different machines. This approach of horizontal scaling enables Elasticsearch\nto store much larger indices than could fit on a single machine. To ensure high availability and \nscale out read access, shards are usually also replicated onto multiple machines. The main copy \nis called the primary, all other copies are simply called replicas. The number of primary shards \nfor an index is fixed at creation time, which allows to deterministically route requests for specific \ndocuments to the right shard, based on a hash of the document key (called the document \"_id\"). In the \ncontext of data replication, shards do their work independently from each other. The specification \ntherefore only considers a single primary shard together with its copies, the replicas. It assumes a \nfixed set of nodes, each of which can host either the primary or one of the replicas. Shard allocation \n(i.e. which node has which shard) is dynamic and determined by the master, a process in the cluster \nthat is backed by a consensus module. The TLA+ specification does not model the consensus module, it \nassumes that this component is working correctly. It shows however how data replication integrates with \nthe consensus module to achieve its guarantees.\n\nHow data is replicated\n----------------------\n\nClients send requests to an arbitrary node in the cluster. The node then routes the request to the\nnode in the cluster that has the primary shard for the corresponding document id. The document is\nindexed at the primary and then replicated concurrently to the replicas. The replicas index the\ndocument and confirm successful replication to the primary. The primary then acknowledges successful\nreplication to the client.\n\nWhat's covered / not covered in this model\n------------------------------------------\n\nFailures covered by the model:\n\n- node crashes\n\n- disconnects between nodes on a per request basis\n\nAlso covered:\n\n- cluster state batching / asynchronous application (each node applies the cluster state, which is\nthe state backed by the consensus model, at different points in time)\n\n- network delays: messages can arrive out-of-order and be delayed\n\nLimitations of the model:\n\n- shard initialization / recovery is not modeled: the model initially assumes shards to be started.\nWhen a shard fails, it is not reallocated / reassigned to another node but stays unassigned.\nWhen a primary shard fails, a random replica is promoted to primary (if replica exists).\n\n- only the transaction log is modeled. Lucene store as an optimistic consumer of the transaction log\nis not modeled.\n\n- adding nodes to the cluster is not modeled, whereas in Elasticsearch, nodes can dynamically \nbe added to the cluster and those nodes will share in the hosting of shard data (shard data is \nmoved to the new node through the process of recovery, mentioned above, which is also not modeled).\n\nOther differences between model and current Java implementation:\n\n- the Java implementation uses zero-based numbering for sequence numbers whereas the TLA+ model\nstarts from one, as this is the natural way to access the first element of a sequence in TLA+.\n\n- ...\n\n\n------------------------------ MODULE replication ---------------------------------\n\n\\* Imported modules used in this specification\nEXTENDS Naturals, FiniteSets, Sequences, TLC\n\n----\n\n\\* `^\\Large\\bf Constants ^'\n\n\\* The specification first defines the constants of the model, which amount to values or sets of\n\\* values that are fixed.\n\n\\* Set of node ids uniquely representing each data node in the cluster\nCONSTANTS Nodes\n\n\\* Set of possible document ids (i.e. values for \"_id\" field)\nCONSTANTS DocumentIds\n\n(* Communication between the nodes is done using an RPC-like mechanism.\n   For each request there is an associated response. In-flight requests / responses are modeled\n   using messages, which are represented in TLA+ as record types. To distinguish requests from\n   responses, the message record type contains a field \"request\" that denotes whether the message is\n   a request or a response (takes as value one of {TRUE, FALSE}). It also contains the node id of\n   the sender and receiver of the call (in the fields \"source\" and \"dest\"). The procedure that is\n   called is found under the field \"method\".\n\n   For example, sending a replication request from node n1 to n2 would yield the following message:\n      [request   |-> TRUE,\n       method    |-> Replication,\n       source    |-> n1,\n       dest      |-> n2]\n\n   Responses also have a field \"success\" which indicates whether the call was successful\n   or not (one of {TRUE, FALSE}).\n\n   The model currently supports two RPC methods, one to replicate data from the primary to the \n   replicas and another one to trim the translog (explained later). The reroute logic for rerouting\n   requests to the primary is not modeled as it has no impact on consistency/durability guarantees.\n*) \nCONSTANTS Replication, TrimTranslog\n\n(* Shard allocation is determined by the master and broadcasted to the data nodes in the form of a\n   routing table, which is a map from node id to one of {Primary, Replica, Unassigned}, denoting \n   whether the respective node has the primary shard, a replica shard or no shard assigned at all.\n*)\nCONSTANTS Primary, Replica, Unassigned\n\n\\* The constant \"Nil\" denotes a non-existing value (e.g. in transaction log) or a place-holder for\n\\* a value that is to be computed.\nCONSTANTS Nil\n\n----\n\n\\* `^\\Large\\bf Variables ^'\n\n\\* The following describes the variable state of the model.\n\n\\* Set of in-flight requests and responses sent between data nodes.\nVARIABLE messages\n\n(* Beside managing and broadcasting the routing table, the master also tracks if\n   a primary failed and/or a replica was promoted to primary, incrementing a number called the \n   \"primary term\" whenever this happens. Each new primary operates under a new term, allowing nodes\n   to reject replication requests that come from a primary that has been demoted by the master.\n   The routing table and primary term together form the cluster state, which is simply a record type\n   containing both:\n\n      [routingTable |->\n          [n1 |-> Primary,\n           n2 |-> Replica,\n           n3 |-> Unassigned],\n       primaryTerm |-> 1]\n\n   The following variable represents the current cluster state on the master, which is not\n   explicitly modeled as a node.\n*)\nVARIABLE clusterStateOnMaster\n\n\\* For simplicity we assume that each client (index) request uses a new unique value to be indexed.\n\\* This is just a natural number incremented on each client operation.\nVARIABLE nextClientValue\n\n\\* The set of (acknowledged) client responses. Stored in a variable so that we can make assertions\n\\* about successfully acknowledged requests (e.g. that they've been successfully stored).\nVARIABLE clientResponses\n\n\\* To improve readibility of the specification, the following placeholder clientVars can be used\n\\* instead of explicitly writing the two variables on the right hand side.\nclientVars == <<nextClientValue, clientResponses>>\n\n(* After indexing a document into the primary, it is replicated concurrently to the replicas.\n   Writes are only acknowledged to the client after all replicas have acknowledged their writes to\n   the primary. To correlate acknowledgements from multiple replicas for the same write on the\n   primary, we use a unique request id that is shared by the concurrent replication requests going\n   out to the replicas for each specific indexing operation on the primary. The responses carry the\n   same request id as the requests they were originating from.\n\n   This is just a natural number denoting the next available request id. It is incremented whenever\n   a request id is used.\n*)\nVARIABLE nextRequestId\n\n\n\\* The following variables capture state on a per-node basis (maps with domain nodes).\n\n(* Cluster states are determined by the master and broadcasted to nodes. Due to the distributed\n   nature of the system, they can arrive and be applied at different times on the nodes. ES only\n   guarantees that an older state is not applied on a node after a new one has been applied on the\n   same node. It supports batching, however, so cluster states can be skipped if a newer has\n   already arrived on a node before the old one has been processed on that node.\n\n   Cluster states applied on each node are represented as a map from node id to cluster state that\n   is currently applied on this node \n*)\nVARIABLE clusterStateOnNode\n\n(* The cluster state contains the current term number. Nodes might learn about the highest primary\n   term number not only through cluster state updates, but also through other node-to-node\n   communication such as replication requests. They store the most recent information (highest term\n   they've heard about). The variable \"currentTerm\" is a map from node id to primary term number,\n   representing the highest primary term number that is known to the node.\n*)\nVARIABLE currentTerm\n\n(* The transaction log is a history of operations. The primary shard determines the order in which\n   operations occur by assigning consecutive sequence numbers to the operations that are indexed.\n   The sequence number represents a slot in the transaction log that is occupied by the operation.\n   When a write on a primary is replicated to replicas, the replication request contains the sequence\n   number that was assigned to this operation on the primary. The replica then assigns the operation\n   to the same slot in its transaction log. Due to the concurrent nature of replication, replicas\n   might fill these slots out-of-order. If the primary crashes or some replication requests don't make\n   it to the replica, the replica can end up in a state where its transaction log has holes in it\n   (slots that are not filled while subsequent slots are filled).\n\n   Example of a transaction log on the primary and a replica:\n   `.\n                ---------------------\n                | 1 | 2 | 3 | 4 | 5 |\n      primary   |-------------------|\n                | x | x | x | x |   |\n                ---------------------\n\n                ---------------------\n                | 1 | 2 | 3 | 4 | 5 |\n      replica   |-------------------|  (request for slot 2 is still in-flight)\n                | x |   | x | x |   |\n                ---------------------\n   .'\n\n   The transaction log is modeled as a map from node id to map from sequence number to record type\n   consisting of document id, value to be stored, primary term and \"pending confirmation\" marker\n   (more on that later).\n*)\nVARIABLE tlog\n\n(* Having a transaction log in place, it is useful to know about the highest slot in the transaction\n   log where all slots below it have been successfully replicated to all replicas, i.e. the common\n   history shared by all in-sync shard copies. It is useful because in the case where a primary\n   fails, a replica which is promoted to primary knows that it has to only worry about being out of sync\n   with other replicas on slots that are beyond this slot. The primary is in charge of tracking\n   this information, also called global checkpoint. For this, replica shards share information with the\n   primary on the highest slot they have filled where all lower slots are filled as well, called the\n   local checkpoint. The primary then establishes the global checkpoint as the minimum of the local\n   checkpoint value received from all shard copies (including its own local checkpoint) and broadcasts \n   this information to the replicas.\n\n   The global checkpoint is modeled as a map from node id to sequence number.\n*)\nVARIABLE globalCheckPoint\n\n(* The local checkpoint is modeled as a map from node id (node that is doing the tracking)\n   to node id (node for which the local checkpoint is being tracked) to sequence number.\n\n   Only the primary maintains the local checkpoints from all replicas, but because of the possibility of \n   the primary changing over time, and in order to separate the state for each node more clearly, we maintain \n   a node id to local checkpoint map for each node in the cluster.\n*)\nVARIABLE localCheckPoint\n\n\\* The placeholder \"nodeVars\" is used as a shorthand for all node variables\nnodeVars == <<clusterStateOnNode, tlog, localCheckPoint, globalCheckPoint, currentTerm>>\n\n\n----\n\n\\* `^\\Large\\bf General helper functions ^'\n\n\\* Return the minimum value from a set, or undefined if the set is empty.\nMin(s) == CHOOSE x \\in s : \\A y \\in s : x <= y\n\n\\* Return the maximum value from a set, or undefined if the set is empty.\nMax(s) == CHOOSE x \\in s : \\A y \\in s : x >= y\n\n----\n\n\\* `^\\Large\\bf Helper functions on routing table ^'\n\n(* Note, in this section, the terms \"shard\" and \"node id\" are conflated, because\n   we are only considering one shard and all its copies, so each shard can be \n   uniquely identified by the node it resides on. The term \"shard\" or \"node\" is chosen \n   solely based on the context of what is being explained or specified.\n*)\n\n\\* Returns shards that are marked as Primary in routing table\nPrimaries(routingTable) == {n \\in DOMAIN routingTable : routingTable[n] = Primary}\n\n\\* Returns shards that are marked as Replica in routing table\nReplicas(routingTable) == {n \\in DOMAIN routingTable : routingTable[n] = Replica}\n\n\\* Returns shards that are marked as Primary or Replica in routing table\nAssigned(routingTable) == {n \\in DOMAIN routingTable : routingTable[n] /= Unassigned}\n\n\\* Determines whether the shard on node n was promoted to primary when a cluster state update occurs\nShardWasPromotedToPrimary(n, incomingRoutingTable, localRoutingTable) ==\n  LET oldPrimaries == Primaries(localRoutingTable)\n      newPrimaries == Primaries(incomingRoutingTable)\n  IN  /\\ n \\notin oldPrimaries\n      /\\ n \\in newPrimaries\n\n\\* Calculates new cluster state based on shard failure on node n\nFailShardOnMaster(n) ==\n  LET rt == clusterStateOnMaster.routingTable\n  IN\n    IF rt[n] = Unassigned THEN\n      UNCHANGED <<clusterStateOnMaster>>\n    ELSE\n      \\* increase primary term on primary failure\n      LET newPt == IF rt[n] = Primary THEN\n                     clusterStateOnMaster.primaryTerm + 1\n                   ELSE\n                     clusterStateOnMaster.primaryTerm\n      IN\n        IF rt[n] = Primary /\\ Cardinality(Replicas(rt)) > 0 THEN\n          \\* promote replica to primary\n          \\E r \\in Replicas(rt):\n            clusterStateOnMaster' = [clusterStateOnMaster EXCEPT\n              !.routingTable = [rt EXCEPT ![n] = Unassigned, ![r] = Primary],\n              !.primaryTerm  = newPt]\n        ELSE\n          clusterStateOnMaster' = [clusterStateOnMaster EXCEPT\n            !.routingTable[n] = Unassigned,\n            !.primaryTerm  = newPt]\n\n----\n\n\\* `^\\Large\\bf Helper functions for sending/receiving messages ^'\n\n\\* Remove request from the set of messages and add response instead\nReply(response, request) == messages' = {response} \\cup (messages \\ {request})\n\n\\* Generate default replication response based on replication request m\n\\* Copies most of the fields over for convenience (to restore caller information upon return)\nDefaultReplicationResponse(m) == [request   |-> FALSE,\n                                  method    |-> m.method,\n                                  source    |-> m.dest,\n                                  dest      |-> m.source,\n                                  req       |-> m.req,\n                                  id        |-> m.id,\n                                  seq       |-> m.seq,\n                                  rterm     |-> m.rterm,\n                                  sterm     |-> m.sterm,\n                                  value     |-> m.value,\n                                  client    |-> m.client,\n                                  localCP   |-> 0,\n                                  success   |-> TRUE]\n\n\\* Generate default trim translog response based on trim translog request m\nDefaultTrimTranslogResponse(m) == [request   |-> FALSE,\n                                   method    |-> m.method,\n                                   source    |-> m.dest,\n                                   dest      |-> m.source,\n                                   req       |-> m.req,\n                                   maxseq    |-> m.maxseq, \\* trim above this sequence number\n                                   term      |-> m.term, \\* trim entries with term lower than this\n                                   success   |-> TRUE]\n\n\\* Generate default response based on request m\nDefaultResponse(m) == IF m.method = Replication THEN\n                        DefaultReplicationResponse(m)\n                      ELSE\n                        DefaultTrimTranslogResponse(m)\n\n\\* Generate default failure response based on request m\nFailedResponse(m) == [DefaultResponse(m) EXCEPT !.success = FALSE]\n\n----\n\n\\* `^\\Large\\bf Helper functions on translog ^'\n\n(* When a request comes to a primary, it has to select a slot (the sequence number) to put the\n   request into. It corresponds to the slot in the transaction log right after the highest slot\n   that's filled.\n   The following function yields the highest slot that's filled in the transaction log, or 0 if\n   no such slot exists.\n*)\nMaxSeq(ntlog) == Max(DOMAIN ntlog \\cup {0})\n\n(* `^\\bf\\large MaxConfirmedSeq ^'\n   The local checkpoint is defined as the highest slot in the translog, where all lower slots\n   are filled. It is not only holes in the translog that prevent the local checkpoint from moving foward. \n   We actually want to prevent the local checkpoint from moving past slots which are filled but marked as \n   pending confirmation. Pending entries in the translog are entries that appear after the global checkpoint that are not\n   allowed to contribute to the advancement of the local checkpoint until a resyncing phase happens due to \n   the primary shard changing nodes. Translog entries thus have a \"pc\" (pending confirmation) marker\n   (\\in {TRUE, FALSE}) that says whether the local checkpoint can move past them.\n   This function yields highest sequence number which are not pending confirmation and where\n   all lower slots are not pending confirmation either.\n   Yields 0 if no such number exists.\n\n   Examples: (T stands for TRUE, F for FALSE) \n   `.\n                  ---------------------\n                  | 1 | 2 | 3 | 4 | 5 |\n                  |-------------------|     MaxConfirmedSeq = 1\n                  | x | x | x | x |   |\n      pc markers: | F | T | T | F |   |\n                  ---------------------\n\n                  ---------------------\n                  | 1 | 2 | 3 | 4 | 5 |\n                  |-------------------|     MaxConfirmedSeq = 2\n                  | x | x |   | x |   |\n      pc markers: | F | F |   | F |   |\n                  ---------------------\n   .'\n*)\nMaxConfirmedSeq(ntlog) ==\n  LET ConfirmedTlogSlot(i) == i \\in DOMAIN ntlog /\\ ntlog[i].pc = FALSE\n  IN  CHOOSE i \\in (DOMAIN ntlog \\cup {0}) : /\\ ConfirmedTlogSlot(i+1) = FALSE\n                                             /\\ \\A j \\in 1..i : ConfirmedTlogSlot(j)\n\n(* `^\\bf\\large MarkPC ^'\n   Yields translog where all entries at position strictly larger than \"globalCP\" (representing the\n   global checkpoint) are marked as \"pending confirmation\".\n\n   Example: \n   `.\n      ---------------------   MarkPC          ---------------------\n      | 1 | 2 | 3 | 4 | 5 |   ----------->    | 1 | 2 | 3 | 4 | 5 |\n      |-------------------|   globalCP = 1    |-------------------|\n      | x | x |   | x |   |                   | x | x |   | x |   |\n      | F | F |   | F |   |                   | F | T |   | T |   |\n      ---------------------                   ---------------------\n   .'\n*)\nMarkPC(ntlog, globalCP) ==\n  [j \\in DOMAIN ntlog |-> [ntlog[j] EXCEPT !.pc = IF j > globalCP THEN TRUE ELSE @]]\n\n(* `^\\bf\\large FillAndUnmarkPC ^'\n   Yields translog where all gaps are filled and the pending confirmation marker is set to FALSE\n   for values at position strictly larger than \"globalCP\" representing the global checkpoint\n\n   Example: \n   `.\n      ---------------------   FillAndUnmarkPC ---------------------\n      | 1 | 2 | 3 | 4 | 5 |   ----------->    | 1 | 2 | 3 | 4 | 5 |\n      |-------------------|   globalCP = 1    |-------------------|\n      | x | x |   | x |   |                   | x | x | x | x |   |\n      | T | T |   | F |   |                   | T | F | F | F |   |\n      ---------------------                   ---------------------\n   .'\n*)\nFillAndUnmarkPC(ntlog, storedTerm, globalCP) ==\n  [j \\in 1..Max(DOMAIN ntlog \\cup {0}) |->\n    IF j > globalCP THEN\n      IF j \\in DOMAIN ntlog THEN\n        [ntlog[j] EXCEPT !.pc = FALSE]\n      ELSE\n        [id    |-> Nil,\n         term  |-> storedTerm,\n         value |-> Nil,\n         pc    |-> FALSE]\n    ELSE\n      ntlog[j]]\n\n(* `^\\bf\\large TrimTlog ^'\n   Trim elements from translog with position strictly greater than maxseq and\n   term strictly lower than minterm.\n\n   Example: \n   `.\n          ---------------------   TrimTlog        ---------------------\n          | 1 | 2 | 3 | 4 | 5 |   ----------->    | 1 | 2 | 3 | 4 | 5 |\n          |-------------------|   maxseq = 2      |-------------------|\n          | x | x | x | x | x |   minterm = 2     | x | x | x |   | x |\n          | T | T | T | F | T |                   | T | T | T |   | F |\n   terms: | 1 | 1 | 2 | 1 | 2 |                   | 1 | 1 | 2 |   | 2 |\n          ---------------------                   ---------------------\n   .'\n*)\nTrimTlog(ntlog, maxseq, minterm) ==\n  [j \\in {i \\in DOMAIN ntlog : i <= maxseq \\/ ntlog[i].term >= minterm} |-> ntlog[j]]\n\n----\n\n\\* `^\\Large\\bf Initial states ^'\n\n\\* All possible routing tables where there is one primary\nRoutingTablesWithPrimary ==\n  UNION {\n    {\n      [n \\in {pn} |-> Primary] @@ \\* pn has the primary\n      [n \\in rs |-> Replica] @@ \\* rs is the subset of nodes having replicas\n      [n \\in ((Nodes \\ rs) \\ {pn}) |-> Unassigned] \\* remaining nodes have unassigned shards\n        : rs \\in SUBSET (Nodes \\ {pn})\n    } : pn \\in Nodes\n  }\n\n\\* Possible initial routing tables are those which have a primary or where all shards are unassigned\nInitialRoutingTables == RoutingTablesWithPrimary \\cup {[n \\in Nodes |-> Unassigned]}\n\n\\* The following constant denotes the set of possible initial cluster states that are to be\n\\* considered for exploring the model, containing cluster states such as\n\\* [ routingTable |-> [n1 |-> Primary, n2 |-> Replica, n3 |-> Replica], primaryTerm |-> 1 ]\nInitialClusterStates == { [routingTable |-> rt, primaryTerm |-> 1] : rt \\in InitialRoutingTables }\n\nInit == /\\ clusterStateOnMaster \\in InitialClusterStates\n        /\\ messages           = {}\n        /\\ nextClientValue    = 1\n        /\\ clientResponses    = {}\n        /\\ nextRequestId      = 1\n        /\\ tlog               = [n \\in Nodes |-> << >>]\n        /\\ localCheckPoint    = [n1 \\in Nodes |-> [n2 \\in Nodes |-> 0]]\n        /\\ globalCheckPoint   = [n \\in Nodes |-> 0]\n        /\\ clusterStateOnNode = [n \\in Nodes |-> clusterStateOnMaster]\n        /\\ currentTerm        = [n \\in Nodes |-> clusterStateOnMaster.primaryTerm]\n\n----\n\n\\* `^\\Large\\bf Next-step relations ^'\n\n\\* Index request arrives on node n with document id docId\nClientRequest(n, docId) ==\n  /\\ clusterStateOnNode[n].routingTable[n] = Primary \\* node believes itself to be the primary\n  /\\ LET\n       replicas     == Replicas(clusterStateOnNode[n].routingTable)\n       primaryTerm  == currentTerm[n]\n       tlogEntry    == [id    |-> docId,\n                        term  |-> primaryTerm,\n                        value |-> nextClientValue,\n                        pc    |-> FALSE]\n       seq          == MaxSeq(tlog[n]) + 1\n       \\* create replication requests for each replica that the primary knows about\n       replRequests == {([request  |-> TRUE,\n                          method   |-> Replication,\n                          source   |-> n,\n                          dest     |-> rn,\n                          req      |-> nextRequestId,\n                          id       |-> docId,\n                          value    |-> nextClientValue,\n                          seq      |-> seq,\n                          rterm    |-> primaryTerm, \\* current term when issuing request\n                          sterm    |-> primaryTerm, \\* term to be stored (differs for fast resync)\n                          client   |-> TRUE, \\* it's a replication request initiated by client\n                          globalCP |-> globalCheckPoint[n]]) : rn \\in replicas}\n     IN \n       \\* put entry into translog\n       /\\ tlog' = [tlog EXCEPT ![n] = (seq :> tlogEntry) @@ @]\n       \\* Make sure that each client request uses a unique value\n       /\\ nextClientValue' = nextClientValue + 1\n       \\* set next unique key to use for replication requests so that we can relate responses\n       /\\ nextRequestId' = nextRequestId + 1\n       \\* update local checkpoint\n       /\\ localCheckPoint' = [localCheckPoint EXCEPT ![n][n] = seq]\n       /\\ Assert(localCheckPoint'[n][n] = localCheckPoint[n][n] + 1, \"localCheckPoint incremented\")\n       \\* send out replication requests\n       /\\ messages' = messages \\cup replRequests\n       /\\ IF replicas = {} THEN\n            \\* no replicas, directly acknowledge to the client\n            /\\ clientResponses' = clientResponses \\cup {[success |-> TRUE,\n                                                         id      |-> docId,\n                                                         value   |-> nextClientValue,\n                                                         seq     |-> seq,\n                                                         term    |-> primaryTerm]}\n          ELSE\n            \\* replication requests sent out, wait for responses before acking to client\n            /\\ UNCHANGED <<clientResponses>>\n  /\\ UNCHANGED <<clusterStateOnMaster, clusterStateOnNode, globalCheckPoint, currentTerm>>\n\n\\* Helper function for marking translog entries as pending confirmation if incoming term is higher\n\\* than current term on node n.\nMaybeMarkPC(incomingTerm, n, globalCP) ==\n  IF incomingTerm > currentTerm[n] THEN\n    \\* there is a new primary, cannot safely advance local checkpoint\n    \\* before resync done, move it back to global checkpoint and add\n    \\* pending confirmation marker to all entries above global checkpoint\n    MarkPC(tlog[n], globalCP)\n  ELSE\n    tlog[n]\n    \n(* \n`^\\bf Note on handling replication requests with higher primary terms^'\nIf a replica receives a replication request with a primary term greater than its current primary term, \nit means that new primary was promoted. The `^na\\\"ive^' handling of this case would be to forget all translog\noperations above global checkpoint, reset local checkpoint to global checkpoint and await replay \nof operations above global checkpoint from the newly promoted primary.\nHowever, this approach does not work, because newly promoted primary might fail during resync process\nand if our replica is promoted to primary - it may miss operations above global checkpoint, effectively \nlosing acknowledged writes.\n\nThat's why we preserve existing entries in translog above global checkpoint but mark them as \npending confirmation. During operations replay, replica replaces its translog entry with the entry received \nfrom the primary (which can be noop) and resets pending confirmation flag. \n*)\n\\* Replication request arrives on node n with message m\nHandleReplicationRequest(n, m) ==\n   /\\ m.request = TRUE\n   /\\ m.method = Replication\n   /\\ IF m.rterm < currentTerm[n] THEN\n        \\* don't accept replication requests with lower term than we have\n        \\* lower term means that it's coming from a primary that has since been demoted\n        /\\ Reply(FailedResponse(m), m)\n        /\\ UNCHANGED <<clusterStateOnMaster, nextRequestId, clientVars, nodeVars>>\n      ELSE\n        /\\ LET\n             tlogEntry     == [id    |-> m.id,\n                               term  |-> m.sterm,\n                               value |-> m.value,\n                               pc    |-> FALSE]\n             newGlobalCP   == Max({m.globalCP, globalCheckPoint[n]})\n             \\* mark translog entries as pending if higher term and write request into translog\n             newTlog       == (m.seq :> tlogEntry) @@ MaybeMarkPC(m.rterm, n, newGlobalCP)\n             \\* recompute local checkpoint\n             localCP       == MaxConfirmedSeq(newTlog)\n           IN \n             /\\ tlog' = [tlog EXCEPT ![n] = newTlog]\n             /\\ currentTerm' = [currentTerm EXCEPT ![n] = m.rterm]\n             /\\ globalCheckPoint' = [globalCheckPoint EXCEPT ![n] = newGlobalCP]\n             /\\ Reply([DefaultResponse(m) EXCEPT !.localCP = localCP], m)\n        /\\ UNCHANGED <<clusterStateOnMaster, clusterStateOnNode, nextClientValue, nextRequestId,\n                       clientResponses, localCheckPoint>>\n\n\\* Trim translog request arrives on node n with message m\nHandleTrimTranslogRequest(n, m) ==\n  /\\ m.request = TRUE\n  /\\ m.method = TrimTranslog\n  /\\ IF m.term < currentTerm[n] THEN\n       \\* don't handle requests with lower term than we have\n       \\* lower term means that it's coming from a primary that has since been demoted\n       /\\ Reply(FailedResponse(m), m)\n       /\\ UNCHANGED <<tlog, globalCheckPoint, currentTerm>>\n     ELSE\n       /\\ LET\n            newGlobalCP   == Max({m.globalCP, globalCheckPoint[n]})\n            \\* mark translog entries as pending if higher term and trim translog\n            newTlog       == TrimTlog(MaybeMarkPC(m.term, n, newGlobalCP), m.maxseq, m.term)\n          IN\n            /\\ tlog' = [tlog EXCEPT ![n] = newTlog]\n            /\\ globalCheckPoint' = [globalCheckPoint EXCEPT ![n] = newGlobalCP]\n            /\\ currentTerm' = [currentTerm EXCEPT ![n] = m.term]\n            /\\ Reply(DefaultResponse(m), m)\n  /\\ UNCHANGED <<clusterStateOnMaster, nextRequestId, clientVars, localCheckPoint,\n                 clusterStateOnNode>>\n\n\\* Helper function for handling replication responses\nFinishIfNeeded(m) ==\n  \\* check if this is the last response we're waiting for\n  IF /\\ m.client\n     /\\ { ms \\in messages : ms.req = m.req } = {m}\n     \\* check if the request has not been failed already to the client\n     /\\ { cr \\in clientResponses : cr.success = FALSE /\\ cr.req = m.req } = {} THEN\n    clientResponses' = clientResponses \\cup {[success |-> TRUE,\n                                              id      |-> m.id,\n                                              value   |-> m.value,\n                                              seq     |-> m.seq,\n                                              term    |-> m.rterm]}\n  ELSE\n    UNCHANGED <<clientResponses>>\n\n\\* Helper function for handling replication responses\nFinishAsFailed(m) ==\n  /\\ clientResponses' = clientResponses \\cup {[success |-> FALSE,\n                                               req     |-> m.req]}\n\n\\* Replication response arrives on node n from node rn with message m\nHandleReplicationResponse(n, rn, m) ==\n  /\\ m.request = FALSE\n  /\\ m.method = Replication\n  \\* are we still interested in the response or already marked the overall client request as failed?\n  /\\ IF m.success THEN\n       \\* is it a newer local checkpoint than we have?\n       /\\ IF m.localCP > localCheckPoint[n][rn] /\\\n             \\* is the shard still active on this node?\n             clusterStateOnNode[n].routingTable[n] /= Unassigned THEN\n            LET\n              newLocalCheckPoint == [localCheckPoint EXCEPT ![n][rn] = m.localCP]\n              assigned           == Assigned(clusterStateOnNode[n].routingTable)\n              computedGlobalCP   == Min({newLocalCheckPoint[n][i] : i \\in assigned})\n            IN\n              /\\ localCheckPoint'  = newLocalCheckPoint\n              \\* also update global checkpoint if necessary\n              /\\ globalCheckPoint' = [globalCheckPoint EXCEPT ![n] = computedGlobalCP]\n          ELSE\n            UNCHANGED <<localCheckPoint, globalCheckPoint>>\n       /\\ UNCHANGED <<clusterStateOnMaster, clusterStateOnNode>>\n       /\\ FinishIfNeeded(m)\n     ELSE\n       \\* replication failed, ask master to fail shard\n       /\\ IF m.rterm < clusterStateOnMaster.primaryTerm THEN\n            \\* term outdated, fail itself and don't ack client write\n            /\\ FinishAsFailed(m)\n            /\\ UNCHANGED <<clusterStateOnMaster>>\n          ELSE\n            \\* fail shard and respond to client\n            /\\ FailShardOnMaster(rn)\n            /\\ FinishIfNeeded(m)\n       /\\ UNCHANGED <<localCheckPoint, globalCheckPoint>>\n  /\\ messages' = messages \\ {m}\n  /\\ UNCHANGED <<nextClientValue, nextRequestId, tlog, clusterStateOnNode,\n                 currentTerm>>\n\n\n\\* Trim translog response arrives on node n from node rn with message m\nHandleTrimTranslogResponse(n, rn, m) ==\n   /\\ m.request = FALSE\n   /\\ m.method = TrimTranslog\n   /\\ messages' = messages \\ {m}\n   /\\ IF m.success = FALSE /\\ m.term >= clusterStateOnMaster.primaryTerm THEN\n        \\* fail shard\n        FailShardOnMaster(rn)\n      ELSE\n        UNCHANGED <<clusterStateOnMaster>>\n   /\\ UNCHANGED <<nextClientValue, nextRequestId, nodeVars, clientResponses>>\n\n\\* Cluster state propagated from master is applied to node n\nApplyClusterStateFromMaster(n) ==\n  /\\ clusterStateOnNode[n] /= clusterStateOnMaster\n  /\\ clusterStateOnNode' = [clusterStateOnNode EXCEPT ![n] = clusterStateOnMaster]\n  /\\ IF ShardWasPromotedToPrimary(n, clusterStateOnMaster.routingTable,\n         clusterStateOnNode[n].routingTable) THEN\n       \\* shard promoted to primary, resync with replicas\n       LET\n         ntlog          == tlog[n]\n         globalCP       == globalCheckPoint[n]\n         newTerm        == clusterStateOnMaster.primaryTerm\n         \\* fill gaps in tlog and remove pending confirmation marker\n         newTlog        == FillAndUnmarkPC(ntlog, newTerm, globalCP)\n         replicas       == Replicas(clusterStateOnMaster.routingTable)\n         numReplicas    == Cardinality(replicas)\n         startSeq       == globalCP + 1\n         endSeq         == Max((DOMAIN ntlog) \\cup {0})\n         numDocs        == endSeq + 1 - startSeq\n         \\* resend all translog entries above global checkpoint to replicas\n         replRequests   == {([request  |-> TRUE,\n                              method   |-> Replication,\n                              source   |-> n,\n                              dest     |-> rn,\n                              req      |-> nextRequestId + (i - startSeq),\n                              seq      |-> i,\n                              rterm    |-> newTerm, \\* new term when issuing request\n                              sterm    |-> newTlog[i].term, \\* stored term for entry\n                              id       |-> newTlog[i].id,\n                              value    |-> newTlog[i].value,\n                              client   |-> FALSE, \\* request not initiated by client\n                              globalCP |-> globalCP]) : i \\in startSeq..endSeq, rn \\in replicas}\n         \\* send trim request to replicas\n         trimRequests   == {[request  |-> TRUE,\n                             method   |-> TrimTranslog,\n                             source   |-> n,\n                             dest     |-> rn,\n                             req      |-> nextRequestId + numDocs,\n                             maxseq   |-> endSeq,\n                             term     |-> newTerm,\n                             client   |-> FALSE,\n                             globalCP |-> globalCP] : rn \\in replicas}\n       IN\n         /\\ currentTerm' = [currentTerm EXCEPT ![n] = newTerm]\n         /\\ tlog' = [tlog EXCEPT ![n] = newTlog]\n         /\\ localCheckPoint' = [localCheckPoint EXCEPT ![n][n] = MaxConfirmedSeq(newTlog)]\n         /\\ messages' = messages \\cup replRequests \\cup trimRequests\n         /\\ nextRequestId' = nextRequestId + numDocs + 1\n    ELSE\n      /\\ UNCHANGED <<messages, nextRequestId, currentTerm, localCheckPoint, tlog>>\n  /\\ UNCHANGED <<clusterStateOnMaster, clientVars,\n                 globalCheckPoint>>\n\n\n\\* Fail request message\nFailRequestMessage(m) ==\n  /\\ m.request = TRUE\n  /\\ Reply(FailedResponse(m), m)\n  /\\ UNCHANGED <<clusterStateOnMaster, nextRequestId, clientVars, nodeVars>>\n\n\\* Fail response message\nFailResponseMessage(m) ==\n  /\\ m.request = FALSE\n  /\\ m.success = TRUE\n  /\\ Reply([m EXCEPT !.success = FALSE], m)\n  /\\ UNCHANGED <<clusterStateOnMaster, nextRequestId, clientVars, nodeVars>>\n\n\\* Node fault detection on master finds node n to be isolated from the cluster or crashed\nNodeFaultDetectionKicksNodeOut(n) ==\n  /\\ clusterStateOnMaster.routingTable[n] /= Unassigned \\* not already unassigned\n  /\\ FailShardOnMaster(n) \n  /\\ UNCHANGED <<messages, nextRequestId, clientVars, nodeVars>>\n\n\\* Defines how the variables may transition.\nNext == \\/ \\E n \\in Nodes : \\E docId \\in DocumentIds : ClientRequest(n, docId)\n        \\/ \\E m \\in messages : HandleReplicationRequest(m.dest, m)\n        \\/ \\E m \\in messages : HandleReplicationResponse(m.dest, m.source, m)\n        \\/ \\E m \\in messages : HandleTrimTranslogRequest(m.dest, m)\n        \\/ \\E m \\in messages : HandleTrimTranslogResponse(m.dest, m.source, m)\n        \\/ \\E m \\in messages : FailRequestMessage(m)\n        \\/ \\E m \\in messages : FailResponseMessage(m)\n        \\/ \\E n \\in Nodes : ApplyClusterStateFromMaster(n)\n        \\/ \\E n \\in Nodes : NodeFaultDetectionKicksNodeOut(n)\n\n----\n\n\\* `^\\Large\\bf Helper functions for making assertions ^'\n\n\\* no active messages\nNoActiveMessages == messages = {}\n\n\\* shard that is considered active by the master\nActiveShard(n) == clusterStateOnMaster.routingTable[n] /= Unassigned\n\n\\* cluster state on master has been applied to all nodes that are still supposed to have an active shard\nClusterStateAppliedOnAllNodesWithActiveShards ==\n  \\A n \\in Nodes : ActiveShard(n) => clusterStateOnNode[n] = clusterStateOnMaster\n\n\\* everything in the translog up to and including slot i\nUpToSlot(ntlog, i) == [j \\in 1..i |-> ntlog[j]]\n\n\\* copy of translog, where we ignore the pending confirmation marker\nExceptPC(ntlog) == [j \\in DOMAIN ntlog |-> [r \\in DOMAIN ntlog[j] \\ {\"pc\"} |-> ntlog[j][r] ]]\n\n\\* all shard copies contain same data\nAllCopiesSameContents ==\n  \\A n1, n2 \\in Nodes:\n       /\\ n1 /= n2\n       /\\ ActiveShard(n1)\n       /\\ ActiveShard(n2) \n    => ExceptPC(tlog[n1]) = ExceptPC(tlog[n2])\n\n----\n\n\\* `^\\Large\\bf Main invariants ^'\n\n\\* checks if the translog for all nodes are equivalent up to their global checkpoint, only differing\n\\* in the safety marker (which can be false sometimes if the global checkpoint on one shard is lower\n\\* than on another one)\nSameTranslogUpToGlobalCheckPoint ==\n  \\A n1, n2 \\in Nodes:\n       /\\ n1 /= n2\n       /\\ ActiveShard(n1)\n       /\\ ActiveShard(n2)\n    => ExceptPC(UpToSlot(tlog[n1], globalCheckPoint[n1])) = \n         ExceptPC(UpToSlot(tlog[n2], globalCheckPoint[n1]))\n\n\\* checks if the translog for all nodes is eventually the same\nAllCopiesSameContentsOnQuietDown ==\n      (/\\ NoActiveMessages\n       /\\ ClusterStateAppliedOnAllNodesWithActiveShards)\n    => AllCopiesSameContents\n\n\\* checks if all (acked) responses to client are successfully and correctly stored \nAllAckedResponsesStored ==\n    \\A r \\in clientResponses : \\A n \\in Nodes :\n      /\\ r.success = TRUE\n      /\\ ActiveShard(n)\n      => /\\ r.seq \\in DOMAIN tlog[n]\n         /\\ tlog[n][r.seq].id = r.id\n         /\\ tlog[n][r.seq].value = r.value\n         /\\ tlog[n][r.seq].term = r.term\n\n\\* checks that the global checkpoint is the same as or below the local checkpoint on each node\nGlobalCheckPointBelowLocalCheckPoints ==\n    \\A n \\in Nodes : globalCheckPoint[n] <= MaxConfirmedSeq(tlog[n])\n\n\\* local checkpoint always corresponds to MaxSeq and MaxConfirmedSeq on the primary node\nLocalCheckPointMatchesMaxConfirmedSeq ==\n  \\A n \\in Nodes : clusterStateOnNode[n].routingTable[n] = Primary\n    => /\\ localCheckPoint[n][n] = MaxConfirmedSeq(tlog[n])\n       /\\ MaxSeq(tlog[n]) = MaxConfirmedSeq(tlog[n])\n\n\\* routing table is well-formed (has at most one primary, and has no replicas if no primaries)\nWellFormedRoutingTable(routingTable) ==\n  /\\ Cardinality(Primaries(routingTable)) <= 1\n  /\\ (   Cardinality(Primaries(routingTable)) = 0\n      => Cardinality(Assigned (routingTable)) = 0)\n\nStateConstraint ==\n  /\\ nextClientValue <= 3\n  /\\ Cardinality(messages) <= 5\n  /\\ 0 < Cardinality(Assigned (clusterStateOnMaster.routingTable))\n\n=============================================================================\n"
  },
  {
    "path": "data/tla/replication.toolbox/.project",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<projectDescription>\n\t<name>elastic</name>\n\t<comment></comment>\n\t<projects>\n\t</projects>\n\t<buildSpec>\n\t\t<buildCommand>\n\t\t\t<name>toolbox.builder.TLAParserBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t\t<buildCommand>\n\t\t\t<name>toolbox.builder.PCalAlgorithmSearchingBuilder</name>\n\t\t\t<arguments>\n\t\t\t</arguments>\n\t\t</buildCommand>\n\t</buildSpec>\n\t<natures>\n\t\t<nature>toolbox.natures.TLANature</nature>\n\t</natures>\n\t<linkedResources>\n\t\t<link>\n\t\t\t<name>replication.tla</name>\n\t\t\t<type>1</type>\n\t\t\t<locationURI>PARENT-1-PROJECT_LOC/replication.tla</locationURI>\n\t\t</link>\n\t</linkedResources>\n</projectDescription>\n"
  },
  {
    "path": "data/tla/replication.toolbox/.settings/org.lamport.tla.toolbox.prefs",
    "content": "ProjectRootFile=PARENT-1-PROJECT_LOC/replication.tla\neclipse.preferences.version=1\n"
  },
  {
    "path": "data/tla/replication.toolbox/replication___model.launch",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<launchConfiguration type=\"org.lamport.tla.toolbox.tool.tlc.modelCheck\">\n<stringAttribute key=\"TLCCmdLineParameters\" value=\"\"/>\n<intAttribute key=\"autoLockTime\" value=\"15\"/>\n<stringAttribute key=\"configurationName\" value=\"model\"/>\n<intAttribute key=\"dfidDepth\" value=\"100\"/>\n<booleanAttribute key=\"dfidMode\" value=\"false\"/>\n<intAttribute key=\"distributedFPSetCount\" value=\"0\"/>\n<stringAttribute key=\"distributedNetworkInterface\" value=\"192.168.178.34\"/>\n<intAttribute key=\"distributedNodesCount\" value=\"1\"/>\n<stringAttribute key=\"distributedTLC\" value=\"off\"/>\n<stringAttribute key=\"distributedTLCVMArgs\" value=\"\"/>\n<intAttribute key=\"fpBits\" value=\"0\"/>\n<intAttribute key=\"fpIndex\" value=\"1\"/>\n<intAttribute key=\"maxHeapSize\" value=\"20\"/>\n<intAttribute key=\"maxSetSize\" value=\"1000000\"/>\n<booleanAttribute key=\"mcMode\" value=\"true\"/>\n<stringAttribute key=\"modelBehaviorInit\" value=\"Init\"/>\n<stringAttribute key=\"modelBehaviorNext\" value=\"Next\"/>\n<stringAttribute key=\"modelBehaviorSpec\" value=\"Spec\"/>\n<intAttribute key=\"modelBehaviorSpecType\" value=\"2\"/>\n<stringAttribute key=\"modelBehaviorVars\" value=\"nextClientValue, clusterStateOnMaster, globalCheckPoint, tlog, messages, clientResponses, currentTerm, clusterStateOnNode, nextRequestId, localCheckPoint\"/>\n<stringAttribute key=\"modelComments\" value=\"\"/>\n<booleanAttribute key=\"modelCorrectnessCheckDeadlock\" value=\"false\"/>\n<listAttribute key=\"modelCorrectnessInvariants\">\n<listEntry value=\"1AllCopiesSameContentsOnQuietDown\"/>\n<listEntry value=\"1WellFormedRoutingTable(clusterStateOnMaster.routingTable)\"/>\n<listEntry value=\"1GlobalCheckPointBelowLocalCheckPoints\"/>\n<listEntry value=\"1SameTranslogUpToGlobalCheckPoint\"/>\n<listEntry value=\"1AllAckedResponsesStored\"/>\n<listEntry value=\"1LocalCheckPointMatchesMaxConfirmedSeq\"/>\n</listAttribute>\n<listAttribute key=\"modelCorrectnessProperties\">\n<listEntry value=\"1&lt;&gt;AllCopiesSameContents\"/>\n<listEntry value=\"1&lt;&gt;NoActiveMessages\"/>\n<listEntry value=\"1&lt;&gt;AllAckedResponsesStored\"/>\n</listAttribute>\n<stringAttribute key=\"modelExpressionEval\" value=\"\"/>\n<stringAttribute key=\"modelParameterActionConstraint\" value=\"\"/>\n<listAttribute key=\"modelParameterConstants\">\n<listEntry value=\"Primary;;Primary;1;0\"/>\n<listEntry value=\"Replica;;Replica;1;0\"/>\n<listEntry value=\"Unassigned;;Unassigned;1;0\"/>\n<listEntry value=\"Nil;;Nil;1;0\"/>\n<listEntry value=\"Nodes;;{n1, n2, n3};1;1\"/>\n<listEntry value=\"DocumentIds;;{id1, id2};1;1\"/>\n<listEntry value=\"Replication;;Replication;1;0\"/>\n<listEntry value=\"TrimTranslog;;TrimTranslog;1;0\"/>\n</listAttribute>\n<stringAttribute key=\"modelParameterContraint\" value=\"StateConstraint\"/>\n<listAttribute key=\"modelParameterDefinitions\"/>\n<stringAttribute key=\"modelParameterModelValues\" value=\"{}\"/>\n<stringAttribute key=\"modelParameterNewDefinitions\" value=\"\"/>\n<intAttribute key=\"numberOfWorkers\" value=\"4\"/>\n<booleanAttribute key=\"recover\" value=\"false\"/>\n<stringAttribute key=\"result.mail.address\" value=\"\"/>\n<intAttribute key=\"simuAril\" value=\"-1\"/>\n<intAttribute key=\"simuDepth\" value=\"100\"/>\n<intAttribute key=\"simuSeed\" value=\"-1\"/>\n<stringAttribute key=\"specName\" value=\"replication\"/>\n<stringAttribute key=\"view\" value=\"\"/>\n</launchConfiguration>\n"
  }
]