├── .clang-format ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ └── proposal.md ├── dependabot.yml └── workflows │ ├── action.yml │ ├── linter.yml │ ├── proto-check.yml │ ├── proto-dockerfile.yml │ └── stale.yml ├── .gitignore ├── .markdownlint.yml ├── CHANGELOG.md ├── Makefile ├── README.md ├── buf.gen.yaml ├── buf.yaml ├── ivy-proofs ├── Dockerfile ├── README.md ├── abstract_tendermint.ivy ├── accountable_safety_1.ivy ├── accountable_safety_2.ivy ├── check_proofs.sh ├── classic_safety.ivy ├── count_lines.sh ├── docker-compose.yml ├── domain_model.ivy ├── network_shim.ivy ├── output │ └── .gitignore ├── tendermint.ivy └── tendermint_test.ivy ├── proto ├── Dockerfile ├── README.md └── tendermint │ ├── abci │ └── types.proto │ ├── blocksync │ └── types.proto │ ├── consensus │ └── types.proto │ ├── crypto │ ├── keys.proto │ └── proof.proto │ ├── libs │ └── bits │ │ └── types.proto │ ├── mempool │ └── types.proto │ ├── p2p │ ├── conn.proto │ ├── pex.proto │ └── types.proto │ ├── statesync │ └── types.proto │ ├── types │ ├── block.proto │ ├── evidence.proto │ ├── params.proto │ ├── types.proto │ └── validator.proto │ └── version │ └── types.proto ├── rfc ├── 001-block-retention.md ├── 002-nonzero-genesis.md ├── 003-ed25519-verification.md ├── 004-abci++.md ├── 005-reverse-sync.md ├── 006-semantic-versioning.md ├── README.md ├── images │ ├── abci++.png │ ├── abci.png │ └── block-retention.png └── rfc_template.md ├── rust-spec ├── fastsync │ └── README.md └── lightclient │ ├── README.md │ └── verification │ └── README.md ├── spec ├── README.md ├── abci++ │ ├── README.md │ ├── abci++_app_requirements_002_draft.md │ ├── abci++_basic_concepts_002_draft.md │ ├── abci++_methods_002_draft.md │ ├── abci++_tmint_expected_behavior_002_draft.md │ ├── v0.md │ ├── v1.md │ ├── v2.md │ ├── v3.md │ └── v4.md ├── abci │ ├── README.md │ ├── abci.md │ ├── apps.md │ └── client-server.md ├── blockchain │ ├── blockchain.md │ ├── encoding.md │ ├── readme.md │ └── state.md ├── consensus │ ├── bft-time.md │ ├── consensus-paper │ │ ├── IEEEtran.bst │ │ ├── IEEEtran.cls │ │ ├── README.md │ │ ├── algorithmicplus.sty │ │ ├── conclusion.tex │ │ ├── consensus.tex │ │ ├── definitions.tex │ │ ├── homodel.sty │ │ ├── intro.tex │ │ ├── latex8.bst │ │ ├── latex8.sty │ │ ├── lit.bib │ │ ├── paper.tex │ │ ├── proof.tex │ │ ├── rounddiag.sty │ │ └── technote.sty │ ├── consensus.md │ ├── creating-proposal.md │ ├── evidence.md │ ├── light-client │ │ ├── README.md │ │ ├── accountability.md │ │ ├── assets │ │ │ └── light-node-image.png │ │ ├── detection.md │ │ └── verification.md │ ├── proposer-based-timestamp │ │ ├── README.md │ │ ├── pbts-algorithm_002_draft.md │ │ ├── pbts-sysmodel_002_draft.md │ │ ├── tla │ │ │ ├── TendermintPBT_001_draft.tla │ │ │ ├── TendermintPBT_002_draft.tla │ │ │ └── typedefs.tla │ │ └── v1 │ │ │ ├── pbts-algorithm_001_draft.md │ │ │ ├── pbts-sysmodel_001_draft.md │ │ │ └── pbts_001_draft.md │ ├── proposer-selection.md │ ├── readme.md │ ├── signing.md │ └── wal.md ├── core │ ├── data_structures.md │ ├── encoding.md │ ├── genesis.md │ ├── readme.md │ └── state.md ├── light-client │ ├── README.md │ ├── accountability │ │ ├── 001indinv-apalache.csv │ │ ├── MC_n4_f1.tla │ │ ├── MC_n4_f2.tla │ │ ├── MC_n4_f2_amnesia.tla │ │ ├── MC_n4_f3.tla │ │ ├── MC_n5_f1.tla │ │ ├── MC_n5_f2.tla │ │ ├── MC_n6_f1.tla │ │ ├── README.md │ │ ├── Synopsis.md │ │ ├── TendermintAccDebug_004_draft.tla │ │ ├── TendermintAccInv_004_draft.tla │ │ ├── TendermintAccTrace_004_draft.tla │ │ ├── TendermintAcc_004_draft.tla │ │ ├── results │ │ │ ├── 001indinv-apalache-mem-log.svg │ │ │ ├── 001indinv-apalache-mem.svg │ │ │ ├── 001indinv-apalache-ncells.svg │ │ │ ├── 001indinv-apalache-nclauses.svg │ │ │ ├── 001indinv-apalache-report.md │ │ │ ├── 001indinv-apalache-time-log.svg │ │ │ ├── 001indinv-apalache-time.svg │ │ │ └── 001indinv-apalache-unstable.csv │ │ ├── run.sh │ │ └── typedefs.tla │ ├── assets │ │ └── light-node-image.png │ ├── attacks │ │ ├── Blockchain_003_draft.tla │ │ ├── Isolation_001_draft.tla │ │ ├── LCVerificationApi_003_draft.tla │ │ ├── MC_5_3.tla │ │ ├── isolate-attackers_001_draft.md │ │ ├── isolate-attackers_002_reviewed.md │ │ └── notes-on-evidence-handling.md │ ├── detection │ │ ├── 004bmc-apalache-ok.csv │ │ ├── 005bmc-apalache-error.csv │ │ ├── Blockchain_003_draft.tla │ │ ├── LCD_MC3_3_faulty.tla │ │ ├── LCD_MC3_4_faulty.tla │ │ ├── LCD_MC4_4_faulty.tla │ │ ├── LCD_MC5_5_faulty.tla │ │ ├── LCDetector_003_draft.tla │ │ ├── LCVerificationApi_003_draft.tla │ │ ├── README.md │ │ ├── detection_001_reviewed.md │ │ ├── detection_003_reviewed.md │ │ ├── discussions.md │ │ ├── draft-functions.md │ │ └── req-ibc-detection.md │ ├── experiments.png │ ├── supervisor │ │ ├── supervisor_001_draft.md │ │ ├── supervisor_001_draft.tla │ │ └── supervisor_002_draft.md │ └── verification │ │ ├── 001bmc-apalache.csv │ │ ├── 002bmc-apalache-ok.csv │ │ ├── 003bmc-apalache-error.csv │ │ ├── 004bmc-apalache-ok.csv │ │ ├── 005bmc-apalache-error.csv │ │ ├── Blockchain_002_draft.tla │ │ ├── Blockchain_003_draft.tla │ │ ├── Blockchain_A_1.tla │ │ ├── LCVerificationApi_003_draft.tla │ │ ├── Lightclient_002_draft.tla │ │ ├── Lightclient_003_draft.tla │ │ ├── Lightclient_A_1.tla │ │ ├── MC4_3_correct.tla │ │ ├── MC4_3_faulty.tla │ │ ├── MC4_4_correct.tla │ │ ├── MC4_4_correct_drifted.tla │ │ ├── MC4_4_faulty.tla │ │ ├── MC4_4_faulty_drifted.tla │ │ ├── MC4_5_correct.tla │ │ ├── MC4_5_faulty.tla │ │ ├── MC4_6_faulty.tla │ │ ├── MC4_7_faulty.tla │ │ ├── MC5_5_correct.tla │ │ ├── MC5_5_correct_peer_two_thirds_faulty.tla │ │ ├── MC5_5_faulty.tla │ │ ├── MC5_5_faulty_peer_two_thirds_faulty.tla │ │ ├── MC5_7_faulty.tla │ │ ├── MC7_5_faulty.tla │ │ ├── MC7_7_faulty.tla │ │ ├── README.md │ │ ├── verification_001_published.md │ │ ├── verification_002_draft.md │ │ └── verification_003_draft.md ├── p2p │ ├── config.md │ ├── connection.md │ ├── messages │ │ ├── README.md │ │ ├── block-sync.md │ │ ├── consensus.md │ │ ├── evidence.md │ │ ├── mempool.md │ │ ├── pex.md │ │ └── state-sync.md │ ├── node.md │ ├── peer.md │ └── readme.md └── rpc │ └── README.md └── third_party └── proto └── gogoproto └── gogo.proto /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Proto 3 | BasedOnStyle: Google 4 | IndentWidth: 2 5 | ColumnLimit: 0 6 | AlignConsecutiveAssignments: true 7 | AlignConsecutiveDeclarations: true 8 | SpacesInSquareBrackets: true 9 | ReflowComments: true 10 | SortIncludes: true 11 | SortUsingDeclarations: true 12 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # CODEOWNERS: https://help.github.com/articles/about-codeowners/ 2 | 3 | * @milosevic @ebuchman @josef-widder @konnov 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/proposal.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Protocol Change Proposal 3 | about: Create a proposal to request a change to the protocol 4 | 5 | --- 6 | 7 | 12 | 13 | # Protocol Change Proposal 14 | 15 | ## Summary 16 | 17 | 18 | 19 | ## Problem Definition 20 | 21 | 25 | 26 | ## Proposal 27 | 28 | 29 | 30 | ____ 31 | 32 | #### For Admin Use 33 | 34 | - [ ] Not duplicate issue 35 | - [ ] Appropriate labels applied 36 | - [ ] Appropriate contributors tagged 37 | - [ ] Contributor assigned/self-assigned 38 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "11:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /.github/workflows/action.yml: -------------------------------------------------------------------------------- 1 | name: Check Markdown links 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: [master] 9 | 10 | jobs: 11 | markdown-link-check: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@master 15 | - uses: gaurav-nelson/github-action-markdown-link-check@1.0.13 16 | with: 17 | check-modified-files-only: 'yes' 18 | -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | build: 11 | name: Super linter 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout Code 15 | uses: actions/checkout@v2 16 | with: 17 | # Full git history is needed to get a proper list of changed files within `super-linter` 18 | fetch-depth: 0 19 | - name: Lint Code Base 20 | uses: docker://github/super-linter:v4 21 | env: 22 | LINTER_RULES_PATH: . 23 | VALIDATE_ALL_CODEBASE: false 24 | DEFAULT_BRANCH: master 25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | VALIDATE_MD: true 27 | MARKDOWN_CONFIG_FILE: .markdownlint.yml 28 | VALIDATE_PROTOBUF: false 29 | VALIDATE_JSCPD: false 30 | VALIDATE_NATURAL_LANGUAGE: false 31 | -------------------------------------------------------------------------------- /.github/workflows/proto-check.yml: -------------------------------------------------------------------------------- 1 | name: Proto Check 2 | # Protobuf runs buf (https://buf.build/) lint and check-breakage 3 | # This workflow is only run when a file in the proto directory 4 | # has been modified. 5 | on: 6 | workflow_dispatch: # allow running workflow manually 7 | pull_request: 8 | paths: 9 | - "proto/*" 10 | jobs: 11 | proto-lint: 12 | runs-on: ubuntu-latest 13 | timeout-minutes: 4 14 | steps: 15 | - uses: actions/checkout@v2.4.0 16 | - name: lint 17 | run: make proto-lint 18 | proto-breakage: 19 | runs-on: ubuntu-latest 20 | timeout-minutes: 4 21 | steps: 22 | - uses: actions/checkout@v2.4.0 23 | - name: check-breakage 24 | run: make proto-check-breaking-ci 25 | -------------------------------------------------------------------------------- /.github/workflows/proto-dockerfile.yml: -------------------------------------------------------------------------------- 1 | # This workflow (re)builds and pushes a Docker image containing the 2 | # protobuf build tools used by the other workflows. 3 | # 4 | # When making changes that require updates to the builder image, you 5 | # should merge the updates first and wait for this workflow to complete, 6 | # so that the changes will be available for the dependent workflows. 7 | # 8 | 9 | name: Build & Push Proto Builder Image 10 | on: 11 | pull_request: 12 | paths: 13 | - "proto/*" 14 | push: 15 | branches: 16 | - master 17 | paths: 18 | - "proto/*" 19 | schedule: 20 | # run this job once a month to recieve any go or buf updates 21 | - cron: "0 9 1 * *" 22 | 23 | env: 24 | REGISTRY: ghcr.io 25 | IMAGE_NAME: tendermint/docker-build-proto 26 | 27 | jobs: 28 | build: 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v2.4.0 32 | - name: Check out and assign tags 33 | id: prep 34 | run: | 35 | DOCKER_IMAGE="${REGISTRY}/${IMAGE_NAME}" 36 | VERSION=noop 37 | if [[ "$GITHUB_REF" == "refs/tags/*" ]]; then 38 | VERSION="${GITHUB_REF#refs/tags/}" 39 | elif [[ "$GITHUB_REF" == "refs/heads/*" ]]; then 40 | VERSION="$(echo "${GITHUB_REF#refs/heads/}" | sed -r 's#/+#-#g')" 41 | if [[ "${{ github.event.repository.default_branch }}" = "$VERSION" ]]; then 42 | VERSION=latest 43 | fi 44 | fi 45 | TAGS="${DOCKER_IMAGE}:${VERSION}" 46 | echo ::set-output name=tags::"${TAGS}" 47 | 48 | - name: Set up docker buildx 49 | uses: docker/setup-buildx-action@v1.6.0 50 | 51 | - name: Log in to the container registry 52 | uses: docker/login-action@v1.12.0 53 | with: 54 | registry: ${{ env.REGISTRY }} 55 | username: ${{ github.actor }} 56 | password: ${{ secrets.GITHUB_TOKEN }} 57 | 58 | - name: Build and publish image 59 | uses: docker/build-push-action@v2.9.0 60 | with: 61 | context: ./proto 62 | file: ./proto/Dockerfile 63 | push: ${{ github.event_name != 'pull_request' }} 64 | tags: ${{ steps.prep.outputs.tags }} 65 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: "Close stale pull requests" 2 | on: 3 | schedule: 4 | - cron: "0 0 * * *" 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/stale@v4 11 | with: 12 | repo-token: ${{ secrets.GITHUB_TOKEN }} 13 | stale-pr-message: "This pull request has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions." 16 | days-before-stale: -1 17 | days-before-pr-stale: 14 18 | days-before-pr-close: 4 19 | exempt-pr-labels: "pinned, proposal" 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.aux 2 | *.bbl 3 | *.blg 4 | *.log 5 | *.pdf 6 | *.gz 7 | *.dvi 8 | .idea 9 | *.pb.go 10 | -------------------------------------------------------------------------------- /.markdownlint.yml: -------------------------------------------------------------------------------- 1 | default: true 2 | MD001: false 3 | MD007: { indent: 4 } 4 | MD013: false 5 | MD024: { siblings_only: true } 6 | MD025: false 7 | MD033: false 8 | MD036: false 9 | MD010: false 10 | MD012: false 11 | MD028: false 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to the spec will be documented in this file for easy reference. Changes are grouped by version. 4 | 5 | ## [Unreleased] 6 | 7 | - [RPC] [#276](https://github.com/tendermint/spec/pull/276): Add specification for RPC (@marbar3778) 8 | - [RPC] [#304](https://github.com/tendermint/spec/pull/304): Clarify timestamp format (@marbar3778) 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # The Docker image containing the generator, formatter, and linter. 2 | # This is generated by proto/Dockerfile. To update tools, make changes 3 | # there and run the Build & Push Proto Builder Image workflow. 4 | IMAGE := ghcr.io/tendermint/docker-build-proto:latest 5 | DOCKER_PROTO_BUILDER := docker run -v $(shell pwd):/workspace --workdir /workspace $(IMAGE) 6 | HTTPS_GIT := https://github.com/tendermint/spec.git 7 | 8 | ############################################################################### 9 | ### Protobuf ### 10 | ############################################################################### 11 | 12 | proto-all: proto-lint proto-check-breaking 13 | .PHONY: proto-all 14 | 15 | proto-gen: 16 | @echo "Generating Protobuf files" 17 | @$(DOCKER_PROTO_BUILDER) buf generate --template=./buf.gen.yaml --config ./buf.yaml 18 | .PHONY: proto-gen 19 | 20 | proto-lint: 21 | @$(DOCKER_PROTO_BUILDER) buf lint --error-format=json --config ./buf.yaml 22 | .PHONY: proto-lint 23 | 24 | proto-format: 25 | @echo "Formatting Protobuf files" 26 | @$(DOCKER_PROTO_BUILDER) find . -name '*.proto' -path "./proto/*" -exec clang-format -i {} \; 27 | .PHONY: proto-format 28 | 29 | proto-check-breaking: 30 | @$(DOCKER_PROTO_BUILDER) buf breaking --against .git --config ./buf.yaml 31 | .PHONY: proto-check-breaking 32 | 33 | proto-check-breaking-ci: 34 | @$(DOCKER_PROTO_BUILDER) buf breaking --against $(HTTPS_GIT) --config ./buf.yaml 35 | .PHONY: proto-check-breaking-ci 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **THIS REPOSITORY HAS BEEN ARCHIVED. THE TENDERMINT SPECIFICATION IS NOW LOCATED IN THE [TENDERMINT/TENDERMINT](https://github.com/tendermint/tendermint/tree/master/spec) REPOSITORY.** 2 | 3 | --- 4 | 5 | # Tendermint Spec 6 | 7 | This repository contains specifications for the Tendermint protocol. 8 | 9 | There are currently two implementations of the Tendermint protocol, 10 | maintained by two separate-but-collaborative entities: 11 | One in [Go](https://github.com/tendermint/tendermint), 12 | maintained by Interchain GmbH, 13 | and one in [Rust](https://github.com/informalsystems/tendermint-rs), 14 | maintained by Informal Systems. 15 | 16 | ### Data Structures 17 | 18 | - [Encoding and Digests](./spec/core/encoding.md) 19 | - [Blockchain](./spec/core/data_structures.md) 20 | - [State](./spec/core/state.md) 21 | 22 | ### Consensus Protocol 23 | 24 | - [Consensus Algorithm](./spec/consensus/consensus.md) 25 | - [Creating a proposal](./spec/consensus/creating-proposal.md) 26 | - [Time](./spec/consensus/bft-time.md) 27 | - [Light-Client](./spec/consensus/light-client/README.md) 28 | 29 | ### P2P and Network Protocols 30 | 31 | - [The Base P2P Layer](./spec/p2p/node.md): multiplex the protocols ("reactors") on authenticated and encrypted TCP connections 32 | 33 | #### P2P Messages 34 | 35 | - [Peer Exchange (PEX)](./spec/p2p/messages/pex.md): gossip known peer addresses so peers can find each other 36 | - [Block Sync](./spec/p2p/messages/block-sync.md): gossip blocks so peers can catch up quickly 37 | - [Consensus](./spec/p2p/messages/consensus.md): gossip votes and block parts so new blocks can be committed 38 | - [Mempool](./spec/p2p/messages/mempool.md): gossip transactions so they get included in blocks 39 | - [Evidence](./spec/p2p/messages/evidence.md): sending invalid evidence will stop the peer 40 | 41 | ### ABCI 42 | 43 | - [ABCI](./spec/abci/README.md): Details about interactions between the 44 | application and consensus engine over ABCI 45 | 46 | ### ABCI++ 47 | 48 | - [ABCI++](./spec/abci++/README.md): Specification of interactions between the 49 | application and consensus engine over ABCI++ 50 | 51 | ### RFC 52 | 53 | - [RFC](./rfc/README.md): RFCs describe proposals to change the spec. 54 | 55 | ### ProtoBuf 56 | 57 | - [Proto](./proto/README.md): The data structures of the Tendermint protocol are located in the `proto` directory. These specify P2P messages that each implementation should follow to be compatible. 58 | -------------------------------------------------------------------------------- /buf.gen.yaml: -------------------------------------------------------------------------------- 1 | # The version of the generation template (required). 2 | # The only currently-valid value is v1beta1. 3 | version: v1beta1 4 | 5 | # The plugins to run. 6 | plugins: 7 | # The name of the plugin. 8 | - name: gogofaster 9 | # The directory where the generated proto output will be written. 10 | # The directory is relative to where the generation tool was run. 11 | out: proto 12 | # Set options to assign import paths to the well-known types 13 | # and to enable service generation. 14 | opt: Mgoogle/protobuf/timestamp.proto=github.com/gogo/protobuf/types,Mgoogle/protobuf/duration.proto=github.com/golang/protobuf/ptypes/duration,plugins=grpc,paths=source_relative 15 | -------------------------------------------------------------------------------- /buf.yaml: -------------------------------------------------------------------------------- 1 | version: v1beta1 2 | 3 | build: 4 | roots: 5 | - proto 6 | - third_party/proto 7 | lint: 8 | use: 9 | - BASIC 10 | - FILE_LOWER_SNAKE_CASE 11 | - UNARY_RPC 12 | ignore: 13 | - gogoproto 14 | breaking: 15 | use: 16 | - FILE 17 | -------------------------------------------------------------------------------- /ivy-proofs/Dockerfile: -------------------------------------------------------------------------------- 1 | # we need python2 support, which was dropped after buster: 2 | FROM debian:buster 3 | 4 | RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections 5 | RUN apt-get update 6 | RUN apt-get install -y apt-utils 7 | 8 | # Install and configure locale `en_US.UTF-8` 9 | RUN apt-get install -y locales && \ 10 | sed -i -e "s/# $en_US.*/en_US.UTF-8 UTF-8/" /etc/locale.gen && \ 11 | dpkg-reconfigure --frontend=noninteractive locales && \ 12 | update-locale LANG=en_US.UTF-8 13 | ENV LANG=en_US.UTF-8 14 | 15 | RUN apt-get update 16 | RUN apt-get install -y git python2 python-pip g++ cmake python-ply python-tk tix pkg-config libssl-dev python-setuptools 17 | 18 | # create a user: 19 | RUN useradd -ms /bin/bash user 20 | USER user 21 | WORKDIR /home/user 22 | 23 | RUN git clone --recurse-submodules https://github.com/kenmcmil/ivy.git 24 | WORKDIR /home/user/ivy/ 25 | RUN git checkout 271ee38980699115508eb90a0dd01deeb750a94b 26 | 27 | RUN python2.7 build_submodules.py 28 | RUN mkdir -p "/home/user/python/lib/python2.7/site-packages" 29 | ENV PYTHONPATH="/home/user/python/lib/python2.7/site-packages" 30 | # need to install pyparsing manually because otherwise wrong version found 31 | RUN pip install pyparsing 32 | RUN python2.7 setup.py install --prefix="/home/user/python/" 33 | ENV PATH=$PATH:"/home/user/python/bin/" 34 | WORKDIR /home/user/tendermint-proof/ 35 | 36 | ENTRYPOINT ["/home/user/tendermint-proof/check_proofs.sh"] 37 | 38 | -------------------------------------------------------------------------------- /ivy-proofs/README.md: -------------------------------------------------------------------------------- 1 | # Ivy Proofs 2 | 3 | ```copyright 4 | Copyright (c) 2020 Galois, Inc. 5 | SPDX-License-Identifier: Apache-2.0 6 | ``` 7 | 8 | ## Contents 9 | 10 | This folder contains: 11 | 12 | * `tendermint.ivy`, a specification of Tendermint algorithm as described in *The latest gossip on BFT consensus* by E. Buchman, J. Kwon, Z. Milosevic. 13 | * `abstract_tendermint.ivy`, a more abstract specification of Tendermint that is more verification-friendly. 14 | * `classic_safety.ivy`, a proof that Tendermint satisfies the classic safety property of BFT consensus: if every two quorums have a well-behaved node in common, then no two well-behaved nodes ever disagree. 15 | * `accountable_safety_1.ivy`, a proof that, assuming every quorum contains at least one well-behaved node, if two well-behaved nodes disagree, then there is evidence demonstrating at least f+1 nodes misbehaved. 16 | * `accountable_safety_2.ivy`, a proof that, regardless of any assumption about quorums, well-behaved nodes cannot be framed by malicious nodes. In other words, malicious nodes can never construct evidence that incriminates a well-behaved node. 17 | * `network_shim.ivy`, the network model and a convenience `shim` object to interface with the Tendermint specification. 18 | * `domain_model.ivy`, a specification of the domain model underlying the Tendermint specification, i.e. rounds, value, quorums, etc. 19 | 20 | All specifications and proofs are written in [Ivy](https://github.com/kenmcmil/ivy). 21 | 22 | The license above applies to all files in this folder. 23 | 24 | 25 | ## Building and running 26 | 27 | The easiest way to check the proofs is to use [Docker](https://www.docker.com/). 28 | 29 | 1. Install [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/). 30 | 2. Build a Docker image: `docker-compose build` 31 | 3. Run the proofs inside the Docker container: `docker-compose run 32 | tendermint-proof`. This will check all the proofs with the `ivy_check` 33 | command and write the output of `ivy_check` to a subdirectory of `./output/' 34 | -------------------------------------------------------------------------------- /ivy-proofs/accountable_safety_2.ivy: -------------------------------------------------------------------------------- 1 | #lang ivy1.7 2 | 3 | include tendermint 4 | include abstract_tendermint 5 | 6 | # Here we prove the second accountability property: no well-behaved node is 7 | # ever observed to violate the accountability properties. 8 | 9 | # The proof is done in two steps: first we prove the the abstract specification 10 | # satisfies the property, and then we show by refinement that this property 11 | # also holds in the concrete specification. 12 | 13 | # To see what is checked in the refinement proof, use `ivy_show isolate=accountable_safety_2 accountable_safety_2.ivy` 14 | # To see what is checked in the abstract correctness proof, use `ivy_show isolate=abstract_accountable_safety_2 accountable_safety_2.ivy` 15 | # To check the whole proof, use `ivy_check complete=fo accountable_safety_2.ivy`. 16 | 17 | # Proof that the property holds in the abstract specification 18 | # ============================================================ 19 | 20 | isolate abstract_accountable_safety_2 = { 21 | 22 | instantiate abstract_tendermint 23 | 24 | # the main property: 25 | invariant [wb_never_punished] well_behaved(N) -> ~(observed_equivocation(N) | observed_unlawful_prevote(N)) 26 | 27 | # the main invariant for proving wb_not_punished: 28 | invariant well_behaved(N) & precommitted(N,R,V) & ~locked(N,R,V) & V ~= value.nil -> exists R2,V2 . V2 ~= value.nil & R < R2 & precommitted(N,R2,V2) & locked(N,R2,V2) 29 | 30 | invariant (exists N . well_behaved(N) & precommitted(N,R,V) & V ~= value.nil) -> exists Q . nset.is_quorum(Q) & forall N . nset.member(N,Q) -> observed_prevoted(N,R,V) 31 | 32 | invariant well_behaved(N) -> (observed_prevoted(N,R,V) <-> prevoted(N,R,V)) 33 | invariant well_behaved(N) -> (observed_precommitted(N,R,V) <-> precommitted(N,R,V)) 34 | 35 | # nodes stop prevoting or precommitting in lower rounds when doing so in a higher round: 36 | invariant well_behaved(N) & prevoted(N,R2,V2) & R1 < R2 -> left_round(N,R1) 37 | invariant well_behaved(N) & locked(N,R2,V2) & R1 < R2 -> left_round(N,R1) 38 | 39 | invariant [precommit_unique_per_round] well_behaved(N) & precommitted(N,R,V1) & precommitted(N,R,V2) -> V1 = V2 40 | 41 | } with nset, round, abstract_accountable_safety_2.defs.observed_equivocation_def, abstract_accountable_safety_2.defs.observed_unlawful_prevote_def 42 | 43 | # Proof that the property holds in the concrete specification 44 | # =========================================================== 45 | 46 | isolate accountable_safety_2 = { 47 | 48 | instantiate tendermint(abstract_accountable_safety_2) 49 | 50 | invariant well_behaved(N) -> ~(abstract_accountable_safety_2.observed_equivocation(N) | abstract_accountable_safety_2.observed_unlawful_prevote(N)) 51 | 52 | } with round, value, shim, abstract_accountable_safety_2, abstract_accountable_safety_2.defs.observed_equivocation_def, abstract_accountable_safety_2.defs.observed_unlawful_prevote_def 53 | -------------------------------------------------------------------------------- /ivy-proofs/check_proofs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # returns non-zero error code if any proof fails 4 | 5 | success=0 6 | log_dir=$(cat /dev/urandom | tr -cd 'a-f0-9' | head -c 6) 7 | cmd="ivy_check seed=$RANDOM" 8 | mkdir -p output/$log_dir 9 | 10 | echo "Checking classic safety:" 11 | res=$($cmd classic_safety.ivy | tee "output/$log_dir/classic_safety.txt" | tail -n 1) 12 | if [ "$res" = "OK" ]; then 13 | echo "OK" 14 | else 15 | echo "FAILED" 16 | success=1 17 | fi 18 | 19 | echo "Checking accountable safety 1:" 20 | res=$($cmd accountable_safety_1.ivy | tee "output/$log_dir/accountable_safety_1.txt" | tail -n 1) 21 | if [ "$res" = "OK" ]; then 22 | echo "OK" 23 | else 24 | echo "FAILED" 25 | success=1 26 | fi 27 | 28 | echo "Checking accountable safety 2:" 29 | res=$($cmd complete=fo accountable_safety_2.ivy | tee "output/$log_dir/accountable_safety_2.txt" | tail -n 1) 30 | if [ "$res" = "OK" ]; then 31 | echo "OK" 32 | else 33 | echo "FAILED" 34 | success=1 35 | fi 36 | 37 | echo 38 | echo "See ivy_check output in the output/ folder" 39 | exit $success 40 | -------------------------------------------------------------------------------- /ivy-proofs/classic_safety.ivy: -------------------------------------------------------------------------------- 1 | #lang ivy1.7 2 | # --- 3 | # layout: page 4 | # title: Proof of Classic Safety 5 | # --- 6 | 7 | include tendermint 8 | include abstract_tendermint 9 | 10 | # Here we prove the classic safety property: assuming that every two quorums 11 | # have a well-behaved node in common, no two well-behaved nodes ever disagree. 12 | 13 | # The proof is done in two steps: first we prove the the abstract specification 14 | # satisfies the property, and then we show by refinement that this property 15 | # also holds in the concrete specification. 16 | 17 | # To see what is checked in the refinement proof, use `ivy_show isolate=classic_safety classic_safety.ivy` 18 | # To see what is checked in the abstract correctness proof, use `ivy_show isolate=abstract_classic_safety classic_safety.ivy` 19 | 20 | # To check the whole proof, use `ivy_check classic_safety.ivy`. 21 | 22 | # Note that all the verification conditions sent to Z3 for this proof are in 23 | # EPR. 24 | 25 | # Classic safety in the abstract model 26 | # ==================================== 27 | 28 | # We start by proving that classic safety holds in the abstract model. 29 | 30 | isolate abstract_classic_safety = { 31 | 32 | instantiate abstract_tendermint 33 | 34 | invariant [classic_safety] classic_bft.quorum_intersection & decided(N1,R1,V1) & decided(N2,R2,V2) -> V1 = V2 35 | 36 | # The notion of choosable value 37 | # ----------------------------- 38 | 39 | relation choosable(R:round, V:value) 40 | definition choosable(R,V) = exists Q . nset.is_quorum(Q) & forall N . well_behaved(N) & nset.member(N,Q) -> ~left_round(N,R) | precommitted(N,R,V) 41 | 42 | # Main invariants 43 | # --------------- 44 | 45 | # `classic_safety` is inductive relative to those invariants 46 | 47 | invariant [decision_is_quorum_precommit] (exists N1 . decided(N1,R,V)) -> exists Q. nset.is_quorum(Q) & forall N2. well_behaved(N2) & nset.member(N2, Q) -> precommitted(N2,R,V) 48 | 49 | invariant [precommitted_is_quorum_prevote] V ~= value.nil & (exists N1 . precommitted(N1,R,V)) -> exists Q. nset.is_quorum(Q) & forall N2. well_behaved(N2) & nset.member(N2, Q) -> prevoted(N2,R,V) 50 | 51 | invariant [prevote_unique_per_round] prevoted(N,R,V1) & prevoted(N,R,V2) -> V1 = V2 52 | 53 | # This is the core invariant: as long as a precommitted value is still choosable, it remains protected by a lock and prevents any new value from being prevoted: 54 | invariant [locks] classic_bft.quorum_intersection & V ~= value.nil & precommitted(N,R,V) & choosable(R,V) -> locked(N,R,V) & forall R2,V2 . R < R2 & prevoted(N,R2,V2) -> V2 = V | V2 = value.nil 55 | 56 | # Supporting invariants 57 | # --------------------- 58 | 59 | # The main invariants are inductive relative to those 60 | 61 | invariant decided(N,R,V) -> V ~= value.nil 62 | 63 | invariant left_round(N,R2) & R1 < R2 -> left_round(N,R1) # if a node left round R2>R1, then it also left R1: 64 | 65 | invariant prevoted(N,R2,V2) & R1 < R2 -> left_round(N,R1) 66 | invariant precommitted(N,R2,V2) & R1 < R2 -> left_round(N,R1) 67 | 68 | } with round, nset, classic_bft.quorum_intersection_def 69 | 70 | # The refinement proof 71 | # ==================== 72 | 73 | # Now, thanks to the refinement relation that we establish in 74 | # `concrete_tendermint.ivy`, we prove that classic safety transfers to the 75 | # concrete specification: 76 | isolate classic_safety = { 77 | 78 | # We instantiate the `tendermint` module providing `abstract_classic_safety` as abstract model. 79 | instantiate tendermint(abstract_classic_safety) 80 | 81 | # We prove that if every two quorums have a well-behaved node in common, 82 | # then well-behaved nodes never disagree: 83 | invariant [classic_safety] classic_bft.quorum_intersection & server.decision(N1) ~= value.nil & server.decision(N2) ~= value.nil -> server.decision(N1) = server.decision(N2) 84 | 85 | } with value, round, proposers, shim, abstract_classic_safety # here we list all the specifications that we rely on for this proof 86 | -------------------------------------------------------------------------------- /ivy-proofs/count_lines.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | r='^\s*$\|^\s*\#\|^\s*\}\s*$\|^\s*{\s*$' # removes comments and blank lines and lines that contain only { or } 4 | N1=`cat tendermint.ivy domain_model.ivy network_shim.ivy | grep -v $r'\|.*invariant.*' | wc -l` 5 | N2=`cat abstract_tendermint.ivy | grep "observed_" | wc -l` # the observed_* variables specify the observations of the nodes 6 | SPEC_LINES=`expr $N1 + $N2` 7 | echo "spec lines: $SPEC_LINES" 8 | N3=`cat abstract_tendermint.ivy | grep -v $r'\|.*observed_.*' | wc -l` 9 | N4=`cat accountable_safety_1.ivy | grep -v $r | wc -l` 10 | PROOF_LINES=`expr $N3 + $N4` 11 | echo "proof lines: $PROOF_LINES" 12 | RATIO=`bc <<< "scale=2;$PROOF_LINES / $SPEC_LINES"` 13 | echo "proof-to-code ratio for the accountable-safety property: $RATIO" 14 | -------------------------------------------------------------------------------- /ivy-proofs/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | tendermint-proof: 4 | build: . 5 | volumes: 6 | - ./:/home/user/tendermint-proof:ro 7 | - ./output:/home/user/tendermint-proof/output:rw 8 | 9 | -------------------------------------------------------------------------------- /ivy-proofs/network_shim.ivy: -------------------------------------------------------------------------------- 1 | #lang ivy1.7 2 | # --- 3 | # layout: page 4 | # title: Network model and network shim 5 | # --- 6 | 7 | # Here we define a network module, which is our model of the network, and a 8 | # shim module that sits on top of the network and which, upon receiving a 9 | # message, calls the appropriate protocol handler. 10 | 11 | include domain_model 12 | 13 | # Here we define an enumeration type for identifying the 3 different types of 14 | # messages that nodes send. 15 | object msg_kind = { # TODO: merge with step_t 16 | type this = {proposal, prevote, precommit} 17 | } 18 | 19 | # Here we define the type of messages `msg`. Its members are structs with the fields described below. 20 | object msg = { 21 | type this = struct { 22 | m_kind : msg_kind, 23 | m_src : node, 24 | m_round : round, 25 | m_value : value, 26 | m_vround : round 27 | } 28 | } 29 | 30 | # This is our model of the network: 31 | isolate net = { 32 | 33 | export action recv(dst:node,v:msg) 34 | action send(src:node,dst:node,v:msg) 35 | # Note that the `recv` action is exported, meaning that it can be called 36 | # non-deterministically by the environment any time it is enabled. In other 37 | # words, a packet that is in flight can be received at any time. In this 38 | # sense, the network is fully asynchronous. Moreover, there is no 39 | # requirement that a given message will be received at all. 40 | 41 | # The state of the network consists of all the packets that have been 42 | # sent so far, along with their destination. 43 | relation sent(V:msg, N:node) 44 | 45 | after init { 46 | sent(V, N) := false 47 | } 48 | 49 | before send { 50 | sent(v,dst) := true 51 | } 52 | 53 | before recv { 54 | require sent(v,dst) # only sent messages can be received. 55 | } 56 | } 57 | 58 | # The network shim sits on top of the network and, upon receiving a message, 59 | # calls the appropriate protocol handler. It also exposes a `broadcast` action 60 | # that sends to all nodes. 61 | 62 | isolate shim = { 63 | 64 | # In order not repeat the same code for each handler, we use a handler 65 | # module parameterized by the type of message it will handle. Below we 66 | # instantiate this module for the 3 types of messages of Tendermint 67 | module handler(p_kind) = { 68 | action handle(dst:node,m:msg) 69 | object spec = { 70 | before handle { 71 | assert sent(m,dst) & m.m_kind = p_kind 72 | } 73 | } 74 | } 75 | 76 | instance proposal_handler : handler(msg_kind.proposal) 77 | instance prevote_handler : handler(msg_kind.prevote) 78 | instance precommit_handler : handler(msg_kind.precommit) 79 | 80 | relation sent(M:msg,N:node) 81 | 82 | action broadcast(src:node,m:msg) 83 | action send(src:node,dst:node,m:msg) 84 | 85 | specification { 86 | after init { 87 | sent(M,D) := false; 88 | } 89 | before broadcast { 90 | sent(m,D) := true 91 | } 92 | before send { 93 | sent(m,dst) := true 94 | } 95 | } 96 | 97 | # Here we give an implementation of it that satisfies its specification: 98 | implementation { 99 | 100 | implement net.recv(dst:node,m:msg) { 101 | 102 | if m.m_kind = msg_kind.proposal { 103 | call proposal_handler.handle(dst,m) 104 | } 105 | else if m.m_kind = msg_kind.prevote { 106 | call prevote_handler.handle(dst,m) 107 | } 108 | else if m.m_kind = msg_kind.precommit { 109 | call precommit_handler.handle(dst,m) 110 | } 111 | } 112 | 113 | implement broadcast { # broadcast sends to all nodes, including the sender. 114 | var iter := node.iter.create(0); 115 | while ~iter.is_end 116 | invariant net.sent(M,D) -> sent(M,D) 117 | { 118 | var n := iter.val; 119 | call net.send(src,n,m); 120 | iter := iter.next; 121 | } 122 | } 123 | 124 | implement send { 125 | call net.send(src,dst,m) 126 | } 127 | 128 | private { 129 | invariant net.sent(M,D) -> sent(M,D) 130 | } 131 | } 132 | 133 | } with net, node # to prove that the shim implementation satisfies the shim specification, we rely on the specification of net and node. 134 | -------------------------------------------------------------------------------- /ivy-proofs/output/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore 5 | -------------------------------------------------------------------------------- /ivy-proofs/tendermint_test.ivy: -------------------------------------------------------------------------------- 1 | #lang ivy1.7 2 | 3 | include tendermint 4 | include abstract_tendermint 5 | 6 | isolate ghost_ = { 7 | instantiate abstract_tendermint 8 | } 9 | 10 | isolate protocol = { 11 | instantiate tendermint(ghost_) # here we instantiate the parameter of the tendermint module with `ghost_`; however note that we don't extract any code for `ghost_` (it's not in the list of object in the extract, and it's thus sliced away). 12 | implementation { 13 | definition init_val(n:node) = <<< `n`%2 >>> 14 | } 15 | # attribute test = impl 16 | } with ghost_, shim, value, round, proposers 17 | 18 | # Here we run a simple scenario that exhibits an execution in which nodes make 19 | # a decision. We do this to rule out trivial modeling errors. 20 | 21 | # One option to check that this scenario is valid is to run it in Ivy's REPL. 22 | # For this, first compile the scenario: 23 | #```ivyc target=repl isolate=code trace=true tendermint_test.ivy 24 | # Then, run the produced binary (e.g. for 4 nodes): 25 | #``` ./tendermint_test 4 26 | # Finally, call the action: 27 | #``` scenarios.scenario_1 28 | # Note that Ivy will check at runtime that all action preconditions are 29 | # satisfied. For example, runing the scenario twice will cause a violation of 30 | # the precondition of the `start` action, because a node cannot start twice 31 | # (see `require ~_has_started` in action `start`). 32 | 33 | # Another possibility would be to run `ivy_check` on the scenario, but that 34 | # does not seem to work at the moment. 35 | 36 | isolate scenarios = { 37 | individual all:nset # will be used as parameter to actions requiring a quorum 38 | 39 | after init { 40 | var iter := node.iter.create(0); 41 | while ~iter.is_end 42 | { 43 | all := all.insert(iter.val); 44 | iter := iter.next; 45 | }; 46 | assert nset.is_quorum(all); # we can also use asserts to make sure we are getting what we expect 47 | } 48 | 49 | export action scenario_1 = { 50 | # all nodes start: 51 | var iter := node.iter.create(0); 52 | while ~iter.is_end 53 | { 54 | call protocol.server.start(iter.val); 55 | iter := iter.next; 56 | }; 57 | # all nodes receive the leader's proposal: 58 | var m:msg; 59 | m.m_kind := msg_kind.proposal; 60 | m.m_src := 0; 61 | m.m_round := 0; 62 | m.m_value := 0; 63 | m.m_vround := round.minus_one; 64 | iter := node.iter.create(0); 65 | while ~iter.is_end 66 | { 67 | call net.recv(iter.val,m); 68 | iter := iter.next; 69 | }; 70 | # all nodes prevote: 71 | iter := node.iter.create(0); 72 | while ~iter.is_end 73 | { 74 | call protocol.server.l_22(iter.val,0); 75 | iter := iter.next; 76 | }; 77 | # all nodes receive each other's prevote messages; 78 | m.m_kind := msg_kind.prevote; 79 | m.m_vround := 0; 80 | iter := node.iter.create(0); 81 | while ~iter.is_end 82 | { 83 | var iter2 := node.iter.create(0); # the sender 84 | while ~iter2.is_end 85 | { 86 | m.m_src := iter2.val; 87 | call net.recv(iter.val,m); 88 | iter2 := iter2.next; 89 | }; 90 | iter := iter.next; 91 | }; 92 | # all nodes precommit: 93 | iter := node.iter.create(0); 94 | while ~iter.is_end 95 | { 96 | call protocol.server.l_36(iter.val,0,0,all); 97 | iter := iter.next; 98 | }; 99 | # all nodes receive each other's pre-commits 100 | m.m_kind := msg_kind.precommit; 101 | iter := node.iter.create(0); 102 | while ~iter.is_end 103 | { 104 | var iter2 := node.iter.create(0); # the sender 105 | while ~iter2.is_end 106 | { 107 | m.m_src := iter2.val; 108 | call net.recv(iter.val,m); 109 | iter2 := iter2.next; 110 | }; 111 | iter := iter.next; 112 | }; 113 | # now all nodes can decide: 114 | iter := node.iter.create(0); 115 | while ~iter.is_end 116 | { 117 | call protocol.server.l_49_decide(iter.val,0,0,all); 118 | iter := iter.next; 119 | }; 120 | } 121 | 122 | # TODO: add more scenarios 123 | 124 | } with round, node, proposers, value, nset, protocol, shim, net 125 | 126 | # extract code = protocol, shim, round, node 127 | extract code = round, node, proposers, value, nset, protocol, shim, net, scenarios 128 | -------------------------------------------------------------------------------- /proto/Dockerfile: -------------------------------------------------------------------------------- 1 | # This Dockerfile defines an image containing tools for linting, formatting, 2 | # and compiling the Tendermint protos. 3 | FROM golang:1.17-alpine 4 | 5 | # Install a commonly used set of programs for use with our protos. 6 | # clang-extra-tools is included here because it provides clang-format, 7 | # used to format the .proto files. 8 | RUN apk add --no-cache build-base clang-extra-tools curl git 9 | 10 | ENV GOLANG_PROTOBUF_VERSION=1.3.1 \ 11 | GOGO_PROTOBUF_VERSION=1.3.2 12 | 13 | # Retrieve the go protoc programs and copy them into the PATH 14 | RUN go install github.com/golang/protobuf/protoc-gen-go@v${GOLANG_PROTOBUF_VERSION} && \ 15 | go install github.com/gogo/protobuf/protoc-gen-gogo@v${GOGO_PROTOBUF_VERSION} && \ 16 | go install github.com/gogo/protobuf/protoc-gen-gogofaster@v${GOGO_PROTOBUF_VERSION} && \ 17 | mv "$(go env GOPATH)"/bin/* /usr/local/bin/ 18 | 19 | # Copy the 'buf' program out of the buildbuf/buf container. 20 | COPY --from=bufbuild/buf:latest /usr/local/bin/* /usr/local/bin/ 21 | -------------------------------------------------------------------------------- /proto/README.md: -------------------------------------------------------------------------------- 1 | # Protocol Buffers 2 | 3 | This sections defines the types and messages shared across implementations. The definition of the data structures are located in the [core/data_structures](../spec/core/data_structures.md) for the core data types and ABCI definitions are located in the [ABCI](../spec/abci/README.md) section. 4 | 5 | ## Process of Updates 6 | 7 | The `.proto` files within this section are core to the protocol and updates must be treated as such. 8 | 9 | ### Steps 10 | 11 | 1. Make an issue with the proposed change. 12 | - Within in the issue members from both the Tendermint-go and Tendermint-rs team will leave comments. If there is not consensus on the change an [RFC](../rfc/README.md) may be requested. 13 | 1a. Submission of an RFC as a pull request should be made to facilitate further discussion. 14 | 1b. Merge the RFC. 15 | 2. Make the necessary changes to the `.proto` file(s), [core data structures](../spec/core/data_structures.md) and/or [ABCI protocol](../spec/abci/apps.md). 16 | 3. Open issues within Tendermint-go and Tendermint-rs repos. This is used to notify the teams that a change occurred in the spec. 17 | 1. Tag the issue with a spec version label. This will notify the team the changed has been made on master but has not entered a release. 18 | 19 | ### Versioning 20 | 21 | The spec repo aims to be versioned. Once it has been versioned, updates to the protobuf files will live on master. After a certain amount of time, decided on by Tendermint-go and Tendermint-rs team leads, a release will be made on the spec repo. The spec may contain minor releases as well, depending on the implementation these changes may lead to a breaking change. If so, the implementation team should open an issue within the spec repo requiring a major release of the spec. 22 | 23 | If the steps above were followed each implementation should have issues tagged with a spec change label. Once all issues have been completed the team should signify their readiness for release. 24 | -------------------------------------------------------------------------------- /proto/tendermint/blocksync/types.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.blocksync; 3 | 4 | import "tendermint/types/block.proto"; 5 | 6 | // BlockRequest requests a block for a specific height 7 | message BlockRequest { 8 | int64 height = 1; 9 | } 10 | 11 | // NoBlockResponse informs the node that the peer does not have block at the 12 | // requested height 13 | message NoBlockResponse { 14 | int64 height = 1; 15 | } 16 | 17 | // BlockResponse returns block to the requested 18 | message BlockResponse { 19 | tendermint.types.Block block = 1; 20 | } 21 | 22 | // StatusRequest requests the status of a peer. 23 | message StatusRequest {} 24 | 25 | // StatusResponse is a peer response to inform their status. 26 | message StatusResponse { 27 | int64 height = 1; 28 | int64 base = 2; 29 | } 30 | 31 | message Message { 32 | oneof sum { 33 | BlockRequest block_request = 1; 34 | NoBlockResponse no_block_response = 2; 35 | BlockResponse block_response = 3; 36 | StatusRequest status_request = 4; 37 | StatusResponse status_response = 5; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /proto/tendermint/consensus/types.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.consensus; 3 | 4 | import "gogoproto/gogo.proto"; 5 | import "tendermint/types/types.proto"; 6 | import "tendermint/libs/bits/types.proto"; 7 | 8 | // NewRoundStep is sent for every step taken in the ConsensusState. 9 | // For every height/round/step transition 10 | message NewRoundStep { 11 | int64 height = 1; 12 | int32 round = 2; 13 | uint32 step = 3; 14 | int64 seconds_since_start_time = 4; 15 | int32 last_commit_round = 5; 16 | } 17 | 18 | // NewValidBlock is sent when a validator observes a valid block B in some round 19 | // r, 20 | // i.e., there is a Proposal for block B and 2/3+ prevotes for the block B in 21 | // the round r. 22 | // In case the block is also committed, then IsCommit flag is set to true. 23 | message NewValidBlock { 24 | int64 height = 1; 25 | int32 round = 2; 26 | tendermint.types.PartSetHeader block_part_set_header = 3 27 | [(gogoproto.nullable) = false]; 28 | tendermint.libs.bits.BitArray block_parts = 4; 29 | bool is_commit = 5; 30 | } 31 | 32 | // Proposal is sent when a new block is proposed. 33 | message Proposal { 34 | tendermint.types.Proposal proposal = 1 [(gogoproto.nullable) = false]; 35 | } 36 | 37 | // ProposalPOL is sent when a previous proposal is re-proposed. 38 | message ProposalPOL { 39 | int64 height = 1; 40 | int32 proposal_pol_round = 2; 41 | tendermint.libs.bits.BitArray proposal_pol = 3 42 | [(gogoproto.nullable) = false]; 43 | } 44 | 45 | // BlockPart is sent when gossipping a piece of the proposed block. 46 | message BlockPart { 47 | int64 height = 1; 48 | int32 round = 2; 49 | tendermint.types.Part part = 3 [(gogoproto.nullable) = false]; 50 | } 51 | 52 | // Vote is sent when voting for a proposal (or lack thereof). 53 | message Vote { 54 | tendermint.types.Vote vote = 1; 55 | } 56 | 57 | // HasVote is sent to indicate that a particular vote has been received. 58 | message HasVote { 59 | int64 height = 1; 60 | int32 round = 2; 61 | tendermint.types.SignedMsgType type = 3; 62 | int32 index = 4; 63 | } 64 | 65 | // VoteSetMaj23 is sent to indicate that a given BlockID has seen +2/3 votes. 66 | message VoteSetMaj23 { 67 | int64 height = 1; 68 | int32 round = 2; 69 | tendermint.types.SignedMsgType type = 3; 70 | tendermint.types.BlockID block_id = 4 71 | [(gogoproto.customname) = "BlockID", (gogoproto.nullable) = false]; 72 | } 73 | 74 | // VoteSetBits is sent to communicate the bit-array of votes seen for the 75 | // BlockID. 76 | message VoteSetBits { 77 | int64 height = 1; 78 | int32 round = 2; 79 | tendermint.types.SignedMsgType type = 3; 80 | tendermint.types.BlockID block_id = 4 81 | [(gogoproto.customname) = "BlockID", (gogoproto.nullable) = false]; 82 | tendermint.libs.bits.BitArray votes = 5 [(gogoproto.nullable) = false]; 83 | } 84 | 85 | message Message { 86 | oneof sum { 87 | NewRoundStep new_round_step = 1; 88 | NewValidBlock new_valid_block = 2; 89 | Proposal proposal = 3; 90 | ProposalPOL proposal_pol = 4; 91 | BlockPart block_part = 5; 92 | Vote vote = 6; 93 | HasVote has_vote = 7; 94 | VoteSetMaj23 vote_set_maj23 = 8; 95 | VoteSetBits vote_set_bits = 9; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /proto/tendermint/crypto/keys.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.crypto; 3 | 4 | import "gogoproto/gogo.proto"; 5 | 6 | // PublicKey defines the keys available for use with Tendermint Validators 7 | message PublicKey { 8 | option (gogoproto.compare) = true; 9 | option (gogoproto.equal) = true; 10 | 11 | oneof sum { 12 | bytes ed25519 = 1; 13 | bytes secp256k1 = 2; 14 | bytes sr25519 = 3; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /proto/tendermint/crypto/proof.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.crypto; 3 | 4 | import "gogoproto/gogo.proto"; 5 | 6 | message Proof { 7 | int64 total = 1; 8 | int64 index = 2; 9 | bytes leaf_hash = 3; 10 | repeated bytes aunts = 4; 11 | } 12 | 13 | message ValueOp { 14 | // Encoded in ProofOp.Key. 15 | bytes key = 1; 16 | 17 | // To encode in ProofOp.Data 18 | Proof proof = 2; 19 | } 20 | 21 | message DominoOp { 22 | string key = 1; 23 | string input = 2; 24 | string output = 3; 25 | } 26 | 27 | // ProofOp defines an operation used for calculating Merkle root 28 | // The data could be arbitrary format, providing nessecary data 29 | // for example neighbouring node hash 30 | message ProofOp { 31 | string type = 1; 32 | bytes key = 2; 33 | bytes data = 3; 34 | } 35 | 36 | // ProofOps is Merkle proof defined by the list of ProofOps 37 | message ProofOps { 38 | repeated ProofOp ops = 1 [(gogoproto.nullable) = false]; 39 | } 40 | -------------------------------------------------------------------------------- /proto/tendermint/libs/bits/types.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.libs.bits; 3 | 4 | message BitArray { 5 | int64 bits = 1; 6 | repeated uint64 elems = 2; 7 | } 8 | -------------------------------------------------------------------------------- /proto/tendermint/mempool/types.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.mempool; 3 | 4 | message Txs { 5 | repeated bytes txs = 1; 6 | } 7 | 8 | message Message { 9 | oneof sum { 10 | Txs txs = 1; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /proto/tendermint/p2p/conn.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.p2p; 3 | 4 | import "gogoproto/gogo.proto"; 5 | import "tendermint/crypto/keys.proto"; 6 | 7 | message PacketPing {} 8 | 9 | message PacketPong {} 10 | 11 | message PacketMsg { 12 | int32 channel_id = 1 [(gogoproto.customname) = "ChannelID"]; 13 | bool eof = 2 [(gogoproto.customname) = "EOF"]; 14 | bytes data = 3; 15 | } 16 | 17 | message Packet { 18 | oneof sum { 19 | PacketPing packet_ping = 1; 20 | PacketPong packet_pong = 2; 21 | PacketMsg packet_msg = 3; 22 | } 23 | } 24 | 25 | message AuthSigMessage { 26 | tendermint.crypto.PublicKey pub_key = 1 [(gogoproto.nullable) = false]; 27 | bytes sig = 2; 28 | } 29 | -------------------------------------------------------------------------------- /proto/tendermint/p2p/pex.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.p2p; 3 | 4 | import "gogoproto/gogo.proto"; 5 | 6 | message PexAddress { 7 | string url = 1 [(gogoproto.customname) = "URL"]; 8 | 9 | reserved 2, 3; // See https://github.com/tendermint/spec/pull/352 10 | } 11 | 12 | message PexRequest {} 13 | 14 | message PexResponse { 15 | repeated PexAddress addresses = 1 [(gogoproto.nullable) = false]; 16 | } 17 | 18 | message PexMessage { 19 | reserved 1, 2; // See https://github.com/tendermint/spec/pull/352 20 | oneof sum { 21 | PexRequest pex_request = 3; 22 | PexResponse pex_response = 4; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /proto/tendermint/p2p/types.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.p2p; 3 | 4 | import "gogoproto/gogo.proto"; 5 | import "google/protobuf/timestamp.proto"; 6 | 7 | message ProtocolVersion { 8 | uint64 p2p = 1 [(gogoproto.customname) = "P2P"]; 9 | uint64 block = 2; 10 | uint64 app = 3; 11 | } 12 | 13 | message NodeInfo { 14 | ProtocolVersion protocol_version = 1 [(gogoproto.nullable) = false]; 15 | string node_id = 2 [(gogoproto.customname) = "NodeID"]; 16 | string listen_addr = 3; 17 | string network = 4; 18 | string version = 5; 19 | bytes channels = 6; 20 | string moniker = 7; 21 | NodeInfoOther other = 8 [(gogoproto.nullable) = false]; 22 | } 23 | 24 | message NodeInfoOther { 25 | string tx_index = 1; 26 | string rpc_address = 2 [(gogoproto.customname) = "RPCAddress"]; 27 | } 28 | 29 | message PeerInfo { 30 | string id = 1 [(gogoproto.customname) = "ID"]; 31 | repeated PeerAddressInfo address_info = 2; 32 | google.protobuf.Timestamp last_connected = 3 [(gogoproto.stdtime) = true]; 33 | } 34 | 35 | message PeerAddressInfo { 36 | string address = 1; 37 | google.protobuf.Timestamp last_dial_success = 2 38 | [(gogoproto.stdtime) = true]; 39 | google.protobuf.Timestamp last_dial_failure = 3 40 | [(gogoproto.stdtime) = true]; 41 | uint32 dial_failures = 4; 42 | } 43 | -------------------------------------------------------------------------------- /proto/tendermint/statesync/types.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.statesync; 3 | 4 | import "gogoproto/gogo.proto"; 5 | import "tendermint/types/types.proto"; 6 | import "tendermint/types/params.proto"; 7 | 8 | message Message { 9 | oneof sum { 10 | SnapshotsRequest snapshots_request = 1; 11 | SnapshotsResponse snapshots_response = 2; 12 | ChunkRequest chunk_request = 3; 13 | ChunkResponse chunk_response = 4; 14 | LightBlockRequest light_block_request = 5; 15 | LightBlockResponse light_block_response = 6; 16 | ParamsRequest params_request = 7; 17 | ParamsResponse params_response = 8; 18 | } 19 | } 20 | 21 | message SnapshotsRequest {} 22 | 23 | message SnapshotsResponse { 24 | uint64 height = 1; 25 | uint32 format = 2; 26 | uint32 chunks = 3; 27 | bytes hash = 4; 28 | bytes metadata = 5; 29 | } 30 | 31 | message ChunkRequest { 32 | uint64 height = 1; 33 | uint32 format = 2; 34 | uint32 index = 3; 35 | } 36 | 37 | message ChunkResponse { 38 | uint64 height = 1; 39 | uint32 format = 2; 40 | uint32 index = 3; 41 | bytes chunk = 4; 42 | bool missing = 5; 43 | } 44 | 45 | message LightBlockRequest { 46 | uint64 height = 1; 47 | } 48 | 49 | message LightBlockResponse { 50 | tendermint.types.LightBlock light_block = 1; 51 | } 52 | 53 | message ParamsRequest { 54 | uint64 height = 1; 55 | } 56 | 57 | message ParamsResponse { 58 | uint64 height = 1; 59 | tendermint.types.ConsensusParams consensus_params = 2 60 | [(gogoproto.nullable) = false]; 61 | } 62 | -------------------------------------------------------------------------------- /proto/tendermint/types/block.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.types; 3 | 4 | import "gogoproto/gogo.proto"; 5 | import "tendermint/types/types.proto"; 6 | import "tendermint/types/evidence.proto"; 7 | 8 | message Block { 9 | Header header = 1 [(gogoproto.nullable) = false]; 10 | Data data = 2 [(gogoproto.nullable) = false]; 11 | tendermint.types.EvidenceList evidence = 3 [(gogoproto.nullable) = false]; 12 | Commit last_commit = 4; 13 | } 14 | -------------------------------------------------------------------------------- /proto/tendermint/types/evidence.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.types; 3 | 4 | import "gogoproto/gogo.proto"; 5 | import "google/protobuf/timestamp.proto"; 6 | import "tendermint/types/types.proto"; 7 | import "tendermint/types/validator.proto"; 8 | 9 | message Evidence { 10 | oneof sum { 11 | DuplicateVoteEvidence duplicate_vote_evidence = 1; 12 | LightClientAttackEvidence light_client_attack_evidence = 2; 13 | } 14 | } 15 | 16 | // DuplicateVoteEvidence contains evidence of a validator signed two conflicting 17 | // votes. 18 | message DuplicateVoteEvidence { 19 | tendermint.types.Vote vote_a = 1; 20 | tendermint.types.Vote vote_b = 2; 21 | int64 total_voting_power = 3; 22 | int64 validator_power = 4; 23 | google.protobuf.Timestamp timestamp = 5 24 | [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; 25 | } 26 | 27 | // LightClientAttackEvidence contains evidence of a set of validators attempting 28 | // to mislead a light client. 29 | message LightClientAttackEvidence { 30 | tendermint.types.LightBlock conflicting_block = 1; 31 | int64 common_height = 2; 32 | repeated tendermint.types.Validator byzantine_validators = 3; 33 | int64 total_voting_power = 4; 34 | google.protobuf.Timestamp timestamp = 5 35 | [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; 36 | } 37 | 38 | message EvidenceList { 39 | repeated Evidence evidence = 1 [(gogoproto.nullable) = false]; 40 | } 41 | -------------------------------------------------------------------------------- /proto/tendermint/types/validator.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.types; 3 | 4 | import "gogoproto/gogo.proto"; 5 | import "tendermint/crypto/keys.proto"; 6 | 7 | message ValidatorSet { 8 | repeated Validator validators = 1; 9 | Validator proposer = 2; 10 | int64 total_voting_power = 3; 11 | } 12 | 13 | message Validator { 14 | bytes address = 1; 15 | tendermint.crypto.PublicKey pub_key = 2 [(gogoproto.nullable) = false]; 16 | int64 voting_power = 3; 17 | int64 proposer_priority = 4; 18 | } 19 | 20 | message SimpleValidator { 21 | tendermint.crypto.PublicKey pub_key = 1; 22 | int64 voting_power = 2; 23 | } 24 | -------------------------------------------------------------------------------- /proto/tendermint/version/types.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package tendermint.version; 3 | 4 | import "gogoproto/gogo.proto"; 5 | 6 | // Consensus captures the consensus rules for processing a block in the 7 | // blockchain, including all blockchain data structures and the rules of the 8 | // application's state transition machine. 9 | message Consensus { 10 | option (gogoproto.equal) = true; 11 | 12 | uint64 block = 1; 13 | uint64 app = 2; 14 | } 15 | -------------------------------------------------------------------------------- /rfc/002-nonzero-genesis.md: -------------------------------------------------------------------------------- 1 | # RFC 002: Non-Zero Genesis 2 | 3 | ## Changelog 4 | 5 | - 2020-07-26: Initial draft (@erikgrinaker) 6 | - 2020-07-28: Use weak chain linking, i.e. `predecessor` field (@erikgrinaker) 7 | - 2020-07-31: Drop chain linking (@erikgrinaker) 8 | - 2020-08-03: Add `State.InitialHeight` (@erikgrinaker) 9 | 10 | ## Author(s) 11 | 12 | - Erik Grinaker (@erikgrinaker) 13 | 14 | ## Context 15 | 16 | The recommended upgrade path for block protocol-breaking upgrades is currently to hard fork the 17 | chain (see e.g. [`cosmoshub-3` upgrade](https://blog.cosmos.network/cosmos-hub-3-upgrade-announcement-39c9da941aee)). 18 | This is done by halting all validators at a predetermined height, exporting the application 19 | state via application-specific tooling, and creating an entirely new chain using the exported 20 | application state. 21 | 22 | As far as Tendermint is concerned, the upgraded chain is a completely separate chain, with e.g. 23 | a new chain ID and genesis file. Notably, the new chain starts at height 1, and has none of the 24 | old chain's block history. This causes problems for integrators, e.g. coin exchanges and 25 | wallets, that assume a monotonically increasing height for a given blockchain. Users also find 26 | it confusing that a given height can now refer to distinct states depending on the chain 27 | version. 28 | 29 | An ideal solution would be to always retain block backwards compatibility in such a way that chain 30 | history is never lost on upgrades. However, this may require a significant amount of engineering 31 | work that is not viable for the planned Stargate release (Tendermint 0.34), and may prove too 32 | restrictive for future development. 33 | 34 | As a first step, allowing the new chain to start from an initial height specified in the genesis 35 | file would at least provide monotonically increasing heights. There was a proposal to include the 36 | last block header of the previous chain as well, but since the genesis file is not verified and 37 | hashed (only specific fields are) this would not be trustworthy. 38 | 39 | External tooling will be required to map historical heights onto e.g. archive nodes that contain 40 | blocks from previous chain version. Tendermint will not include any such functionality. 41 | 42 | ## Proposal 43 | 44 | Tendermint will allow chains to start from an arbitrary initial height: 45 | 46 | - A new field `initial_height` is added to the genesis file, defaulting to `1`. It can be set to any 47 | non-negative integer, and `0` is considered equivalent to `1`. 48 | 49 | - A new field `InitialHeight` is added to the ABCI `RequestInitChain` message, with the same value 50 | and semantics as the genesis field. 51 | 52 | - A new field `InitialHeight` is added to the `state.State` struct, where `0` is considered invalid. 53 | Including the field here simplifies implementation, since the genesis value does not have to be 54 | propagated throughout the code base separately, but it is not strictly necessary. 55 | 56 | ABCI applications may have to be updated to handle arbitrary initial heights, otherwise the initial 57 | block may fail. 58 | 59 | ## Status 60 | 61 | Accepted 62 | 63 | ## Consequences 64 | 65 | ### Positive 66 | 67 | - Heights can be unique throughout the history of a "logical" chain, across hard fork upgrades. 68 | 69 | ### Negative 70 | 71 | - Upgrades still cause loss of block history. 72 | 73 | - Integrators will have to map height ranges to specific archive nodes/networks to query history. 74 | 75 | ### Neutral 76 | 77 | - There is no explicit link to the last block of the previous chain. 78 | 79 | ## References 80 | 81 | - [#2543: Allow genesis file to start from non-zero height w/ prev block header](https://github.com/tendermint/tendermint/issues/2543) 82 | -------------------------------------------------------------------------------- /rfc/003-ed25519-verification.md: -------------------------------------------------------------------------------- 1 | # RFC 003: Ed25519 Verification 2 | 3 | ## Changelog 4 | 5 | - August 21, 2020: initialized 6 | 7 | ## Author(s) 8 | 9 | - Marko (@marbar3778) 10 | 11 | ## Context 12 | 13 | Ed25519 keys are the only supported key types for Tendermint validators currently. Tendermint-Go wraps the ed25519 key implementation from the go standard library. As more clients are implemented to communicate with the canonical Tendermint implementation (Tendermint-Go) different implementations of ed25519 will be used. Due to [RFC 8032](https://www.rfc-editor.org/rfc/rfc8032.html) not guaranteeing implementation compatibility, Tendermint clients must to come to an agreement of how to guarantee implementation compatibility. [Zcash](https://z.cash/) has multiple implementations of their client and have identified this as a problem as well. The team at Zcash has made a proposal to address this issue, [Zcash improvement proposal 215](https://zips.z.cash/zip-0215). 14 | 15 | ## Proposal 16 | 17 | - Tendermint-Go would adopt [hdevalence/ed25519consensus](https://github.com/hdevalence/ed25519consensus). 18 | - This library is implements `ed25519.Verify()` in accordance to zip-215. Tendermint-go will continue to use `crypto/ed25519` for signing and key generation. 19 | 20 | - Tendermint-rs would adopt [ed25519-zebra](https://github.com/ZcashFoundation/ed25519-zebra) 21 | - related [issue](https://github.com/informalsystems/tendermint-rs/issues/355) 22 | 23 | Signature verification is one of the major bottlenecks of Tendermint-go, batch verification can not be used unless it has the same consensus rules, ZIP 215 makes verification safe in consensus critical areas. 24 | 25 | This change constitutes a breaking changes, therefore must be done in a major release. No changes to validator keys or operations will be needed for this change to be enabled. 26 | 27 | This change has no impact on signature aggregation. To enable this signature aggregation Tendermint will have to use different signature schema (Schnorr, BLS, ...). Secondly, this change will enable safe batch verification for the Tendermint-Go client. Batch verification for the rust client is already supported in the library being used. 28 | 29 | As part of the acceptance of this proposal it would be best to contract or discuss with a third party the process of conducting a security review of the go library. 30 | 31 | ## Status 32 | 33 | Proposed 34 | 35 | ## Consequences 36 | 37 | ### Positive 38 | 39 | - Consistent signature verification across implementations 40 | - Enable safe batch verification 41 | 42 | ### Negative 43 | 44 | #### Tendermint-Go 45 | 46 | - Third_party dependency 47 | - library has not gone through a security review. 48 | - unclear maintenance schedule 49 | - Fragmentation of the ed25519 key for the go implementation, verification is done using a third party library while the rest 50 | uses the go standard library 51 | 52 | ### Neutral 53 | 54 | ## References 55 | 56 | [It’s 255:19AM. Do you know what your validation criteria are?](https://hdevalence.ca/blog/2020-10-04-its-25519am) 57 | -------------------------------------------------------------------------------- /rfc/README.md: -------------------------------------------------------------------------------- 1 | **THIS REPOSITORY HAS BEEN ARCHIVED. THE TENDERMINT SPECIFICATION IS NOW LOCATED IN THE [TENDERMINT/TENDERMINT](https://github.com/tendermint/tendermint/tree/master/spec) REPOSITORY.** 2 | 3 | --- 4 | 5 | # Request for Comments (RFC) 6 | 7 | RFC stands for `Request for Comments`. It is a social device use to float and polish an idea prior to the inclusion into an existing or new spec/paper/research topic. 8 | 9 | An RFC should not be used for bug reports or trivial discussions - the overhead of compiling an RFC does not justify it. 10 | 11 | An RFC should not consist only of a problem statement (use a standard issue for that). 12 | 13 | A RFC should consist of: 14 | 15 | - Changelog 16 | - Context on the relevant goals and the current state 17 | - Proposed Solution 18 | - Summary of pros and cons 19 | - References 20 | 21 | If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match. 22 | 23 | **Note the context/background should be written in the present tense.** 24 | 25 | Some RFC's will be presented at a Tendermint Dev Session. If you are an outside contributor and have submitted a RFC, you may be invited to present your RFC at one of these calls. 26 | 27 | ## Table of Contents 28 | 29 | - [001-block-retention](./001-block-retention.md) 30 | - [002-nonzero-genesis](./002-nonzero-genesis.md) 31 | - [003-ed25519-verification](./003-ed25519-verification.md) 32 | - [004-abci++](./004-abci++.md) 33 | - [005-reverse-sync](./005-reverse-sync.md) 34 | - [006-semantic-versioning](./006-semantic-versioning.md) 35 | -------------------------------------------------------------------------------- /rfc/images/abci++.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tendermint/spec/9d5734e21479dfc9c308f5630678c800d85a2067/rfc/images/abci++.png -------------------------------------------------------------------------------- /rfc/images/abci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tendermint/spec/9d5734e21479dfc9c308f5630678c800d85a2067/rfc/images/abci.png -------------------------------------------------------------------------------- /rfc/images/block-retention.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tendermint/spec/9d5734e21479dfc9c308f5630678c800d85a2067/rfc/images/block-retention.png -------------------------------------------------------------------------------- /rfc/rfc_template.md: -------------------------------------------------------------------------------- 1 | # RFC {RFC-NUMBER}: {TITLE} 2 | 3 | ## Changelog 4 | 5 | - {date}: {changelog} 6 | 7 | ## Author(s) 8 | 9 | - {First Name} {github handle} 10 | 11 | ## Context 12 | 13 | > This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution. 14 | 15 | ## Proposal 16 | 17 | > It should contain a detailed breakdown of how the problem should be resolved including diagrams and other supporting materials needed to present the case and implementation roadmap for the proposed changes. The reader should be able to fully understand the proposal. This section should be broken up using ## subsections as needed. 18 | 19 | ## Status 20 | 21 | > A decision may be "proposed" if it hasn't been agreed upon yet, or "accepted" once it is agreed upon. If a later RFC changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement. 22 | 23 | {Deprecated|Proposed|Accepted} 24 | 25 | ## Consequences 26 | 27 | > This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones. 28 | 29 | ### Positive 30 | 31 | ### Negative 32 | 33 | ### Neutral 34 | 35 | ## References 36 | 37 | > Are there any relevant PR comments, issues that led up to this, or articles referenced for why we made the given design choice? If so link them here! 38 | 39 | - {reference link} 40 | -------------------------------------------------------------------------------- /rust-spec/fastsync/README.md: -------------------------------------------------------------------------------- 1 | # Fast Sync 2 | 3 | Deprecated see [tendermint/docs/tendermint-core/block-sync](https://github.com/tendermint/tendermint/blob/master/docs/tendermint-core/block-sync/README.md) 4 | -------------------------------------------------------------------------------- /rust-spec/lightclient/README.md: -------------------------------------------------------------------------------- 1 | # Light Clients 2 | 3 | Deprecated see [spec/light-client](../../spec/light-client) 4 | -------------------------------------------------------------------------------- /rust-spec/lightclient/verification/README.md: -------------------------------------------------------------------------------- 1 | # Verification 2 | 3 | Deprecated see [spec/light-client/verification](../../../spec/light-client/verification/README.md) 4 | -------------------------------------------------------------------------------- /spec/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | title: Overview 4 | parent: 5 | title: Spec 6 | order: 7 7 | --- 8 | 9 | **THIS REPOSITORY HAS BEEN ARCHIVED. THE TENDERMINT SPECIFICATION IS NOW LOCATED IN THE [TENDERMINT/TENDERMINT](https://github.com/tendermint/tendermint/tree/master/spec) REPOSITORY.** 10 | 11 | --- 12 | 13 | # Tendermint Spec 14 | 15 | This is a Markdown specification of the Tendermint blockchain. 16 | It defines the base data structures, how they are validated, 17 | and how they are communicated over the network. 18 | 19 | If you find discrepancies between the spec and the code that 20 | do not have an associated issue or pull request on github, 21 | please submit them to our [bug bounty](https://tendermint.com/security)! 22 | 23 | ## Contents 24 | 25 | - [Overview](#overview) 26 | 27 | ### Data Structures 28 | 29 | - [Encoding and Digests](./core/encoding.md) 30 | - [Blockchain](./core/data_structures.md) 31 | - [State](./core/state.md) 32 | 33 | ### Consensus Protocol 34 | 35 | - [Consensus Algorithm](./consensus/consensus.md) 36 | - [Creating a proposal](./consensus/creating-proposal.md) 37 | - [Time](./consensus/bft-time.md) 38 | - [Light-Client](./consensus/light-client/README.md) 39 | 40 | ### P2P and Network Protocols 41 | 42 | - [The Base P2P Layer](./p2p/node.md): multiplex the protocols ("reactors") on authenticated and encrypted TCP connections 43 | - [Peer Exchange (PEX)](./p2p/messages/pex.md): gossip known peer addresses so peers can find each other 44 | - [Block Sync](./p2p/messages/block-sync.md): gossip blocks so peers can catch up quickly 45 | - [Consensus](./p2p/messages/consensus.md): gossip votes and block parts so new blocks can be committed 46 | - [Mempool](./p2p/messages/mempool.md): gossip transactions so they get included in blocks 47 | - [Evidence](./p2p/messages/evidence.md): sending invalid evidence will stop the peer 48 | 49 | ### RPC 50 | 51 | - [RPC SPEC](./rpc/README.md): Specification of the Tendermint remote procedure call interface. 52 | 53 | ### Software 54 | 55 | - [ABCI](./abci/README.md): Details about interactions between the 56 | application and consensus engine over ABCI 57 | - [ABCI++](./abci++/README.md): Specification of interactions between the 58 | application and consensus engine over ABCI++ 59 | - [Write-Ahead Log](./consensus/wal.md): Details about how the consensus 60 | engine preserves data and recovers from crash failures 61 | 62 | ## Overview 63 | 64 | Tendermint provides Byzantine Fault Tolerant State Machine Replication using 65 | hash-linked batches of transactions. Such transaction batches are called "blocks". 66 | Hence, Tendermint defines a "blockchain". 67 | 68 | Each block in Tendermint has a unique index - its Height. 69 | Height's in the blockchain are monotonic. 70 | Each block is committed by a known set of weighted Validators. 71 | Membership and weighting within this validator set may change over time. 72 | Tendermint guarantees the safety and liveness of the blockchain 73 | so long as less than 1/3 of the total weight of the Validator set 74 | is malicious or faulty. 75 | 76 | A commit in Tendermint is a set of signed messages from more than 2/3 of 77 | the total weight of the current Validator set. Validators take turns proposing 78 | blocks and voting on them. Once enough votes are received, the block is considered 79 | committed. These votes are included in the _next_ block as proof that the previous block 80 | was committed - they cannot be included in the current block, as that block has already been 81 | created. 82 | 83 | Once a block is committed, it can be executed against an application. 84 | The application returns results for each of the transactions in the block. 85 | The application can also return changes to be made to the validator set, 86 | as well as a cryptographic digest of its latest state. 87 | 88 | Tendermint is designed to enable efficient verification and authentication 89 | of the latest state of the blockchain. To achieve this, it embeds 90 | cryptographic commitments to certain information in the block "header". 91 | This information includes the contents of the block (eg. the transactions), 92 | the validator set committing the block, as well as the various results returned by the application. 93 | Note, however, that block execution only occurs _after_ a block is committed. 94 | Thus, application results can only be included in the _next_ block. 95 | 96 | Also note that information like the transaction results and the validator set are never 97 | directly included in the block - only their cryptographic digests (Merkle roots) are. 98 | Hence, verification of a block requires a separate data structure to store this information. 99 | We call this the `State`. Block verification also requires access to the previous block. 100 | -------------------------------------------------------------------------------- /spec/abci++/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | parent: 4 | title: ABCI++ 5 | order: 3 6 | --- 7 | 8 | **THIS REPOSITORY HAS BEEN ARCHIVED. THE TENDERMINT SPECIFICATION IS NOW LOCATED IN THE [TENDERMINT/TENDERMINT](https://github.com/tendermint/tendermint/tree/master/spec) REPOSITORY.** 9 | 10 | --- 11 | 12 | # ABCI++ 13 | 14 | ## Introduction 15 | 16 | ABCI++ is a major evolution of ABCI (**A**pplication **B**lock**c**hain **I**nterface). 17 | Like its predecessor, ABCI++ is the interface between Tendermint (a state-machine 18 | replication engine) and the actual state machine being replicated (i.e., the Application). 19 | The API consists of a set of _methods_, each with a corresponding `Request` and `Response` 20 | message type. 21 | 22 | The methods are always initiated by Tendermint. The Application implements its logic 23 | for handling all ABCI++ methods. 24 | Thus, Tendermint always sends the `Request*` messages and receives the `Response*` messages 25 | in return. 26 | 27 | All ABCI++ messages and methods are defined in 28 | [protocol buffers](https://github.com/tendermint/spec/blob/master/proto/tendermint/abci/types.proto). 29 | This allows Tendermint to run with applications written in many programming languages. 30 | 31 | This specification is split as follows: 32 | 33 | - [Basic concepts and definitions](./abci++_basic_concepts_002_draft.md) - definitions and descriptions 34 | of concepts that are needed to understand other parts of this sepcification. 35 | - [Methods](./abci++_methods_002_draft.md) - complete details on all ABCI++ methods 36 | and message types. 37 | - [Requirements for the Application](./abci++_app_requirements_002_draft.md) - formal requirements 38 | on the Application's logic to ensure liveness of Tendermint. These requirements define what 39 | Tendermint expects from the Application. 40 | - [Tendermint's expected behavior](./abci++_tmint_expected_behavior_002_draft.md) - specification of 41 | how the different ABCI++ methods may be called by Tendermint. This explains what the Application 42 | is to expect from Tendermint. 43 | 44 | >**TODO** Re-read these and remove redundant info 45 | 46 | - [Applications](../abci/apps.md) - how to manage ABCI application state and other 47 | details about building ABCI applications 48 | - [Client and Server](../abci/client-server.md) - for those looking to implement their 49 | own ABCI application servers 50 | -------------------------------------------------------------------------------- /spec/abci++/v0.md: -------------------------------------------------------------------------------- 1 | # Tendermint v0 Markdown pseudocode 2 | 3 | This translates the latex code for Tendermint consensus from the Tendermint paper into markdown. 4 | 5 | ### Initialization 6 | 7 | ```go 8 | h_p ← 0 9 | round_p ← 0 10 | step_p is one of {propose, prevote, precommit} 11 | decision_p ← Vector() 12 | lockedRound_p ← -1 13 | lockedValue_p ← nil 14 | validValue_p ← nil 15 | validRound_p ← -1 16 | ``` 17 | 18 | ### StartRound(round) 19 | 20 | ```go 21 | function startRound(round) { 22 | round_p ← round 23 | step_p ← propose 24 | if proposer(h_p, round_p) = p { 25 | if validValue_p != nil { 26 | proposal ← validValue_p 27 | } else { 28 | proposal ← getValue() 29 | } 30 | broadcast ⟨PROPOSAL, h_p, round_p, proposal, validRound_p⟩ 31 | } else { 32 | schedule OnTimeoutPropose(h_p,round_p) to be executed after timeoutPropose(round_p) 33 | } 34 | } 35 | ``` 36 | 37 | ### ReceiveProposal 38 | 39 | In the case where the local node is not locked on any round, the following is ran: 40 | 41 | ```go 42 | upon ⟨PROPOSAL, h_p, round_p, v, −1) from proposer(h_p, round_p) while step_p = propose do { 43 | if valid(v) ∧ (lockedRound_p = −1 ∨ lockedValue_p = v) { 44 | broadcast ⟨PREVOTE, h_p, round_p, id(v)⟩ 45 | } else { 46 | broadcast ⟨PREVOTE, h_p, round_p, nil⟩ 47 | } 48 | step_p ← prevote 49 | } 50 | ``` 51 | 52 | In the case where the node is locked on a round, the following is ran: 53 | 54 | ```go 55 | upon ⟨PROPOSAL, h_p, round_p, v, vr⟩ from proposer(h_p, round_p) 56 | AND 2f + 1 ⟨PREVOTE, h_p, vr, id(v)⟩ 57 | while step_p = propose ∧ (vr ≥ 0 ∧ vr < round_p) do { 58 | if valid(v) ∧ (lockedRound_p ≤ vr ∨ lockedValue_p = v) { 59 | broadcast ⟨PREVOTE, h_p, round_p, id(v)⟩ 60 | } else { 61 | broadcast ⟨PREVOTE, h_p, round_p, nil⟩ 62 | } 63 | step_p ← prevote 64 | } 65 | ``` 66 | 67 | ### Prevote timeout 68 | 69 | Upon receiving 2f + 1 prevotes, setup a timeout. 70 | 71 | ```go 72 | upon 2f + 1 ⟨PREVOTE, h_p, vr, *⟩ with step_p = prevote for the first time, do { 73 | schedule OnTimeoutPrevote(h_p, round_p) to be executed after timeoutPrevote(round_p) 74 | } 75 | ``` 76 | 77 | with OnTimeoutPrevote defined as: 78 | 79 | ```go 80 | function OnTimeoutPrevote(height, round) { 81 | if (height = h_p && round = round_p && step_p = prevote) { 82 | broadcast ⟨PRECOMMIT, h_p, round_p, nil⟩ 83 | step_p ← precommit 84 | } 85 | } 86 | ``` 87 | 88 | ### Receiving enough prevotes to precommit 89 | 90 | The following code is ran upon receiving 2f + 1 prevotes for the same block 91 | 92 | ```go 93 | upon ⟨PROPOSAL, h_p, round_p, v, *⟩ 94 | from proposer(h_p, round_p) 95 | AND 2f + 1 ⟨PREVOTE, h_p, round_p, id(v)⟩ 96 | while valid(v) ∧ step_p >= prevote for the first time do { 97 | if (step_p = prevote) { 98 | lockedValue_p ← v 99 | lockedRound_p ← round_p 100 | broadcast ⟨PRECOMMIT, h_p, round_p, id(v)⟩ 101 | step_p ← precommit 102 | } 103 | validValue_p ← v 104 | validRound_p ← round_p 105 | } 106 | ``` 107 | 108 | And upon receiving 2f + 1 prevotes for nil: 109 | 110 | ```go 111 | upon 2f + 1 ⟨PREVOTE, h_p, round_p, nil⟩ 112 | while step_p = prevote do { 113 | broadcast ⟨PRECOMMIT, h_p, round_p, nil⟩ 114 | step_p ← precommit 115 | } 116 | ``` 117 | 118 | ### Precommit timeout 119 | 120 | Upon receiving 2f + 1 precommits, setup a timeout. 121 | 122 | ```go 123 | upon 2f + 1 ⟨PRECOMMIT, h_p, vr, *⟩ for the first time, do { 124 | schedule OnTimeoutPrecommit(h_p, round_p) to be executed after timeoutPrecommit(round_p) 125 | } 126 | ``` 127 | 128 | with OnTimeoutPrecommit defined as: 129 | 130 | ```go 131 | function OnTimeoutPrecommit(height, round) { 132 | if (height = h_p && round = round_p) { 133 | StartRound(round_p + 1) 134 | } 135 | } 136 | ``` 137 | 138 | ### Upon Receiving 2f + 1 precommits 139 | 140 | The following code is ran upon receiving 2f + 1 precommits for the same block 141 | 142 | ```go 143 | upon ⟨PROPOSAL, h_p, r, v, *⟩ 144 | from proposer(h_p, r) 145 | AND 2f + 1 ⟨ PRECOMMIT, h_p, r, id(v)⟩ 146 | while decision_p[h_p] = nil do { 147 | if (valid(v)) { 148 | decision_p[h_p] ← v 149 | h_p ← h_p + 1 150 | reset lockedRound_p, lockedValue_p,validRound_p and validValue_p to initial values 151 | StartRound(0) 152 | } 153 | } 154 | ``` 155 | 156 | If we don't see 2f + 1 precommits for the same block, we wait until we get 2f + 1 precommits, and the timeout occurs. -------------------------------------------------------------------------------- /spec/abci++/v1.md: -------------------------------------------------------------------------------- 1 | # Tendermint v1 Markdown pseudocode 2 | 3 | This adds hooks for the existing ABCI to the prior pseudocode 4 | 5 | ### Initialization 6 | 7 | ```go 8 | h_p ← 0 9 | round_p ← 0 10 | step_p is one of {propose, prevote, precommit} 11 | decision_p ← Vector() 12 | lockedValue_p ← nil 13 | validValue_p ← nil 14 | validRound_p ← -1 15 | ``` 16 | 17 | ### StartRound(round) 18 | 19 | ```go 20 | function startRound(round) { 21 | round_p ← round 22 | step_p ← propose 23 | if proposer(h_p, round_p) = p { 24 | if validValue_p != nil { 25 | proposal ← validValue_p 26 | } else { 27 | txdata ← mempool.GetBlock() 28 | // getBlockProposal fills in header 29 | proposal ← getBlockProposal(txdata) 30 | } 31 | broadcast ⟨PROPOSAL, h_p, round_p, proposal, validRound_p⟩ 32 | } else { 33 | schedule OnTimeoutPropose(h_p,round_p) to be executed after timeoutPropose(round_p) 34 | } 35 | } 36 | ``` 37 | 38 | ### ReceiveProposal 39 | 40 | In the case where the local node is not locked on any round, the following is ran: 41 | 42 | ```go 43 | upon ⟨PROPOSAL, h_p, round_p, v, −1) from proposer(h_p, round_p) while step_p = propose do { 44 | if valid(v) ∧ (lockedRound_p = −1 ∨ lockedValue_p = v) { 45 | broadcast ⟨PREVOTE, h_p, round_p, id(v)⟩ 46 | } else { 47 | broadcast ⟨PREVOTE, h_p, round_p, nil⟩ 48 | } 49 | step_p ← prevote 50 | } 51 | ``` 52 | 53 | In the case where the node is locked on a round, the following is ran: 54 | 55 | ```go 56 | upon ⟨PROPOSAL, h_p, round_p, v, vr⟩ 57 | from proposer(h_p, round_p) 58 | AND 2f + 1 ⟨PREVOTE, h_p, vr, id(v)⟩ 59 | while step_p = propose ∧ (vr ≥ 0 ∧ vr < round_p) do { 60 | if valid(v) ∧ (lockedRound_p ≤ vr ∨ lockedValue_p = v) { 61 | broadcast ⟨PREVOTE, h_p, round_p, id(v)⟩ 62 | } else { 63 | broadcast ⟨PREVOTE, h_p, round_p, nil⟩ 64 | } 65 | step_p ← prevote 66 | } 67 | ``` 68 | 69 | ### Prevote timeout 70 | 71 | Upon receiving 2f + 1 prevotes, setup a timeout. 72 | 73 | ```go 74 | upon 2f + 1 ⟨PREVOTE, h_p, vr, -1⟩ 75 | with step_p = prevote for the first time, do { 76 | schedule OnTimeoutPrevote(h_p, round_p) to be executed after timeoutPrevote(round_p) 77 | } 78 | ``` 79 | 80 | with OnTimeoutPrevote defined as: 81 | 82 | ```go 83 | function OnTimeoutPrevote(height, round) { 84 | if (height = h_p && round = round_p && step_p = prevote) { 85 | broadcast ⟨PRECOMMIT, h_p, round_p, nil⟩ 86 | step_p ← precommit 87 | } 88 | } 89 | ``` 90 | 91 | ### Receiving enough prevotes to precommit 92 | 93 | The following code is ran upon receiving 2f + 1 prevotes for the same block 94 | 95 | ```go 96 | upon ⟨PROPOSAL, h_p, round_p, v, *⟩ 97 | from proposer(h_p, round_p) 98 | AND 2f + 1 ⟨PREVOTE, h_p, vr, id(v)⟩ 99 | while valid(v) ∧ step_p >= prevote for the first time do { 100 | if (step_p = prevote) { 101 | lockedValue_p ← v 102 | lockedRound_p ← round_p 103 | broadcast ⟨PRECOMMIT, h_p, round_p, id(v)⟩ 104 | step_p ← precommit 105 | } 106 | validValue_p ← v 107 | validRound_p ← round_p 108 | } 109 | ``` 110 | 111 | And upon receiving 2f + 1 prevotes for nil: 112 | 113 | ```go 114 | upon 2f + 1 ⟨PREVOTE, h_p, round_p, nil⟩ 115 | while step_p = prevote do { 116 | broadcast ⟨PRECOMMIT, h_p, round_p, nil⟩ 117 | step_p ← precommit 118 | } 119 | ``` 120 | 121 | ### Precommit timeout 122 | 123 | Upon receiving 2f + 1 precommits, setup a timeout. 124 | 125 | ```go 126 | upon 2f + 1 ⟨PRECOMMIT, h_p, vr, *⟩ for the first time, do { 127 | schedule OnTimeoutPrecommit(h_p, round_p) to be executed after timeoutPrecommit(round_p) 128 | } 129 | ``` 130 | 131 | with OnTimeoutPrecommit defined as: 132 | 133 | ```go 134 | function OnTimeoutPrecommit(height, round) { 135 | if (height = h_p && round = round_p) { 136 | StartRound(round_p + 1) 137 | } 138 | } 139 | ``` 140 | 141 | ### Upon Receiving 2f + 1 precommits 142 | 143 | The following code is ran upon receiving 2f + 1 precommits for the same block 144 | 145 | ```go 146 | upon ⟨PROPOSAL, h_p, r, v, *⟩ 147 | from proposer(h_p, r) 148 | AND 2f + 1 ⟨ PRECOMMIT, h_p, r, id(v)⟩ 149 | while decision_p[h_p] = nil do { 150 | if (valid(v)) { 151 | decision_p[h_p] ← v 152 | h_p ← h_p + 1 153 | reset lockedRound_p, lockedValue_p,validRound_p and validValue_p to initial values 154 | ABCI.BeginBlock(v.header) 155 | ABCI.DeliverTxs(v.data) 156 | ABCI.EndBlock() 157 | StartRound(0) 158 | } 159 | } 160 | ``` 161 | 162 | If we don't see 2f + 1 precommits for the same block, we wait until we get 2f + 1 precommits, and the timeout occurs. -------------------------------------------------------------------------------- /spec/abci/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | parent: 4 | title: ABCI 5 | order: 2 6 | --- 7 | 8 | # ABCI 9 | 10 | ABCI stands for "**A**pplication **B**lock**c**hain **I**nterface". 11 | ABCI is the interface between Tendermint (a state-machine replication engine) 12 | and your application (the actual state machine). It consists of a set of 13 | _methods_, each with a corresponding `Request` and `Response`message type. 14 | To perform state-machine replication, Tendermint calls the ABCI methods on the 15 | ABCI application by sending the `Request*` messages and receiving the `Response*` messages in return. 16 | 17 | All ABCI messages and methods are defined in [protocol buffers](../../proto/tendermint/abci/types.proto). 18 | This allows Tendermint to run with applications written in many programming languages. 19 | 20 | This specification is split as follows: 21 | 22 | - [Methods and Types](./abci.md) - complete details on all ABCI methods and 23 | message types 24 | - [Applications](./apps.md) - how to manage ABCI application state and other 25 | details about building ABCI applications 26 | - [Client and Server](./client-server.md) - for those looking to implement their 27 | own ABCI application servers 28 | -------------------------------------------------------------------------------- /spec/abci/client-server.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 3 3 | title: Client and Server 4 | --- 5 | 6 | # Client and Server 7 | 8 | This section is for those looking to implement their own ABCI Server, perhaps in 9 | a new programming language. 10 | 11 | You are expected to have read [ABCI Methods and Types](./abci.md) and [ABCI 12 | Applications](./apps.md). 13 | 14 | ## Message Protocol 15 | 16 | The message protocol consists of pairs of requests and responses defined in the 17 | [protobuf file](../../proto/tendermint/abci/types.proto). 18 | 19 | Some messages have no fields, while others may include byte-arrays, strings, integers, 20 | or custom protobuf types. 21 | 22 | For more details on protobuf, see the [documentation](https://developers.google.com/protocol-buffers/docs/overview). 23 | 24 | For each request, a server should respond with the corresponding 25 | response, where the order of requests is preserved in the order of 26 | responses. 27 | 28 | ## Server Implementations 29 | 30 | To use ABCI in your programming language of choice, there must be a ABCI 31 | server in that language. Tendermint supports three implementations of the ABCI, written in Go: 32 | 33 | - In-process ([Golang](https://github.com/tendermint/tendermint/tree/master/abci), [Rust](https://github.com/tendermint/rust-abci)) 34 | - ABCI-socket 35 | - GRPC 36 | 37 | The latter two can be tested using the `abci-cli` by setting the `--abci` flag 38 | appropriately (ie. to `socket` or `grpc`). 39 | 40 | See examples, in various stages of maintenance, in 41 | [Go](https://github.com/tendermint/tendermint/tree/master/abci/server), 42 | [JavaScript](https://github.com/tendermint/js-abci), 43 | [C++](https://github.com/mdyring/cpp-tmsp), and 44 | [Java](https://github.com/jTendermint/jabci). 45 | 46 | ### In Process 47 | 48 | The simplest implementation uses function calls within Golang. 49 | This means ABCI applications written in Golang can be compiled with Tendermint Core and run as a single binary. 50 | 51 | ### GRPC 52 | 53 | If GRPC is available in your language, this is the easiest approach, 54 | though it will have significant performance overhead. 55 | 56 | To get started with GRPC, copy in the [protobuf 57 | file](../../proto/tendermint/abci/types.proto) and compile it using the GRPC 58 | plugin for your language. For instance, for golang, the command is `protoc 59 | --go_out=plugins=grpc:. types.proto`. See the [grpc documentation for more 60 | details](http://www.grpc.io/docs/). `protoc` will autogenerate all the 61 | necessary code for ABCI client and server in your language, including whatever 62 | interface your application must satisfy to be used by the ABCI server for 63 | handling requests. 64 | 65 | Note the length-prefixing used in the socket implementation (TSP) does not apply for GRPC. 66 | 67 | ### TSP 68 | 69 | Tendermint Socket Protocol is an asynchronous, raw socket server which provides ordered message passing over unix or tcp. 70 | Messages are serialized using Protobuf3 and length-prefixed with a [signed Varint](https://developers.google.com/protocol-buffers/docs/encoding?csw=1#signed-integers) 71 | 72 | If GRPC is not available in your language, or you require higher 73 | performance, or otherwise enjoy programming, you may implement your own 74 | ABCI server using the Tendermint Socket Protocol. The first step is still to auto-generate the relevant data 75 | types and codec in your language using `protoc`. In addition to being proto3 encoded, messages coming over 76 | the socket are length-prefixed to facilitate use as a streaming protocol. proto3 doesn't have an 77 | official length-prefix standard, so we use our own. The first byte in 78 | the prefix represents the length of the Big Endian encoded length. The 79 | remaining bytes in the prefix are the Big Endian encoded length. 80 | 81 | For example, if the proto3 encoded ABCI message is 0xDEADBEEF (4 82 | bytes), the length-prefixed message is 0x0104DEADBEEF. If the proto3 83 | encoded ABCI message is 65535 bytes long, the length-prefixed message 84 | would be like 0x02FFFF.... 85 | 86 | The benefit of using this `varint` encoding over the old version (where integers were encoded as `` is that 87 | it is the standard way to encode integers in Protobuf. It is also generally shorter. 88 | 89 | As noted above, this prefixing does not apply for GRPC. 90 | 91 | An ABCI server must also be able to support multiple connections, as 92 | Tendermint uses four connections. 93 | 94 | ### Async vs Sync 95 | 96 | The main ABCI server (ie. non-GRPC) provides ordered asynchronous messages. 97 | This is useful for DeliverTx and CheckTx, since it allows Tendermint to forward 98 | transactions to the app before it's finished processing previous ones. 99 | 100 | Thus, DeliverTx and CheckTx messages are sent asynchronously, while all other 101 | messages are sent synchronously. 102 | 103 | ## Client 104 | 105 | There are currently two use-cases for an ABCI client. One is a testing 106 | tool, as in the `abci-cli`, which allows ABCI requests to be sent via 107 | command line. The other is a consensus engine, such as Tendermint Core, 108 | which makes requests to the application every time a new transaction is 109 | received or a block is committed. 110 | 111 | It is unlikely that you will need to implement a client. For details of 112 | our client, see 113 | [here](https://github.com/tendermint/tendermint/tree/master/abci/client). 114 | -------------------------------------------------------------------------------- /spec/blockchain/blockchain.md: -------------------------------------------------------------------------------- 1 | # Blockchain 2 | 3 | Deprecated see [core/data_structures.md](../core/data_structures.md) 4 | -------------------------------------------------------------------------------- /spec/blockchain/encoding.md: -------------------------------------------------------------------------------- 1 | # Encoding 2 | 3 | Deprecated see [core/data_structures.md](../core/encoding.md) 4 | -------------------------------------------------------------------------------- /spec/blockchain/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | parent: 4 | title: Blockchain 5 | order: false 6 | --- 7 | 8 | # Blockchain 9 | 10 | This section describes the core types and functionality of the Tendermint protocol implementation. 11 | 12 | [Core Data Structures](../core/data_structures.md) 13 | [Encoding](../core/encoding.md) 14 | [State](../core/state.md) 15 | -------------------------------------------------------------------------------- /spec/blockchain/state.md: -------------------------------------------------------------------------------- 1 | # State 2 | 3 | Deprecated see [core/state.md](../core/state.md) 4 | -------------------------------------------------------------------------------- /spec/consensus/bft-time.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 2 3 | --- 4 | # BFT Time 5 | 6 | Tendermint provides a deterministic, Byzantine fault-tolerant, source of time. 7 | Time in Tendermint is defined with the Time field of the block header. 8 | 9 | It satisfies the following properties: 10 | 11 | - Time Monotonicity: Time is monotonically increasing, i.e., given 12 | a header H1 for height h1 and a header H2 for height `h2 = h1 + 1`, `H1.Time < H2.Time`. 13 | - Time Validity: Given a set of Commit votes that forms the `block.LastCommit` field, a range of 14 | valid values for the Time field of the block header is defined only by 15 | Precommit messages (from the LastCommit field) sent by correct processes, i.e., 16 | a faulty process cannot arbitrarily increase the Time value. 17 | 18 | In the context of Tendermint, time is of type int64 and denotes UNIX time in milliseconds, i.e., 19 | corresponds to the number of milliseconds since January 1, 1970. Before defining rules that need to be enforced by the 20 | Tendermint consensus protocol, so the properties above holds, we introduce the following definition: 21 | 22 | - median of a Commit is equal to the median of `Vote.Time` fields of the `Vote` messages, 23 | where the value of `Vote.Time` is counted number of times proportional to the process voting power. As in Tendermint 24 | the voting power is not uniform (one process one vote), a vote message is actually an aggregator of the same votes whose 25 | number is equal to the voting power of the process that has casted the corresponding votes message. 26 | 27 | Let's consider the following example: 28 | 29 | - we have four processes p1, p2, p3 and p4, with the following voting power distribution (p1, 23), (p2, 27), (p3, 10) 30 | and (p4, 10). The total voting power is 70 (`N = 3f+1`, where `N` is the total voting power, and `f` is the maximum voting 31 | power of the faulty processes), so we assume that the faulty processes have at most 23 of voting power. 32 | Furthermore, we have the following vote messages in some LastCommit field (we ignore all fields except Time field): 33 | - (p1, 100), (p2, 98), (p3, 1000), (p4, 500). We assume that p3 and p4 are faulty processes. Let's assume that the 34 | `block.LastCommit` message contains votes of processes p2, p3 and p4. Median is then chosen the following way: 35 | the value 98 is counted 27 times, the value 1000 is counted 10 times and the value 500 is counted also 10 times. 36 | So the median value will be the value 98. No matter what set of messages with at least `2f+1` voting power we 37 | choose, the median value will always be between the values sent by correct processes. 38 | 39 | We ensure Time Monotonicity and Time Validity properties by the following rules: 40 | 41 | - let rs denotes `RoundState` (consensus internal state) of some process. Then 42 | `rs.ProposalBlock.Header.Time == median(rs.LastCommit) && 43 | rs.Proposal.Timestamp == rs.ProposalBlock.Header.Time`. 44 | 45 | - Furthermore, when creating the `vote` message, the following rules for determining `vote.Time` field should hold: 46 | 47 | - if `rs.LockedBlock` is defined then 48 | `vote.Time = max(rs.LockedBlock.Timestamp + time.Millisecond, time.Now())`, where `time.Now()` 49 | denotes local Unix time in milliseconds 50 | 51 | - else if `rs.Proposal` is defined then 52 | `vote.Time = max(rs.Proposal.Timestamp + time.Millisecond,, time.Now())`, 53 | 54 | - otherwise, `vote.Time = time.Now())`. In this case vote is for `nil` so it is not taken into account for 55 | the timestamp of the next block. 56 | -------------------------------------------------------------------------------- /spec/consensus/consensus-paper/README.md: -------------------------------------------------------------------------------- 1 | # Tendermint-spec 2 | 3 | The repository contains the specification (and the proofs) of the Tendermint 4 | consensus protocol. 5 | 6 | ## How to install Latex on Mac OS 7 | 8 | MacTex is Latex distribution for Mac OS. You can download it [here](http://www.tug.org/mactex/mactex-download.html). 9 | 10 | Popular IDE for Latex-based projects is TexStudio. It can be downloaded 11 | [here](https://www.texstudio.org/). 12 | 13 | ## How to build project 14 | 15 | In order to compile the latex files (and write bibliography), execute 16 | 17 | `$ pdflatex paper`
18 | `$ bibtex paper`
19 | `$ pdflatex paper`
20 | `$ pdflatex paper`
21 | 22 | The generated file is paper.pdf. You can open it with 23 | 24 | `$ open paper.pdf` 25 | -------------------------------------------------------------------------------- /spec/consensus/consensus-paper/conclusion.tex: -------------------------------------------------------------------------------- 1 | \section{Conclusion} \label{sec:conclusion} 2 | 3 | We have proposed a new Byzantine-fault tolerant consensus algorithm that is the 4 | core of the Tendermint BFT SMR platform. The algorithm is designed for the wide 5 | area network with high number of mutually distrusted nodes that communicate 6 | over gossip based peer-to-peer network. It has only a single mode of execution 7 | and the communication pattern is very similar to the "normal" case of the 8 | state-of-the art PBFT algorithm. The algorithm ensures termination with a novel 9 | mechanism that takes advantage of the gossip based communication between nodes. 10 | The proposed algorithm and the proofs are simple and elegant, and we believe 11 | that this makes it easier to understand and implement correctly. 12 | 13 | \section*{Acknowledgment} 14 | 15 | We would like to thank Anton Kaliaev, Ismail Khoffi and Dahlia Malkhi for comments on an earlier version of the paper. We also want to thank Marko Vukolic, Ming Chuan Lin, Maria Potop-Butucaru, Sara Tucci, Antonella Del Pozzo and Yackolley Amoussou-Guenou for pointing out the liveness issues 16 | in the previous version of the algorithm. Finally, we want to thank the Tendermint team members and all project contributors for making Tendermint such a great platform. 17 | -------------------------------------------------------------------------------- /spec/consensus/consensus-paper/homodel.sty: -------------------------------------------------------------------------------- 1 | \newcommand{\NC}{\mbox{\it NC}} 2 | \newcommand{\HO}{\mbox{\it HO}} 3 | \newcommand{\AS}{\mbox{\it AS}} 4 | \newcommand{\SK}{\mbox{\it SK}} 5 | \newcommand{\SHO}{\mbox{\it SHO}} 6 | \newcommand{\AHO}{\mbox{\it AHO}} 7 | \newcommand{\CONS}{\mbox{\it CONS}} 8 | \newcommand{\K}{\mbox{\it K}} 9 | 10 | \newcommand{\Alg}{\mathcal{A}} 11 | \newcommand{\Pred}{\mathcal{P}} 12 | \newcommand{\Spr}{S_p^r} 13 | \newcommand{\Tpr}{T_p^r} 14 | \newcommand{\mupr}{\vec{\mu}_p^{\,r}} 15 | 16 | \newcommand{\MSpr}{S_p^{\rho}} 17 | \newcommand{\MTpr}{T_p^{\rho}} 18 | 19 | 20 | 21 | \newconstruct{\SEND}{$\Spr$:}{}{\ENDSEND}{} 22 | \newconstruct{\TRAN}{$\Tpr$:}{}{\ENDTRAN}{} 23 | \newconstruct{\ROUND}{\textbf{Round}}{\!\textbf{:}}{\ENDROUND}{} 24 | \newconstruct{\VARIABLES}{\textbf{Variables:}}{}{\ENDVARIABLES}{} 25 | \newconstruct{\INIT}{\textbf{Initialization:}}{}{\ENDINIT}{} 26 | 27 | \newconstruct{\MSEND}{$\MSpr$:}{}{\ENDMSEND}{} 28 | \newconstruct{\MTRAN}{$\MTpr$:}{}{\ENDMTRAN}{} 29 | 30 | \newconstruct{\SROUND}{\textbf{Selection Round}}{\!\textbf{:}}{\ENDSROUND}{} 31 | \newconstruct{\VROUND}{\textbf{Validation Round}}{\!\textbf{:}}{\ENDVROUND}{} 32 | \newconstruct{\DROUND}{\textbf{Decision Round}}{\!\textbf{:}}{\ENDDROUND}{} 33 | -------------------------------------------------------------------------------- /spec/consensus/consensus-paper/latex8.sty: -------------------------------------------------------------------------------- 1 | % --------------------------------------------------------------- 2 | % 3 | % $Id: latex8.sty,v 1.2 1995/09/15 15:31:13 ienne Exp $ 4 | % 5 | % by Paolo.Ienne@di.epfl.ch 6 | % 7 | % --------------------------------------------------------------- 8 | % 9 | % no guarantee is given that the format corresponds perfectly to 10 | % IEEE 8.5" x 11" Proceedings, but most features should be ok. 11 | % 12 | % --------------------------------------------------------------- 13 | % with LaTeX2e: 14 | % ============= 15 | % 16 | % use as 17 | % \documentclass[times,10pt,twocolumn]{article} 18 | % \usepackage{latex8} 19 | % \usepackage{times} 20 | % 21 | % --------------------------------------------------------------- 22 | 23 | % with LaTeX 2.09: 24 | % ================ 25 | % 26 | % use as 27 | % \documentstyle[times,art10,twocolumn,latex8]{article} 28 | % 29 | % --------------------------------------------------------------- 30 | % with both versions: 31 | % =================== 32 | % 33 | % specify \pagestyle{empty} to omit page numbers in the final 34 | % version 35 | % 36 | % specify references as 37 | % \bibliographystyle{latex8} 38 | % \bibliography{...your files...} 39 | % 40 | % use Section{} and SubSection{} instead of standard section{} 41 | % and subsection{} to obtain headings in the form 42 | % "1.3. My heading" 43 | % 44 | % --------------------------------------------------------------- 45 | 46 | \typeout{IEEE 8.5 x 11-Inch Proceedings Style `latex8.sty'.} 47 | 48 | % ten point helvetica bold required for captions 49 | % in some sites the name of the helvetica bold font may differ, 50 | % change the name here: 51 | \font\tenhv = phvb at 10pt 52 | %\font\tenhv = phvb7t at 10pt 53 | 54 | % eleven point times bold required for second-order headings 55 | % \font\elvbf = cmbx10 scaled 1100 56 | \font\elvbf = ptmb scaled 1100 57 | 58 | % set dimensions of columns, gap between columns, and paragraph indent 59 | \setlength{\textheight}{8.875in} 60 | \setlength{\textwidth}{6.875in} 61 | \setlength{\columnsep}{0.3125in} 62 | \setlength{\topmargin}{0in} 63 | \setlength{\headheight}{0in} 64 | \setlength{\headsep}{0in} 65 | \setlength{\parindent}{1pc} 66 | \setlength{\oddsidemargin}{-.304in} 67 | \setlength{\evensidemargin}{-.304in} 68 | 69 | % memento from size10.clo 70 | % \normalsize{\@setfontsize\normalsize\@xpt\@xiipt} 71 | % \small{\@setfontsize\small\@ixpt{11}} 72 | % \footnotesize{\@setfontsize\footnotesize\@viiipt{9.5}} 73 | % \scriptsize{\@setfontsize\scriptsize\@viipt\@viiipt} 74 | % \tiny{\@setfontsize\tiny\@vpt\@vipt} 75 | % \large{\@setfontsize\large\@xiipt{14}} 76 | % \Large{\@setfontsize\Large\@xivpt{18}} 77 | % \LARGE{\@setfontsize\LARGE\@xviipt{22}} 78 | % \huge{\@setfontsize\huge\@xxpt{25}} 79 | % \Huge{\@setfontsize\Huge\@xxvpt{30}} 80 | 81 | \def\@maketitle 82 | { 83 | \newpage 84 | \null 85 | \vskip .375in 86 | \begin{center} 87 | {\Large \bf \@title \par} 88 | % additional two empty lines at the end of the title 89 | \vspace*{24pt} 90 | { 91 | \large 92 | \lineskip .5em 93 | \begin{tabular}[t]{c} 94 | \@author 95 | \end{tabular} 96 | \par 97 | } 98 | % additional small space at the end of the author name 99 | \vskip .5em 100 | { 101 | \large 102 | \begin{tabular}[t]{c} 103 | \@affiliation 104 | \end{tabular} 105 | \par 106 | \ifx \@empty \@email 107 | \else 108 | \begin{tabular}{r@{~}l} 109 | E-mail: & {\tt \@email} 110 | \end{tabular} 111 | \par 112 | \fi 113 | } 114 | % additional empty line at the end of the title block 115 | \vspace*{12pt} 116 | \end{center} 117 | } 118 | 119 | \def\abstract 120 | {% 121 | \centerline{\large\bf Abstract}% 122 | \vspace*{12pt}% 123 | \it% 124 | } 125 | 126 | \def\endabstract 127 | { 128 | % additional empty line at the end of the abstract 129 | \vspace*{12pt} 130 | } 131 | 132 | \def\affiliation#1{\gdef\@affiliation{#1}} \gdef\@affiliation{} 133 | 134 | \def\email#1{\gdef\@email{#1}} 135 | \gdef\@email{} 136 | 137 | \newlength{\@ctmp} 138 | \newlength{\@figindent} 139 | \setlength{\@figindent}{1pc} 140 | 141 | \long\def\@makecaption#1#2{ 142 | \vskip 10pt 143 | \setbox\@tempboxa\hbox{\tenhv\noindent #1.~#2} 144 | \setlength{\@ctmp}{\hsize} 145 | \addtolength{\@ctmp}{-\@figindent}\addtolength{\@ctmp}{-\@figindent} 146 | % IF longer than one indented paragraph line 147 | \ifdim \wd\@tempboxa >\@ctmp 148 | % THEN set as an indented paragraph 149 | \begin{list}{}{\leftmargin\@figindent \rightmargin\leftmargin} 150 | \item[]\tenhv #1.~#2\par 151 | \end{list} 152 | \else 153 | % ELSE center 154 | \hbox to\hsize{\hfil\box\@tempboxa\hfil} 155 | \fi} 156 | 157 | % correct heading spacing and type 158 | \def\section{\@startsection {section}{1}{\z@} 159 | {14pt plus 2pt minus 2pt}{14pt plus 2pt minus 2pt} {\large\bf}} 160 | \def\subsection{\@startsection {subsection}{2}{\z@} 161 | {13pt plus 2pt minus 2pt}{13pt plus 2pt minus 2pt} {\elvbf}} 162 | 163 | % add the period after section numbers 164 | \newcommand{\Section}[1]{\section{\hskip -1em.~#1}} 165 | \newcommand{\SubSection}[1]{\subsection{\hskip -1em.~#1}} 166 | 167 | % end of file latex8.sty 168 | % --------------------------------------------------------------- 169 | -------------------------------------------------------------------------------- /spec/consensus/consensus-paper/rounddiag.sty: -------------------------------------------------------------------------------- 1 | % ROUNDDIAG STYLE 2 | % for LaTeX version 2e 3 | % by -- 2008 Martin Hutle 4 | % 5 | % This style file is free software; you can redistribute it and/or 6 | % modify it under the terms of the GNU Lesser General Public 7 | % License as published by the Free Software Foundation; either 8 | % version 2 of the License, or (at your option) any later version. 9 | % 10 | % This style file is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | % Lesser General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU Lesser General Public 16 | % License along with this style file; if not, write to the 17 | % Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 | % Boston, MA 02111-1307, USA. 19 | % 20 | \NeedsTeXFormat{LaTeX2e} 21 | \ProvidesPackage{rounddiag} 22 | \typeout{Document Style `rounddiag' - provides simple round diagrams} 23 | % 24 | \RequirePackage{ifthen} 25 | \RequirePackage{calc} 26 | \RequirePackage{tikz} 27 | 28 | \def\rdstretch{3} 29 | 30 | \tikzstyle{msg}=[->,thick,>=latex] 31 | \tikzstyle{rndline}=[dotted] 32 | \tikzstyle{procline}=[dotted] 33 | 34 | \newenvironment{rounddiag}[2]{ 35 | \begin{center} 36 | \begin{tikzpicture} 37 | \foreach \i in {1,...,#1}{ 38 | \draw[procline] (0,#1-\i) node[xshift=-1em]{$p_{\i}$} -- (#2*\rdstretch+1,#1-\i); 39 | } 40 | \foreach \i in {0,...,#2}{ 41 | \draw[rndline] (\i*\rdstretch+0.5,0) -- (\i*\rdstretch+0.5,#1-1); 42 | } 43 | \newcommand{\rdat}[2]{ 44 | (##2*\rdstretch+0.5,#1-##1) 45 | }% 46 | \newcommand{\round}[2]{% 47 | \def\rdround{##1} 48 | \ifthenelse{\equal{##2}{}}{}{ 49 | \node[yshift=-1em] at ({##1*\rdstretch+0.5-0.5*\rdstretch},0) {##2}; 50 | } 51 | }% 52 | \newcommand{\rdmessage}[3]{\draw[msg] 53 | (\rdround*\rdstretch-\rdstretch+0.5,#1-##1) -- node[yshift=1.2ex]{##3} 54 | (\rdround*\rdstretch+0.5,#1-##2);}% 55 | \newcommand{\rdalltoall}{% 56 | \foreach \i in {1,...,#1}{ 57 | \foreach \j in {1,...,#1}{ 58 | { \rdmessage{\i}{\j}{}}}}}% 59 | }{% 60 | \end{tikzpicture} 61 | \end{center} 62 | } 63 | -------------------------------------------------------------------------------- /spec/consensus/consensus-paper/technote.sty: -------------------------------------------------------------------------------- 1 | \NeedsTeXFormat{LaTeX2e} 2 | \ProvidesPackage{technote}[2007/11/09] 3 | \typeout{Template for quick notes with some useful definitions} 4 | 5 | \RequirePackage{ifthen} 6 | \RequirePackage{calc} 7 | \RequirePackage{amsmath,amssymb,amsthm} 8 | \RequirePackage{epsfig} 9 | \RequirePackage{algorithm} 10 | \RequirePackage[noend]{algorithmicplus} 11 | 12 | \newboolean{technote@noedit} 13 | \setboolean{technote@noedit}{false} 14 | \DeclareOption{noedit}{\setboolean{technote@noedit}{true}} 15 | 16 | \newcounter{technote@lang} 17 | \setcounter{technote@lang}{0} 18 | \DeclareOption{german}{\setcounter{technote@lang}{1}} 19 | \DeclareOption{french}{\setcounter{technote@lang}{2}} 20 | 21 | \DeclareOption{fullpage}{ 22 | \oddsidemargin -10mm % Margin on odd side pages (default=0mm) 23 | \evensidemargin -10mm % Margin on even side pages (default=0mm) 24 | \topmargin -10mm % Top margin space (default=16mm) 25 | \headheight \baselineskip % Height of headers (default=0mm) 26 | \headsep \baselineskip % Separation spc btw header and text (d=0mm) 27 | \footskip 30pt % Separation spc btw text and footer (d=30pt) 28 | \textheight 230mm % Total text height (default=200mm) 29 | \textwidth 180mm % Total text width (default=160mm) 30 | } 31 | 32 | \renewcommand{\algorithmiccomment}[1]{\hfill/* #1 */} 33 | \renewcommand{\algorithmiclnosize}{\scriptsize} 34 | 35 | \newboolean{technote@truenumbers} 36 | \setboolean{technote@truenumbers}{false} 37 | \DeclareOption{truenumbers}{\setboolean{technote@truenumbers}{true}} 38 | 39 | \ProcessOptions 40 | 41 | \newcommand{\N}{\ifthenelse{\boolean{technote@truenumbers}}% 42 | {\mbox{\rm I\hspace{-.5em}N}}% 43 | {\mathbb{N}}} 44 | 45 | \newcommand{\R}{\ifthenelse{\boolean{technote@truenumbers}}% 46 | {\mbox{\rm I\hspace{-.2em}R}}% 47 | {\mathbb{R}}} 48 | 49 | \newcommand{\Z}{\mathbb{Z}} 50 | 51 | \newcommand{\set}[1]{\left\{#1\right\}} 52 | \newcommand{\mathsc}[1]{\mbox{\sc #1}} 53 | \newcommand{\li}[1]{\langle#1\rangle} 54 | \newcommand{\st}{\;s.t.\;} 55 | \newcommand{\Real}{\R} 56 | \newcommand{\Natural}{\N} 57 | \newcommand{\Integer}{\Z} 58 | 59 | % edit commands 60 | \newcommand{\newedit}[2]{ 61 | \newcommand{#1}[2][default]{% 62 | \ifthenelse{\boolean{technote@noedit}}{}{ 63 | \par\vspace{2mm} 64 | \noindent 65 | \begin{tabular}{|l|}\hline 66 | \parbox{\linewidth-\tabcolsep*2}{{\bf #2:}\hfill\ifthenelse{\equal{##1}{default}}{}{##1}}\\\hline 67 | \parbox{\linewidth-\tabcolsep*2}{\rule{0pt}{5mm}##2\rule[-2mm]{0pt}{2mm}}\\\hline 68 | \end{tabular} 69 | \par\vspace{2mm} 70 | } 71 | } 72 | } 73 | 74 | \newedit{\note}{Note} 75 | \newedit{\comment}{Comment} 76 | \newedit{\question}{Question} 77 | \newedit{\content}{Content} 78 | \newedit{\problem}{Problem} 79 | 80 | \newcommand{\mnote}[1]{\marginpar{\scriptsize\it 81 | \begin{minipage}[t]{0.8 in} 82 | \raggedright #1 83 | \end{minipage}}} 84 | 85 | \newcommand{\Insert}[1]{\underline{#1}\marginpar{$|$}} 86 | 87 | \newcommand{\Delete}[1]{\marginpar{$|$} 88 | } 89 | 90 | % lemma, theorem, etc. 91 | \newtheorem{lemma}{Lemma} 92 | \newtheorem{proposition}{Proposition} 93 | \newtheorem{theorem}{Theorem} 94 | \newtheorem{corollary}{Corollary} 95 | \newtheorem{assumption}{Assumption} 96 | \newtheorem{definition}{Definition} 97 | 98 | \gdef\op|{\,|\;} 99 | \gdef\op:{\,:\;} 100 | \newcommand{\assign}{\leftarrow} 101 | \newcommand{\inc}[1]{#1 \assign #1 + 1} 102 | \newcommand{\isdef}{:=} 103 | 104 | \newcommand{\ident}[1]{\mathit{#1}} 105 | \def\newident#1{\expandafter\def\csname #1\endcsname{\ident{#1}}} 106 | 107 | \newcommand{\eg}{{\it e.g.}} 108 | \newcommand{\ie}{{\it i.e.}} 109 | \newcommand{\apriori}{{\it apriori}} 110 | \newcommand{\etal}{{\it et al.}} 111 | 112 | \newcommand\ps@technote{% 113 | \renewcommand\@oddhead{\theheader}% 114 | \let\@evenhead\@oddhead 115 | \renewcommand\@evenfoot 116 | {\hfil\normalfont\textrm{\thepage}\hfil}% 117 | \let\@oddfoot\@evenfoot 118 | } 119 | -------------------------------------------------------------------------------- /spec/consensus/creating-proposal.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 2 3 | --- 4 | # Creating a proposal 5 | 6 | A block consists of a header, transactions, votes (the commit), 7 | and a list of evidence of malfeasance (ie. signing conflicting votes). 8 | 9 | We include no more than 1/10th of the maximum block size 10 | (`ConsensusParams.Block.MaxBytes`) of evidence with each block. 11 | 12 | ## Reaping transactions from the mempool 13 | 14 | When we reap transactions from the mempool, we calculate maximum data 15 | size by subtracting maximum header size (`MaxHeaderBytes`), the maximum 16 | amino overhead for a block (`MaxAminoOverheadForBlock`), the size of 17 | the last commit (if present) and evidence (if present). While reaping 18 | we account for amino overhead for each transaction. 19 | 20 | ```go 21 | func MaxDataBytes(maxBytes int64, valsCount, evidenceCount int) int64 { 22 | return maxBytes - 23 | MaxOverheadForBlock - 24 | MaxHeaderBytes - 25 | int64(valsCount)*MaxVoteBytes - 26 | int64(evidenceCount)*MaxEvidenceBytes 27 | } 28 | ``` 29 | 30 | ## Validating transactions in the mempool 31 | 32 | Before we accept a transaction in the mempool, we check if it's size is no more 33 | than {MaxDataSize}. {MaxDataSize} is calculated using the same formula as 34 | above, except we subtract the max number of evidence, {MaxNum} by the maximum size of evidence 35 | 36 | ```go 37 | func MaxDataBytesUnknownEvidence(maxBytes int64, valsCount int) int64 { 38 | return maxBytes - 39 | MaxOverheadForBlock - 40 | MaxHeaderBytes - 41 | (maxNumEvidence * MaxEvidenceBytes) 42 | } 43 | ``` 44 | -------------------------------------------------------------------------------- /spec/consensus/light-client/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | parent: 4 | title: Light Client 5 | order: false 6 | --- 7 | # Tendermint Light Client Protocol 8 | 9 | Deprecated, please see [light-client](../../light-client/README.md). 10 | -------------------------------------------------------------------------------- /spec/consensus/light-client/accountability.md: -------------------------------------------------------------------------------- 1 | # Fork accountability 2 | 3 | Deprecated, please see [light-client/accountability](../../light-client/accountability/README.md). 4 | -------------------------------------------------------------------------------- /spec/consensus/light-client/assets/light-node-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tendermint/spec/9d5734e21479dfc9c308f5630678c800d85a2067/spec/consensus/light-client/assets/light-node-image.png -------------------------------------------------------------------------------- /spec/consensus/light-client/detection.md: -------------------------------------------------------------------------------- 1 | # Detection 2 | 3 | Deprecated, please see [light-client/detection](../../light-client/detection/README.md). 4 | -------------------------------------------------------------------------------- /spec/consensus/light-client/verification.md: -------------------------------------------------------------------------------- 1 | # Core Verification 2 | 3 | Deprecated, please see [light-client/accountability](../../light-client/verification/README.md). 4 | -------------------------------------------------------------------------------- /spec/consensus/proposer-based-timestamp/tla/typedefs.tla: -------------------------------------------------------------------------------- 1 | -------------------- MODULE typedefs --------------------------- 2 | (* 3 | @typeAlias: PROCESS = Str; 4 | @typeAlias: VALUE = Str; 5 | @typeAlias: STEP = Str; 6 | @typeAlias: ROUND = Int; 7 | @typeAlias: ACTION = Str; 8 | @typeAlias: TRACE = Seq(Str); 9 | @typeAlias: TIME = Int; 10 | @typeAlias: PROPOSAL = <>; 11 | @typeAlias: DECISION = <>; 12 | @typeAlias: RCVPROP = <>; 13 | @typeAlias: PROPMESSAGE = 14 | [ 15 | type: STEP, 16 | src: PROCESS, 17 | round: ROUND, 18 | proposal: PROPOSAL, 19 | validRound: ROUND 20 | ]; 21 | @typeAlias: PREMESSAGE = 22 | [ 23 | type: STEP, 24 | src: PROCESS, 25 | round: ROUND, 26 | id: PROPOSAL 27 | ]; 28 | @typeAlias: MESSAGE = 29 | [ 30 | type: STEP, 31 | src: PROCESS, 32 | round: ROUND, 33 | proposal: PROPOSAL, 34 | validRound: ROUND, 35 | id: PROPOSAL 36 | ]; 37 | *) 38 | TypeAliases == TRUE 39 | 40 | ============================================================================= -------------------------------------------------------------------------------- /spec/consensus/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | parent: 4 | title: Consensus 5 | order: 4 6 | --- 7 | 8 | **THIS REPOSITORY HAS BEEN ARCHIVED. THE TENDERMINT SPECIFICATION IS NOW LOCATED IN THE [TENDERMINT/TENDERMINT](https://github.com/tendermint/tendermint/tree/master/spec) REPOSITORY.** 9 | 10 | --- 11 | 12 | # Consensus 13 | 14 | Specification of the Tendermint consensus protocol. 15 | 16 | ## Contents 17 | 18 | - [Consensus Paper](./consensus-paper) - Latex paper on 19 | [arxiv](https://arxiv.org/abs/1807.04938) describing the 20 | core Tendermint consensus state machine with proofs of safety and termination. 21 | - [BFT Time](./bft-time.md) - How the timestamp in a Tendermint 22 | block header is computed in a Byzantine Fault Tolerant manner 23 | - [Creating Proposal](./creating-proposal.md) - How a proposer 24 | creates a block proposal for consensus 25 | - [Light Client Protocol](./light-client) - A protocol for light weight consensus 26 | verification and syncing to the latest state 27 | - [Signing](./signing.md) - Rules for cryptographic signatures 28 | produced by validators. 29 | - [Write Ahead Log](./wal.md) - Write ahead log used by the 30 | consensus state machine to recover from crashes. 31 | 32 | The protocol used to gossip consensus messages between peers, which is critical 33 | for liveness, is described in the [reactors section](./consensus.md). 34 | 35 | There is also a [stale markdown description](consensus.md) of the consensus state machine 36 | (TODO update this). 37 | -------------------------------------------------------------------------------- /spec/consensus/wal.md: -------------------------------------------------------------------------------- 1 | # WAL 2 | 3 | Consensus module writes every message to the WAL (write-ahead log). 4 | 5 | It also issues fsync syscall through 6 | [File#Sync](https://golang.org/pkg/os/#File.Sync) for messages signed by this 7 | node (to prevent double signing). 8 | 9 | Under the hood, it uses 10 | [autofile.Group](https://godoc.org/github.com/tendermint/tmlibs/autofile#Group), 11 | which rotates files when those get too big (> 10MB). 12 | 13 | The total maximum size is 1GB. We only need the latest block and the block before it, 14 | but if the former is dragging on across many rounds, we want all those rounds. 15 | 16 | ## Replay 17 | 18 | Consensus module will replay all the messages of the last height written to WAL 19 | before a crash (if such occurs). 20 | 21 | The private validator may try to sign messages during replay because it runs 22 | somewhat autonomously and does not know about replay process. 23 | 24 | For example, if we got all the way to precommit in the WAL and then crash, 25 | after we replay the proposal message, the private validator will try to sign a 26 | prevote. But it will fail. That's ok because we’ll see the prevote later in the 27 | WAL. Then it will go to precommit, and that time it will work because the 28 | private validator contains the `LastSignBytes` and then we’ll replay the 29 | precommit from the WAL. 30 | 31 | Make sure to read about [WAL corruption](https://github.com/tendermint/tendermint/blob/master/docs/tendermint-core/running-in-production.md#wal-corruption) 32 | and recovery strategies. 33 | -------------------------------------------------------------------------------- /spec/core/genesis.md: -------------------------------------------------------------------------------- 1 | # Genesis 2 | 3 | The genesis file is the starting point of a chain. An application will populate the `app_state` field in the genesis with their required fields. Tendermint is not able to validate this section because it is unaware what application state consists of. 4 | 5 | ## Genesis Fields 6 | 7 | - `genesis_time`: The genesis time is the time the blockchain started or will start. If nodes are started before this time they will sit idle until the time specified. 8 | - `chain_id`: The chainid is the chain identifier. Every chain should have a unique identifier. When conducting a fork based upgrade, we recommend changing the chainid to avoid network or consensus errors. 9 | - `initial_height`: This field is the starting height of the blockchain. When conducting a chain restart to avoid restarting at height 1, the network is able to start at a specified height. 10 | - `consensus_params` 11 | - `block` 12 | - `max_bytes`: The max amount of bytes a block can be. 13 | - `max_gas`: The maximum amount of gas that a block can have. 14 | - `time_iota_ms`: This parameter has no value anymore in Tendermint-core. 15 | 16 | - `evidence` 17 | - `max_age_num_blocks`: After this preset amount of blocks has passed a single piece of evidence is considered invalid 18 | - `max_age_duration`: After this preset amount of time has passed a single piece of evidence is considered invalid. 19 | - `max_bytes`: The max amount of bytes of all evidence included in a block. 20 | 21 | > Note: For evidence to be considered invalid, evidence must be older than both `max_age_num_blocks` and `max_age_duration` 22 | 23 | - `validator` 24 | - `pub_key_types`: Defines which curves are to be accepted as a valid validator consensus key. Tendermint supports ed25519, sr25519 and secp256k1. 25 | 26 | - `version` 27 | - `app_version`: The version of the application. This is set by the application and is used to identify which version of the app a user should be using in order to operate a node. 28 | 29 | - `validators` 30 | - This is an array of validators. This validator set is used as the starting validator set of the chain. This field can be empty, if the application sets the validator set in `InitChain`. 31 | 32 | - `app_hash`: The applications state root hash. This field does not need to be populated at the start of the chain, the application may provide the needed information via `Initchain`. 33 | 34 | - `app_state`: This section is filled in by the application and is unknown to Tendermint. 35 | -------------------------------------------------------------------------------- /spec/core/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | parent: 4 | title: Core 5 | order: 3 6 | --- 7 | 8 | **THIS REPOSITORY HAS BEEN ARCHIVED. THE TENDERMINT SPECIFICATION IS NOW LOCATED IN THE [TENDERMINT/TENDERMINT](https://github.com/tendermint/tendermint/tree/master/spec) REPOSITORY.** 9 | 10 | --- 11 | 12 | This section describes the core types and functionality of the Tendermint protocol implementation. 13 | 14 | - [Core Data Structures](./data_structures.md) 15 | - [Encoding](./encoding.md) 16 | - [Genesis](./genesis.md) 17 | - [State](./state.md) 18 | -------------------------------------------------------------------------------- /spec/core/state.md: -------------------------------------------------------------------------------- 1 | # State 2 | 3 | The state contains information whose cryptographic digest is included in block headers, and thus is 4 | necessary for validating new blocks. For instance, the validators set and the results of 5 | transactions are never included in blocks, but their Merkle roots are: 6 | the state keeps track of them. 7 | 8 | The `State` object itself is an implementation detail, since it is never 9 | included in a block or gossiped over the network, and we never compute 10 | its hash. The persistence or query interface of the `State` object 11 | is an implementation detail and not included in the specification. 12 | However, the types in the `State` object are part of the specification, since 13 | the Merkle roots of the `State` objects are included in blocks and values are used during 14 | validation. 15 | 16 | ```go 17 | type State struct { 18 | ChainID string 19 | InitialHeight int64 20 | 21 | LastBlockHeight int64 22 | LastBlockID types.BlockID 23 | LastBlockTime time.Time 24 | 25 | Version Version 26 | LastResults []Result 27 | AppHash []byte 28 | 29 | LastValidators ValidatorSet 30 | Validators ValidatorSet 31 | NextValidators ValidatorSet 32 | 33 | ConsensusParams ConsensusParams 34 | } 35 | ``` 36 | 37 | The chain ID and initial height are taken from the genesis file, and not changed again. The 38 | initial height will be `1` in the typical case, `0` is an invalid value. 39 | 40 | Note there is a hard-coded limit of 10000 validators. This is inherited from the 41 | limit on the number of votes in a commit. 42 | 43 | Further information on [`Validator`'s](./data_structures.md#validator), 44 | [`ValidatorSet`'s](./data_structures.md#validatorset) and 45 | [`ConsensusParams`'s](./data_structures.md#consensusparams) can 46 | be found in [data structures](./data_structures.md) 47 | 48 | ## Execution 49 | 50 | State gets updated at the end of executing a block. Of specific interest is `ResponseEndBlock` and 51 | `ResponseCommit` 52 | 53 | ```go 54 | type ResponseEndBlock struct { 55 | ValidatorUpdates []ValidatorUpdate `protobuf:"bytes,1,rep,name=validator_updates,json=validatorUpdates,proto3" json:"validator_updates"` 56 | ConsensusParamUpdates *types1.ConsensusParams `protobuf:"bytes,2,opt,name=consensus_param_updates,json=consensusParamUpdates,proto3" json:"consensus_param_updates,omitempty"` 57 | Events []Event `protobuf:"bytes,3,rep,name=events,proto3" json:"events,omitempty"` 58 | } 59 | ``` 60 | 61 | where 62 | 63 | ```go 64 | type ValidatorUpdate struct { 65 | PubKey crypto.PublicKey `protobuf:"bytes,1,opt,name=pub_key,json=pubKey,proto3" json:"pub_key"` 66 | Power int64 `protobuf:"varint,2,opt,name=power,proto3" json:"power,omitempty"` 67 | } 68 | ``` 69 | 70 | and 71 | 72 | ```go 73 | type ResponseCommit struct { 74 | // reserve 1 75 | Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` 76 | RetainHeight int64 `protobuf:"varint,3,opt,name=retain_height,json=retainHeight,proto3" json:"retain_height,omitempty"` 77 | } 78 | ``` 79 | 80 | `ValidatorUpdates` are used to add and remove validators to the current set as well as update 81 | validator power. Setting validator power to 0 in `ValidatorUpdate` will cause the validator to be 82 | removed. `ConsensusParams` are safely copied across (i.e. if a field is nil it gets ignored) and the 83 | `Data` from the `ResponseCommit` is used as the `AppHash` 84 | 85 | ## Version 86 | 87 | ```go 88 | type Version struct { 89 | consensus Consensus 90 | software string 91 | } 92 | ``` 93 | 94 | [`Consensus`](./data_structures.md#version) contains the protocol version for the blockchain and the 95 | application. 96 | 97 | ## Block 98 | 99 | The total size of a block is limited in bytes by the `ConsensusParams.Block.MaxBytes`. 100 | Proposed blocks must be less than this size, and will be considered invalid 101 | otherwise. 102 | 103 | Blocks should additionally be limited by the amount of "gas" consumed by the 104 | transactions in the block, though this is not yet implemented. 105 | 106 | ## Evidence 107 | 108 | For evidence in a block to be valid, it must satisfy: 109 | 110 | ```go 111 | block.Header.Time-evidence.Time < ConsensusParams.Evidence.MaxAgeDuration && 112 | block.Header.Height-evidence.Height < ConsensusParams.Evidence.MaxAgeNumBlocks 113 | ``` 114 | 115 | A block must not contain more than `ConsensusParams.Evidence.MaxBytes` of evidence. This is 116 | implemented to mitigate spam attacks. 117 | 118 | ## Validator 119 | 120 | Validators from genesis file and `ResponseEndBlock` must have pubkeys of type ∈ 121 | `ConsensusParams.Validator.PubKeyTypes`. 122 | -------------------------------------------------------------------------------- /spec/light-client/accountability/001indinv-apalache.csv: -------------------------------------------------------------------------------- 1 | no,filename,tool,timeout,init,inv,next,args 2 | 1,MC_n4_f1.tla,apalache,10h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit 3 | 2,MC_n4_f2.tla,apalache,10h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit 4 | 3,MC_n5_f1.tla,apalache,10h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit 5 | 4,MC_n5_f2.tla,apalache,10h,TypedInv,TypedInv,,--length=1 --cinit=ConstInit 6 | 5,MC_n4_f1.tla,apalache,20h,Init,TypedInv,,--length=0 --cinit=ConstInit 7 | 6,MC_n4_f2.tla,apalache,20h,Init,TypedInv,,--length=0 --cinit=ConstInit 8 | 7,MC_n5_f1.tla,apalache,20h,Init,TypedInv,,--length=0 --cinit=ConstInit 9 | 8,MC_n5_f2.tla,apalache,20h,Init,TypedInv,,--length=0 --cinit=ConstInit 10 | 9,MC_n4_f1.tla,apalache,20h,TypedInv,Agreement,,--length=0 --cinit=ConstInit 11 | 10,MC_n4_f2.tla,apalache,20h,TypedInv,Accountability,,--length=0 --cinit=ConstInit 12 | 11,MC_n5_f1.tla,apalache,20h,TypedInv,Agreement,,--length=0 --cinit=ConstInit 13 | 12,MC_n5_f2.tla,apalache,20h,TypedInv,Accountability,,--length=0 --cinit=ConstInit 14 | -------------------------------------------------------------------------------- /spec/light-client/accountability/MC_n4_f1.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE MC_n4_f1 ------------------------------- 2 | CONSTANT 3 | \* @type: ROUND -> PROCESS; 4 | Proposer 5 | 6 | \* the variables declared in TendermintAcc3 7 | VARIABLES 8 | \* @type: PROCESS -> ROUND; 9 | round, 10 | \* @type: PROCESS -> STEP; 11 | step, 12 | \* @type: PROCESS -> VALUE; 13 | decision, 14 | \* @type: PROCESS -> VALUE; 15 | lockedValue, 16 | \* @type: PROCESS -> ROUND; 17 | lockedRound, 18 | \* @type: PROCESS -> VALUE; 19 | validValue, 20 | \* @type: PROCESS -> ROUND; 21 | validRound, 22 | \* @type: ROUND -> Set(PROPMESSAGE); 23 | msgsPropose, 24 | \* @type: ROUND -> Set(PREMESSAGE); 25 | msgsPrevote, 26 | \* @type: ROUND -> Set(PREMESSAGE); 27 | msgsPrecommit, 28 | \* @type: Set(MESSAGE); 29 | evidence, 30 | \* @type: ACTION; 31 | action 32 | 33 | INSTANCE TendermintAccDebug_004_draft WITH 34 | Corr <- {"c1", "c2", "c3"}, 35 | Faulty <- {"f1"}, 36 | N <- 4, 37 | T <- 1, 38 | ValidValues <- { "v0", "v1" }, 39 | InvalidValues <- {"v2"}, 40 | MaxRound <- 2 41 | 42 | \* run Apalache with --cinit=ConstInit 43 | ConstInit == \* the proposer is arbitrary -- works for safety 44 | Proposer \in [Rounds -> AllProcs] 45 | 46 | ============================================================================= 47 | -------------------------------------------------------------------------------- /spec/light-client/accountability/MC_n4_f2.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE MC_n4_f2 ------------------------------- 2 | CONSTANT 3 | \* @type: ROUND -> PROCESS; 4 | Proposer 5 | 6 | \* the variables declared in TendermintAcc3 7 | VARIABLES 8 | \* @type: PROCESS -> ROUND; 9 | round, 10 | \* @type: PROCESS -> STEP; 11 | step, 12 | \* @type: PROCESS -> VALUE; 13 | decision, 14 | \* @type: PROCESS -> VALUE; 15 | lockedValue, 16 | \* @type: PROCESS -> ROUND; 17 | lockedRound, 18 | \* @type: PROCESS -> VALUE; 19 | validValue, 20 | \* @type: PROCESS -> ROUND; 21 | validRound, 22 | \* @type: ROUND -> Set(PROPMESSAGE); 23 | msgsPropose, 24 | \* @type: ROUND -> Set(PREMESSAGE); 25 | msgsPrevote, 26 | \* @type: ROUND -> Set(PREMESSAGE); 27 | msgsPrecommit, 28 | \* @type: Set(MESSAGE); 29 | evidence, 30 | \* @type: ACTION; 31 | action 32 | 33 | INSTANCE TendermintAccDebug_004_draft WITH 34 | Corr <- {"c1", "c2"}, 35 | Faulty <- {"f3", "f4"}, 36 | N <- 4, 37 | T <- 1, 38 | ValidValues <- { "v0", "v1" }, 39 | InvalidValues <- {"v2"}, 40 | MaxRound <- 2 41 | 42 | \* run Apalache with --cinit=ConstInit 43 | ConstInit == \* the proposer is arbitrary -- works for safety 44 | Proposer \in [Rounds -> AllProcs] 45 | 46 | ============================================================================= 47 | -------------------------------------------------------------------------------- /spec/light-client/accountability/MC_n4_f2_amnesia.tla: -------------------------------------------------------------------------------- 1 | ---------------------- MODULE MC_n4_f2_amnesia ------------------------------- 2 | EXTENDS Sequences 3 | 4 | CONSTANT 5 | \* @type: ROUND -> PROCESS; 6 | Proposer 7 | 8 | \* the variables declared in TendermintAcc3 9 | VARIABLES 10 | \* @type: PROCESS -> ROUND; 11 | round, 12 | \* @type: PROCESS -> STEP; 13 | step, 14 | \* @type: PROCESS -> VALUE; 15 | decision, 16 | \* @type: PROCESS -> VALUE; 17 | lockedValue, 18 | \* @type: PROCESS -> ROUND; 19 | lockedRound, 20 | \* @type: PROCESS -> VALUE; 21 | validValue, 22 | \* @type: PROCESS -> ROUND; 23 | validRound, 24 | \* @type: ROUND -> Set(PROPMESSAGE); 25 | msgsPropose, 26 | \* @type: ROUND -> Set(PREMESSAGE); 27 | msgsPrevote, 28 | \* @type: ROUND -> Set(PREMESSAGE); 29 | msgsPrecommit, 30 | \* @type: Set(MESSAGE); 31 | evidence, 32 | \* @type: ACTION; 33 | action 34 | 35 | \* the variable declared in TendermintAccTrace3 36 | VARIABLE 37 | \* @type: TRACE; 38 | toReplay 39 | 40 | INSTANCE TendermintAccTrace_004_draft WITH 41 | Corr <- {"c1", "c2"}, 42 | Faulty <- {"f3", "f4"}, 43 | N <- 4, 44 | T <- 1, 45 | ValidValues <- { "v0", "v1" }, 46 | InvalidValues <- {"v2"}, 47 | MaxRound <- 2, 48 | Trace <- << 49 | "UponProposalInPropose", 50 | "UponProposalInPrevoteOrCommitAndPrevote", 51 | "UponProposalInPrecommitNoDecision", 52 | "OnRoundCatchup", 53 | "UponProposalInPropose", 54 | "UponProposalInPrevoteOrCommitAndPrevote", 55 | "UponProposalInPrecommitNoDecision" 56 | >> 57 | 58 | \* run Apalache with --cinit=ConstInit 59 | ConstInit == \* the proposer is arbitrary -- works for safety 60 | Proposer \in [Rounds -> AllProcs] 61 | 62 | ============================================================================= 63 | -------------------------------------------------------------------------------- /spec/light-client/accountability/MC_n4_f3.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE MC_n4_f3 ------------------------------- 2 | CONSTANT 3 | \* @type: ROUND -> PROCESS; 4 | Proposer 5 | 6 | \* the variables declared in TendermintAcc3 7 | VARIABLES 8 | \* @type: PROCESS -> ROUND; 9 | round, 10 | \* @type: PROCESS -> STEP; 11 | step, 12 | \* @type: PROCESS -> VALUE; 13 | decision, 14 | \* @type: PROCESS -> VALUE; 15 | lockedValue, 16 | \* @type: PROCESS -> ROUND; 17 | lockedRound, 18 | \* @type: PROCESS -> VALUE; 19 | validValue, 20 | \* @type: PROCESS -> ROUND; 21 | validRound, 22 | \* @type: ROUND -> Set(PROPMESSAGE); 23 | msgsPropose, 24 | \* @type: ROUND -> Set(PREMESSAGE); 25 | msgsPrevote, 26 | \* @type: ROUND -> Set(PREMESSAGE); 27 | msgsPrecommit, 28 | \* @type: Set(MESSAGE); 29 | evidence, 30 | \* @type: ACTION; 31 | action 32 | 33 | INSTANCE TendermintAccDebug_004_draft WITH 34 | Corr <- {"c1"}, 35 | Faulty <- {"f2", "f3", "f4"}, 36 | N <- 4, 37 | T <- 1, 38 | ValidValues <- { "v0", "v1" }, 39 | InvalidValues <- {"v2"}, 40 | MaxRound <- 2 41 | 42 | \* run Apalache with --cinit=ConstInit 43 | ConstInit == \* the proposer is arbitrary -- works for safety 44 | Proposer \in [Rounds -> AllProcs] 45 | 46 | ============================================================================= 47 | -------------------------------------------------------------------------------- /spec/light-client/accountability/MC_n5_f1.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE MC_n5_f1 ------------------------------- 2 | CONSTANT 3 | \* @type: ROUND -> PROCESS; 4 | Proposer 5 | 6 | \* the variables declared in TendermintAcc3 7 | VARIABLES 8 | \* @type: PROCESS -> ROUND; 9 | round, 10 | \* @type: PROCESS -> STEP; 11 | step, 12 | \* @type: PROCESS -> VALUE; 13 | decision, 14 | \* @type: PROCESS -> VALUE; 15 | lockedValue, 16 | \* @type: PROCESS -> ROUND; 17 | lockedRound, 18 | \* @type: PROCESS -> VALUE; 19 | validValue, 20 | \* @type: PROCESS -> ROUND; 21 | validRound, 22 | \* @type: ROUND -> Set(PROPMESSAGE); 23 | msgsPropose, 24 | \* @type: ROUND -> Set(PREMESSAGE); 25 | msgsPrevote, 26 | \* @type: ROUND -> Set(PREMESSAGE); 27 | msgsPrecommit, 28 | \* @type: Set(MESSAGE); 29 | evidence, 30 | \* @type: ACTION; 31 | action 32 | 33 | INSTANCE TendermintAccDebug_004_draft WITH 34 | Corr <- {"c1", "c2", "c3", "c4"}, 35 | Faulty <- {"f5"}, 36 | N <- 5, 37 | T <- 1, 38 | ValidValues <- { "v0", "v1" }, 39 | InvalidValues <- {"v2"}, 40 | MaxRound <- 2 41 | 42 | \* run Apalache with --cinit=ConstInit 43 | ConstInit == \* the proposer is arbitrary -- works for safety 44 | Proposer \in [Rounds -> AllProcs] 45 | 46 | ============================================================================= 47 | -------------------------------------------------------------------------------- /spec/light-client/accountability/MC_n5_f2.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE MC_n5_f2 ------------------------------- 2 | CONSTANT 3 | \* @type: ROUND -> PROCESS; 4 | Proposer 5 | 6 | \* the variables declared in TendermintAcc3 7 | VARIABLES 8 | \* @type: PROCESS -> ROUND; 9 | round, 10 | \* @type: PROCESS -> STEP; 11 | step, 12 | \* @type: PROCESS -> VALUE; 13 | decision, 14 | \* @type: PROCESS -> VALUE; 15 | lockedValue, 16 | \* @type: PROCESS -> ROUND; 17 | lockedRound, 18 | \* @type: PROCESS -> VALUE; 19 | validValue, 20 | \* @type: PROCESS -> ROUND; 21 | validRound, 22 | \* @type: ROUND -> Set(PROPMESSAGE); 23 | msgsPropose, 24 | \* @type: ROUND -> Set(PREMESSAGE); 25 | msgsPrevote, 26 | \* @type: ROUND -> Set(PREMESSAGE); 27 | msgsPrecommit, 28 | \* @type: Set(MESSAGE); 29 | evidence, 30 | \* @type: ACTION; 31 | action 32 | 33 | INSTANCE TendermintAccDebug_004_draft WITH 34 | Corr <- {"c1", "c2", "c3"}, 35 | Faulty <- {"f4", "f5"}, 36 | N <- 5, 37 | T <- 1, 38 | ValidValues <- { "v0", "v1" }, 39 | InvalidValues <- {"v2"}, 40 | MaxRound <- 2 41 | 42 | \* run Apalache with --cinit=ConstInit 43 | ConstInit == \* the proposer is arbitrary -- works for safety 44 | Proposer \in [Rounds -> AllProcs] 45 | 46 | ============================================================================= 47 | -------------------------------------------------------------------------------- /spec/light-client/accountability/MC_n6_f1.tla: -------------------------------------------------------------------------------- 1 | ----------------------------- MODULE MC_n6_f1 ------------------------------- 2 | CONSTANT 3 | \* @type: ROUND -> PROCESS; 4 | Proposer 5 | 6 | \* the variables declared in TendermintAcc3 7 | VARIABLES 8 | \* @type: PROCESS -> ROUND; 9 | round, 10 | \* @type: PROCESS -> STEP; 11 | step, 12 | \* @type: PROCESS -> VALUE; 13 | decision, 14 | \* @type: PROCESS -> VALUE; 15 | lockedValue, 16 | \* @type: PROCESS -> ROUND; 17 | lockedRound, 18 | \* @type: PROCESS -> VALUE; 19 | validValue, 20 | \* @type: PROCESS -> ROUND; 21 | validRound, 22 | \* @type: ROUND -> Set(PROPMESSAGE); 23 | msgsPropose, 24 | \* @type: ROUND -> Set(PREMESSAGE); 25 | msgsPrevote, 26 | \* @type: ROUND -> Set(PREMESSAGE); 27 | msgsPrecommit, 28 | \* @type: Set(MESSAGE); 29 | evidence, 30 | \* @type: ACTION; 31 | action 32 | 33 | INSTANCE TendermintAccDebug_004_draft WITH 34 | Corr <- {"c1", "c2", "c3", "c4", "c5"}, 35 | Faulty <- {"f6"}, 36 | N <- 4, 37 | T <- 1, 38 | ValidValues <- { "v0", "v1" }, 39 | InvalidValues <- {"v2"}, 40 | MaxRound <- 2 41 | 42 | \* run Apalache with --cinit=ConstInit 43 | ConstInit == \* the proposer is arbitrary -- works for safety 44 | Proposer \in [Rounds -> AllProcs] 45 | 46 | ============================================================================= 47 | -------------------------------------------------------------------------------- /spec/light-client/accountability/Synopsis.md: -------------------------------------------------------------------------------- 1 | 2 | # Synopsis 3 | 4 | A TLA+ specification of a simplified Tendermint consensus, tuned for 5 | fork accountability. The simplifications are as follows: 6 | 7 | - the procotol runs for one height, that is, one-shot consensus 8 | 9 | - this specification focuses on safety, so timeouts are modelled with 10 | with non-determinism 11 | 12 | - the proposer function is non-determinstic, no fairness is assumed 13 | 14 | - the messages by the faulty processes are injected right in the initial states 15 | 16 | - every process has the voting power of 1 17 | 18 | - hashes are modelled as identity 19 | 20 | Having the above assumptions in mind, the specification follows the pseudo-code 21 | of the Tendermint paper: 22 | 23 | Byzantine processes can demonstrate arbitrary behavior, including 24 | no communication. However, we have to show that under the collective evidence 25 | collected by the correct processes, at least `f+1` Byzantine processes demonstrate 26 | one of the following behaviors: 27 | 28 | - Equivocation: a Byzantine process sends two different values 29 | in the same round. 30 | 31 | - Amnesia: a Byzantine process locks a value, although it has locked 32 | another value in the past. 33 | 34 | # TLA+ modules 35 | 36 | - [TendermintAcc_004_draft](TendermintAcc_004_draft.tla) is the protocol 37 | specification, 38 | 39 | - [TendermintAccInv_004_draft](TendermintAccInv_004_draft.tla) contains an 40 | inductive invariant for establishing the protocol safety as well as the 41 | forking cases, 42 | 43 | - `MC_n_f`, e.g., [MC_n4_f1](MC_n4_f1.tla), contains fixed constants for 44 | model checking with the [Apalache model 45 | checker](https://github.com/informalsystems/apalache), 46 | 47 | - [TendermintAccTrace_004_draft](TendermintAccTrace_004_draft.tla) shows how 48 | to restrict the execution space to a fixed sequence of actions (e.g., to 49 | instantiate a counterexample), 50 | 51 | - [TendermintAccDebug_004_draft](TendermintAccDebug_004_draft.tla) contains 52 | the useful definitions for debugging the protocol specification with TLC and 53 | Apalache. 54 | 55 | # Reasoning about fork scenarios 56 | 57 | The theorem statements can be found in 58 | [TendermintAccInv_004_draft.tla](TendermintAccInv_004_draft.tla). 59 | 60 | First, we would like to show that `TypedInv` is an inductive invariant. 61 | Formally, the statement looks as follows: 62 | 63 | ```tla 64 | THEOREM TypedInvIsInductive == 65 | \/ FaultyQuorum 66 | \//\ Init => TypedInv 67 | /\ TypedInv /\ [Next]_vars => TypedInv' 68 | ``` 69 | 70 | When over two-thirds of processes are faulty, `TypedInv` is not inductive. 71 | However, there is no hope to repair the protocol in this case. We run 72 | [Apalache](https://github.com/informalsystems/apalache) to prove this theorem 73 | only for fixed instances of 4 to 5 validators. Apalache does not parse theorem 74 | statements at the moment, so we ran Apalache using a shell script. To find a 75 | parameterized argument, one has to use a theorem prover, e.g., TLAPS. 76 | 77 | Second, we would like to show that the invariant implies `Agreement`, that is, 78 | no fork, provided that less than one third of processes is faulty. By combining 79 | this theorem with the previous theorem, we conclude that the protocol indeed 80 | satisfies Agreement under the condition `LessThanThirdFaulty`. 81 | 82 | ```tla 83 | THEOREM AgreementWhenLessThanThirdFaulty == 84 | LessThanThirdFaulty /\ TypedInv => Agreement 85 | ``` 86 | 87 | Third, in the general case, we either have no fork, or two fork scenarios: 88 | 89 | ```tla 90 | THEOREM AgreementOrFork == 91 | ~FaultyQuorum /\ TypedInv => Accountability 92 | ``` 93 | 94 | # Model checking results 95 | 96 | Check the report on [model checking with Apalache](./results/001indinv-apalache-report.md). 97 | 98 | To run the model checking experiments, use the script: 99 | 100 | ```console 101 | ./run.sh 102 | ``` 103 | 104 | This script assumes that the apalache build is available in 105 | `~/devl/apalache-unstable`. 106 | -------------------------------------------------------------------------------- /spec/light-client/accountability/TendermintAccDebug_004_draft.tla: -------------------------------------------------------------------------------- 1 | ------------------ MODULE TendermintAccDebug_004_draft ------------------------- 2 | (* 3 | A few definitions that we use for debugging TendermintAcc3, which do not belong 4 | to the specification itself. 5 | 6 | * Version 3. Modular and parameterized definitions. 7 | 8 | Igor Konnov, 2020. 9 | *) 10 | 11 | EXTENDS TendermintAccInv_004_draft 12 | 13 | \* make them parameters? 14 | NFaultyProposals == 0 \* the number of injected faulty PROPOSE messages 15 | NFaultyPrevotes == 6 \* the number of injected faulty PREVOTE messages 16 | NFaultyPrecommits == 6 \* the number of injected faulty PRECOMMIT messages 17 | 18 | \* Given a set of allowed messages Msgs, this operator produces a function from 19 | \* rounds to sets of messages. 20 | \* Importantly, there will be exactly k messages in the image of msgFun. 21 | \* We use this action to produce k faults in an initial state. 22 | \* @type: (ROUND -> Set(MESSAGE), Set(MESSAGE), Int) => Bool; 23 | ProduceFaults(msgFun, From, k) == 24 | \E f \in [1..k -> From]: 25 | msgFun = [r \in Rounds |-> {m \in {f[i]: i \in 1..k}: m.round = r}] 26 | 27 | \* As TLC explodes with faults, we may have initial states without faults 28 | InitNoFaults == 29 | /\ round = [p \in Corr |-> 0] 30 | /\ step = [p \in Corr |-> "PROPOSE"] 31 | /\ decision = [p \in Corr |-> NilValue] 32 | /\ lockedValue = [p \in Corr |-> NilValue] 33 | /\ lockedRound = [p \in Corr |-> NilRound] 34 | /\ validValue = [p \in Corr |-> NilValue] 35 | /\ validRound = [p \in Corr |-> NilRound] 36 | /\ msgsPropose = [r \in Rounds |-> EmptyMsgSet] 37 | /\ msgsPrevote = [r \in Rounds |-> EmptyMsgSet] 38 | /\ msgsPrecommit = [r \in Rounds |-> EmptyMsgSet] 39 | /\ evidence = EmptyMsgSet 40 | 41 | (* 42 | A specialized version of Init that injects NFaultyProposals proposals, 43 | NFaultyPrevotes prevotes, NFaultyPrecommits precommits by the faulty processes 44 | *) 45 | InitFewFaults == 46 | /\ round = [p \in Corr |-> 0] 47 | /\ step = [p \in Corr |-> "PROPOSE"] 48 | /\ decision = [p \in Corr |-> NilValue] 49 | /\ lockedValue = [p \in Corr |-> NilValue] 50 | /\ lockedRound = [p \in Corr |-> NilRound] 51 | /\ validValue = [p \in Corr |-> NilValue] 52 | /\ validRound = [p \in Corr |-> NilRound] 53 | /\ ProduceFaults(msgsPrevote', 54 | [type: {"PREVOTE"}, src: Faulty, round: Rounds, id: Values], 55 | NFaultyPrevotes) 56 | /\ ProduceFaults(msgsPrecommit', 57 | [type: {"PRECOMMIT"}, src: Faulty, round: Rounds, id: Values], 58 | NFaultyPrecommits) 59 | /\ ProduceFaults(msgsPropose', 60 | [type: {"PROPOSAL"}, src: Faulty, round: Rounds, 61 | proposal: Values, validRound: Rounds \cup {NilRound}], 62 | NFaultyProposals) 63 | /\ evidence = EmptyMsgSet 64 | 65 | \* Add faults incrementally 66 | NextWithFaults == 67 | \* either the protocol makes a step 68 | \/ Next 69 | \* or a faulty process sends a message 70 | \//\ UNCHANGED <> 72 | /\ \E p \in Faulty: 73 | \E r \in Rounds: 74 | \//\ UNCHANGED <> 75 | /\ \E proposal \in ValidValues \union {NilValue}: 76 | \E vr \in RoundsOrNil: 77 | BroadcastProposal(p, r, proposal, vr) 78 | \//\ UNCHANGED <> 79 | /\ \E id \in ValidValues \union {NilValue}: 80 | BroadcastPrevote(p, r, id) 81 | \//\ UNCHANGED <> 82 | /\ \E id \in ValidValues \union {NilValue}: 83 | BroadcastPrecommit(p, r, id) 84 | 85 | (******************************** PROPERTIES ***************************************) 86 | \* simple reachability properties to see that the spec is progressing 87 | NoPrevote == \A p \in Corr: step[p] /= "PREVOTE" 88 | 89 | NoPrecommit == \A p \in Corr: step[p] /= "PRECOMMIT" 90 | 91 | NoValidPrecommit == 92 | \A r \in Rounds: 93 | \A m \in msgsPrecommit[r]: 94 | m.id = NilValue \/ m.src \in Faulty 95 | 96 | NoHigherRounds == \A p \in Corr: round[p] < 1 97 | 98 | NoDecision == \A p \in Corr: decision[p] = NilValue 99 | 100 | ============================================================================= 101 | 102 | -------------------------------------------------------------------------------- /spec/light-client/accountability/TendermintAccTrace_004_draft.tla: -------------------------------------------------------------------------------- 1 | ------------------ MODULE TendermintAccTrace_004_draft ------------------------- 2 | (* 3 | When Apalache is running too slow and we have an idea of a counterexample, 4 | we use this module to restrict the behaviors only to certain actions. 5 | Once the whole trace is replayed, the system deadlocks. 6 | 7 | Version 1. 8 | 9 | Igor Konnov, 2020. 10 | *) 11 | 12 | EXTENDS Sequences, Apalache, TendermintAcc_004_draft 13 | 14 | \* a sequence of action names that should appear in the given order, 15 | \* excluding "Init" 16 | CONSTANT 17 | \* @type: TRACE; 18 | Trace 19 | 20 | VARIABLE 21 | \* @type: TRACE; 22 | toReplay 23 | 24 | TraceInit == 25 | /\ toReplay = Trace 26 | /\ action' := "Init" 27 | /\ Init 28 | 29 | TraceNext == 30 | /\ Len(toReplay) > 0 31 | /\ toReplay' = Tail(toReplay) 32 | \* Here is the trick. We restrict the action to the expected one, 33 | \* so the other actions will be pruned 34 | /\ action' := Head(toReplay) 35 | /\ Next 36 | 37 | ================================================================================ 38 | -------------------------------------------------------------------------------- /spec/light-client/accountability/results/001indinv-apalache-report.md: -------------------------------------------------------------------------------- 1 | # Results of 001indinv-apalache 2 | 3 | ## 1. Awesome plots 4 | 5 | ### 1.1. Time (logarithmic scale) 6 | 7 | ![time-log](001indinv-apalache-time-log.svg "Time Log") 8 | 9 | ### 1.2. Time (linear) 10 | 11 | ![time-log](001indinv-apalache-time.svg "Time Log") 12 | 13 | ### 1.3. Memory (logarithmic scale) 14 | 15 | ![mem-log](001indinv-apalache-mem-log.svg "Memory Log") 16 | 17 | ### 1.4. Memory (linear) 18 | 19 | ![mem](001indinv-apalache-mem.svg "Memory Log") 20 | 21 | ### 1.5. Number of arena cells (linear) 22 | 23 | ![ncells](001indinv-apalache-ncells.svg "Number of arena cells") 24 | 25 | ### 1.6. Number of SMT clauses (linear) 26 | 27 | ![nclauses](001indinv-apalache-nclauses.svg "Number of SMT clauses") 28 | 29 | ## 2. Input parameters 30 | 31 | no | filename | tool | timeout | init | inv | next | args 32 | ----|----------------|------------|-----------|------------|------------------|--------|------------------------------ 33 | 1 | MC_n4_f1.tla | apalache | 10h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit 34 | 2 | MC_n4_f2.tla | apalache | 10h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit 35 | 3 | MC_n5_f1.tla | apalache | 10h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit 36 | 4 | MC_n5_f2.tla | apalache | 10h | TypedInv | TypedInv | | --length=1 --cinit=ConstInit 37 | 5 | MC_n4_f1.tla | apalache | 20h | Init | TypedInv | | --length=0 --cinit=ConstInit 38 | 6 | MC_n4_f2.tla | apalache | 20h | Init | TypedInv | | --length=0 --cinit=ConstInit 39 | 7 | MC_n5_f1.tla | apalache | 20h | Init | TypedInv | | --length=0 --cinit=ConstInit 40 | 8 | MC_n5_f2.tla | apalache | 20h | Init | TypedInv | | --length=0 --cinit=ConstInit 41 | 9 | MC_n4_f1.tla | apalache | 20h | TypedInv | Agreement | | --length=0 --cinit=ConstInit 42 | 10 | MC_n4_f2.tla | apalache | 20h | TypedInv | Accountability | | --length=0 --cinit=ConstInit 43 | 11 | MC_n5_f1.tla | apalache | 20h | TypedInv | Agreement | | --length=0 --cinit=ConstInit 44 | 12 | MC_n5_f2.tla | apalache | 20h | TypedInv | Accountability | | --length=0 --cinit=ConstInit 45 | 46 | ## 3. Detailed results: 001indinv-apalache-unstable.csv 47 | 48 | 01:no | 02:tool | 03:status | 04:time_sec | 05:depth | 05:mem_kb | 10:ninit_trans | 11:ninit_trans | 12:ncells | 13:nclauses | 14:navg_clause_len 49 | -------|------------|-------------|---------------|------------|-------------|------------------|------------------|-------------|---------------|-------------------- 50 | 1 | apalache | NoError | 11m | 1 | 3.0GB | 0 | 0 | 217K | 1.0M | 89 51 | 2 | apalache | NoError | 11m | 1 | 3.0GB | 0 | 0 | 207K | 1.0M | 88 52 | 3 | apalache | NoError | 16m | 1 | 4.0GB | 0 | 0 | 311K | 2.0M | 101 53 | 4 | apalache | NoError | 14m | 1 | 3.0GB | 0 | 0 | 290K | 1.0M | 103 54 | 5 | apalache | NoError | 9s | 0 | 563MB | 0 | 0 | 2.0K | 14K | 42 55 | 6 | apalache | NoError | 10s | 0 | 657MB | 0 | 0 | 2.0K | 28K | 43 56 | 7 | apalache | NoError | 8s | 0 | 635MB | 0 | 0 | 2.0K | 17K | 44 57 | 8 | apalache | NoError | 10s | 0 | 667MB | 0 | 0 | 3.0K | 32K | 45 58 | 9 | apalache | NoError | 5m05s | 0 | 2.0GB | 0 | 0 | 196K | 889K | 108 59 | 10 | apalache | NoError | 8m08s | 0 | 6.0GB | 0 | 0 | 2.0M | 3.0M | 34 60 | 11 | apalache | NoError | 9m09s | 0 | 3.0GB | 0 | 0 | 284K | 1.0M | 128 61 | 12 | apalache | NoError | 14m | 0 | 7.0GB | 0 | 0 | 4.0M | 5.0M | 38 62 | -------------------------------------------------------------------------------- /spec/light-client/accountability/results/001indinv-apalache-unstable.csv: -------------------------------------------------------------------------------- 1 | 01:no,02:tool,03:status,04:time_sec,05:depth,05:mem_kb,10:ninit_trans,11:ninit_trans,12:ncells,13:nclauses,14:navg_clause_len 2 | 1,apalache,NoError,704,1,3215424,0,0,217385,1305718,89 3 | 2,apalache,NoError,699,1,3195020,0,0,207969,1341979,88 4 | 3,apalache,NoError,1018,1,4277060,0,0,311798,2028544,101 5 | 4,apalache,NoError,889,1,4080012,0,0,290989,1951616,103 6 | 5,apalache,NoError,9,0,577100,0,0,2045,14655,42 7 | 6,apalache,NoError,10,0,673772,0,0,2913,28213,43 8 | 7,apalache,NoError,8,0,651008,0,0,2214,17077,44 9 | 8,apalache,NoError,10,0,683188,0,0,3082,32651,45 10 | 9,apalache,NoError,340,0,3053848,0,0,196943,889859,108 11 | 10,apalache,NoError,517,0,6424536,0,0,2856378,3802779,34 12 | 11,apalache,NoError,587,0,4028516,0,0,284369,1343296,128 13 | 12,apalache,NoError,880,0,7881148,0,0,4382556,5778072,38 14 | -------------------------------------------------------------------------------- /spec/light-client/accountability/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # The script to run all experiments at once 4 | 5 | export SCRIPTS_DIR=~/devl/apalache-tests/scripts 6 | export BUILDS="unstable" 7 | export BENCHMARK=001indinv-apalache 8 | export RUN_SCRIPT=./run-all.sh # alternatively, use ./run-parallel.sh 9 | make -e -f ~/devl/apalache-tests/Makefile.common 10 | -------------------------------------------------------------------------------- /spec/light-client/accountability/typedefs.tla: -------------------------------------------------------------------------------- 1 | -------------------- MODULE typedefs --------------------------- 2 | (* 3 | @typeAlias: PROCESS = Str; 4 | @typeAlias: VALUE = Str; 5 | @typeAlias: STEP = Str; 6 | @typeAlias: ROUND = Int; 7 | @typeAlias: ACTION = Str; 8 | @typeAlias: TRACE = Seq(Str); 9 | @typeAlias: PROPMESSAGE = 10 | [ 11 | type: STEP, 12 | src: PROCESS, 13 | round: ROUND, 14 | proposal: VALUE, 15 | validRound: ROUND 16 | ]; 17 | @typeAlias: PREMESSAGE = 18 | [ 19 | type: STEP, 20 | src: PROCESS, 21 | round: ROUND, 22 | id: VALUE 23 | ]; 24 | @typeAlias: MESSAGE = 25 | [ 26 | type: STEP, 27 | src: PROCESS, 28 | round: ROUND, 29 | proposal: VALUE, 30 | validRound: ROUND, 31 | id: VALUE 32 | ]; 33 | *) 34 | TypeAliases == TRUE 35 | 36 | ============================================================================= -------------------------------------------------------------------------------- /spec/light-client/assets/light-node-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tendermint/spec/9d5734e21479dfc9c308f5630678c800d85a2067/spec/light-client/assets/light-node-image.png -------------------------------------------------------------------------------- /spec/light-client/attacks/MC_5_3.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE MC_5_3 ------------------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4", "n5"} 4 | COMMON_HEIGHT == 1 5 | CONFLICT_HEIGHT == 3 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | FAULTY_RATIO == <<1, 2>> \* < 1 / 2 faulty validators 8 | 9 | VARIABLES 10 | blockchain, \* the reference blockchain 11 | refClock, \* current time in the reference blockchain 12 | Faulty, \* the set of faulty validators 13 | state, \* the state of the light client detector 14 | conflictingBlock, \* an evidence that two peers reported conflicting blocks 15 | attackers 16 | 17 | INSTANCE Isolation_001_draft 18 | ============================================================================ 19 | -------------------------------------------------------------------------------- /spec/light-client/detection/004bmc-apalache-ok.csv: -------------------------------------------------------------------------------- 1 | no;filename;tool;timeout;init;inv;next;args 2 | 1;LCD_MC3_3_faulty.tla;apalache;1h;;CommonHeightOnEvidenceInv;;--length=10 3 | 2;LCD_MC3_3_faulty.tla;apalache;1h;;AccuracyInv;;--length=10 4 | 3;LCD_MC3_3_faulty.tla;apalache;1h;;PrecisionInvLocal;;--length=10 5 | 4;LCD_MC3_4_faulty.tla;apalache;1h;;CommonHeightOnEvidenceInv;;--length=10 6 | 5;LCD_MC3_4_faulty.tla;apalache;1h;;AccuracyInv;;--length=10 7 | 6;LCD_MC3_4_faulty.tla;apalache;1h;;PrecisionInvLocal;;--length=10 8 | 7;LCD_MC4_4_faulty.tla;apalache;1h;;CommonHeightOnEvidenceInv;;--length=10 9 | 8;LCD_MC4_4_faulty.tla;apalache;1h;;AccuracyInv;;--length=10 10 | 9;LCD_MC4_4_faulty.tla;apalache;1h;;PrecisionInvLocal;;--length=10 11 | -------------------------------------------------------------------------------- /spec/light-client/detection/005bmc-apalache-error.csv: -------------------------------------------------------------------------------- 1 | no;filename;tool;timeout;init;inv;next;args 2 | 1;LCD_MC3_3_faulty.tla;apalache;1h;;PrecisionInvGrayZone;;--length=10 3 | 2;LCD_MC3_4_faulty.tla;apalache;1h;;PrecisionInvGrayZone;;--length=10 4 | 3;LCD_MC4_4_faulty.tla;apalache;1h;;PrecisionInvGrayZone;;--length=10 5 | -------------------------------------------------------------------------------- /spec/light-client/detection/LCD_MC3_3_faulty.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE LCD_MC3_3_faulty --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 3 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == FALSE 10 | IS_SECONDARY_CORRECT == TRUE 11 | FAULTY_RATIO == <<2, 3>> \* < 1 / 3 faulty validators 12 | 13 | VARIABLES 14 | blockchain, (* the reference blockchain *) 15 | localClock, (* current time in the light client *) 16 | refClock, (* current time in the reference blockchain *) 17 | Faulty, (* the set of faulty validators *) 18 | state, (* the state of the light client detector *) 19 | fetchedLightBlocks1, (* a function from heights to LightBlocks *) 20 | fetchedLightBlocks2, (* a function from heights to LightBlocks *) 21 | fetchedLightBlocks1b, (* a function from heights to LightBlocks *) 22 | commonHeight, (* the height that is trusted in CreateEvidenceForPeer *) 23 | nextHeightToTry, (* the index in CreateEvidenceForPeer *) 24 | evidences 25 | 26 | INSTANCE LCDetector_003_draft 27 | ============================================================================ 28 | -------------------------------------------------------------------------------- /spec/light-client/detection/LCD_MC3_4_faulty.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE LCD_MC3_4_faulty --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 4 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == FALSE 10 | IS_SECONDARY_CORRECT == TRUE 11 | FAULTY_RATIO == <<2, 3>> \* < 1 / 3 faulty validators 12 | 13 | VARIABLES 14 | blockchain, (* the reference blockchain *) 15 | localClock, (* current time in the light client *) 16 | refClock, (* current time in the reference blockchain *) 17 | Faulty, (* the set of faulty validators *) 18 | state, (* the state of the light client detector *) 19 | fetchedLightBlocks1, (* a function from heights to LightBlocks *) 20 | fetchedLightBlocks2, (* a function from heights to LightBlocks *) 21 | fetchedLightBlocks1b, (* a function from heights to LightBlocks *) 22 | commonHeight, (* the height that is trusted in CreateEvidenceForPeer *) 23 | nextHeightToTry, (* the index in CreateEvidenceForPeer *) 24 | evidences 25 | 26 | INSTANCE LCDetector_003_draft 27 | ============================================================================ 28 | -------------------------------------------------------------------------------- /spec/light-client/detection/LCD_MC4_4_faulty.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE LCD_MC4_4_faulty --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 4 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == FALSE 10 | IS_SECONDARY_CORRECT == TRUE 11 | FAULTY_RATIO == <<2, 3>> \* < 2 / 3 faulty validators 12 | 13 | VARIABLES 14 | blockchain, (* the reference blockchain *) 15 | localClock, (* current time in the light client *) 16 | refClock, (* current time in the reference blockchain *) 17 | Faulty, (* the set of faulty validators *) 18 | state, (* the state of the light client detector *) 19 | fetchedLightBlocks1, (* a function from heights to LightBlocks *) 20 | fetchedLightBlocks2, (* a function from heights to LightBlocks *) 21 | fetchedLightBlocks1b, (* a function from heights to LightBlocks *) 22 | commonHeight, (* the height that is trusted in CreateEvidenceForPeer *) 23 | nextHeightToTry, (* the index in CreateEvidenceForPeer *) 24 | evidences 25 | 26 | INSTANCE LCDetector_003_draft 27 | ============================================================================ 28 | -------------------------------------------------------------------------------- /spec/light-client/detection/LCD_MC5_5_faulty.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE LCD_MC5_5_faulty --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4", "n5"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 5 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == FALSE 10 | IS_SECONDARY_CORRECT == TRUE 11 | FAULTY_RATIO == <<2, 3>> \* < 1 / 3 faulty validators 12 | 13 | VARIABLES 14 | blockchain, (* the reference blockchain *) 15 | localClock, (* current time in the light client *) 16 | refClock, (* current time in the reference blockchain *) 17 | Faulty, (* the set of faulty validators *) 18 | state, (* the state of the light client detector *) 19 | fetchedLightBlocks1, (* a function from heights to LightBlocks *) 20 | fetchedLightBlocks2, (* a function from heights to LightBlocks *) 21 | fetchedLightBlocks1b, (* a function from heights to LightBlocks *) 22 | commonHeight, (* the height that is trusted in CreateEvidenceForPeer *) 23 | nextHeightToTry, (* the index in CreateEvidenceForPeer *) 24 | evidences 25 | 26 | INSTANCE LCDetector_003_draft 27 | ============================================================================ 28 | -------------------------------------------------------------------------------- /spec/light-client/detection/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | parent: 4 | title: Fork Detection 5 | order: 2 6 | --- 7 | 8 | **THIS REPOSITORY HAS BEEN ARCHIVED. THE TENDERMINT SPECIFICATION IS NOW LOCATED IN THE [TENDERMINT/TENDERMINT](https://github.com/tendermint/tendermint/tree/master/spec) REPOSITORY.** 9 | 10 | --- 11 | 12 | # Tendermint fork detection and IBC fork detection 13 | 14 | ## Status 15 | 16 | This is a work in progress. 17 | This directory captures the ongoing work and discussion on fork 18 | detection both in the context of a Tendermint light node and in the 19 | context of IBC. It contains the following files 20 | 21 | ### detection.md 22 | 23 | a draft of the light node fork detection including "proof of fork" 24 | definition, that is, the data structure to submit evidence to full 25 | nodes. 26 | 27 | ### [discussions.md](./discussions.md) 28 | 29 | A collection of ideas and intuitions from recent discussions 30 | 31 | - the outcome of recent discussion 32 | - a sketch of the light client supervisor to provide the context in 33 | which fork detection happens 34 | - a discussion about lightstore semantics 35 | 36 | ### [req-ibc-detection.md](./req-ibc-detection.md) 37 | 38 | - a collection of requirements for fork detection in the IBC 39 | context. In particular it contains a section "Required Changes in 40 | ICS 007" with necessary updates to ICS 007 to support Tendermint 41 | fork detection 42 | 43 | ### [draft-functions.md](./draft-functions.md) 44 | 45 | In order to address the collected requirements, we started to sketch 46 | some functions that we will need in the future when we specify in more 47 | detail the 48 | 49 | - fork detections 50 | - proof of fork generation 51 | - proof of fork verification 52 | 53 | on the following components. 54 | 55 | - IBC on-chain components 56 | - Relayer 57 | 58 | ### TODOs 59 | 60 | We decided to merge the files while there are still open points to 61 | address to record the current state an move forward. In particular, 62 | the following points need to be addressed: 63 | 64 | - 65 | 66 | - 67 | 68 | - 69 | 70 | - 71 | 72 | Most likely we will write a specification on the light client 73 | supervisor along the outcomes of 74 | 75 | - 76 | 77 | that also addresses initialization 78 | 79 | - 80 | -------------------------------------------------------------------------------- /spec/light-client/experiments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tendermint/spec/9d5734e21479dfc9c308f5630678c800d85a2067/spec/light-client/experiments.png -------------------------------------------------------------------------------- /spec/light-client/supervisor/supervisor_001_draft.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE supervisor_001_draft ------------------------ 2 | (* 3 | This is the beginning of a spec that will eventually use verification and detector API 4 | *) 5 | 6 | EXTENDS Integers, FiniteSets 7 | 8 | VARIABLES 9 | state, 10 | output 11 | 12 | vars == <> 13 | 14 | CONSTANT 15 | INITDATA 16 | 17 | Init == 18 | /\ state = "Init" 19 | /\ output = "none" 20 | 21 | NextInit == 22 | /\ state = "Init" 23 | /\ \/ state' = "EnterLoop" 24 | \/ state' = "FailedToInitialize" 25 | /\ UNCHANGED output 26 | 27 | NextVerifyToTarget == 28 | /\ state = "EnterLoop" 29 | /\ \/ state' = "EnterLoop" \* replace primary 30 | \/ state' = "EnterDetect" 31 | \/ state' = "ExhaustedPeersPrimary" 32 | /\ UNCHANGED output 33 | 34 | NextAttackDetector == 35 | /\ state = "EnterDetect" 36 | /\ \/ state' = "NoEvidence" 37 | \/ state' = "EvidenceFound" 38 | \/ state' = "ExhaustedPeersSecondaries" 39 | /\ UNCHANGED output 40 | 41 | NextVerifyAndDetect == 42 | \/ NextVerifyToTarget 43 | \/ NextAttackDetector 44 | 45 | NextOutput == 46 | /\ state = "NoEvidence" 47 | /\ state' = "EnterLoop" 48 | /\ output' = "data" \* to generate a trace 49 | 50 | NextTerminated == 51 | /\ \/ state = "FailedToInitialize" 52 | \/ state = "ExhaustedPeersPrimary" 53 | \/ state = "EvidenceFound" 54 | \/ state = "ExhaustedPeersSecondaries" 55 | /\ UNCHANGED vars 56 | 57 | Next == 58 | \/ NextInit 59 | \/ NextVerifyAndDetect 60 | \/ NextOutput 61 | \/ NextTerminated 62 | 63 | InvEnoughPeers == 64 | /\ state /= "ExhaustedPeersPrimary" 65 | /\ state /= "ExhaustedPeersSecondaries" 66 | 67 | 68 | ============================================================================= 69 | \* Modification History 70 | \* Last modified Sun Oct 18 11:48:45 CEST 2020 by widder 71 | \* Created Sun Oct 18 11:18:53 CEST 2020 by widder 72 | -------------------------------------------------------------------------------- /spec/light-client/supervisor/supervisor_002_draft.md: -------------------------------------------------------------------------------- 1 | # Draft of Light Client Supervisor for discussion 2 | 3 | ## Modification to the initialization 4 | 5 | The lightclient is initialized with LCInitData 6 | 7 | ### **[LC-DATA-INIT.2]** 8 | 9 | ```go 10 | type LCInitData struct { 11 | TrustedBlock LightBlock 12 | Genesis GenesisDoc 13 | TrustedHash []byte 14 | TrustedHeight int64 15 | } 16 | ``` 17 | 18 | where only one of the components must be provided. `GenesisDoc` is 19 | defined in the [Tendermint 20 | Types](https://github.com/tendermint/tendermint/blob/master/types/genesis.go). 21 | 22 | 23 | ### Initialization 24 | 25 | The light client is based on subjective initialization. It has to 26 | trust the initial data given to it by the user. It cannot perform any 27 | detection of an attack yet instead requires an initial point of trust. 28 | There are three forms of initial data which are used to obtain the 29 | first trusted block: 30 | 31 | - A trusted block from a prior initialization 32 | - A trusted height and hash 33 | - A genesis file 34 | 35 | The golang light client implementation checks this initial data in that 36 | order; first attempting to find a trusted block from the trusted store, 37 | then acquiring a light block from the primary at the trusted height and matching 38 | the hash, or finally checking for a genesis file to verify the initial header. 39 | 40 | The light client doesn't need to check if the trusted block is within the 41 | trusted period because it already trusts it, however, if the light block is 42 | outside the trust period, there is a higher chance the light client won't be 43 | able to verify anything. 44 | 45 | Cross-checking this trusted block with providers upon initialization is helpful 46 | for ensuring that the node is responsive and correctly configured but does not 47 | increase trust since proving a conflicting block is a 48 | [light client attack](https://github.com/tendermint/spec/blob/master/spec/light-client/detection/detection_003_reviewed.md#tmbc-lc-attack1) 49 | and not just a [bogus](https://github.com/tendermint/spec/blob/master/spec/light-client/detection/detection_003_reviewed.md#tmbc-bogus1) block could result in 50 | performing backwards verification beyond the trusted period, thus a fruitless 51 | endeavour. 52 | 53 | However, with the notion of it's better to fail earlier than later, the golang 54 | light client implementation will perform a consistency check on all providers 55 | and will error if one returns a different header, allowing the user 56 | the opportunity to reinitialize. 57 | 58 | #### **[LC-FUNC-INIT.2]:** 59 | 60 | ```go 61 | func InitLightClient(initData LCInitData) (LightStore, Error) { 62 | var initialBlock LightBlock 63 | 64 | switch { 65 | case LCInitData.TrustedBlock != nil: 66 | // we trust the block from a prior initialization 67 | initialBlock = LCInitData.TrustedBlock 68 | 69 | case LCInitData.TrustedHash != nil: 70 | untrustedBlock := FetchLightBlock(PeerList.Primary(), LCInitData.TrustedHeight) 71 | 72 | 73 | // verify that the hashes match 74 | if untrustedBlock.Hash() != LCInitData.TrustedHash { 75 | return nil, Error("Primary returned block with different hash") 76 | } 77 | // after checking the hash we now trust the block 78 | initialBlock = untrustedBlock 79 | } 80 | case LCInitData.Genesis != nil: 81 | untrustedBlock := FetchLightBlock(PeerList.Primary(), LCInitData.Genesis.InitialHeight) 82 | 83 | // verify that 2/3+ of the validator set signed the untrustedBlock 84 | if err := VerifyCommitFull(untrustedBlock.Commit, LCInitData.Genesis.Validators); err != nil { 85 | return nil, err 86 | } 87 | 88 | // we can now trust the block 89 | initialBlock = untrustedBlock 90 | default: 91 | return nil, Error("No initial data was provided") 92 | 93 | // This is done in the golang version but is optional and not strictly part of the protocol 94 | if err := CrossCheck(initialBlock, PeerList.Witnesses()); err != nil { 95 | return nil, err 96 | } 97 | 98 | // initialize light store 99 | lightStore := new LightStore; 100 | lightStore.Add(newBlock); 101 | return (lightStore, OK); 102 | } 103 | 104 | func CrossCheck(lb LightBlock, witnesses []Provider) error { 105 | for _, witness := range witnesses { 106 | witnessBlock := FetchLightBlock(witness, lb.Height) 107 | 108 | if witnessBlock.Hash() != lb.Hash() { 109 | return Error("Witness has different block") 110 | } 111 | } 112 | return OK 113 | } 114 | 115 | ``` 116 | 117 | - Implementation remark 118 | - none 119 | - Expected precondition 120 | - *LCInitData* contains either a genesis file of a lightblock 121 | - if genesis it passes `ValidateAndComplete()` see [Tendermint](https://informal.systems) 122 | - Expected postcondition 123 | - *lightStore* initialized with trusted lightblock. It has either been 124 | cross-checked (from genesis) or it has initial trust from the 125 | user. 126 | - Error condition 127 | - if precondition is violated 128 | - empty peerList 129 | 130 | ---- 131 | 132 | -------------------------------------------------------------------------------- /spec/light-client/verification/001bmc-apalache.csv: -------------------------------------------------------------------------------- 1 | no,filename,tool,timeout,init,inv,next,args 2 | 1,MC4_3_correct.tla,apalache,1h,,PositiveBeforeTrustedHeaderExpires,,--length=30 3 | 2,MC4_3_correct.tla,apalache,1h,,CorrectnessInv,,--length=30 4 | 3,MC4_3_correct.tla,apalache,1h,,PrecisionInv,,--length=30 5 | 4,MC4_3_correct.tla,apalache,1h,,SuccessOnCorrectPrimaryAndChainOfTrust,,--length=30 6 | 5,MC4_3_correct.tla,apalache,1h,,NoFailedBlocksOnSuccessInv,,--length=30 7 | 6,MC4_3_correct.tla,apalache,1h,,StoredHeadersAreVerifiedOrNotTrustedInv,,--length=30 8 | 7,MC4_3_correct.tla,apalache,1h,,CorrectPrimaryAndTimeliness,,--length=30 9 | 8,MC4_3_correct.tla,apalache,1h,,Complexity,,--length=30 10 | 9,MC4_3_faulty.tla,apalache,1h,,PositiveBeforeTrustedHeaderExpires,,--length=30 11 | 10,MC4_3_faulty.tla,apalache,1h,,CorrectnessInv,,--length=30 12 | 11,MC4_3_faulty.tla,apalache,1h,,PrecisionInv,,--length=30 13 | 12,MC4_3_faulty.tla,apalache,1h,,SuccessOnCorrectPrimaryAndChainOfTrust,,--length=30 14 | 13,MC4_3_faulty.tla,apalache,1h,,NoFailedBlocksOnSuccessInv,,--length=30 15 | 14,MC4_3_faulty.tla,apalache,1h,,StoredHeadersAreVerifiedOrNotTrustedInv,,--length=30 16 | 15,MC4_3_faulty.tla,apalache,1h,,CorrectPrimaryAndTimeliness,,--length=30 17 | 16,MC4_3_faulty.tla,apalache,1h,,Complexity,,--length=30 18 | 17,MC5_5_correct.tla,apalache,1h,,PositiveBeforeTrustedHeaderExpires,,--length=30 19 | 18,MC5_5_correct.tla,apalache,1h,,CorrectnessInv,,--length=30 20 | 19,MC5_5_correct.tla,apalache,1h,,PrecisionInv,,--length=30 21 | 20,MC5_5_correct.tla,apalache,1h,,SuccessOnCorrectPrimaryAndChainOfTrust,,--length=30 22 | 21,MC5_5_correct.tla,apalache,1h,,NoFailedBlocksOnSuccessInv,,--length=30 23 | 22,MC5_5_correct.tla,apalache,1h,,StoredHeadersAreVerifiedOrNotTrustedInv,,--length=30 24 | 23,MC5_5_correct.tla,apalache,1h,,CorrectPrimaryAndTimeliness,,--length=30 25 | 24,MC5_5_correct.tla,apalache,1h,,Complexity,,--length=30 26 | 25,MC5_5_faulty.tla,apalache,1h,,PositiveBeforeTrustedHeaderExpires,,--length=30 27 | 26,MC5_5_faulty.tla,apalache,1h,,CorrectnessInv,,--length=30 28 | 27,MC5_5_faulty.tla,apalache,1h,,PrecisionInv,,--length=30 29 | 28,MC5_5_faulty.tla,apalache,1h,,SuccessOnCorrectPrimaryAndChainOfTrust,,--length=30 30 | 29,MC5_5_faulty.tla,apalache,1h,,NoFailedBlocksOnSuccessInv,,--length=30 31 | 30,MC5_5_faulty.tla,apalache,1h,,StoredHeadersAreVerifiedOrNotTrustedInv,,--length=30 32 | 31,MC5_5_faulty.tla,apalache,1h,,CorrectPrimaryAndTimeliness,,--length=30 33 | 32,MC5_5_faulty.tla,apalache,1h,,Complexity,,--length=30 34 | 33,MC7_5_faulty.tla,apalache,10h,,PositiveBeforeTrustedHeaderExpires,,--length=30 35 | 34,MC7_5_faulty.tla,apalache,10h,,CorrectnessInv,,--length=30 36 | 35,MC7_5_faulty.tla,apalache,10h,,PrecisionInv,,--length=30 37 | 36,MC7_5_faulty.tla,apalache,10h,,SuccessOnCorrectPrimaryAndChainOfTrust,,--length=30 38 | 37,MC7_5_faulty.tla,apalache,10h,,NoFailedBlocksOnSuccessInv,,--length=30 39 | 38,MC7_5_faulty.tla,apalache,10h,,StoredHeadersAreVerifiedOrNotTrustedInv,,--length=30 40 | 39,MC7_5_faulty.tla,apalache,10h,,CorrectPrimaryAndTimeliness,,--length=30 41 | 40,MC7_5_faulty.tla,apalache,10h,,Complexity,,--length=30 42 | 41,MC4_7_faulty.tla,apalache,10h,,PositiveBeforeTrustedHeaderExpires,,--length=30 43 | 42,MC4_7_faulty.tla,apalache,10h,,CorrectnessInv,,--length=30 44 | 43,MC4_7_faulty.tla,apalache,10h,,PrecisionInv,,--length=30 45 | 44,MC4_7_faulty.tla,apalache,10h,,SuccessOnCorrectPrimaryAndChainOfTrust,,--length=30 46 | 45,MC4_7_faulty.tla,apalache,10h,,NoFailedBlocksOnSuccessInv,,--length=30 47 | 46,MC4_7_faulty.tla,apalache,10h,,StoredHeadersAreVerifiedOrNotTrustedInv,,--length=30 48 | 47,MC4_7_faulty.tla,apalache,10h,,CorrectPrimaryAndTimeliness,,--length=30 49 | 48,MC4_7_faulty.tla,apalache,10h,,Complexity,,--length=30 50 | -------------------------------------------------------------------------------- /spec/light-client/verification/002bmc-apalache-ok.csv: -------------------------------------------------------------------------------- 1 | no;filename;tool;timeout;init;inv;next;args 2 | 1;MC4_3_correct.tla;apalache;1h;;TargetHeightOnSuccessInv;;--length=5 3 | 2;MC4_3_correct.tla;apalache;1h;;StoredHeadersAreVerifiedOrNotTrustedInv;;--length=5 4 | 3;MC4_3_correct.tla;apalache;1h;;CorrectnessInv;;--length=5 5 | 4;MC4_3_correct.tla;apalache;1h;;NoTrustOnFaultyBlockInv;;--length=5 6 | 5;MC4_3_correct.tla;apalache;1h;;ProofOfChainOfTrustInv;;--length=5 7 | 6;MC4_3_correct.tla;apalache;1h;;NoFailedBlocksOnSuccessInv;;--length=5 8 | 7;MC4_3_correct.tla;apalache;1h;;Complexity;;--length=5 9 | 8;MC4_3_correct.tla;apalache;1h;;ApiPostInv;;--length=5 10 | 9;MC4_4_correct.tla;apalache;1h;;TargetHeightOnSuccessInv;;--length=7 11 | 10;MC4_4_correct.tla;apalache;1h;;CorrectnessInv;;--length=7 12 | 11;MC4_4_correct.tla;apalache;1h;;NoTrustOnFaultyBlockInv;;--length=7 13 | 12;MC4_4_correct.tla;apalache;1h;;ProofOfChainOfTrustInv;;--length=7 14 | 13;MC4_4_correct.tla;apalache;1h;;NoFailedBlocksOnSuccessInv;;--length=7 15 | 14;MC4_4_correct.tla;apalache;1h;;Complexity;;--length=7 16 | 15;MC4_4_correct.tla;apalache;1h;;ApiPostInv;;--length=7 17 | 16;MC4_5_correct.tla;apalache;1h;;TargetHeightOnSuccessInv;;--length=11 18 | 17;MC4_5_correct.tla;apalache;1h;;CorrectnessInv;;--length=11 19 | 18;MC4_5_correct.tla;apalache;1h;;NoTrustOnFaultyBlockInv;;--length=11 20 | 19;MC4_5_correct.tla;apalache;1h;;ProofOfChainOfTrustInv;;--length=11 21 | 20;MC4_5_correct.tla;apalache;1h;;NoFailedBlocksOnSuccessInv;;--length=11 22 | 21;MC4_5_correct.tla;apalache;1h;;Complexity;;--length=11 23 | 22;MC4_5_correct.tla;apalache;1h;;ApiPostInv;;--length=11 24 | 23;MC5_5_correct.tla;apalache;1h;;TargetHeightOnSuccessInv;;--length=11 25 | 24;MC5_5_correct.tla;apalache;1h;;CorrectnessInv;;--length=11 26 | 25;MC5_5_correct.tla;apalache;1h;;NoTrustOnFaultyBlockInv;;--length=11 27 | 26;MC5_5_correct.tla;apalache;1h;;ProofOfChainOfTrustInv;;--length=11 28 | 27;MC5_5_correct.tla;apalache;1h;;NoFailedBlocksOnSuccessInv;;--length=11 29 | 28;MC5_5_correct.tla;apalache;1h;;Complexity;;--length=11 30 | 29;MC5_5_correct.tla;apalache;1h;;ApiPostInv;;--length=11 31 | 30;MC4_3_faulty.tla;apalache;1h;;TargetHeightOnSuccessInv;;--length=5 32 | 31;MC4_3_faulty.tla;apalache;1h;;StoredHeadersAreVerifiedOrNotTrustedInv;;--length=5 33 | 32;MC4_3_faulty.tla;apalache;1h;;CorrectnessInv;;--length=5 34 | 33;MC4_3_faulty.tla;apalache;1h;;NoTrustOnFaultyBlockInv;;--length=5 35 | 34;MC4_3_faulty.tla;apalache;1h;;ProofOfChainOfTrustInv;;--length=5 36 | 35;MC4_3_faulty.tla;apalache;1h;;NoFailedBlocksOnSuccessInv;;--length=5 37 | 36;MC4_3_faulty.tla;apalache;1h;;Complexity;;--length=5 38 | 37;MC4_3_faulty.tla;apalache;1h;;ApiPostInv;;--length=5 39 | 38;MC4_4_faulty.tla;apalache;1h;;TargetHeightOnSuccessInv;;--length=7 40 | 39;MC4_4_faulty.tla;apalache;1h;;StoredHeadersAreVerifiedOrNotTrustedInv;;--length=7 41 | 40;MC4_4_faulty.tla;apalache;1h;;CorrectnessInv;;--length=7 42 | 41;MC4_4_faulty.tla;apalache;1h;;NoTrustOnFaultyBlockInv;;--length=7 43 | 42;MC4_4_faulty.tla;apalache;1h;;ProofOfChainOfTrustInv;;--length=7 44 | 43;MC4_4_faulty.tla;apalache;1h;;NoFailedBlocksOnSuccessInv;;--length=7 45 | 44;MC4_4_faulty.tla;apalache;1h;;Complexity;;--length=7 46 | 45;MC4_4_faulty.tla;apalache;1h;;ApiPostInv;;--length=7 47 | 46;MC4_5_faulty.tla;apalache;1h;;TargetHeightOnSuccessInv;;--length=11 48 | 47;MC4_5_faulty.tla;apalache;1h;;StoredHeadersAreVerifiedOrNotTrustedInv;;--length=11 49 | 48;MC4_5_faulty.tla;apalache;1h;;CorrectnessInv;;--length=11 50 | 49;MC4_5_faulty.tla;apalache;1h;;NoTrustOnFaultyBlockInv;;--length=11 51 | 50;MC4_5_faulty.tla;apalache;1h;;ProofOfChainOfTrustInv;;--length=11 52 | 51;MC4_5_faulty.tla;apalache;1h;;NoFailedBlocksOnSuccessInv;;--length=11 53 | 52;MC4_5_faulty.tla;apalache;1h;;Complexity;;--length=11 54 | 53;MC4_5_faulty.tla;apalache;1h;;ApiPostInv;;--length=11 55 | 56 | -------------------------------------------------------------------------------- /spec/light-client/verification/003bmc-apalache-error.csv: -------------------------------------------------------------------------------- 1 | no;filename;tool;timeout;init;inv;next;args 2 | 1;MC4_3_correct.tla;apalache;1h;;StoredHeadersAreVerifiedInv;;--length=5 3 | 2;MC4_3_correct.tla;apalache;1h;;PositiveBeforeTrustedHeaderExpires;;--length=5 4 | 3;MC4_3_correct.tla;apalache;1h;;CorrectPrimaryAndTimeliness;;--length=5 5 | 4;MC4_3_correct.tla;apalache;1h;;PrecisionInv;;--length=5 6 | 5;MC4_3_correct.tla;apalache;1h;;PrecisionBuggyInv;;--length=5 7 | 6;MC4_3_correct.tla;apalache;1h;;SuccessOnCorrectPrimaryAndChainOfTrustGlobal;;--length=5 8 | 7;MC4_3_correct.tla;apalache;1h;;SuccessOnCorrectPrimaryAndChainOfTrustLocal;;--length=5 9 | 8;MC4_4_correct.tla;apalache;1h;;StoredHeadersAreVerifiedInv;;--length=7 10 | 9;MC4_4_correct.tla;apalache;1h;;PositiveBeforeTrustedHeaderExpires;;--length=7 11 | 10;MC4_4_correct.tla;apalache;1h;;CorrectPrimaryAndTimeliness;;--length=7 12 | 11;MC4_4_correct.tla;apalache;1h;;PrecisionInv;;--length=7 13 | 12;MC4_4_correct.tla;apalache;1h;;PrecisionBuggyInv;;--length=7 14 | 13;MC4_4_correct.tla;apalache;1h;;SuccessOnCorrectPrimaryAndChainOfTrustGlobal;;--length=7 15 | 14;MC4_4_correct.tla;apalache;1h;;SuccessOnCorrectPrimaryAndChainOfTrustLocal;;--length=7 16 | 15;MC4_5_correct.tla;apalache;1h;;StoredHeadersAreVerifiedInv;;--length=11 17 | 16;MC4_5_correct.tla;apalache;1h;;PositiveBeforeTrustedHeaderExpires;;--length=11 18 | 17;MC4_5_correct.tla;apalache;1h;;CorrectPrimaryAndTimeliness;;--length=11 19 | 18;MC4_5_correct.tla;apalache;1h;;PrecisionInv;;--length=11 20 | 19;MC4_5_correct.tla;apalache;1h;;PrecisionBuggyInv;;--length=11 21 | 20;MC4_5_correct.tla;apalache;1h;;SuccessOnCorrectPrimaryAndChainOfTrustGlobal;;--length=11 22 | 21;MC4_5_correct.tla;apalache;1h;;SuccessOnCorrectPrimaryAndChainOfTrustLocal;;--length=11 23 | 22;MC4_5_correct.tla;apalache;1h;;StoredHeadersAreVerifiedOrNotTrustedInv;;--length=11 24 | 23;MC4_3_faulty.tla;apalache;1h;;StoredHeadersAreVerifiedInv;;--length=5 25 | 24;MC4_3_faulty.tla;apalache;1h;;PositiveBeforeTrustedHeaderExpires;;--length=5 26 | 25;MC4_3_faulty.tla;apalache;1h;;CorrectPrimaryAndTimeliness;;--length=5 27 | 26;MC4_3_faulty.tla;apalache;1h;;PrecisionInv;;--length=5 28 | 27;MC4_3_faulty.tla;apalache;1h;;PrecisionBuggyInv;;--length=5 29 | 28;MC4_3_faulty.tla;apalache;1h;;SuccessOnCorrectPrimaryAndChainOfTrustGlobal;;--length=5 30 | 29;MC4_3_faulty.tla;apalache;1h;;SuccessOnCorrectPrimaryAndChainOfTrustLocal;;--length=5 31 | 30;MC4_4_faulty.tla;apalache;1h;;StoredHeadersAreVerifiedInv;;--length=7 32 | 31;MC4_4_faulty.tla;apalache;1h;;PositiveBeforeTrustedHeaderExpires;;--length=7 33 | 32;MC4_4_faulty.tla;apalache;1h;;CorrectPrimaryAndTimeliness;;--length=7 34 | 33;MC4_4_faulty.tla;apalache;1h;;PrecisionInv;;--length=7 35 | 34;MC4_4_faulty.tla;apalache;1h;;PrecisionBuggyInv;;--length=7 36 | 35;MC4_4_faulty.tla;apalache;1h;;SuccessOnCorrectPrimaryAndChainOfTrustGlobal;;--length=7 37 | 36;MC4_4_faulty.tla;apalache;1h;;SuccessOnCorrectPrimaryAndChainOfTrustLocal;;--length=7 38 | 37;MC4_5_faulty.tla;apalache;1h;;StoredHeadersAreVerifiedInv;;--length=11 39 | 38;MC4_5_faulty.tla;apalache;1h;;PositiveBeforeTrustedHeaderExpires;;--length=11 40 | 39;MC4_5_faulty.tla;apalache;1h;;CorrectPrimaryAndTimeliness;;--length=11 41 | 40;MC4_5_faulty.tla;apalache;1h;;PrecisionInv;;--length=11 42 | 41;MC4_5_faulty.tla;apalache;1h;;PrecisionBuggyInv;;--length=11 43 | 42;MC4_5_faulty.tla;apalache;1h;;SuccessOnCorrectPrimaryAndChainOfTrustGlobal;;--length=11 44 | 43;MC4_5_faulty.tla;apalache;1h;;SuccessOnCorrectPrimaryAndChainOfTrustLocal;;--length=11 45 | 44;MC4_5_faulty.tla;apalache;1h;;StoredHeadersAreVerifiedOrNotTrustedInv;;--length=11 46 | -------------------------------------------------------------------------------- /spec/light-client/verification/004bmc-apalache-ok.csv: -------------------------------------------------------------------------------- 1 | no;filename;tool;timeout;init;inv;next;args 2 | 1;LCD_MC3_3_faulty.tla;apalache;1h;;CommonHeightOnEvidenceInv;;--length=10 3 | 2;LCD_MC3_3_faulty.tla;apalache;1h;;AccuracyInv;;--length=10 4 | 3;LCD_MC3_3_faulty.tla;apalache;1h;;PrecisionInvLocal;;--length=10 5 | 4;LCD_MC3_4_faulty.tla;apalache;1h;;CommonHeightOnEvidenceInv;;--length=10 6 | 5;LCD_MC3_4_faulty.tla;apalache;1h;;AccuracyInv;;--length=10 7 | 6;LCD_MC3_4_faulty.tla;apalache;1h;;PrecisionInvLocal;;--length=10 8 | 7;LCD_MC4_4_faulty.tla;apalache;1h;;CommonHeightOnEvidenceInv;;--length=10 9 | 8;LCD_MC4_4_faulty.tla;apalache;1h;;AccuracyInv;;--length=10 10 | 9;LCD_MC4_4_faulty.tla;apalache;1h;;PrecisionInvLocal;;--length=10 11 | -------------------------------------------------------------------------------- /spec/light-client/verification/005bmc-apalache-error.csv: -------------------------------------------------------------------------------- 1 | no;filename;tool;timeout;init;inv;next;args 2 | 1;LCD_MC3_3_faulty.tla;apalache;1h;;PrecisionInvGrayZone;;--length=10 3 | 2;LCD_MC3_4_faulty.tla;apalache;1h;;PrecisionInvGrayZone;;--length=10 4 | 3;LCD_MC4_4_faulty.tla;apalache;1h;;PrecisionInvGrayZone;;--length=10 5 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC4_3_correct.tla: -------------------------------------------------------------------------------- 1 | ---------------------------- MODULE MC4_3_correct --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 3 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == TRUE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================== 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC4_3_faulty.tla: -------------------------------------------------------------------------------- 1 | ---------------------------- MODULE MC4_3_faulty --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 3 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == FALSE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================== 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC4_4_correct.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE MC4_4_correct --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 4 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == TRUE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================ 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC4_4_correct_drifted.tla: -------------------------------------------------------------------------------- 1 | ---------------------- MODULE MC4_4_correct_drifted --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 4 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 30 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == TRUE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================== 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC4_4_faulty.tla: -------------------------------------------------------------------------------- 1 | ---------------------------- MODULE MC4_4_faulty --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 4 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == FALSE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================== 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC4_4_faulty_drifted.tla: -------------------------------------------------------------------------------- 1 | ---------------------- MODULE MC4_4_faulty_drifted --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 4 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 30 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == FALSE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================== 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC4_5_correct.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE MC4_5_correct --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 5 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == TRUE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================ 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC4_5_faulty.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE MC4_5_faulty --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 5 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | IS_PRICLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | MARY_CORRECT == FALSE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================ 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC4_6_faulty.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE MC4_6_faulty --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 6 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | IS_PRCLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IMARY_CORRECT == FALSE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================ 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC4_7_faulty.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE MC4_7_faulty --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 7 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == FALSE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================ 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC5_5_correct.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE MC5_5_correct --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4", "n5"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 5 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == TRUE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================ 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC5_5_correct_peer_two_thirds_faulty.tla: -------------------------------------------------------------------------------- 1 | ------------------- MODULE MC5_5_correct_peer_two_thirds_faulty ---------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4", "n5"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 5 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == TRUE 10 | FAULTY_RATIO == <<2, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================ 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC5_5_faulty.tla: -------------------------------------------------------------------------------- 1 | ----------------- MODULE MC5_5_faulty --------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4", "n5"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 5 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == FALSE 10 | FAULTY_RATIO == <<2, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================ 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC5_5_faulty_peer_two_thirds_faulty.tla: -------------------------------------------------------------------------------- 1 | ----------------- MODULE MC5_5_faulty_peer_two_thirds_faulty --------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4", "n5"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 5 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == FALSE 10 | FAULTY_RATIO == <<2, 3>> \* < 2 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================ 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC5_7_faulty.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE MC5_7_faulty --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4", "n5"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 7 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == FALSE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================ 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC7_5_faulty.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE MC7_5_faulty --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4", "n5", "n6", "n7"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 5 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == FALSE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================ 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/MC7_7_faulty.tla: -------------------------------------------------------------------------------- 1 | ------------------------- MODULE MC7_7_faulty --------------------------- 2 | 3 | AllNodes == {"n1", "n2", "n3", "n4", "n5", "n6", "n7"} 4 | TRUSTED_HEIGHT == 1 5 | TARGET_HEIGHT == 7 6 | TRUSTING_PERIOD == 1400 \* two weeks, one day is 100 time units :-) 7 | CLOCK_DRIFT == 10 \* how much we assume the local clock is drifting 8 | REAL_CLOCK_DRIFT == 3 \* how much the local clock is actually drifting 9 | IS_PRIMARY_CORRECT == FALSE 10 | FAULTY_RATIO == <<1, 3>> \* < 1 / 3 faulty validators 11 | 12 | VARIABLES 13 | state, nextHeight, fetchedLightBlocks, lightBlockStatus, latestVerified, 14 | nprobes, 15 | localClock, 16 | refClock, blockchain, Faulty 17 | 18 | (* the light client previous state components, used for monitoring *) 19 | VARIABLES 20 | prevVerified, 21 | prevCurrent, 22 | prevLocalClock, 23 | prevVerdict 24 | 25 | INSTANCE Lightclient_003_draft 26 | ============================================================================ 27 | -------------------------------------------------------------------------------- /spec/light-client/verification/verification_003_draft.md: -------------------------------------------------------------------------------- 1 | # Light Client Verificaiton 2 | 3 | #### **[LCV-FUNC-VERIFYCOMMITLIGHT.1]** 4 | 5 | VerifyCommitLight verifies that 2/3+ of the signatures for a validator set were for 6 | a given blockID. The function will finish early and thus may not check all signatures. 7 | 8 | ```go 9 | func VerifyCommitLight(chainID string, vals *ValidatorSet, blockID BlockID, 10 | height int64, commit *Commit) error { 11 | // run a basic validation of the arguments 12 | if err := verifyBasicValsAndCommit(vals, commit, height, blockID); err != nil { 13 | return err 14 | } 15 | 16 | // calculate voting power needed 17 | votingPowerNeeded := vals.TotalVotingPower() * 2 / 3 18 | 19 | var ( 20 | val *Validator 21 | valIdx int32 22 | seenVals = make(map[int32]int, len(commit.Signatures)) 23 | talliedVotingPower int64 = 0 24 | voteSignBytes []byte 25 | ) 26 | for idx, commitSig := range commit.Signatures { 27 | // ignore all commit signatures that are not for the block 28 | if !commitSig.ForBlock() { 29 | continue 30 | } 31 | 32 | // If the vals and commit have a 1-to-1 correspondance we can retrieve 33 | // them by index else we need to retrieve them by address 34 | if lookUpByIndex { 35 | val = vals.Validators[idx] 36 | } else { 37 | valIdx, val = vals.GetByAddress(commitSig.ValidatorAddress) 38 | 39 | // if the signature doesn't belong to anyone in the validator set 40 | // then we just skip over it 41 | if val == nil { 42 | continue 43 | } 44 | 45 | // because we are getting validators by address we need to make sure 46 | // that the same validator doesn't commit twice 47 | if firstIndex, ok := seenVals[valIdx]; ok { 48 | secondIndex := idx 49 | return fmt.Errorf("double vote from %v (%d and %d)", val, firstIndex, secondIndex) 50 | } 51 | seenVals[valIdx] = idx 52 | } 53 | 54 | voteSignBytes = commit.VoteSignBytes(chainID, int32(idx)) 55 | 56 | if !val.PubKey.VerifySignature(voteSignBytes, commitSig.Signature) { 57 | return fmt.Errorf("wrong signature (#%d): %X", idx, commitSig.Signature) 58 | } 59 | 60 | // Add the voting power of the validator 61 | // to the tally 62 | talliedVotingPower += val.VotingPower 63 | 64 | // check if we have enough signatures and can thus exit early 65 | if talliedVotingPower > votingPowerNeeded { 66 | return nil 67 | } 68 | } 69 | 70 | if got, needed := talliedVotingPower, votingPowerNeeded; got <= needed { 71 | return ErrNotEnoughVotingPowerSigned{Got: got, Needed: needed} 72 | } 73 | 74 | return nil 75 | } 76 | ``` -------------------------------------------------------------------------------- /spec/p2p/config.md: -------------------------------------------------------------------------------- 1 | # P2P Config 2 | 3 | Here we describe configuration options around the Peer Exchange. 4 | These can be set using flags or via the `$TMHOME/config/config.toml` file. 5 | 6 | ## Seed Mode 7 | 8 | `--p2p.seed_mode` 9 | 10 | The node operates in seed mode. In seed mode, a node continuously crawls the network for peers, 11 | and upon incoming connection shares some peers and disconnects. 12 | 13 | ## Seeds 14 | 15 | `--p2p.seeds “id100000000000000000000000000000000@1.2.3.4:26656,id200000000000000000000000000000000@2.3.4.5:4444”` 16 | 17 | Dials these seeds when we need more peers. They should return a list of peers and then disconnect. 18 | If we already have enough peers in the address book, we may never need to dial them. 19 | 20 | ## Persistent Peers 21 | 22 | `--p2p.persistent_peers “id100000000000000000000000000000000@1.2.3.4:26656,id200000000000000000000000000000000@2.3.4.5:26656”` 23 | 24 | Dial these peers and auto-redial them if the connection fails. 25 | These are intended to be trusted persistent peers that can help 26 | anchor us in the p2p network. The auto-redial uses exponential 27 | backoff and will give up after a day of trying to connect. 28 | 29 | But If `persistent_peers_max_dial_period` is set greater than zero, 30 | pause between each dial to each persistent peer will not exceed `persistent_peers_max_dial_period` 31 | during exponential backoff and we keep trying again without giving up 32 | 33 | **Note:** If `seeds` and `persistent_peers` intersect, 34 | the user will be warned that seeds may auto-close connections 35 | and that the node may not be able to keep the connection persistent. 36 | 37 | ## Private Peers 38 | 39 | `--p2p.private_peer_ids “id100000000000000000000000000000000,id200000000000000000000000000000000”` 40 | 41 | These are IDs of the peers that we do not add to the address book or gossip to 42 | other peers. They stay private to us. 43 | 44 | ## Unconditional Peers 45 | 46 | `--p2p.unconditional_peer_ids “id100000000000000000000000000000000,id200000000000000000000000000000000”` 47 | 48 | These are IDs of the peers which are allowed to be connected by both inbound or outbound regardless of 49 | `max_num_inbound_peers` or `max_num_outbound_peers` of user's node reached or not. 50 | -------------------------------------------------------------------------------- /spec/p2p/connection.md: -------------------------------------------------------------------------------- 1 | # P2P Multiplex Connection 2 | 3 | ## MConnection 4 | 5 | `MConnection` is a multiplex connection that supports multiple independent streams 6 | with distinct quality of service guarantees atop a single TCP connection. 7 | Each stream is known as a `Channel` and each `Channel` has a globally unique _byte id_. 8 | Each `Channel` also has a relative priority that determines the quality of service 9 | of the `Channel` compared to other `Channel`s. 10 | The _byte id_ and the relative priorities of each `Channel` are configured upon 11 | initialization of the connection. 12 | 13 | The `MConnection` supports three packet types: 14 | 15 | - Ping 16 | - Pong 17 | - Msg 18 | 19 | ### Ping and Pong 20 | 21 | The ping and pong messages consist of writing a single byte to the connection; 0x1 and 0x2, respectively. 22 | 23 | When we haven't received any messages on an `MConnection` in time `pingTimeout`, we send a ping message. 24 | When a ping is received on the `MConnection`, a pong is sent in response only if there are no other messages 25 | to send and the peer has not sent us too many pings (TODO). 26 | 27 | If a pong or message is not received in sufficient time after a ping, the peer is disconnected from. 28 | 29 | ### Msg 30 | 31 | Messages in channels are chopped into smaller `msgPacket`s for multiplexing. 32 | 33 | ```go 34 | type msgPacket struct { 35 | ChannelID byte 36 | EOF byte // 1 means message ends here. 37 | Bytes []byte 38 | } 39 | ``` 40 | 41 | The `msgPacket` is serialized using [Proto3](https://developers.google.com/protocol-buffers/docs/proto3). 42 | The received `Bytes` of a sequential set of packets are appended together 43 | until a packet with `EOF=1` is received, then the complete serialized message 44 | is returned for processing by the `onReceive` function of the corresponding channel. 45 | 46 | ### Multiplexing 47 | 48 | Messages are sent from a single `sendRoutine`, which loops over a select statement and results in the sending 49 | of a ping, a pong, or a batch of data messages. The batch of data messages may include messages from multiple channels. 50 | Message bytes are queued for sending in their respective channel, with each channel holding one unsent message at a time. 51 | Messages are chosen for a batch one at a time from the channel with the lowest ratio of recently sent bytes to channel priority. 52 | 53 | ## Sending Messages 54 | 55 | There are two methods for sending messages: 56 | 57 | ```go 58 | func (m MConnection) Send(chID byte, msg interface{}) bool {} 59 | func (m MConnection) TrySend(chID byte, msg interface{}) bool {} 60 | ``` 61 | 62 | `Send(chID, msg)` is a blocking call that waits until `msg` is successfully queued 63 | for the channel with the given id byte `chID`. The message `msg` is serialized 64 | using the `tendermint/go-amino` submodule's `WriteBinary()` reflection routine. 65 | 66 | `TrySend(chID, msg)` is a nonblocking call that queues the message msg in the channel 67 | with the given id byte chID if the queue is not full; otherwise it returns false immediately. 68 | 69 | `Send()` and `TrySend()` are also exposed for each `Peer`. 70 | 71 | ## Peer 72 | 73 | Each peer has one `MConnection` instance, and includes other information such as whether the connection 74 | was outbound, whether the connection should be recreated if it closes, various identity information about the node, 75 | and other higher level thread-safe data used by the reactors. 76 | 77 | ## Switch/Reactor 78 | 79 | The `Switch` handles peer connections and exposes an API to receive incoming messages 80 | on `Reactors`. Each `Reactor` is responsible for handling incoming messages of one 81 | or more `Channels`. So while sending outgoing messages is typically performed on the peer, 82 | incoming messages are received on the reactor. 83 | 84 | ```go 85 | // Declare a MyReactor reactor that handles messages on MyChannelID. 86 | type MyReactor struct{} 87 | 88 | func (reactor MyReactor) GetChannels() []*ChannelDescriptor { 89 | return []*ChannelDescriptor{ChannelDescriptor{ID:MyChannelID, Priority: 1}} 90 | } 91 | 92 | func (reactor MyReactor) Receive(chID byte, peer *Peer, msgBytes []byte) { 93 | r, n, err := bytes.NewBuffer(msgBytes), new(int64), new(error) 94 | msgString := ReadString(r, n, err) 95 | fmt.Println(msgString) 96 | } 97 | 98 | // Other Reactor methods omitted for brevity 99 | ... 100 | 101 | switch := NewSwitch([]Reactor{MyReactor{}}) 102 | 103 | ... 104 | 105 | // Send a random message to all outbound connections 106 | for _, peer := range switch.Peers().List() { 107 | if peer.IsOutbound() { 108 | peer.Send(MyChannelID, "Here's a random message") 109 | } 110 | } 111 | ``` 112 | -------------------------------------------------------------------------------- /spec/p2p/messages/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | parent: 4 | title: Messages 5 | order: 1 6 | --- 7 | 8 | # Messages 9 | 10 | An implementation of the spec consists of many components. While many parts of these components are implementation specific, the p2p messages are not. In this section we will be covering all the p2p messages of components. 11 | 12 | There are two parts to the P2P messages, the message and the channel. The channel is message specific and messages are specific to components of Tendermint. When a node connect to a peer it will tell the other node which channels are available. This notifies the peer what services the connecting node offers. You can read more on channels in [connection.md](../connection.md#mconnection) 13 | 14 | - [Block Sync](./block-sync.md) 15 | - [Mempool](./mempool.md) 16 | - [Evidence](./evidence.md) 17 | - [State Sync](./state-sync.md) 18 | - [Pex](./pex.md) 19 | - [Consensus](./consensus.md) 20 | -------------------------------------------------------------------------------- /spec/p2p/messages/block-sync.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 2 3 | --- 4 | 5 | # Block Sync 6 | 7 | ## Channel 8 | 9 | Block sync has one channel. 10 | 11 | | Name | Number | 12 | |-------------------|--------| 13 | | BlockchainChannel | 64 | 14 | 15 | ## Message Types 16 | 17 | There are multiple message types for Block Sync 18 | 19 | ### BlockRequest 20 | 21 | BlockRequest asks a peer for a block at the height specified. 22 | 23 | | Name | Type | Description | Field Number | 24 | |--------|-------|---------------------------|--------------| 25 | | Height | int64 | Height of requested block | 1 | 26 | 27 | ### NoBlockResponse 28 | 29 | NoBlockResponse notifies the peer requesting a block that the node does not contain it. 30 | 31 | | Name | Type | Description | Field Number | 32 | |--------|-------|---------------------------|--------------| 33 | | Height | int64 | Height of requested block | 1 | 34 | 35 | ### BlockResponse 36 | 37 | BlockResponse contains the block requested. 38 | 39 | | Name | Type | Description | Field Number | 40 | |-------|----------------------------------------------|-----------------|--------------| 41 | | Block | [Block](../../core/data_structures.md#block) | Requested Block | 1 | 42 | 43 | ### StatusRequest 44 | 45 | StatusRequest is an empty message that notifies the peer to respond with the highest and lowest blocks it has stored. 46 | 47 | > Empty message. 48 | 49 | ### StatusResponse 50 | 51 | StatusResponse responds to a peer with the highest and lowest block stored. 52 | 53 | | Name | Type | Description | Field Number | 54 | |--------|-------|-------------------------------------------------------------------|--------------| 55 | | Height | int64 | Current Height of a node | 1 | 56 | | base | int64 | First known block, if pruning is enabled it will be higher than 1 | 1 | 57 | 58 | ### Message 59 | 60 | Message is a [`oneof` protobuf type](https://developers.google.com/protocol-buffers/docs/proto#oneof). The `oneof` consists of five messages. 61 | 62 | | Name | Type | Description | Field Number | 63 | |-------------------|----------------------------------|--------------------------------------------------------------|--------------| 64 | | block_request | [BlockRequest](#blockrequest) | Request a block from a peer | 1 | 65 | | no_block_response | [NoBlockResponse](#noblockresponse) | Response saying it doe snot have the requested block | 2 | 66 | | block_response | [BlockResponse](#blockresponse) | Response with requested block | 3 | 67 | | status_request | [StatusRequest](#statusrequest) | Request the highest and lowest block numbers from a peer | 4 | 68 | | status_response | [StatusResponse](#statusresponse) | Response with the highest and lowest block numbers the store | 5 | 69 | -------------------------------------------------------------------------------- /spec/p2p/messages/evidence.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 3 3 | --- 4 | 5 | # Evidence 6 | 7 | ## Channel 8 | 9 | Evidence has one channel. The channel identifier is listed below. 10 | 11 | | Name | Number | 12 | |-----------------|--------| 13 | | EvidenceChannel | 56 | 14 | 15 | ## Message Types 16 | 17 | ### Evidence 18 | 19 | Verified evidence that has already been propagated throughout the network. This evidence will appear within the EvidenceList struct of a [block](../../core/data_structures.md#block) as well. 20 | 21 | | Name | Type | Description | Field Number | 22 | |----------|-------------------------------------------------------------|------------------------|--------------| 23 | | evidence | [Evidence](../../core/data_structures.md#evidence) | Valid evidence | 1 | 24 | -------------------------------------------------------------------------------- /spec/p2p/messages/mempool.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 4 3 | --- 4 | # Mempool 5 | 6 | ## Channel 7 | 8 | Mempool has one channel. The channel identifier is listed below. 9 | 10 | | Name | Number | 11 | |----------------|--------| 12 | | MempoolChannel | 48 | 13 | 14 | ## Message Types 15 | 16 | There is currently only one message that Mempool broadcasts and receives over 17 | the p2p gossip network (via the reactor): `TxsMessage` 18 | 19 | ### Txs 20 | 21 | A list of transactions. These transactions have been checked against the application for validity. This does not mean that the transactions are valid, it is up to the application to check this. 22 | 23 | | Name | Type | Description | Field Number | 24 | |------|----------------|----------------------|--------------| 25 | | txs | repeated bytes | List of transactions | 1 | 26 | 27 | ### Message 28 | 29 | Message is a [`oneof` protobuf type](https://developers.google.com/protocol-buffers/docs/proto#oneof). The one of consists of one message [`Txs`](#txs). 30 | 31 | | Name | Type | Description | Field Number | 32 | |------|-------------|-----------------------|--------------| 33 | | txs | [Txs](#txs) | List of transactions | 1 | 34 | -------------------------------------------------------------------------------- /spec/p2p/messages/pex.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 6 3 | --- 4 | 5 | # Peer Exchange 6 | 7 | ## Channels 8 | 9 | Pex has one channel. The channel identifier is listed below. 10 | 11 | | Name | Number | 12 | |------------|--------| 13 | | PexChannel | 0 | 14 | 15 | ## Message Types 16 | 17 | ### PexRequest 18 | 19 | PexRequest is an empty message requesting a list of peers. 20 | 21 | > EmptyRequest 22 | 23 | ### PexResponse 24 | 25 | PexResponse is an list of net addresses provided to a peer to dial. 26 | 27 | | Name | Type | Description | Field Number | 28 | |-------|------------------------------------|------------------------------------------|--------------| 29 | | addresses | repeated [PexAddress](#PexAddress) | List of peer addresses available to dial | 1 | 30 | 31 | ### PexAddress 32 | 33 | PexAddress provides needed information for a node to dial a peer. This is in the form of a `URL` that gets parsed 34 | into a `NodeAddress`. See [ParseNodeAddress](https://github.com/tendermint/tendermint/blob/f2a8f5e054cf99ebe246818bb6d71f41f9a30faa/internal/p2p/address.go#L43) for more details. 35 | 36 | | Name | Type | Description | Field Number | 37 | |------|--------|------------------|--------------| 38 | | url | string | See [golang url](https://golang.org/pkg/net/url/#URL) | 1 | 39 | 40 | ### Message 41 | 42 | Message is a [`oneof` protobuf type](https://developers.google.com/protocol-buffers/docs/proto#oneof). The one of consists of two messages. 43 | 44 | | Name | Type | Description | Field Number | 45 | |--------------|---------------------------|------------------------------------------------------|--------------| 46 | | pex_request | [PexRequest](#PexRequest) | Empty request asking for a list of addresses to dial | 3 | 47 | | pex_response | [PexResponse](#PexResponse) | List of addresses to dial | 4 | 48 | -------------------------------------------------------------------------------- /spec/p2p/node.md: -------------------------------------------------------------------------------- 1 | **THIS REPOSITORY HAS BEEN ARCHIVED. THE TENDERMINT SPECIFICATION IS NOW LOCATED IN THE [TENDERMINT/TENDERMINT](https://github.com/tendermint/tendermint/tree/master/spec) REPOSITORY.** 2 | 3 | --- 4 | 5 | # Peer Discovery 6 | 7 | A Tendermint P2P network has different kinds of nodes with different requirements for connectivity to one another. 8 | This document describes what kind of nodes Tendermint should enable and how they should work. 9 | 10 | ## Seeds 11 | 12 | Seeds are the first point of contact for a new node. 13 | They return a list of known active peers and then disconnect. 14 | 15 | Seeds should operate full nodes with the PEX reactor in a "crawler" mode 16 | that continuously explores to validate the availability of peers. 17 | 18 | Seeds should only respond with some top percentile of the best peers it knows about. 19 | 20 | ## New Full Node 21 | 22 | A new node needs a few things to connect to the network: 23 | 24 | - a list of seeds, which can be provided to Tendermint via config file or flags, 25 | or hardcoded into the software by in-process apps 26 | - a `ChainID`, also called `Network` at the p2p layer 27 | - a recent block height, H, and hash, HASH for the blockchain. 28 | 29 | The values `H` and `HASH` must be received and corroborated by means external to Tendermint, and specific to the user - ie. via the user's trusted social consensus. 30 | This requirement to validate `H` and `HASH` out-of-band and via social consensus 31 | is the essential difference in security models between Proof-of-Work and Proof-of-Stake blockchains. 32 | 33 | With the above, the node then queries some seeds for peers for its chain, 34 | dials those peers, and runs the Tendermint protocols with those it successfully connects to. 35 | 36 | When the peer catches up to height H, it ensures the block hash matches HASH. 37 | If not, Tendermint will exit, and the user must try again - either they are connected 38 | to bad peers or their social consensus is invalid. 39 | 40 | ## Restarted Full Node 41 | 42 | A node checks its address book on startup and attempts to connect to peers from there. 43 | If it can't connect to any peers after some time, it falls back to the seeds to find more. 44 | 45 | Restarted full nodes can run the `blockchain` or `consensus` reactor protocols to sync up 46 | to the latest state of the blockchain from wherever they were last. 47 | In a Proof-of-Stake context, if they are sufficiently far behind (greater than the length 48 | of the unbonding period), they will need to validate a recent `H` and `HASH` out-of-band again 49 | so they know they have synced the correct chain. 50 | 51 | ## Validator Node 52 | 53 | A validator node is a node that interfaces with a validator signing key. 54 | These nodes require the highest security, and should not accept incoming connections. 55 | They should maintain outgoing connections to a controlled set of "Sentry Nodes" that serve 56 | as their proxy shield to the rest of the network. 57 | 58 | Validators that know and trust each other can accept incoming connections from one another and maintain direct private connectivity via VPN. 59 | 60 | ## Sentry Node 61 | 62 | Sentry nodes are guardians of a validator node and provide it access to the rest of the network. 63 | They should be well connected to other full nodes on the network. 64 | Sentry nodes may be dynamic, but should maintain persistent connections to some evolving random subset of each other. 65 | They should always expect to have direct incoming connections from the validator node and its backup(s). 66 | They do not report the validator node's address in the PEX and 67 | they may be more strict about the quality of peers they keep. 68 | 69 | Sentry nodes belonging to validators that trust each other may wish to maintain persistent connections via VPN with one another, but only report each other sparingly in the PEX. 70 | -------------------------------------------------------------------------------- /spec/p2p/readme.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | parent: 4 | title: P2P 5 | order: 6 6 | --- 7 | --------------------------------------------------------------------------------